Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C19 - Amber Shay #112

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
116 changes: 112 additions & 4 deletions adagrams/game.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,119 @@
"""Adagrams: It's really scrabble"""

import random

LETTER_POOL = {
'A': 9,
'B': 2,
'C': 2,
'D': 4,
'E': 12,
'F': 2,
'G': 3,
'H': 2,
'I': 9,
'J': 1,
'K': 1,
'L': 4,
'M': 2,
'N': 6,
'O': 8,
'P': 2,
'Q': 1,
'R': 6,
'S': 4,
'T': 6,
'U': 4,
'V': 2,
'W': 2,
'X': 1,
'Y': 2,
'Z': 1
}

letter_value = {
1: ['A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T'],
2: ['D', 'G'],
3: ['B', 'C', 'M', 'P'],
4: ['F', 'H', 'V', 'W', 'Y'],
5: ['K'],
8: ['J', 'X'],
10: ['Q', 'Z']
}


def draw_letters():
pass
"""Output a list of ten strings, where each string is a letter of
len(1) as defined in LETTER_POOL."""

letter_pool_copy = LETTER_POOL.copy()
letters = []

while len(letters) < 10:
letter_key = random.choice(list(letter_pool_copy.keys()))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice idea! One thing to consider: should each letter have the same probability of being chosen, though? For example, should "Z" have a probability of 1 in 26 or 1 in 98 (the total amount of tiles that can be drawn)?

How could we represent that in a data structure? Maybe a list of all tiles and their duplicates (ie, ['A','A','A','B','B'] and so on) to randomly choose from.

A more advanced solution might be using the random.choice method, but with more than one param. Here's an example of how you can "weigh" your string or list: https://www.geeksforgeeks.org/how-to-get-weighted-random-choice-in-python/

if letter_pool_copy[letter_key] != 0:
letter_pool_copy[letter_key] -= 1
letters.append(letter_key)

return letters


def uses_available_letters(word, letter_bank):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works fine! We've only just talked about Big O and time/space complexity, but one thing to notice here is we have a 3 nested for loops, even if we haven't explicitly stated for___ in ___ three times.

The remove method loops through letter_bank_case and if letter in letter_bank_case loops under the hood. Nothing wrong with 2 nested for loops. At times they are the easier solution. But! we have 3 here, and a dictionary of letters counted from the letter_bank_case would help us here.

How might we create a "frequency map" (a dictionary of items counted) with a constant lookup (O(1)) of letters found in letter_bank_case, then use it to check if all those letters are in the word?

pass
"""Each letter in the word 1) is not case-sensitive and 2) is not
utilized more than the available frequency outlined in LETTER_POOL."""

letter_bank_copy = letter_bank.copy()
letter_bank_case = [element.upper() for element in letter_bank_copy]
Comment on lines +65 to +66

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider combining these into one! Line 65 is not making a true copy of letter_bank. copy makes a "shallow" copy that still points to the original reference IDs of the items inside the list. Let's refactor line 66 a bit:

    letter_bank_copy = [element.upper() for element in letter_bank.deepcopy()]

This would now make a "deep" copy of each value in the list, and then convert each value to its uppercase in memory,.


for letter in word.upper():
letter.upper()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need this a second time. The letter value will be uppercase already because of word.upper()

Suggested change
letter.upper()

if letter in letter_bank_case:
letter_bank_case.remove(letter)
else:
return False

return True


def score_word(word):

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here again we've got 3 nested loops. Let's refactor the letter_value dictionary so that each letter is its own key. Is there some overhead setting that up? Yes. But it would also let us look up a letter's score in "constant" time (letter in score_dict) rather than iterating through an entire list, which is "linear" time (O(n)) (letter in ['A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T']).

Again, we only just discussed time complexity and Big O, but that's a brief explanation as to why a dictionary is a beneficial data structure we can use to hold data that needs to be frequently looked up.

pass
"""Assign point value to the word as outlined in letter_value."""

current_score = 0
for letter in word:
letter = letter.upper()
Comment on lines +82 to +83

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's combine these lines:

for letter in word.upper():

for key, val in letter_value.items():
if letter in val:
current_score += key
if 6 < len(word) <= 10:
current_score += 8

return current_score


def get_highest_word_score(word_list):
pass
"""Return the highest scoring word. For ties: the first
10-letter word wins. If there are no 10-letter words, the
shortest word wins."""

highest_score = 0
winning_word = ""

for word in word_list:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Your conditional statements are well organized and easy to read! Good job!

score = score_word(word)
print(f'word: {word}, score: {score}')

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget to remove any print statements that are for debugging purposes when you submit a final project!

Suggested change
print(f'word: {word}, score: {score}')

if score > highest_score:
if len(word) == 10:
highest_score = score
winning_word = word
elif len(word) < 10 and len(winning_word) != 10:
highest_score = score
winning_word = word
elif score == highest_score:
if len(word) == 10 and len(winning_word) != 10:
highest_score = score
winning_word = word
elif len(winning_word) != 10 and len(word) < 10 and len(word) < len(winning_word):
highest_score = score
winning_word = word

return (winning_word, highest_score)