Skip to content

Dragonfly - Sno Ochoa #33

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open

Dragonfly - Sno Ochoa #33

wants to merge 2 commits into from

Conversation

ra-choa
Copy link

@ra-choa ra-choa commented Mar 21, 2025

I understand that wave 04 function could be made DRI, if possible, could I receive specific direction/ feedback to help condense that code section? Thank you!

Copy link

@mikellewade mikellewade left a comment

Choose a reason for hiding this comment

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

Nice work on Adagrams, Sno!

Comment on lines +3 to +16
LETTER_POOL = ["A", "A", "A", "A", "A", "A", "A", "A", "A", "B", "B",
"C", "C", "D", "D", "D", "D",
"E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E", "E",
"F", "F", "G", "G", "G", "H", "H",
"I", "I", "I", "I", "I", "I", "I", "I", "I",
"J", "K", "L", "L", "L", "L",
"M", "M", "N", "N", "N", "N", "N", "N",
"O", "O", "O", "O", "O", "O", "O", "O",
"P", "P", "Q",
"R", "R", "R", "R", "R", "R",
"S", "S", "S", "S",
"T", "T", "T", "T", "T", "T",
"U", "U", "U", "U", "V", "V",
"W", "W", "X", "Y", "Y", "Z"]

Choose a reason for hiding this comment

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

Though this is functionally sound, let's think about the maintainability of this. Imagine if the client asked you to change the weights of 6 random letters. With this set up we are more likely to make some errors in the count. We should to go for a data structure that is more maintainable like a dictionary. We could store the letters as keys and their weights associated values. It could look like this:

LETTER_DICT = {
	    "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
	}

With this we could then use some looping to iterate over the dictionary to get an dynamically build LETTER_POOL.

Choose a reason for hiding this comment

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

Also something to consider when making constant variable, and variables in general, is the scope. The larger the scope the more functions and operations have access to them. This can create more chances for them to unintentionally changed. So, a question I tend to ask myself is "what needs access to the variable I am about to create?".

Comment on lines +18 to +45
SCORE_CHART = {
"A" : 1,
"E" : 1,
"I" : 1,
"O" : 1,
"U" : 1,
"L" : 1,
"N" : 1,
"R" : 1,
"S" : 1,
"T" : 1,
"D" : 2,
"G" : 2,
"B" : 3,
"C" : 3,
"M" : 3,
"P" : 3,
"F" : 4,
"H" : 4,
"V" : 4,
"W" : 4,
"Y" : 4,
"K" : 5,
"J" : 8,
"X" : 8,
"Q" :10,
"Z" :10
}
Copy link

@mikellewade mikellewade Mar 26, 2025

Choose a reason for hiding this comment

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

I would condense this to a few lines that way our codebase could look a more uniform since we did LETTER_POOL like this.

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

def draw_letters():
pass
tile_hand = []
LETTER_POOL_copy = LETTER_POOL.copy()

Choose a reason for hiding this comment

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

Since this variable is now being altered and modified we no longer need to use the python convention of naming constant variables.

Suggested change
LETTER_POOL_copy = LETTER_POOL.copy()
letter_pool_copy = LETTER_POOL.copy()

tile_hand = []
LETTER_POOL_copy = LETTER_POOL.copy()
while len(tile_hand) < 10:
index = randint(0,len(LETTER_POOL_copy) -1)

Choose a reason for hiding this comment

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

Operators like - should be surrounded with white spaces. Take a look at the PEP8 style guide on white spaces. In industry, code that doesn't follow an agreed upon code styles will need to be revised to ensure the codebase is neat and consistent.

Suggested change
index = randint(0,len(LETTER_POOL_copy) -1)
index = randint(0,len(LETTER_POOL_copy) - 1)

Comment on lines +61 to +65
for i in letter_bank:
if i not in letter_bank_count:
letter_bank_count[i] = 1
else:
letter_bank_count[i] += 1

Choose a reason for hiding this comment

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

Love a frequency map! You could condense this into one line my using the .get method available for dictionaries. I would also like to suggest that you name you i into something more descriptive such as letter or char.

Suggested change
for i in letter_bank:
if i not in letter_bank_count:
letter_bank_count[i] = 1
else:
letter_bank_count[i] += 1
for letter in letter_bank:
letter_bank_count[letter] = letter_bank_count.get(letter, 0) + 1

Comment on lines +67 to +72
for char in word:
if char in letter_bank and letter_bank_count[char] > 0:
letter_bank_count[char] -= 1

else:
return False

Choose a reason for hiding this comment

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

⭐️

tile_hand.append(LETTER_POOL_copy[index])
LETTER_POOL_copy.remove(LETTER_POOL_copy[index])

return tile_hand

Choose a reason for hiding this comment

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

Another approach you could take to this is use a cumulative weight. This would cut the list of 98 letters from our code. We would essentially make another dictionary cumulating the weights:

LETTER_POOL = {'A': 9, 'B': 2, 'C': 2, 'D': 4, 'E': 12}
cumulative_weights = {'A': 9, 'B': 11, 'C': 13, 'D': 17, 'E': 29} # Total Weight: 29
Letter Count Cumulative Weight
A 9 9 (1-9 → 'A')
B 2 11 (10-11 → 'B')
C 2 13 (12-13 → 'C')
D 4 17 (14-17 → 'D')
E 12 29 (18-29 → 'E')

We could then randomly select a number between 1 - total weight. After that we would loop through the cumulative_weights dictionary and if the random number we got is less than the cumulative weight we are looking at on the current iteration we will select that that letter.

Note: The chances of choosing any number between 1 - 9 from a pile of numbers 1 - 98 is the same as choosing one of the 9 A's from the pile of 98 letters.

This code could look something like this:

Click to view the draw_letters function
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
}

def compute_cumulative_weights(letter_pool):
    cumulative_weights = {}
    total_weight = 0
  
    for letter, weight in letter_pool.items():
        total_weight += weight
        cumulative_weights[letter] = total_weight
      
    return cumulative_weights, total_weight

def draw_letters():
    cumulative, total_weight = compute_cumulative_weights(LETTER_POOL)
    selected_letters = []

    for _ in range(10):
        rand_value = random.randint(1, total_weight)  # Pick a random number
      
        for letter, cumulative_weight in cumulative.items():
            if rand_value <= cumulative_weight:
                selected_letters.append(letter)
                break

    return selected_letters

Comment on lines +80 to +81
if word == "":
total_score = 0

Choose a reason for hiding this comment

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

Is this section of code contributing as much as we think? Looking at the other two sections of code you have in this function do you think that this case is being covered somewhere else?

Comment on lines +93 to +120
winning_word_score = score_word(word_list[0])

for index in range(1, len(word_list)):
contender_word = word_list[index]
contender_word_score = score_word(contender_word)

if winning_word_score > contender_word_score:
winning_word = winning_word

elif winning_word_score < contender_word_score:
winning_word = contender_word

elif winning_word_score == contender_word_score:
if len(winning_word) >= 10:
winning_word = winning_word
elif len(word_list[index]) >= 10:
winning_word = contender_word
elif len(winning_word) < len(contender_word):
winning_word = winning_word
else:
winning_word = contender_word

winning_word_score = score_word(winning_word)

result = (winning_word, winning_word_score)

return result

Choose a reason for hiding this comment

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

So, I know that you asked for guidance on how to condense this function. Let's think about how we could break this down into sub-problems, specifically two. The first one can be to make a list of the words of that tie for the highest score. The second, implement the tie breaking logic. There are also a few lines where you set winning_word to winning_word you don't need to do this since you are essentially asking it to point to the same data that its already pointing to. It seems like you were writing if statements to check for conditions when winning_word stays the same and for when you need to update it to contender_word. You just need to check for the latter. Also you can remove line 118 and just have return winning_word, winning_word_score on line 120instead since this will automatically return a tuple. So, breaking up the function into two sub problems and then only checking for conditions whenwinning_word` would change could lead to something like this:

def get_highest_word_score(word_list):
    top_score = 0
    tied_words = []

    for word in word_list:
        score = score_word(word)

        if score > top_score:
            top_score = score
            tied_words = [word]
        elif score == top_score:
            tied_words.append(word)
    
    top_word = tied_words[0]

    for word in tied_words:
        if len(word) == 10:
            return word, top_score
        elif len(word) < len(top_word):
            top_word = word
    
    return top_word, top_score

Comment on lines +118 to +120

return result

Choose a reason for hiding this comment

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

Suggested change
result = (winning_word, winning_word_score)
return result
return winning_word, winning_word_score

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants