9/15 Scrabble


#1

Hi,

Would anyone be willing to look over the below and let me know why it doesn’t work?
Thought process:

  1. define function
  2. create “total” variable which will contain final word score
  3. create list called “wordscore” to contain numbers from tile scores in dictionary
  4. iterate through word input and append each letter’s value to wordscore list
  5. iterate through wordscore list and add each value in it to total
  6. return total

score = {“a”: 1, “c”: 3, “b”: 3, “e”: 1, “d”: 2, “g”: 2,
“f”: 4, “i”: 1, “h”: 4, “k”: 5, “j”: 8, “m”: 3,
“l”: 1, “o”: 1, “n”: 1, “q”: 10, “p”: 3, “s”: 1,
“r”: 1, “u”: 1, “t”: 1, “w”: 4, “v”: 4, “y”: 4,
“x”: 8, “z”: 10}

def scrabble_score(word):
total == 0
wordscore = []
for letter in word:
wordscore.append(score[letter])
for number in wordscore:
total += number
return total


#2

You appear to be overthinking the problem.

Not needed. The only thing this function is supposed to do is add up the score from a lookup table.

Simplify this to,

total += score[letter]

#3

Story of my life. Thanks.


#4

There is a plus side to this, especially in programming. You look ahead and build capability into your code even when it isn’t needed yet.

In a real Scrabble game, it is possible to form three words in one turn. It might be rare, or at least not much more often than 29 in Cribbage, but it can happen. That means being able to send three words to the scoring function, account for the intersections (a square can only be scored once) and amend any bonus value as apply.

Your code could easily return the list for further processing. The total would be unnecessary since it would be computed when all the data is in and the special cases evaluated. There would be every reason to return each letter score.

This is something I like to call, re-purposing. When a snippet of code is meant to do one thing, and a tweak makes it do another. When it does both, you have added horsepower, especially if your program uses both.

Happy coding!


A large program is the sum of its parts, and then some. Look under the hood and expect to find a gazillion little programs all waiting to be called for their specific function.

def scrabble_score(word):
    return total

Without the messy bits, we can see that the above has only one functional role… return a total when the letters of the word are iterated and queried from a lookup table.

Were this a real game we were building there would be another thing to take into account… Only 100 tiles, so a limited number of letters. pizzaz wouldn’t be allowed because there are not three z's. Plus the game would need to remove letters on the board or already drawn from the bag.

https://en.wikipedia.org/wiki/File:Scrabble_tiles_en.jpg

One’s word cannot contain a z if it is still in the bag. There is but one z.

So technically, we need a way to keep track of all this, starting with a function that does a general test just to see if the word is possible, before going into all the other details.

Tiles
>>> tiles = {
'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,
' ': 2
}

Number of tiles in all…

>>> sum(tiles.values())
100
>>> 

Clearly, pizzaz will fail, but pi az will not.

Our score dictionary would need to be updated to include the ' ' key with a value of 0.


Proof-of-Concept
>>> bag = tiles.copy()
>>> bag
{'a': 9, ' ': 2, 'c': 2, 'b': 2, 'e': 12, 'd': 4, 'g': 3, 'f': 2, 'i': 9, 'h': 2, 'k': 1, 'j': 1, 'm': 2, 'l': 4, 'o': 8, 'n': 6, 'q': 1, 'p': 2, 's': 4, 'r': 6, 'u': 4, 't': 6, 'w': 2, 'v': 2, 'y': 2, 'x': 1, 'z': 1}
>>> for x in 'pizzaz':
	if bag[x]:
		bag[x] -= 1
	else:
		print False

		
False
False
>>> 

That reveals true False returns that can be relied upon.

Literals Test
>>> bag = tiles.copy()
>>> for x in 'pizzaz':
    if bag[x]:
        bag[x] -= 1
    else:
        print False
        break
else:
    print True

    
False
>>> bag = tiles.copy()
>>> for x in 'pi  az':
    if bag[x]:
        bag[x] -= 1
    else:
        print False
        break
else:
    print True

    
True
>>> 

bag_test
>>> def bag_test(word):
	bag = tiles.copy()
	for x in word:
		if bag[x]:
			bag[x] -= 1
		else:
			return False
	else:
		return True

	
>>> bag_test('pizzaz')
False
>>> bag_test('pi  az')
True
>>> 

Now we bring in another line of thinking

def letter_frequency(word):
    return {letter: word.count(letter) for letter in set(word)}

Which gives us this avenue of analysis…

frequencies = letter_frequency(word)
for letter in frequencies:
    if frequencies[letter] > tiles[letter]: break

#5

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.