Learn faster and stay on-track by joining this free class with other self-learners.
Register for MIT OpenCourseWare 6.00 Introduction to Computer Science and Programming now.
|
MIT OpenCourseWare 6.00 Introduction to Computer Science and ProgrammingClass length: 24 weeks. Start anytime. Creator: duallain Status: Established |
Join this class! |
|
Lesson 11: Assignment 1Assignment 6: Word games 2
Homework Submissions13 total# 6.00 Problem Set 6
#
# The 6.00 Word Game
#
# Scott Brenner
# Problem 1: 25 minutes
# Problem 2: 35 minutes
# Problem 3: ~8 hours Lots of careless problems along the way. Problems cause by short periods of time to work on problems and trouble with large sclae organization.
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
COMPUTER_TIME_FACTOR = 1
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
WORDLIST_FILENAME = "words.txt"
# -----------------------------------
# PREPROCESSSING FUNCTIONS- These prep the word lists/dictionaries for game play. They should execute only once--when the app is launched. They include function used for scoring and for the computer-player.
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def sort_word(word_string):
"""
Takes a string, alphabetizes it and returns it as a string.
"""
char_list =[]
sorted_string = ''
for char in word_string:
char_list.append(char)
char_list.sort()
for char in char_list:
sorted_string += char
return sorted_string
def get_word_rearrangements(a_list_of_words):
"""
This function takes a list of words and returns a dictionary of strings mapped to actual words.
This function is used by the computer-player to find valid words.
Create a dict where, for any set of letters, you can determine if there is some acceptable word that is a rearrangement of those letters.
Let d = {}
For every word w in the word list:
Let d[(string containing the letters of w in sorted order)] = w
"""
rearrange_dict = {}
for word in a_list_of_words:
# build a list from the char in word: 1) convert word string to list, 2) sort list, 3) convert list back to string.
char_list =[]
my_string = ''
for char in word:
char_list.append(char)
char_list.sort()
for each in range(len(char_list)):
my_string +=char_list[each]
rearrange_dict[my_string] = word
#print "In get_word_rearrangements. Rrearrange_dict:", rearrange_dict
return rearrange_dict
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter.lower()]
if len(word) == n:
score += 50
return score
# -----------------------------------
# GAME PLAY FUNCTIONS- These functions start and play the game play. They will execute mulitple times.
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
freq = get_frequency_dict(word)
newhand = {}
for char in hand:
newhand[char] = hand[char]-freq.get(char,0)
return newhand
#return dict( ( c, hand[c] - freq.get(c,0) ) for c in hand )
def is_valid_word(word, hand, point_dict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
freq = get_frequency_dict(word) # Create dictionary frequency dictionary for word. E.g., if work is 'hello', freq = {'h': 1, 'e': 1, 'l': 2, 'o': 1}.
for letter in word:
if freq[letter] > hand.get(letter, 0): # Confirm that each letter needed to spell word is in the hand in sufficient quantity.
return False
return word in point_dict
def play_hand(hand, word_list):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word is displayed,
the remaining letters in the hand are displayed, and the user
is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total_points = 0.0
initial_handlen = sum(hand.values())
foo = True
elapsed_time = 0.0
chessTime = get_time_limit(point_dict, COMPUTER_TIME_FACTOR)
print "\nComputer will have %0.2f seconds to play the hand.\n" % chessTime
# this is commented out because it was replaced by the line above. The line above sets chessTime based on computer speed. The commented code aske the user for chessTime.
# while foo:
# chessTime = raw_input('Enter time limit, in seconds, for players:')
# if chessTime.isdigit():
# chessTime = float(chessTime)
# foo = False
while sum(hand.values()) > 0:
print
print 'Current Hand:',
display_hand(hand)
startTime = time.time()
# userWord = raw_input('Enter word, or a . to indicate that you are finished: ')
userWord = pick_best_word_faster(hand, arranged_words) # 'faster' function
# userWord = pick_best_word(hand, point_dict) # orignial fuction
endTime = time.time()
playTime = endTime - startTime
print "It took %0.5f seconds to play %s." % (playTime, userWord)
elapsed_time += playTime
if userWord == '.':
break
elif elapsed_time > chessTime:
print "It took %0.5f seconds to play %s." % (playTime, userWord)
# print 'It took %0.2f seconds to enter your word.' % elapsed_time
print 'Your total time to play the hand exceeded %0.5f seconds. Your final score is %0.2f points.' % (chessTime, total_points)
break
else:
isValid = is_valid_word(userWord, hand, word_list)
if not isValid:
print 'Invalid word, please try again.'
else:
if playTime < 1: playTime = 1
points = get_word_score(userWord, initial_handlen) / playTime
total_points += points
print '%s earned %0.5f points. Total: %0.5f points' % (userWord, points, total_points)
hand = update_hand(hand, userWord)
#print 'Updated hand:%s' % hand
print 'Total score: %0.5f points.' % total_points
return total_points
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand. When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
# hand_score = 0.0
# counter = 0
# while hand_score < 40 or counter < 5:
# hand = deal_hand(HAND_SIZE)
# hand_score = play_hand(hand.copy(), word_list)
# print "Counter %i." %counter
# counter += 1
# print "Counter %i." %counter
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list)
print
elif cmd == 'e':
break
else:
print "Invalid command."
# -----------------------------------
# COMPUTER PLAYER FUNCTIONS- These functions play the computer's hand. They find and play the best word. They will execute mulitple times.
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
"""
freq = get_frequency_dict(hand) # Create dictionary frequency dictionary for the hand
best_word = ""
best_word_value = 0
for word in points_dict:
if is_valid_word(word, hand, points_dict):
word_value = get_word_score(word, HAND_SIZE)
#print "The word is %s, with value %i. The best word is %s, with value %i." % (word, word_value, best_word, best_word_value)
if word_value > best_word_value:
best_word = word
best_word_value = word_value
if best_word_value > 0:
return best_word
return "."
def get_words_to_point(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
word_value_dictionary = {}
for word in word_list:
word_value_dictionary[word] = get_word_score(word, 7)
return word_value_dictionary
#return len(word_value_dictionary)
def pick_best_word_faster(hand, rearrange_dict):
"""
Takes a hand {dictionary} and a dictionary of letter combinations that map to a valid word.
Returns the highest value word or '.'-if there is no valid word possible.
Pseudo-code:
To find some word that can be made out of the letters in HAND:
For each subset S of the letters of HAND:
Let w = (string containing the letters of S in sorted order)
If w in d:
return d[w]
This function must convert the hand{dictionary} to a string. In doing so it must check to make sure that the value of each key in the had is > 0
"""
#print "In pick best. Hand:", hand
hand_string = ''
for each in hand:
if hand[each] > 0:
hand_string += each * hand[each]
#print "Hand sorted: %s" %hand_string
best_word =''
best_word_score = 0
subsets = build_substrings(hand_string)
subset_value = 0
for subset in subsets:
sorted_subset = sort_word(subset)
if sorted_subset in rearrange_dict:
subset_value = get_word_score(sorted_subset, HAND_SIZE)
if subset_value > best_word_score:
best_word = rearrange_dict[sorted_subset]
best_word_score = subset_value
if best_word_score > 0:
return best_word
else:
return '.'
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the multiplier k.
points_dict should be the same dictionary that is created by get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
def build_substrings(string):
"""
Works on the premiss that given a set of the substrings of a string the
the subsets of a string with one more char is the formed by taking all the
substrings in the known subset and also adding to them the set formed by
adding the character to every element in the old set and then adding the
new char.
"""
result = []
if len(string) == 1:
result.append(string)
else:
for substring in build_substrings(string[:-1]):
result.append(substring)
substring = substring + string[-1]
result.append(substring)
result.append(string[-1])
result = list(set(result)) # Convert result into a set. Sets have no duplicates. Then convert back to list.
result.sort()
# now iterate through substrings and sort the characters of each substring
#for each in
return result
# -----------------------------------
# PLAY GAME: Build data structures used for entire session and play game.
#
if __name__ == '__main__':
word_list = load_words()
point_dict = get_words_to_point(word_list)
arranged_words = get_word_rearrangements(word_list)
#print len(arranged_words)
play_game(word_list)
## Problem 5 ##
# your response here.
# as many lines as you want.
#
# pick_best_word()
# This method creates a dictionary of every valid word mapped to the point value. Then it iterates through the dictionary comparing the hand to the word. If they word can be made from the hand then the word's score is compared to the word score of the earlier possible word. The higher score word is retained.
# Under this method the point value dictionary must be built and then the function iterates through comparing the hand to eveyr possible word.
# Amortizing the time-cost of building the dictionary over each pick, the time complexity of this method grows with the length of the word list and independently from the size of the hand. Adding letters to the hand will increase the time to execute but only negligibly. I think the computational complexity of the function is linear.
#
# With a hand size of 7 letters the time to pick best word was less than .6 seconds.
# With a hand size of 17 letters the time to pick best word was ~.6 seconds.
# With a hand size of 25 letters the time to pick best word was ~.65 seconds.
#
# pick_best_word_faster()
# This method also begins by creating a dictionary. Each value in the dictioanry is a valid word. Each key is a alphabetized string of the letters in the word. E.g., {'acot':'taco'}. Note that each key is unique but the value isn't necessarily unique. The dictionary value for 'acot' could be 'coat'. This is because the dictionary only needs to list every valid alpahbetized string of letters. Not ever valid word. This makes the dictionary the same size or shorter than the dictionary created in pick_best_word(). For the word list used in this problem the savings is ~14,000 entries (83667 words, 69091 dict keys)
# Armed with this dictionary the function can take advantage of the speed of the "in dictionary" function, which I thinks is logarithmic. The next part of this function is build a set of substrings of hand. The function then iterates through this set of substrings checking if they are in the dictionary, and comparing their point value to the prior highest value string in the dictionary. The function returns the highest point value value from the dictionary.
# This method is much faster than pick_best_word() because is takes adavantice of the bysect search functionality built into search dicstionaries. This bysect search algorithm grow logarithmically based on the length of dictionary.
# Adding letters to the hand will increase the time to execute the function that creates the subsets, but they dicitonary search is the more significant funciton. I think the computational complexity of the function is logarithmic.
# With a hand size of 7 letters the time to pick best word was less than .001 seconds.
# With a hand size of 17 letters the time to pick best word was between .3 and .5 seconds.
# With a hand size of 25 letters the time to pick best word was between 15 and 45 seconds.
# Comparing the two functions, it appears the pick_best_word_faster() is much faster for relatively small hands and any size dictionary. But pick_best_word() is faster if the hands will be large. Not surprisingly the 'better' function depends on the specifics of the problem.
# 6.00 Problem Set 6
#
# The 6.00 Word Game
#
import time
import random
import string
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter.lower()]
if len(word) == n:
score += 50
return score
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
freq = get_frequency_dict(word)
newhand = {}
for char in hand:
newhand[char] = hand[char]-freq.get(char,0)
return newhand
#return dict( ( c, hand[c] - freq.get(c,0) ) for c in hand )
def is_valid_word(word, hand, word_list):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lower case strings
"""
freq = get_frequency_dict(word)
for letter in word:
if freq[letter] > hand.get(letter, 0):
return False
return word in word_list
def play_hand(hand, word_list):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word is displayed,
the remaining letters in the hand are displayed, and the user
is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total = 0
initial_handlen = sum(hand.values())
time_limit = input("Enter time limit, in seconds, for players: ")*1.0
time_remaining = time_limit
while sum(hand.values()) > 0:
print 'Current Hand:',
display_hand(hand)
start_time = time.time()
userWord = raw_input('Enter word, or a . to indicate that you are finished: ')
if userWord == '.':
break
else:
isValid = is_valid_word(userWord, hand, word_list)
if not isValid:
print 'Invalid word, please try again.'
else:
end_time = time.time()
total_time = end_time - start_time
time_remaining = time_remaining - total_time
if time_remaining <= 0.0:
print 'It took %0.2f seconds to provide an answer.' % total_time
print 'Total time exceeds %d seconds. You scored %d points' % (time_limit, total)
break
print 'It took %0.2f seconds to provide an answer.' % total_time
print 'You have %0.2f seconds remaining.' % time_remaining
points = get_word_score(userWord, initial_handlen)
total += points
print '%s earned %d points. Total: %d points' % (userWord, points, total)
hand = update_hand(hand, userWord)
print 'Total score: %d points.' % total
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list)
print
elif cmd == 'e':
break
else:
print "Invalid command."
def get_words_to_points(word_list):
"""
Basically takes word_list and turns it into a dictionary list where the elements are the words
and the values are the points of each word.
Returns the dictionary of words and points.
"""
points_dict = {}
for i in xrange(len(word_list)):
points_dict[word_list[i]] = get_word_score(word_list[i], HAND_SIZE)
return points_dict
def pick_best_word(hand, points_dict):
"""
Selects the best word based on points within a set of letters.
hand = list of your letters
"""
hand_freq = get_frequency_dict(hand)
bestWord = ""
for word in points_dict:
hasAllLetters = True
word_freq = get_frequency_dict(word)
#check if
for letter in word_freq:
if word_freq[letter] > hand.count(letter):
hasAllLetters = False
break
if hasAllLetters:
if points_dict[word] > get_word_score(bestWord,HAND_SIZE):
bestWord = word
return bestWord
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a funciton of the multiplier k.
"""
start_time = time.time()
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
##if __name__ == '__main__':
## word_list = load_words()
## play_game(word_list)
No comments. Sign up or log in to comment This one took ages, I probably finished it in 10 times or something. Didn't do last and stole a little part of someone else's code because I was lazy. I truly am a grade A student. # Problem Set 5: 6.00 Word Game
# Name:
# Collaborators:
# Time:
#
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
# TO DO ...
score=0
for i in word:
score+= SCRABBLE_LETTER_VALUES[i]
if len(word)==n: score+=50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
#
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
# TO DO ...
hand_copy=hand
for letter in word:
hand_copy[letter] -= 1
if hand_copy[letter]==0: del hand_copy[letter]
return hand_copy
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
# TO DO ...
hand_copy=hand.copy()
truth = 0
if word in points_dict:
for letter in word:
if hand_copy.get(letter,0) >0:
truth+=1
if truth==len(word): return word in points_dict
return False
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
global points_dict
points_dict={}
for word in word_list:
points_dict[word]=get_word_score(word,HAND_SIZE)
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the
given hand.
Return '.' if no words can be made with the given hand.
"""
high_score=0
best_word = '.'
for word in points_dict: #neem een woord uit alle woorden
letters=get_frequency_dict(word) #zet om zoals hand
all_letters_check=0 #nodig om te zien of alle letters kloppen, niet zomaar één
number_of_letters=0
for letter in word:
number_of_letters+=letters[letter]
#print word,letter,number_of_letters
for letter in word: #neem één letter
if hand.get(letter,0)>=letters[letter]: #als die letter vaker/gelijk in je hand voorkomt dan in het woord
#print "here", word, number_of_letters, all_letters_check
all_letters_check+=letters[letter] #doe je all_letters_check + het aantal letters in het woord uit dict
if all_letters_check==number_of_letters and get_word_score(word,HAND_SIZE) > high_score:
#print "one lower- -->", "letter:",letter, word, number_of_letters, all_letters_check, best_word
best_word=word
high_score= get_word_score(word,HAND_SIZE)
print best_word
return best_word
def wordsort(word):
sorted_word=''
word=list(word)
word.sort()
for letter in word:
sorted_word=sorted_word[:]+letter
return sorted_word
def get_word_rearrangements(word_list):
rearrange_dict={}
sortword=''
for word in word_list:
sortword=wordsort(word)
rearrange_dict[sortword]=word
return rearrange_dict
def createCombinations(string): #taken from someone else on opencourseware
if len(string) == 1:
return [string]
solutions = []
# Let T = the current string of letters
# Let S = the current starting letter in our string
# Let R = the rest of the string starting with the letter
# immediately following S
# Let K = the solutions for R
#
# The solution for T is is the set of
# [S] + [S + K[0], S + K[1], S + K[2], ..., S + K[n]] + K
solutions.append(string[0])
subsolutions = createCombinations(string[1:])
for subso in subsolutions:
solutions.append(string[0] + subso)
solutions.append(subso)
return solutions
def turn_back(hand):
"""
takes your hand as a dictionary and returns it as a string.
not a pretty solution to the problem I had but meh
"""
hand_string=''
for letter in hand.keys():
for j in range(hand[letter]):
hand_string=hand_string[:]+letter
return hand_string
def pick_best_word_faster(hand, rearrange_dict):
string_hand=turn_back(hand)
hands = createCombinations(string_hand)
high_score=0
best_word='.'
word_in_dict=''
for hand in hands:
hand=wordsort(hand)
if hand in rearrange_dict:
word_in_dict=rearrange_dict[hand]
if get_word_score(word_in_dict,HAND_SIZE) > high_score:
best_word=word_in_dict
high_score=get_word_score(word_in_dict,HAND_SIZE)
return best_word
#
# Problem #4: Playing a hand
#
def play_hand(hand, word_list):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
# TO DO ...
time_limit=int(raw_input("enter the time limit for the game in seconds: "))
computer_word=0
score=0
starting_length=len(hand)
timestart=time.time()
while computer_word != "." and len(hand)>0:
print
display_hand(hand)
#word_input=raw_input("please insert a word you'd like to play or \".\" to stop your turn > ")
computer_word=pick_best_word_faster(hand, rearrange_dict)
print computer_word
time2=time.time()
time_taken=round(float(time2-timestart),2)
time_limit -= time_taken
if is_valid_word(computer_word,hand,word_list):
update_hand(hand,computer_word)
if time_taken <1: time_taken=1
if time_limit>0:
score+=(get_word_score(computer_word,starting_length))/time_taken
print 'it took you',time_taken,'seconds to answer'
print "you scored",round((get_word_score(computer_word,starting_length))/time_taken,2),"with this word"
print "your total score is: ",round(score,2)
print "you have %s time remaining" % (time_limit)
timestart=time.time()
else:
print "I'm sorry, you ran out of time..."
break
else:
if time_limit<=0:
print "I'm sorry, you ran out of time..."
break
if computer_word != ".": print "this is not a valid word"
print "total end score is: ",round(score,2)
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
# TO DO ...
## print "play_game not implemented." # delete this once you've completed Problem #4
## play_hand(deal_hand(HAND_SIZE), word_list) # delete this once you've completed Problem #4
## uncomment the following block of code once you've completed Problem #4
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
#time_limit=int(raw_input("enter the time limit for the game in seconds: "))
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
get_words_to_points(word_list)
time_limit=get_time_limit(points_dict, 1)
rearrange_dict= get_word_rearrangements(word_list)
play_game(word_list)
No comments. Sign up or log in to comment Problem 5: The complexity of pick_best_word is O(n^2) or Quadratic. You have to iterate the length of the word_list and then the length of each word. Since there are 83667 words in the list, then you need to iterate 83667 * len(word) which is anywhere from 2 to 7 letters long. It took my computer typically 0.34 seconds to find a word. The complexity of pick_best_word_faster is O(2^n) or Exponential. While the algorithm is more complex, it is only limited by the maximum times you have to iterate through the Hand. Since there are 7 letters maximum in the hand then it only needs to make 2^7 or 128 steps. It took my computer typically 0.001 seconds to find a word # 6.00 Problem Set 6
#
# The 6.00 Word Game
# Name: tuckertuck
# Time: 9:00
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
#
# Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter.lower()]
if len(word) == n:
score += 50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
#hand = {'g':1,'o':1,'l':1,'d':1,'e':1,'s':1,'t':1}
return hand
#
# Update a hand by removing letters
#
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
freq = get_frequency_dict(word)
newhand = {}
for char in hand:
newhand[char] = hand[char]-freq.get(char,0)
return newhand
#return dict( ( c, hand[c] - freq.get(c,0) ) for c in hand )
#
# Test word validity
#
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
freq = get_frequency_dict(word)
for letter in word:
if freq[letter] > hand.get(letter, 0):
return False
return word in points_dict
# Problem 1 & 2: Computing Time
#
# Playing a hand
#
def play_hand(hand, word_list, clock):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word is displayed,
the remaining letters in the hand are displayed, and the user
is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total = 0
update_clock = clock
initial_handlen = sum(hand.values())
while sum(hand.values()) > 0:
print
print 'Current Hand:',
display_hand(hand)
start_time = time.time()
## userWord = raw_input('Enter word, or a . to indicate that you are finished: ') # Human Player
## userWord = pick_best_word(hand, points_dict) # Computer Player
userWord = pick_best_word_faster(hand, rearrange_dict) # Even Faster Computer Player
if userWord == '.':
break
else:
isValid = is_valid_word(userWord, hand, points_dict)
if not isValid:
print 'Invalid word, please try again.'
else:
end_time = time.time()
total_time = (end_time - start_time)#*(1+time_limit)
update_clock -= total_time
print 'It took %0.3f seconds to provide an answer.' % total_time
if update_clock >= 0:
if total_time == 0: points = get_word_score(userWord, initial_handlen)
else: points = get_word_score(userWord, initial_handlen)/(1+total_time)
#print total_time
total += points
print 'You have %0.2f seconds remaining.' % update_clock
print '%s earned %0.2f points. Total: %0.2f points.' % (userWord, points, total)
hand = update_hand(hand, userWord)
else:
print 'Total time exceeds %s seconds. You scored %0.2f points.' % (clock, total)
break
print 'Total score: %0.2f points.' % total
#
# Playing a game
# Make sure you understand how this code works!
#
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
#chess_clock = int(raw_input('Enter time limit, in seconds, for players: '))
chess_clock = time_limit
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list, chess_clock)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list, chess_clock)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#
# Problem #3: Computer Player
#
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
"""
#print hand
ans = False
best = False
score = 0
for word in points_dict:
word_freq = get_frequency_dict(word)
#print word
for letter in word_freq:
#print letter
if letter in hand and word_freq[letter] <= hand[letter]:
ans = True
continue
else:
ans = False
break
if ans == True:
#print word
new_score = points_dict[word]
if new_score > score:
score = new_score
best_word = word
best = True
if best == True:
#print best_word
return best_word
else: return '.'
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
points_dict = {}
for word in word_list:
points_dict[word] = get_word_score(word, HAND_SIZE)
return points_dict
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
#
# Problem #4: Even Faster Computer Player
#
def pick_best_word_faster(hand, rearrange_dict):
"""
Return the highest scoring word from points_dict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
Uses a binary counter to map whether a letter is part of the subset or not
"""
ans = False
best = False
score = 0
sorted_hand = sort_dic(hand)
#print sorted_hand
if sorted_hand in rearrange_dict:
#print points_dict[rearrange_dict[sorted_hand]]
return rearrange_dict[sorted_hand]
elif len(sorted_hand) > 1:
## Binary represents whether letter gets used in the hand.
for a in range(2):
for b in range(2):
for c in range(2):
for d in range(2):
for e in range(2):
for f in range(2):
for g in range(2):
binary = (g,f,e,d,c,b,a)
dic = dict(zip(sorted_hand,binary))
#print dic
sorted_dic = sort_dic(dic)
#print binary, sorted_dic
#print sorted_hand
if sorted_dic in rearrange_dict:
word = rearrange_dict[sorted_dic]
#print word
new_score = points_dict[word]
if new_score > score:
score = new_score
best_word = word
best = True
if best == True:
#print best_word
return best_word
else: return '.'
def sort_dic(hand):
"""
Returns Tuple of alphabetized letters in a given Dictionary of value >= 1
"""
l = []
for letter in hand.keys():
for j in range(hand[letter]):
l.append(letter)
sorted_tuple = tuple(sorted(l))
return sorted_tuple
def get_word_rearrangements(word_list):
rearrange_dict = {}
for word in word_list:
dorw = tuple(sorted(word))
#print dorw, word
rearrange_dict[dorw] = word
return rearrange_dict
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
rearrange_dict = get_word_rearrangements(word_list)
points_dict = get_words_to_points(word_list)
time_limit = get_time_limit(points_dict, 2)
play_game(word_list)
No comments. Sign up or log in to comment # Problem Set 5: 6.00 Word Game
# Name:
# Collaborators:
# Time:
#
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
print
return wordlist
def get_frequency_dict(word):
"""
Returns a dictionary where the keys are letters of the word
and the values are integer counts, for the number of times that
a letter is repeated in the word.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in word:
freq[x] = freq.get(x,0) + 1#adds one to the value of the key:value pair each time the letter 'key' is found in 'sequence'
return freq
# (end of helper code)
# -----------------------------------
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
# TO DO ...
score = 0
for letter in word:
#print letter, 'adds to score:', SCRABBLE_LETTER_VALUES[letter]
score += SCRABBLE_LETTER_VALUES[letter]
if n == len(word):
return score + 50
else:
return score
#######################
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the prin.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]#chooses a random vowel from the 'VOWELS' list
hand[x] = hand.get(x, 0) + 1#adds key-value pair of 'ramdonly chosen vowel':number of previously present said vowel plus one.
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
#
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
# TO DO ...
remaining_hand=hand.copy()
for letter in word:
remaining_hand[letter]=remaining_hand.get(letter,0) - 1
for letter in remaining_hand.keys():
if remaining_hand[letter] == 0:
del remaining_hand[letter]
return remaining_hand
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the points_dict and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or points_dict.
word: string
hand: dictionary (string -> int)
points_dict: list of lowercase strings
"""
# TO DO ...
frequency = get_frequency_dict(word)#gets the frequency of letters ocurring in 'word'
for letter in word:
if letter not in hand or hand[letter]<frequency[letter]:
return False
if word in points_dict:
return True
else: return False
#
# Problem #4: Playing a hand
#
def get_words_to_points(word_list,n):
"""
Return a dict that maps every word in word_list to its point value.
word_list = list of words
n = maximum size of hand
"""
points_dict={}
print 'Computing word scores...'
for word in word_list:
points_dict[word] = get_word_score (word,n)
return points_dict
##def get_sorted_words_to_points(rearrange_dict,n):
##"""
##Return a dict that maps every word in rearrange_dict to its point value.
##rearrange_dict = list of words in sorted characters
##n = maximum size of hand
##"""
##
##points_dict={}
##print 'Computing word scores...'
##for word in rearrange_dict.values():
##points_dict[word] = get_word_score (word,n)
##return points_dict
##def reverse_lookup(dict,value):
##""" Gets the first key of value: 'value' in dict.
##
##If no such key is in it, return'.'
##"""
##for key in dict:
##if value == dict[key]:
##return key
##else:
##return '.'
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the
given hand.
Return '.' if no words can be made with the given hand.
"""
best_score = 0#will store the best possible score
best_word = 'which_is_it' #will hold best scoring word
for word in points_dict.keys():
frequencies = get_frequency_dict(word)
for letter in word: #dismisses words which contain
if letter not in hand: # leters not in hand
break
elif frequencies[letter] > hand[letter]:#dismisses word if it has more of letter then hand has.
break
else:
continue
else:
if points_dict[word] > best_score:
best_score = points_dict[word]
best_word = word
if best_score == 0: #means no word in points_dict(the word list) could be made with letters in hand
print 'It is not possible to form a word with the letters in this hand.'
return '.'
else:
print 'The best word in',
display_hand(hand),
print 'is:', best_word
return best_word
#pick_best_word(deal_hand(7), get_words_to_points(load_words(), 7)) #test pick_best_word function
def get_word_arrangements(word_list):
"""Creates a dictionary word-->sorted letters"""
rearrange_dict = {}
for word in word_list:
letter_list=list(word)#a list of letters in word
letter_list.sort()
newword=''.join(letter_list)
rearrange_dict[newword]=word
#print rearrange_dict
return rearrange_dict
def get_substrings_of(string):
"""Retrieves a list of all possible substrings in a string.
Works on the premisse that the substrings subset of a string with
one more character is the formed by taking all the substrings in the
current subset and adding this character to every element.
"""
result = []
if len(string) == 1: #the base case
result.append(string)
pass
else:
for item in get_substrings_of(string[:-1]):
result.append(item)
substring = item + string[-1]
result.append(substring)
result.append(string[-1])
result = list(set( result )) #remove dupes
return result
def pick_best_word_faster(hand, rearrange_dict): #currently its not returning the best word!!
"""Well, it should pick the highest-scoring word faster!
Return the highest scoring word from points_dict that can be made with the
given hand.
Return '.' if no words can be made with the given hand.
"""
#this part gets the hand dictionary and outputs a list of
#its letters
letter_list = []
for letter in hand.keys():
for j in range(hand[letter]):
letter_list.append(letter)
letter_list.sort()
#display_hand(hand)
#print letter_list
sortedhandstring = ''
for letter in letter_list:
sortedhandstring += letter
#print word
#this part takes a list of substrings an gives a list of sorted sub-
#strings
sorted_substring_list=[]
for substring in get_substrings_of(sortedhandstring):
substring_letters=[]
for letter in substring:
substring_letters.append(letter)
substring_letters.sort()
sorted_substring = ''
for letter in substring_letters:
sorted_substring += letter
else:
sorted_substring_list.append(sorted_substring)
#print sorted_substring_list
#this parts filters substrings which cannot form words:
for substring in sorted_substring_list[:]:
if substring not in rearrange_dict:
sorted_substring_list.remove(substring)
hand_points = get_words_to_points(sorted_substring_list,HAND_SIZE)
if hand_points:
high_scoring = max(hand_points, key=hand_points.get)
return rearrange_dict[high_scoring]
else:
print 'No english words in this hand'
return '.'
def play_hand(hand, word_list,points_dict):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
# TO DO ...
#print "play_hand not implemented." # replace this with your code...
totalscore = 0 #starting score
#time_limit=input('Enter a time limit, in seconds, for players: ')
#if type(time_limit) != type(1):
# time_limit=input('Enter a time limit, in seconds, for players: ')
#else:
choice = input("Who should play, CPU(1), faster CPU(2) or you(3)? Input number: ")
if choice == 1 or choice ==2:
time_limit= get_time_limit(points_dict, 1)
beggining = time.time()
elif choice == 3:
while True:
try:
time_limit= int(input('What should the time limit be?: '))
break
except (NameError, TypeError):
print 'Plase enter the amount of time in seconds: '
continue
beggining = time.time()
while len(hand)>0:
if choice == 1:
print 'Your hand is: '
display_hand(hand)
word = pick_best_word(hand, points_dict)
elif choice == 2:
print 'Your hand is: '
display_hand(hand)
word = pick_best_word_faster(hand, rearrange_dict)
elif choice == 3:
print
print 'Your hand is: '
display_hand(hand)
beggining = time.time()
word = raw_input('Enter a word composed of letters from your hand or a . to indicate that you are finished: ')
else:
print 'Invalid Input!'
print
if word == '.':
ending = time.time()
timetaken = ending - beggining
print 'It took %0.2f seconds to provide an answer' % timetaken
print 'Totalscore: %0.2f' % totalscore
return
elif not is_valid_word(word, hand, word_list):
print word, "either isn't a proper english word or contains letters which are not in your hand!"
print
print 'Current hand:',
display_hand(hand)
else:
ending = time.time()
timetaken = ending - beggining
remaining_time = time_limit - timetaken
if remaining_time >= 0:
print 'It took %0.2f seconds to provide a proper answer' % timetaken
score = get_word_score(word, HAND_SIZE)
scoreadjusted = score/timetaken
totalscore += scoreadjusted
print word, 'earned you %0.2f points' %scoreadjusted
hand = update_hand(hand, word)#the word uses up letters in the hand
print 'Current hand:',
display_hand(hand)
print 'remaining time: %0.2f' % remaining_time
else:
print "You've run out of time!"
totalscoreadjusted = totalscore/timetaken
print 'Totalscore: %0.2f' % totalscoreadjusted
break
else:
ending = time.time()
timetaken = ending - beggining
print 'Total score: %0.2f' % totalscore
return
#play_hand(deal_hand(HAND_SIZE), load_words())
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
# TO DO ...
## uncomment the following block of code once you've completed Problem #4
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list,points_dict)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list,points_dict)
print
elif cmd == 'e':
break
else:
print "Invalid command."
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list, HAND_SIZE)
rearrange_dict = get_word_arrangements(word_list)
#points_dict = get_sorted_words_to_points(rearrange_dict, HAND_SIZE)
##pick_best_word_faster(deal_hand(7), rearrange_dict)
play_game(word_list)
No comments. Sign up or log in to comment Took me some time and going through some ugly code to come up with an algorithm to create every possible string combination for pick_best_word_faster, but the solution ended up being really simple in the end, which felt great. Not sure if problem 5 is a trick question or if my algorithm could be done more efficiently, but complexity is actually greater for pickBestWordFaster, but it only shows for a large hand size. import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 20
POINTS_DICT = {}
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
def getWordScore(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter]
if len(word) == n:
score += 50
return score
#
# Make sure you understand how this function works and what it does!
#
def displayHand(hand):
"""
Displays the letters currently in the hand.
For example:
displayHand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def updateHand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
wordFreqDict = get_frequency_dict(word)
updatedHand = {}
for letter in hand:
updatedHand[letter] = hand[letter] - wordFreqDict.get(letter, 0)
if not updatedHand[letter]:
del updatedHand[letter]
return updatedHand
def canMakeWord(word, hand):
"""
Returns True if word can be made with the provided hand,
False if it cannot
"""
wordFreqDict = get_frequency_dict(word)
for letter in wordFreqDict:
if hand.get(letter, 0) < wordFreqDict[letter]:
return False
return True
def isValidWord(word, hand, pointsDict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
return pointsDict.get(word, False) and canMakeWord(word, hand)
def displayHand(hand):
"""
Displays the current hand
"""
for letter in hand:
print letter,hand[letter]
def getWordInput(hand):
word = raw_input('Enter a word or . to indicate that you are finished: ')
inputIsValid = isValidWord(word, hand, POINTS_DICT) or word == '.'
while not inputIsValid:
word = raw_input('Word not valid. Please choose another word: ')
inputIsValid = isValidWord(word, hand, POINTS_DICT) or word == '.'
return word
def getWordsToPoints(wordList):
"""
Return a dict that maps every word in wordList to its point value.
"""
pointsDict = {}
for word in wordList:
pointsDict[word] = getWordScore(word, HAND_SIZE)
return pointsDict
def pickBestWord(hand, pointsDict):
"""
Return the highest scoring word from pointsDict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
"""
bestScore = 0
bestWord = '.'
for word in pointsDict.keys():
if canMakeWord(word, hand) and pointsDict[word] > bestScore:
bestScore = pointsDict[word]
bestWord = word
return bestWord
def createCombinations(string):
if len(string) == 1:
return [string]
solutions = []
# Let T = the current string of letters
# Let S = the current starting letter in our string
# Let R = the rest of the string starting with the letter
# immediately following S
# Let K = the solutions for R
#
# The solution for T is is the set of
# [S] + [S + K[0], S + K[1], S + K[2], ..., S + K[n]] + K
solutions.append(string[0])
subsolutions = createCombinations(string[1:])
for subso in subsolutions:
solutions.append(string[0] + subso)
solutions.append(subso)
return solutions
def pickBestWordFaster(hand, pointsDict, wordRearrangements):
bestScore = 0
bestWord = '.'
currentHandAsString = ''
for letter in hand:
for i in range(hand[letter]):
currentHandAsString += letter
sortedCurrentHandAsString = ''.join(sorted(currentHandAsString))
allPossibleSolutions = createCombinations(sortedCurrentHandAsString)
for solution in allPossibleSolutions:
if solution in wordRearrangements and pointsDict[wordRearrangements[solution]] > bestScore:
bestScore = pointsDict[wordRearrangements[solution]]
bestWord = wordRearrangements[solution]
return bestWord
def getWordRearrangements(wordList):
"""
Builds and returns a dictionary of words where the key is composed
of all letters in a word, sorted alphabetically and the value is
the word itself.
"""
rearranged = {}
for word in wordList:
rearranged[''.join(sorted(word))] = word
return rearranged
def getTimeLimit(pointsDict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k
"""
startTime = time.time()
for word in pointsDict:
get_frequency_dict(word)
getWordScore(word, HAND_SIZE)
endTime = time.time()
return (endTime - startTime) * k
def play_hand(hand, word_list):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
print 'Enter time limit, in seconds, for players: '
timeLimit = getTimeLimit(POINTS_DICT, 20)
print "Time Limit: %0.8f seconds " % timeLimit
timeLeft = timeLimit
print "Current Hand: "
displayHand(hand)
score = 0
gameIsDone = False
while len(hand) and not gameIsDone:
startTime = time.time()
# word = pickBestWord(hand, POINTS_DICT)
word = pickBestWordFaster(hand, POINTS_DICT, REARRANGE_DICT)
print '"%s"' % word
totalTime = time.time() - startTime
if word == '.':
gameIsDone = True
continue
print 'It took %0.10f seconds to provide an answer' % totalTime
timeLeft -= totalTime
if (timeLeft > 0):
# Only give a maximum of the total letter score
if totalTime < 1:
totalTime = 1
wordScore = getWordScore(word, HAND_SIZE) / totalTime
score += wordScore
hand = updateHand(hand, word)
print 'Score for "%s": %0.2f. Total score so far: %0.2f' % (word, wordScore, score)
print "Remaining letters: "
displayHand(hand)
else:
print "Total time exceeds %0.8f seconds" % timeLimit
gameIsDone = True
print
print "Final Score: %0.2f" % score
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE)
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list)
print
elif cmd == 'r':
play_hand(hand.copy(), word_list)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
POINTS_DICT = getWordsToPoints(word_list)
REARRANGE_DICT = getWordRearrangements(word_list)
# for rearranged in REARRANGE_DICT:
# print "Rearranged: %s, Word: %s" % (rearranged, REARRANGE_DICT[rearranged])
play_game(word_list)
## Problem 5 ##
#
# pickBestWord:
# Need to iterate all possible words (length(words))
# size of current word * size of word list
# Seems to be quadratic
#
# pickBestWordFaster
# Need to iterate all possible subsets of sorted(hand), which is dependent
# f(x) = 1 + 2(f(x - 1))
# Problem size is doubling each step, exponential where n is the size of hand
# This seems to be faster when the hand size is less than 20
# Testing code below
#
# x = 19
# hand = deal_hand(x)
# print "Comparing pickBestWord and PickBestWordFaster with %d" % x
# start = time.time()
# word = pickBestWord(hand, POINTS_DICT)
# end = time.time()
#
# print "pickBestWord took %0.8f seconds" % (end - start)
#
# start = time.time()
# word = pickBestWordFaster(hand, POINTS_DICT, REARRANGE_DICT)
# end = time.time()
# print "pickBestWordFaster took %0.8f seconds" % (end - start)
Comments:I think the purpose of Problem 5 is to teach us that even though an algorithm is more complex in certain scopes it is more efficient. # Problem Set 6: Modifed 6.00 Word Game (from ps5.py)
# Name: chrcoe
# Collaborators: hendrix from curiousreef for substrings algorithm
# Time: 2:25 min
#
import time
import random
import string
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
#HAND_SIZE = 25 #test seems to be one too big for this computer
#HAND_SIZE = 24 #test seems to be the max usuable, any higher, I get a MemoryError
#HAND_SIZE = 23
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
###
### Scoring a word
###
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
wordScore = 0
for letter in word:
wordScore += SCRABBLE_LETTER_VALUES[letter]
#print wordScore
if len(word) == n:
wordScore += 50 #adds 50 to score for using all n letters on first try
return wordScore
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
###
### Update a hand by removing letters
###
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
newHand = hand.copy()
for letter in word:
newHand[letter] += -1
return newHand
###
### Test word validity
### UPDATED for problem #3 of Problem Set 6.
# now takes the argument points_dict instead of word_list
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the points_dict and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or points_dict.
word: string
hand: dictionary (string -> int)
points_dict: dictionary (string -> int)
returns: boolean value
"""
newHand = hand.copy()
if points_dict.has_key(word): #test if the word is in points_dict
for letter in word: #tests every letter in word to see if it is in hand
if newHand.get(letter, 0) > 0: #if it's positive (meaning it is there)
newHand[letter] -= 1 #remove 1 of the letters for next check
else:return False
return True
else: return False
# get_time_limit function from problem set.
# called by main function calls at bottom of program
# stored in global variable time_limit
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
points_dict: dictionary (string -> int)
k: int
returns: float
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
#
# Problem #3: Computer player -> time taken: 95 min
#
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
word_list: list of lowercase strings
returns: dictionary (string -> int)
"""
#walk through word_list and return get_word_score(word_from_wordlist, HAND_SIZE)
scores = {}
for word in word_list:
scores[word] = get_word_score(word, HAND_SIZE)
return scores
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
hand: dictionary (string -> int)
points_dict: dictionary (string -> int)
returns: list index 0
"""
#walk through points_dict to add all words that are 'makeable' with current hand
#add these to a makeable_dict dictionary with word:score and sort this by highest score
#return the highest scoring word possible form this sorted list.
possibleWords = {}
for word in points_dict:
if is_valid_word(word, hand, points_dict):
possibleWords[word] = points_dict[word]
bestScore = [0,0]
if possibleWords:
for word in possibleWords: #compares current word to the word in bestScore[1]
if possibleWords[word] > bestScore[1]: #if current word is better than bestScore[0]
bestScore[0] = word
bestScore[1] = possibleWords[word]
if bestScore[0] == 0:
return '.' #player gives up
return bestScore[0] #else returns the word
#
# Problem #4: Even Faster Computer player -> time taken: 25 min (so far)
#
def get_word_rearrangements(word_list):
"""
Return a dict that maps every word in word_list to that word sorted alphabetically.
word_list: list of lowercase strings
returns: sorted dictionary (string -> int)
"""
#walk through word_list and return sorted version
rearrange_dict = {}
for word in word_list:
tempList = [] #convert word into list from a string
tempList = list(word)
tempList.sort()
sortedList = "" #null string-we need this to put the now sorted list back into rearrange_dict
for letter in tempList:
sortedList += letter #adds each letter from tempList in order into sortedList
rearrange_dict[sortedList] = word #from pseudocode given
return rearrange_dict
def pick_best_word_faster(hand, rearrange_dict):
"""
Return the highest scoring word from rearrange_dict that can be made with the given hand.
Return '.' if no words can be made with the given hand.
hand: dictionary (string -> int)
rearrange_dict: dictionary (string -> int)
returns: list index 0
"""
def substrings(string):
"""
Given a string provides all the substrings.
needed help on this from hendrix of curiousreef
"""
result = []
if len(string) == 1:
result.append(string)
else:
for substring in substrings(string[:-1]):
result.append(substring)
substring = substring + string[-1]
result.append(substring)
result.append(string[-1])
return result
stringHand = ""
for letter in hand.keys():
for i in range(hand[letter]):
stringHand +=letter
sortedHand = ""
listHand = list(stringHand) #list version of hand
listHand.sort()
for letter in listHand:
sortedHand += letter
possibleWords = {}
for word in substrings(sortedHand):
if word in rearrange_dict:
possibleWords[rearrange_dict[word]]=points_dict[rearrange_dict[word]]
bestScore = [0,0]
if possibleWords:
for word in possibleWords: #compares current word to the word in bestScore[1]
if possibleWords[word] > bestScore[1]: #if current word is better than bestScore[0]
bestScore[0] = word
bestScore[1] = possibleWords[word]
if bestScore[0] == 0:
return '.' #player gives up
return bestScore[0] #else returns the word
#
# Problem #1: How long? time taken: 20 min
# Problem #2: time Limit time taken: 5 min
#
def play_hand(hand, points_dict):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
#max_time = float(raw_input('Enter time limit (in seconds): '))
max_time = time_limit
print '\nTime limit set as:',time_limit,'seconds.'
time_left = max_time
print '\nCurrent hand:',
#display_hand(hand)
newHand = hand.copy()
display_hand(newHand)
#print sum(newHand.values()),'before loop\n'
currentScore = 0.0
#wordScore = get_word_score(userWord,HAND_SIZE)
while sum(newHand.values()) != 0:
start_time = time.time() #added ability to time how long user takes
#userWord = str(raw_input('Enter a word from the given hand (or . to quit):'))
#userWord = pick_best_word(newHand,points_dict)
userWord = pick_best_word_faster(newHand,rearrange_dict)
#this will call pick_best_word which will be the computer playing.
end_time = time.time()
total_time = end_time - start_time
time_left -= total_time
print 'It took',round(total_time,4),'seconds to enter \'',userWord,'\'.','You have',round(time_left,4),'seconds remaining.'
#print sum(newHand.values()),'beg of loop\n'
if userWord == '.': #when you press . you quit prematurely
break
if time_left <= 0: #tests time left
print 'Total time exceeds,',max_time,'seconds.'
break
elif not is_valid_word(userWord, newHand, points_dict): #test for word validity
print 'Invalid word'
print '\nCurrent hand:',
display_hand(newHand)
else:
roundedTotal = 1 + total_time #fixing divide by zero errors by making points
#awarded as such: Normal word score/1 + time taken to answer
wordScore=round(get_word_score(userWord,HAND_SIZE)/roundedTotal,4)
currentScore += wordScore
print '\''+userWord+'\'','earns you',wordScore,'points.','Total:',currentScore,'points.'
newHand = update_hand(newHand, userWord)
print '\nCurrent hand:',
display_hand(newHand)
#print sum(newHand.values()),'end of loop\n'
print '\nFinal score:',currentScore,'Thanks for playing!'
#
# Playing a game
# Make sure you understand how this code works!
#
def play_game(points_dict):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
#print "play_game not implemented." # delete this once you've completed Problem #4
#play_hand(deal_hand(HAND_SIZE), word_list) # delete this once you've completed Problem #4
#testDict = {'h':1,'e':2,'l':4,'o':2,'j':1} #for testing only
#testDict1 = {'h':1,'e':1,'l':2,'o':1}
#play_hand(testDict1, word_list) #for testing only
## uncomment the following block of code once you've completed Problem #4
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or q to quit: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dict)
print
elif cmd == 'r':
play_hand(hand.copy(), points_dict)
print
elif cmd == 'q':
break
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list) #builds points_dict list of values for each word
rearrange_dict = get_word_rearrangements(word_list) #builds rearrange_dict list of values for each word
time_limit = get_time_limit(points_dict,1) #sets global time_limit based on computer
play_game(points_dict)
##=========================================================================
##
## Problem 5 ##
## Characterize the time complexity of your implementation (in terms of the
## size of word_list and the number of letters in a hand) of both
## pick_best_word and pick_best_word_faster.
##
##=========================================================================
No comments. Sign up or log in to comment # 6.00 Problem Set 6
#
# The 6.00 Word Game
#
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4,
'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1,
'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1,
's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8,
'y': 4, 'z': 10}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter.lower()]
if len(word) == n:
score += 50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
# My function
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
for letter in word: # goes through the word
if hand[letter] > 1: # if the number of letters in hand is > 1
hand[letter] = hand.pop(letter) - 1 # the number is reduced by 1
else:
hand.pop(letter) # if less than one, the key:value pair is removed
# pop(key, default = error) removes the key:value pair and displays the value
return hand
# Their function didn't work with my setup. It only reduced the value(key). It didn't remove
# the key completly. The presence of 'key':0 sent my program into an infinite loop.
##def update_hand(hand, word):
## """
## Assumes that 'hand' has all the letters in word.
## In other words, this assumes that however many times
## a letter appears in 'word', 'hand' has at least as
## many of that letter in it.
##
## Updates the hand: uses up the letters in the given word
## and returns the new hand, without those letters in it.
##
## word: string
## hand: dictionary (string -> int)
## returns: dictionary (string -> int)
## """
## freq = get_frequency_dict(word)
## newhand = {}
## for char in hand:
## newhand[char] = hand[char]-freq.get(char,0)
## return newhand
## #return dict( ( c, hand[c] - freq.get(c,0) ) for c in hand )
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dictionary):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
freq = get_frequency_dict(word)
for letter in word:
if freq[letter] > hand.get(letter, 0):
return False
return word in points_dictionary
#
# Problem #4: Playing a hand
#
##def play_hand(hand, points_dict):
## """
## Allows the user to play the given hand, as follows:
##
## * The hand is displayed.
##
## * The user may input a word.
##
## * An invalid word is rejected, and a message is displayed asking
## the user to choose another word.
##
## * When a valid word is entered, it uses up letters from the hand.
##
## * After every valid word: the score for that word is displayed,
## the remaining letters in the hand are displayed, and the user
## is asked to input another word.
##
## * The sum of the word scores is displayed when the hand finishes.
##
## * The hand finishes when there are no more unused letters.
## The user can also finish playing the hand by inputing a single
## period (the string '.') instead of a word.
##
## hand: dictionary (string -> int)
## word_list: list of lowercase strings
## """
## total_time = 0
## total = 0
## initial_handlen = sum(hand.values())
## while sum(hand.values()) > 0:
## print 'Current Hand:',
## display_hand(hand)
## start_time = time.time() # time to start counting
## good_words = find_all_words(hand, points_dict)
## userWord = pick_best_word(good_words)
## if userWord == '.':
## break
## else:
## isValid = is_valid_word(userWord, hand, points_dict)
## if not isValid:
## print 'Invalid word, please try again.'
## else:
## end_time = time.time() # time to end counting
## time_spent = end_time - start_time
## total_time += time_spent
## try:
## points = round(get_word_score(userWord, initial_handlen)/time_spent, 2)
## except: # just in case the entry time is near 0 seconds
## time_spent = 0.1 # This error pathway sets a minimum time
## print 'It took less than %0.2f seconds to provide an answer' % (time_spent)
## print 'You are too fast. Let\'s say it took at least %0.2f seconds to answer' % (total_time)
## print 'It took %0.2f seconds to provide an answer' % (time_spent)
## # The %0.2f tells python to insert the variable total_time as a floating point
## # that is rounded to the second decimal (hundreths place)
## time_left = time_clock(total_time, time_limit)
## if time_left > 0:
## total += points
## print '%s earned %0.2f points. Total: %0.2f points' % (userWord, points, total)
## print 'You have %0.2f seconds remaining' % (time_left)
## hand = update_hand(hand, userWord)
## else:
## print '%s earned %0.2f points, but ...' % (userWord, points)
## print 'Total time exceeds %s seconds.' % (time_limit)
## break
## print 'Total score: %s points.' % total
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(points_dictionary):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dictionary)
print
elif cmd == 'r':
play_hand(hand.copy(), points_dictionary)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#
## Problem # 6. Functions used for Problem set 6.
#
def hand_convert_to_list(hand):
""" Converts the dictionary 'hand' into a list of keys*frequency"""
keylist = hand.keys()
number_of_letters = hand_length_count(hand)
temp_dict = hand.copy()
check = False
while not check:
for key in keylist:
if temp_dict[key] > 1:
keylist.append(key)
temp_dict[key] = temp_dict.pop(key) - 1
if len(keylist) == number_of_letters:
check = True
return keylist
def hand_length_count(hand):
"""returns the total number of letters in scrabble dictionary"""
number_of_letters = 0
for letter in hand:
number_of_letters += hand[letter]
return number_of_letters
def find_all_words(hand, points_dict):
"""Return the highest scoring words from points_dict that
can be made with the given hand"""
ctr = sum(hand.values())
good_words = {}
while ctr > 1:
for word in points_dict:
if len(word) == ctr and word_compare(hand, word):
good_words[word] = points_dict[word]
ctr -= 1
if len(good_words) != 0:
return good_words
else:
return '.'
def choose_best_words(good_words):
"""Returns a sub-dictionary of the highest scoring words from find_all_words"""
if good_words == '.':
return '.'
highest = 0
best_words = {}
for word in good_words:
if good_words[word] >= highest:
highest = good_words[word]
best_words[word] = highest
return best_words
def pick_best_word(good_words):
"""Returns highest scoring word from find_all_words"""
if good_words == '.':
return '.'
highest = 0
for word in good_words:
if good_words[word] >= highest:
highest = good_words[word]
best_word = word
return best_word
def get_words_to_points(word_list):
"""Return a dictionary that maps every word in word_list to its point value"""
points_dict = {}
for word in word_list:
points_dict[word] = get_word_score(word, 10)
return points_dict
def word_compare(hand, key):
"""Returns True if key can be made by letters in hand. Returns False otherwise"""
handlist = hand_convert_to_list(hand)
keylist = list(key)
for letter in keylist:
if letter in handlist:
handlist.remove(letter)
else:
return False
return True
def get_time_limit(points_dict, k):
"""Return the time limit for the computer player as a function of the multiplier k.
points_dict should be the same dictionary that is created by get_words_to_points."""
start_time = time.time()
# Do some computation. the only purpose of the computation is so we can figure out
# how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time)*k
def time_clock(time_spent, time_limit):
""" Sets a time limit to a round."""
time_left = time_limit - time_spent
if time_left < 0:
time_left = 0
return time_left
#
## Problem 7. Even Faster Computer Player
#
def rearrange_words(word_list):
""" Returns a dictionary of all words in word_list linked to the sorted letters in the word"""
rearrange_dict = {}
for word in word_list:
rearrangedlist = sorted(word)
rearrangedstring = ''.join(rearrangedlist)
rearrange_dict[rearrangedstring] = word
return rearrange_dict
def get_rearranged_to_points(rearrange_dict):
"""Return a dictionary that maps every sorted string in rearrange_dict to its point value"""
rearrange_points_dict = {}
for sortedstring in rearrange_dict:
rearrange_points_dict[sortedstring] = get_word_score(sortedstring, 10)
return rearrange_points_dict
def play_hand(hand, rearrange_points):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word is displayed,
the remaining letters in the hand are displayed, and the user
is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total_time = 0
total = 0
initial_handlen = sum(hand.values())
while sum(hand.values()) > 0:
print 'Current Hand:',
display_hand(hand)
start_time = time.time() # time to start counting
userWord = pick_best_word(find_all_words_faster(hand, rearrange_points))
if userWord == '.':
break
else:
isValid = is_valid_word(userWord, hand, rearrange_points)
if not isValid:
print 'Invalid word, please try again.'
else:
end_time = time.time() # time to end counting
time_spent = end_time - start_time
total_time += time_spent
try:
points = round(get_word_score(userWord, initial_handlen)/time_spent, 2)
except: # just in case the entry time is near 0 seconds
time_spent = 0.01 # This error pathway sets a minimum time
print 'It took less than %0.2f seconds to provide an answer' % (time_spent)
print 'You are too fast. Let\'s say it took at least %0.2f seconds to answer' % (time_spent)
points = round(get_word_score(userWord, initial_handlen)/time_spent, 2)
print 'It took %0.2f seconds to provide an answer' % (time_spent)
# The %0.2f tells python to insert the variable total_time as a floating point
# that is rounded to the second decimal (hundreths place)
time_left = time_clock(total_time, time_limit)
if time_left > 0:
total += points
print '%s earned %0.2f points. Total: %0.2f points' % (rearrange_dict[userWord], points, total)
print 'You have %0.2f seconds remaining' % (time_left)
hand = update_hand(hand, userWord)
else:
print '%s earned %0.2f points, but ...' % (userWord, points)
print 'Total time exceeds %s seconds.' % (time_limit)
break
print 'Total score: %s points.' % total
def find_all_words_faster(hand, rearranged_points):
"""Retruns all words that can be made with hand"""
good_words = {}
sortedhandlist = sorted(hand_convert_to_string(hand))
sortedhandstring = ''.join(sortedhandlist)
for word in rearrange_points:
if word in sortedhandstring:
good_words[word] = rearrange_points[word]
if len(good_words) != 0:
return good_words
else:
return '.'
def hand_convert_to_string(hand):
"""Converts the dictionary 'hand' into srtring"""
keylist = hand_convert_to_list(hand)
keyliststring = ''.join(keylist)
return keyliststring
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list)
rearrange_dict = rearrange_words(word_list)
rearrange_points = get_rearranged_to_points(rearrange_dict)
time_limit = get_time_limit(points_dict, k = 1)
play_game(rearrange_points)
#
## Problem #8. Algorithm Analysis
#
# The differences between find_all_words and find_all_words_faster is that find_all_words
# uses a function called word_compare and checks that the len(word) is the same for
# a particular search. word_compare compares letter for letter two words.
# find_all_words_faster only uses a word in dictionary statement which should be O(len(word_list)).
# word_compare is O(len(hand)), because it must go through hand. find_all_words also searches through
# word_list. Because, it also compares word length it must go through ~len(hand) times.
# Thus, the order of find_all_word is O(len(hand)^2*len(wordlist)). Then find_all_words is
# approximately 7*7 = 49 times slower, which is consistent with observed word submission times.
# On a side note. If the ctr feature in find_all_words is removed, the average time to find
# good_words increases by ~0.08 seconds. This may be small, but is consistent.
No comments. Sign up or log in to comment
# Problem Set 6: Word Game
# Name: chip
import random
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
HAND_LIMIT = 20
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
WORDLIST_FILENAME = "words.txt"
def get_word_rearrangements(word_list):
rearrange_dict = []
for word in word_list:
rearrange_dict.append("".join(sorted(word)))
return rearrange_dict
def get_frequency_dict(sequence):
freq = {}
for x in sequence:
freq[x] = freq.get(x, 0) + 1
return freq
def display_hand(hand):
for letter in hand.keys():
for j in range(hand[letter]):
print(letter) # print all on the same line
def deal_hand(n):
hand={}
num_vowels = n // 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def update_hand(hand, word):
new_hand = hand.copy()
for c in word:
if c in new_hand:
new_hand[c] -= 1;
if new_hand[c] == 0:
del new_hand[c]
return new_hand
def is_valid_word(word, hand, word_list):
test_hand = hand.copy()
if word not in word_list:
return False
for c in word:
if c not in test_hand:
return False
else:
if test_hand[c] == 0:
return False
test_hand[c] -= 1
return True
def load_words():
inFile = open(WORDLIST_FILENAME, encoding='utf-8')
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
return wordlist
def get_word_score(word, n):
score = 0
for c in word:
score += SCRABBLE_LETTER_VALUES[c]
if len(word) == n:
score += 50
return score
def get_words_to_points(word_list):
points_dict = {}
for word in word_list:
points_dict[word] = get_word_score(word,0)
return points_dict
def pick_best_word(hand, points_dict):
posibilities = {}
for (word, point) in points_dict.items():
posible_word = True
hand_copy = hand.copy()
for ch in word:
if ch not in hand_copy.keys():
posible_word = False
break
else:
del hand_copy[ch]
if posible_word:
posibilities[point] = word
key_vals = posibilities.keys()
sorted(key_vals)
if len(posibilities) == 0:
return "."
else:
return posibilities[max(key_vals)]
def pick_best_word_faster(hand, points_dict, rearrange_dict):
posibilities = {}
sorted_hand = "".join(sorted("".join(hand)))
for (word, point) in points_dict.items():
if sorted_hand in rearrange_dict:
posibilities[point] = word
if len(posibilities) == 0:
return "."
else:
return posibilities[max(posibilities.keys())]
def play_hand(hand, word_list, rearrange_dict):
points_dict = get_words_to_points(word_list)
total_points, time_spend, total_time = 0,0,0
while True:
print("Current hand: ")
display_hand(hand)
start_time = time.time()
print("You have " + str(HAND_LIMIT - total_time) + " seconds ramaining!")
word = pick_best_word_faster(hand, points_dict, rearrange_dict)
# word = input("Enter word, or . to indicate thar you are finished: ")
time_spend += (time.time() - start_time)
total_time += time_spend
if word == ".":
print("Total score: ",total_points)
break
if total_time > HAND_LIMIT:
print("Time limit exceeded!")
break
if not is_valid_word(word, hand, word_list):
print("Ivalid word, please try again!")
continue
points = get_word_score(word, len(hand))
print(("It took {0:2f} seconds to provide an answer.").format(time_spend))
total_points += (points / time_spend)
print(word, "earned", points,"points. Total:",total_points)
hand = update_hand(hand, word)
time_spend = 0
def play_game(word_list, rearrange_dict):
hand = deal_hand(HAND_SIZE)
while True:
cmd = input("Enter n to deal a new hand, r to replay the last hand, or e to end game: ")
if cmd == "n":
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), word_list, rearrange_dict)
print()
elif cmd == "r":
play_hand(hand.copy(), word_list, rearrange_dict)
print()
elif cmd == "e":
break
else:
print("Invalid command.")
word_list = load_words()
rearrange_dict = get_word_rearrangements(word_list)
play_game(word_list, rearrange_dict)
No comments. Sign up or log in to comment This is the first problem set I found really difficult, well I should say that I was finding it easy until the faster computer player part which really foxed me for a long time! Eventually I got it though and I think it is working pretty good (this has been the most rewarding problem set as well as the hardest). I'm not sure about my complexity analysis either, but I timed both the faster and my old computer player and the difference is pretty substantial, small hands are faster using the get_best_word_faster function but as hand size grows my original function is far better with large hands taking a loooong time in the "faster" function. By the time hand size got up to 24 characters my pick_best_word_faster function was taking almost 20 seconds and I couldn't even get a 25 character hand to finish running! Can't wait to have a look at other peoples answers. # Problem Set 6: 6.00 Word Game 2
# Name: Mark Calderwood
# Collaborators:
# Time:
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
#---6.0 problem 3 functions
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
scores = {}
for word in word_list:
scores[word] = get_word_score(word, HAND_SIZE)
return scores
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the
given hand.
Return '.' if no words can be made with the given hand.
"""
makeable_words = {}
for word in points_dict:
if is_valid_word(word, hand, points_dict):
makeable_words[word] = points_dict[word]
current_best = [0,0]
if makeable_words:
for word in makeable_words:
if makeable_words[word] > current_best[1]:
current_best[0] = word
current_best[1] = makeable_words[word]
return current_best[0]
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
"""
start_time = time.time()
# Do a computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
def get_word_rearrangements(word_list):
"""
Return a dict that maps every word in the wordlist to itself sorted
alphabetically e.g. zap to apz for quick access
"""
rearrange_dict = {}
for word in word_list:
temp = [] # to convert the word into a list for sorting
temp = list(word)
temp.sort()
sorted = "" # create a string to put the sorted list back into
for i in temp:
sorted = sorted + i # & add each letter from the 1 at a time
rearrange_dict[sorted] = word #if more than 1 word has the same letters
# just overwrite the old one and keep only the last (it will score the same)
return rearrange_dict
def pick_best_word_faster(hand, rearrange_dict):
"""
Return the highest scoring word from points_dict that can be made with the
given hand (but faster!).
Return '.' if no words can be made with the given hand.
"""
def substrings(string):
"""
Given a string provides all the substrings.
Works on the premiss that given a set of the substrings of a string the
the subsets of a string with one more char is the formed by taking all the
substrings in the known subset and also adding to them the set formed by
adding the character to every element in the old set and then adding the
new char
"""
result = []
if len(string) == 1:
result.append(string)
else:
for substring in substrings(string[:-1]):
result.append(substring)
substring = substring + string[-1]
result.append(substring)
result.append(string[-1])
return result
#prelim, convert the hand into a string
hand_string = ""
for letter in hand.keys():
for j in range(hand[letter]):
hand_string = hand_string + letter
#1st sort the hand
sorted_hand = ""
hand_list = list(hand_string)
hand_list.sort()
for i in hand_list:
sorted_hand = sorted_hand + i
#2nd determine which words we can make stored as a dictionary with points
makeable_words = {}
for sub in substrings(sorted_hand):
if sub in rearrange_dict:
makeable_words[rearrange_dict[sub]]=points_dict[rearrange_dict[sub]]
#3rd choose best word
current_best = [0,0]
if makeable_words:
for word in makeable_words:
if makeable_words[word] > current_best[1]:
current_best[0] = word
current_best[1] = makeable_words[word]
return current_best[0]
#---End of 6.0 problem functions
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
if word == "":
return 0
score = 0
for letter in word:
score = score + SCRABBLE_LETTER_VALUES[letter]
if len(word) == n:
score = score + 50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
#
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
newHand = hand.copy()
for i in word:
newHand[i] -= 1
return newHand
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the points_dict and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or points_dict.
word: string
hand: dictionary (string -> int)
points_dict: dictionary (string -> int)
"""
helperHand = hand.copy()
if points_dict.has_key(word):
for i in word:
if helperHand.get(i, 0) > 0:
helperHand[i] -= 1
else: return False
return True
else: return False
#
# Problem #4: Playing a hand
#
def play_hand(hand, points_dict):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* The time it takes for the word to be entered is recorded
* An invalid word is rejected, and a message is displayed asking
the user to choose another word
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
points_dict: dictionary (string -> int)
"""
def get_time():
"""
Asks the player for the amount of time they wish on the clock for this
hand
Returns: float
"""
while True:
time = raw_input("What should the time limit for this hand be?")
try:
time_limit = float(time)
return time_limit
except:
print"time is not in valid format, please input a number"
def get_input():
"""
Asks the player for a word and returns the word and the time taken
Returns: a two element tuple containing the word as the 1st element and
the time taken as the second
"""
start_time = time.time()
word = raw_input("Enter word, or . to indicate that you are finished: ")
end_time = time.time()
total_time = end_time - start_time
if total_time < 0.001:
total_time = 0.001
return (word, total_time)
computers_hand = hand.copy()
time_limit = get_time()
totalScore = 0.0
word = ''
while word != '.':
print "Current Hand: ",
display_hand(hand)
input = get_input()
word = input[0]
input_time = input[1]
time_limit -= input_time
if time_limit >= 0:
if is_valid_word(word, hand, points_dict):
hand = update_hand(hand, word)
score = points_dict[word]#/input_time
totalScore += score
print word, "in %0.2f seconds earned %0.2f points. Total: %0.2f points." % (
input_time, score, totalScore)
print "time remaining is: %0.2f" % time_limit
elif word == '.':
slow_time_start = time.time()
best_word = pick_best_word(computers_hand, points_dict)
slow_time_stop = time.time()
slow_time_total = slow_time_stop - slow_time_start
fast_time_start = time.time()
fastest_word = pick_best_word_faster(computers_hand, rearrange_dict)
fast_time_stop = time.time()
fast_time_total = fast_time_stop - fast_time_start
print "The computers word would have been %s scoring : %i in %0.5f seconds" \
% (best_word, points_dict[best_word], slow_time_total)
print "The fast computers word would have been %s scoring : %i in %0.5f seconds" \
% (fastest_word, points_dict[best_word], fast_time_total)
break
else:
print "Invalid word, please try again"
print "time remaining is: %0.2f" % time_limit
else:
print "Sorry you ran out of time"
slow_time_start = time.time()
best_word = pick_best_word(computers_hand, points_dict)
slow_time_stop = time.time()
slow_time_total = slow_time_stop - slow_time_start
fast_time_start = time.time()
fastest_word = pick_best_word_faster(computers_hand, rearrange_dict)
fast_time_stop = time.time()
fast_time_total = fast_time_stop - fast_time_start
print "The computers word would have been %s scoring : %i in %0.5f seconds" \
% (best_word, points_dict[best_word], slow_time_total)
print "The fast computers word would have been %s scoring : %i in %0.5f seconds" \
% (fastest_word, points_dict[best_word], fast_time_total)
break
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(points_dict):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dict)
elif cmd == 'r':
play_hand(hand.copy(), points_dict)
elif cmd == 'e':
print "Thanks for playing, maybe you can try again another time?"
break
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list)
rearrange_dict = get_word_rearrangements(word_list)
#time_limit = get_time_limit(points_dict, 5)
play_game(points_dict)
#
# Problem 5 #
# I think my original pick_best_word function is running in linear time
# linked to the size of the word_list. It's not quite that simple because
# as the hand size grows the number of potential words added to the
# makeable_words list grows which then have to be itterated over to determine
# the best but I think this is neglible as once the hand size gets very large
# (large enough that there are enough letters so every word can be made)
# then the number of opperations won't increase any more by adding to the hand
# size.
#
# I think the pick_best_word_faster function runs in at least exponetial time
# but linked to the size of the hand. This is because the function that splits
# the hand into all the substrings takes a looong time to run as hand size gets
# larger and there are clearly more than linear opperations in it. Also the
# number of substrings produced which then have to be looped through increases
# in a more than linear fashion with respect to hand size, perhaps the overall
# order of growth is something like exponential, it certainly takes a long time
# to run very quickly. This would reflect the results I got from timing my
# program, as hand size increases this function becomes very very slow! (I
# started running it with hand size 25 over 20 minutes ago and it hasn't
# finished yet where it took 17.80048 seconds with hand size 24)
No comments. Sign up or log in to comment Word games 2 Problem 4: i copy the function which find subset from BTheMad, thanks! this problem is really hard to comprehend what it is talking about. then i watch lecture 11 in which the prof. said the problem set doesn't tell you everything and you have to do what you think is reasonable. so i quit guessing what the problem want me to do, and just did what i think can solve the problem. as required, i create the rearrangement_dict whose key is a sorted string, and the value is a list, containing all valid word that can be spelled with the letter in the key for example: {'aelpp':[apple,appel]} suppose the given hand is {'a':1,'p':2,'l':1,'e':1} both 'apple' and 'appel' are correct first i turn the given hand to a sorted list [a,e,l,p,p] then find each possible subset of it, turn it back to string and stor in a list. 'aelpp' is one of the subset. then find such value in the rearrangement_dict, and keep the highest score # Problem Set 6: 6.00 Word Game
# Name: Joe Li
# Time: 8:30
#
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score=0
for letter in word:
score+=SCRABBLE_LETTER_VALUES[letter]
if len(word)==n:
score+=50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line'
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
hand2=hand.copy()
for letter in word:
hand2[letter]-=1
return hand2
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
if word not in points_dict: # if the word is not a actual word
return False
for letter in word:
if not letter in hand: # if the letter in word is not available
return False
hand2=update_hand(hand,word)
for i in hand2: # if the letter is available but not enough
if hand2.get(i)<0:
return False
return True
def play_game(word_list):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
# TO DO ...
#play_hand(deal_hand(HAND_SIZE), word_list) # delete this once you've completed Problem #4
## uncomment the following block of code once you've completed Problem #4
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dict,time_limit)
print
elif cmd == 'r':
play_hand(hand.copy(), points_dict,time_limit)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#################################
# #
# Problem Set 6 Starts here #
# #
#################################
#
# Problem #1: How long?
# Problem #2: Time Limit
#
def play_hand(hand, points_dict, time_limit):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total=0 # total score
current=hand.copy() # current hand
left=1
#time_limit=8
print 'Enter time limit, in seconds, for players: '+str(time_limit)
time_remain=time_limit
time_exceeds=False # if time_exceeds: break
while left!=0: # there is still letter left in hand
print 'Current Hand: ',
display_hand(current)
start_time = time.time() # time start
# word=str(raw_input('Enter word, or a . to indicate that you are finished: '))
word=pick_best_word_faster(current,points_dict)
print 'Enter word, or a . to indicate that you are finished: '+word
end_time = time.time() # time end
total_time = end_time - start_time
print 'It took %0.2f seconds to provide an answer.' % total_time
time_remain-=total_time
if time_remain<0: # time_exceeds
print 'Total time exceeds '+str(time_limit)+' seconds. You scored '+str(total)+' points.'
time_exceeds=True
break
print 'You have '+str(time_remain)+' seconds remaining.'
if word!='.': # test word
if is_valid_word(word,current,points_dict):
current=update_hand(current,word)
left=0 # reset left
for letter in current:
left+=current.get(letter) # letter left in hand
score=round(get_word_score(word,HAND_SIZE)/float(total_time),2)
total+=score
print word+' earned '+str(score)+' points. Total: '+str(total)+' points'
else: # word invalid
print 'Invalid word, please try again.'
else: # choose finished
left=0
if time_exceeds==False: # if not time_exceeds: print the total score
# if time_exeeds: have already break
print 'Total score: '+str(total)+' points.'
#
# Problem #3: Computer Player
#
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
points = {}
for word in word_list:
value=0
for letter in word:
value+=SCRABBLE_LETTER_VALUES[letter]
points[word]=value
return points
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict
that can be made with the given hand.
Return '.' if no words can be made with the given hand.
"""
highest=''
for word in points_dict:
if is_valid_word(word,hand,points_dict):
if highest=='' or points_dict[word]>points_dict[highest]:
highest=word
if highest!='':
return highest
return '.' # no word can be spelled with current hand
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the multiplier k.
points_dict should be the same dictionary that is created by get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can # figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * 1
#
# Problem #4: Even Faster Computer Player
#
def sort_string(word):
"""
Return a string with the exact letter of input but in sorted order
word:string
"""
order=[]
for letter in word: # change a string to list
order.append(letter)
order.sort()
sorted_word='' # sort the list
for i in range(len(order)): # change the list back to string
sorted_word+=order[i]
return sorted_word
def get_word_rearrangements(word_list):
"""
Return a dictionary d
key: sorted string
value: a list of the word can be spelled with the letter in the sorted string
all of the word in word_list is included in this dict
"""
d={}
for word in word_list:
string=sort_string(word) # sort the letter of every word in word_list
if d.get(string)==None: # if the subset hasn't been created yet
d[string]=[word] # creat a list containing the subset
else: # if the subset has been created
d[string].append(word) # append the value with the new string
return d
def get_sets_recursive(word, word_list):
"""
Generate all possible string from a given letter list, without order changed
word: list
"""
# this function is written by BTheMad, thanks.
# i have been think this prolem all night
# i guess i'm just too stupid too figure it out
if len(word) > 0:
str_word = "".join(word)
if str_word not in word_list:
word_list.append(str_word)
for letter in word:
tmp_word = word[:]
tmp_word.remove(letter)
if len(tmp_word) > 0 and "".join(tmp_word) not in word_list:
get_sets_recursive(tmp_word, word_list)
return word_list
def pick_best_word_faster(hand,points_dict):
"""
Return the highest scoring word from points_dict
that can be made with the given hand.
Return '.' if no words can be made with the given hand.
"""
sorthand=[]
highest=''
for letter in hand.keys():
for j in range(hand[letter]):
sorthand.append(letter)
sorthand.sort() # make a sorted list of given hand
s=get_sets_recursive(sorthand,[]) # find every subset
for p in s:
if p in rearrange_dict:
for word in rearrange_dict[p]:
if is_valid_word(word,hand,points_dict):
if highest=='' or points_dict[word]>points_dict[highest]: # store the word with highest score
highest=word
if highest!='':
return highest
return '.' # no word can be spelled with current hand
#
# Problem #5: Algorithm Analysis
#
# algorithm of pick_best_word: O(n**2)
# 1.traverse all the words in word_list
# 2.check if the given hand can spell the word
# 3.if it can, keep the score untill find the higher score
#
# algorithm of pick_best_word_faster: O(n)
# 1.map every word in word_list to a ordered string
# 2.find every sorted subset of the given hand
# 3.for each subset, find out the word mapped to it, keep the highest score
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict=get_words_to_points(word_list)
rearrange_dict=get_word_rearrangements()
time_limit=get_time_limit(points_dict,1)
play_game(word_list)
No comments. Sign up or log in to comment Very strange results in fast_pick =/ For some reason it takes too much time to generate all the sub-sets and this kills all the benefits from further access to dictionary. This version contains some profiling and launches both methods. # Problem Set 5: 6.00 Word Game
# Name:
# Collaborators:
# Time:
#
import random
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 10
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def load_words():
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
# (end of helper code)
# -----------------------------------
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
score = 0
if len(word) == 0:
return score
elif word == '.':
return score
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter]
if len(word) == n:
score += 50
return score
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print # print an empty line
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
#
def update_hand(hand, word):
for letter in word:
hand[letter] = hand.get(letter, 0) - 1
if hand[letter] == 0:
del hand[letter]
return hand
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dict):
freq = get_frequency_dict(word)
for letter in word:
if freq[letter] > hand.get(letter, 0):
return False
if points_dict.get(word) > 0:
return True
else:
return False
#
# Problem #6.3: Get points for words
#
def get_words_to_points(word_list):
"""Return a dict that maps every word in a word_list to its point value."""
points_dict = {}
for word in word_list:
points_dict[word] = get_word_score(word, HAND_SIZE)
return points_dict
#
# Problem #6.3: Get points for words
#
def pick_best_word(hand, points_dict):
"""Find best word with given hand and points dictionary"""
word = "."
score = 0
best_score = 0
for tmp_word in points_dict.keys():
if is_valid_word(tmp_word, hand, points_dict):
score = get_word_score(tmp_word, HAND_SIZE)
if score > best_score:
word = tmp_word
best_score = score
return word
#
# Problem #6.4: Get a sequence of letters for a word
#
def get_word_rearrangements(word):
"""Get a string of letters, that are contained in a word"""
tmp_list = list(word)
tmp_list.sort()
sequence = "".join(tmp_list)
return sequence
#
# Problem #6.4: Get a sequence of letters for a hand
#
def get_hand_rearrangements(hand):
""" Get a rearrangements for a given hand """
tmp_list = []
for letter in hand.keys():
for j in range(hand[letter]):
tmp_list.append(letter)
tmp_list.sort()
sequence = "".join(tmp_list)
return sequence
#
# Problem #6.4: Create a rearrangement dictionary
#
def get_rearrange_dic(word_list):
"""Create a list of words as sequences of letter for a word list"""
rearrange_dict = {}
for word in word_list:
rearrange_dict[get_word_rearrangements(word)] = word
return rearrange_dict
def get_sets_recursive(word, word_list):
"""Generate all possible string from a given, without order changed"""
if len(word) > 0:
str_word = "".join(word)
if str_word not in word_list:
word_list.append(str_word)
for letter in word:
tmp_word = word[:]
tmp_word.remove(letter)
if len(tmp_word) > 0 and "".join(tmp_word) not in word_list:
get_sets_recursive(tmp_word, word_list)
return word_list
#
# Problem #6.4: Generate all sequences from a word
#
def get_all_hand_sets(word):
"""Generate all possible string from a given, without order changed"""
word_list = get_sets_recursive(list(word), [])
return word_list
#
# Problem #6.4: Pick word faster, than ever
#
def pick_best_word_faster(hand, rearrange_dict):
"""Faster version of picking word algorithm"""
hand_rearrangements = get_hand_rearrangements(hand)
hand_sets = get_all_hand_sets(hand_rearrangements)
max_score_word = '.'
max_score = 0
score = 0
word = '.'
for sub_set in hand_sets:
if sub_set in rearrange_dict.keys():
word = rearrange_dict[sub_set]
score = get_word_score(word, HAND_SIZE)
if score > max_score:
max_score_word = word
max_score = score
return max_score_word
#
# Problem #6.3: Get timelimit for a computer
#
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the multiplier k.
points_dict should be the same dictionary that is created by get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
#
# Problem #4: Playing a hand
#
def play_hand(hand, points_dict, rearrange_dict):
"""
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
total_score = 0
game_finished = False
time_limit = get_time_limit(points_dict, 10)
print "Time limit is set to %0.2f" %time_limit
total_time = 0
time_left = 0
while not game_finished:
score = 0
round_start = 0
round_end = 0
round_time = 0
print "Current hand: ",
display_hand(hand)
round_start = time.time()
round_start = time.time()
word = pick_best_word(hand, points_dict)
round_end = time.time()
round_time = round_end - round_start
print "###################### %s #########################" %word
print "###################### %d #########################" %get_word_score(word, HAND_SIZE)
print "###################### %0.5f #########################" %round_time
round_start = time.time()
word = pick_best_word_faster(hand, rearrange_dict)
round_end = time.time()
round_time = round_end - round_start
print "###################### %s #########################" %word
print "###################### %d #########################" %get_word_score(word, HAND_SIZE)
print "###################### %0.5f #########################" %round_time
round_end = time.time()
round_time = round_end - round_start
total_time += round_time
time_left = time_limit - total_time
if word == ".":
game_finished = True
elif len(hand) == 0:
game_finished = True
elif total_time > time_limit:
print "Total time exceeds %d seconds" %time_limit
game_finished = True
else:
if is_valid_word(word, hand, points_dict):
score = get_word_score(word, HAND_SIZE) / round_time
total_score += score
print "It took %0.2f seconds to provide an answer." %round_time
print "You have %0.2f seconds remaining." %(time_left)
print "%s earned %0.2f points. Total: %0.2f points." %(word, score, total_score)
hand = update_hand(hand.copy(), word)
else:
print "Invalid word, please try again."
print "You have %0.2f seconds remaining." %(time_left)
if game_finished:
print "Total score: %0.2f" %total_score
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(points_dict, rearrange_dict):
hand = deal_hand(HAND_SIZE) # random init
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dict, rearrange_dict)
print
elif cmd == 'r':
play_hand(hand.copy(), points_dict, rearrange_dict)
print
elif cmd == 'e':
break
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list)
rearrange_dict = get_rearrange_dic(word_list)
play_game(points_dict, rearrange_dict)
No comments. Sign up or log in to comment #!/usr/bin/env python
#-*- coding:utf-8 -*-
import random
import string
import time
VOWELS = 'aeiou'
CONSONANTS = 'bcdfghjklmnpqrstvwxyz'
HAND_SIZE = 7
SCRABBLE_LETTER_VALUES = {
'a': 1, 'b': 3, 'c': 3, 'd': 2, 'e': 1, 'f': 4, 'g': 2, 'h': 4, 'i': 1, 'j': 8, 'k': 5, 'l': 1, 'm': 3, 'n': 1, 'o': 1, 'p': 3, 'q': 10, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 4, 'w': 4, 'x': 8, 'y': 4, 'z': 10
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "/home/dave/Documents/python/Assignments/ps5and6/words.txt"
def load_words():
"""
Returns a list of valid words. Words are strings of lowercase letters.
Depending on the size of the word list, this function may
take a while to finish.
"""
print "Loading word list from file..."
# inFile: file
inFile = open(WORDLIST_FILENAME, 'r', 0)
# wordlist: list of strings
wordlist = []
for line in inFile:
wordlist.append(line.strip().lower())
print " ", len(wordlist), "words loaded."
return wordlist
def get_frequency_dict(sequence):
"""
Returns a dictionary where the keys are elements of the sequence
and the values are integer counts, for the number of times that
an element is repeated in the sequence.
sequence: string or list
return: dictionary
"""
# freqs: dictionary (element_type -> int)
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
def get_time_limit(points_dict, k):
"""
Return the time limit for the computer player as a function of the
multiplier k.
points_dict should be the same dictionary that is created by
get_words_to_points.
"""
start_time = time.time()
# Do some computation. The only purpose of the computation is so we can
# figure out how long your computer takes to perform a known task.
for word in points_dict:
get_frequency_dict(word)
get_word_score(word, HAND_SIZE)
end_time = time.time()
return (end_time - start_time) * k
# (end of helper code)
# -----------------------------------
#
# Problem #1: Scoring a word
#
def get_word_score(word, n):
"""
Returns the score for a word. Assumes the word is a
valid word.
The score for a word is the sum of the points for letters
in the word, plus 50 points if all n letters are used on
the first go.
Letters are scored as in Scrabble; A is worth 1, B is
worth 3, C is worth 3, D is worth 2, E is worth 1, and so on.
word: string (lowercase letters)
returns: int >= 0
"""
score = 0
for letter in word:
score += SCRABBLE_LETTER_VALUES[letter]
if len(word) == n:
score += 50
return score
def get_words_to_points(word_list):
"""
Return a dict that maps every word in word_list to its point value.
"""
scores = {}
for word in word_list:
score = get_word_score(word, HAND_SIZE)
scores[word] = score
return scores
def rearrange_letters(word):
list1 = []
for letter in word:
list1.append(letter)
list1.sort()
word = ""
for letter in list1:
word = word + letter
return word
def get_word_rearrangements(word_list):
d ={}
for word in word_list:
word2 = rearrange_letters(word)
try:
indict = d[word2]
dict_score = get_word_score(indict, HAND_SIZE)
new_score = get_word_score(word, HAND_SIZE)
if new_score > dict_score:
d[word2] = word
else:
continue
except KeyError:
d[word2] = word
return d
#
# Make sure you understand how this function works and what it does!
#
def display_hand(hand):
"""
Displays the letters currently in the hand.
For example:
display_hand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
# print all on the same line
print letter,
# function in template was an empty 'print' statement,
# but the fucntion kept printing 'None' instead of a new line. This fixed it.
return ""
#
# Make sure you understand how this function works and what it does!
#
def deal_hand(n):
"""
Returns a random hand containing n lowercase letters.
At least n/3 the letters in the hand should be VOWELS.
Hands are represented as dictionaries. The keys are
letters and the values are the number of times the
particular letter is repeated in that hand.
n: int >= 0
returns: dictionary (string -> int)
"""
hand={}
num_vowels = n / 3
for i in range(num_vowels):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(num_vowels, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
# Problem #2: Update a hand by removing letters
#
def update_hand(hand, word):
"""
Assumes that 'hand' has all the letters in word.
In other words, this assumes that however many times
a letter appears in 'word', 'hand' has at least as
many of that letter in it.
Updates the hand: uses up the letters in the given word
and returns the new hand, without those letters in it.
Has no side effects: does not mutate hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
# remove letters used by word. Returns new hand minus 'word.'
# Does not deal new letters into hand.
hand2 = hand.copy()
for letter in word:
hand2[letter] += -1
return hand2
#
# Problem #3: Test word validity
#
def is_valid_word(word, hand, points_dict):
"""
Returns True if word is in the word_list and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or word_list.
word: string
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
length_hand = sum(hand.values())
if len(word) > length_hand:
return False
else:
word_dict = get_frequency_dict(word)
hand_temp = hand.copy()
for letter in word_dict.keys():
if letter not in hand.keys():
return False
else:
hand_temp[letter] -= word_dict[letter]
if hand_temp[letter] < 0:
return False
try:
points_dict[word]
return True
except KeyError:
return False
#
# Problem #4: Playing a hand
#
def pick_best_word(hand, points_dict):
"""
Return the highest scoring word from points_dict that can be made with the
given hand.
Return '.' if no words can be made with the given hand.
"""
best_word = ""
best_score = 0
for word in points_dict.keys():
if is_valid_word(word, hand, points_dict):
if points_dict[word] > best_score:
best_word = word
print best_word
return best_word
def all_hands_sorted(hand):
n = len(hand)
hands = [hand]
all_hands = build_hand(hand, hands, n)
for hand in all_hands:
hand.sort()
return hands
# There has to be a better way to implement this. It's so dirty...
def build_hand(hand, hands, n):
for letter in hand:
hand2 = hand[:]
hand2.remove(letter)
if hand2 not in hands:
hands.append(hand2)
build_hand(hand2, hands, n-1)
else:
build_hand(hand2, hands, n - 1)
return hands
def pick_best_word_faster(hand_dict, rearrange_dict):
hand = []
for letter in hand_dict.keys():
for j in range(hand_dict[letter]):
hand.append(letter)
hands = all_hands_sorted(hand)
best_word = ""
score = 0
for hand in hands:
hand_string = ''
for letter in hand:
hand_string = hand_string + letter
try:
word = rearrange_dict[hand_string]
new_score = get_word_score(word, HAND_SIZE)
if new_score > score:
best_word = word
score = new_score
except KeyError:
continue
print best_word
return best_word
def play_hand(hand, points_dict, limit, plyr):
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word.
* An invalid word is rejected, and a message is displayed asking
the user to choose another word.
* When a valid word is entered, it uses up letters from the hand.
* After every valid word: the score for that word and the total
score so far are displayed, the remaining letters in the hand
are displayed, and the user is asked to input another word.
* The sum of the word scores is displayed when the hand finishes.
* The hand finishes when there are no more unused letters.
The user can also finish playing the hand by inputing a single
period (the string '.') instead of a word.
* The final score is displayed.
hand: dictionary (string -> int)
word_list: list of lowercase strings
"""
n = sum(hand.values())
score = 0
while True:
if sum(hand.values()) == 0:
print "\nFinal score: ", score
return
else:
print "Current hand: ", display_hand(hand)
start_time = time.time()
if plyr == 'c':
word = pick_best_word_faster(hand, rearrange_dict)
if word == '':
word = '.'
else:
word = raw_input("\nEnter word, or a . to indicate that you are finished: ")
end_time = time.time()
total_time = end_time - start_time
if total_time == 0:
total_time = 0.0001
print "It took %.2f seconds to provide an answer." % total_time
if limit <= total_time:
print "Time limit exceeded."
print "Final score: ", score
return
else:
limit -= total_time
if is_valid_word(word, hand, points_dict):
hand = update_hand(hand, word)
word_score = get_word_score(word, n)
word_score_t = word_score/total_time
score += word_score_t
print "Word score: ", word_score
print "Score with time penalty %.2f" % word_score_t
print "Current score: %.2f" % score
elif word == '.':
print "Final score: %.2f" % score
return
else:
print "Not a valid word."
print "Time remaining: %.2f" % limit
#
# Problem #5: Playing a game
# Make sure you understand how this code works!
#
def play_game(points_dict):
"""
Allow the user to play an arbitrary number of hands.
* Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
When done playing the hand, ask the 'n' or 'e' question again.
* If the user inputs 'r', let the user play the last hand again.
* If the user inputs 'e', exit the game.
* If the user inputs anything else, ask them again.
"""
hand = deal_hand(HAND_SIZE) # random init
k = get_time_limit(points_dict, 1)
while True:
cmd = raw_input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if cmd == 'e':
break
else:
while True:
plyr = raw_input('Human player (h) or computer player (c)?')
if (plyr == 'h') or (plyr == 'c'):
break
else:
print "Invalid input."
if plyr == 'c':
limit = k
else:
limit = int(raw_input('Enter time limit (sec) for players: '))
if cmd == 'n':
hand = deal_hand(HAND_SIZE)
play_hand(hand.copy(), points_dict, limit, plyr)
print
elif cmd == 'r':
play_hand(hand.copy(), points_dict, limit, plyr)
print
else:
print "Invalid command."
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
word_list = load_words()
points_dict = get_words_to_points(word_list)
rearrange_dict = get_word_rearrangements(word_list)
play_game(points_dict)
Comments:I got through this problem set O.K., but I'm stumped by problem 4. I'm not sure what it's asking and what the purpose of creating a dictionary with sorted letters is? Anyone able to explain this to me? |
No comments. Sign up or log in to comment