@TOC
使用伪代码,来检查你的错误,使得设计变得更简单
为什么要使用伪代码?
这是学堂在线的帮助文件
http://www.xuetangx.com/asset-v1:MITx+6_00_1x+sp+type@asset+block/files_ps04_files_WhyPseudocode.pdf
学习问题的好方法,读别人的代码
<kbd>hand = {'a':1, 'q':1, 'l':2, 'm':1, 'u':1, 'i':1} </kbd>
Notice how the repeated letter 'l' is represented. Remember that with a dictionary, the usual way to access a value is hand['a'], where 'a' is the key we want to find. However, this only works if the key is in the dictionary; otherwise, we get a KeyError. To avoid this, we can use the call hand.get('a',0). This is the "safe" way to access a value if we are not sure the key is in the dictionary. d.get(key,default) returns the value for key if key is in the dictionary d, else default. If default is not given, it returns None, so that this method never raises a KeyError. For example:
<kbd>>>> hand['e'] #这种方式可能会导致错误发生
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'e'
>>> hand.get('e', 0) #这种方式就没有错误
0
</kbd>
设计playHand游戏
第一部分模块,已经给了你,帮助你获得词频和读取单词列表以待查询
# 6.00x Problem Set 4A Template
#
# The 6.00 Word Game
# Created by: Kevin Luu <luuk> and Jenna Wiens <jwiens>
# Modified by: Sarina Canelake <sarina>
#
'''
Scrabble游戏的字母分值如下:
1 A, E, I, L, N, O, R, S, T, U
2 D, G
3 B, C, M, P
4 F, H, V, W, Y
5 K
8 j, X
10 Q, Z
分值是按照字母出现的频率来计分,字母出现的频率越频繁,分值越低
'''
'''
你可以假设输入总是小写字母串或者空串 "".
'''
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
}
# -----------------------------------
# Helper code
# (you don't need to understand this helper code)
WORDLIST_FILENAME = "words.txt"
def loadWords():
"""
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')
# wordList: list of strings
wordList = []
for line in inFile:
wordList.append(line.strip().lower())
print (" ", len(wordList), "words loaded.")
return wordList
def getFrequencyDict(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 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, multiplied by the length of the word, PLUS 50 points if all n
letters are used on the first turn.
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 (see SCRABBLE_LETTER_VALUES)
word: string (lowercase letters)
n: integer (HAND_SIZE; i.e., hand size required for additional points)
returns: int >= 0
"""
for i in word:
assert (i in string.ascii_lowercase or ''),'必须输入小写字母或空字符串'
score=0
for l in word:
SCRABBLE_LETTER_VALUES[l]
print('The score of letter ',l,' is',SCRABBLE_LETTER_VALUES[l])
score+=SCRABBLE_LETTER_VALUES[l]
return score*len(word)+(len(word)==n)*50
第二部分模块,在deaLHand为了得到至少n/3个元音字母,使用了int方法,并且修改了一部分代码以使得能够使用,为下一个部分模块的删改和游戏运行模块打基础
这里涉及到,怎么让多个零散在不同位置的print
输出到同一行??
事实上,print('')
不仅会输出空字符串,而且自带换行符
如果我们改成print('',end='')
那么它就会以end里面的属性结尾,从而不换行!
#
# Problem #2: 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():
# print(letter)
for j in range(hand[letter]):
print (letter,end=' ')
print('') # print all on the same line
#
下面的模块能够给你随机发n
个牌组成的一手牌
# Problem #2: Make sure you understand how this function works and what it does!
#
def dealHand(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={}
numVowels = n / 3
for i in range(int(numVowels)+1):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(int(numVowels)+1, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
#
第三部分模块,hand删减模块,在这里使用了字典操作语言,注意使用hand.get(i,0)
不会在字典没有i
键的时候报错,并且在不存在i
键的时候自动生成该键并且赋值为0(不会修改字典,只是会返回0值或者设定好的值)
a={}
a.get('s',0)
Out[41]: 0
--------------------------
a
Out[42]: {}
--------------------------
a.get('s',23124)
Out[43]: 23124
updateHand模块,注意使用的时候它并不会修改hand的值,所以还要使用hand=updataHand(hand,word)
来修改hand值
# Problem #2: Update a hand by removing letters
#
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 modify hand.
word: string
hand: dictionary (string -> int)
returns: dictionary (string -> int)
"""
newhand={} #不能使用newhand=hand,因为这种赋值实际上是给了hand一个别名,在改动
#newhand的时候也会同时改动hand,从而不能满足要求
for i in hand:
newhand[i]=hand[i]
for i in word:
if newhand.get(i,0)!=0:
newhand[i]=newhand.get(i,0) - 1
return newhand
isValidWord模块
#
# Problem #3: Test word validity
#
def isValidWord(word, hand, wordList):
"""
Returns True if word is in the wordList and is entirely
composed of letters in the hand. Otherwise, returns False.
Does not mutate hand or wordList.
word: string
hand: dictionary (string -> int)
wordList: list of lowercase strings
"""
newhand={}
for i in hand:
newhand[i]=hand[i]
for i in word:
if newhand.get(i,0)==0:
return False
else:
newhand[i]=newhand[i]-1
return word in wordList
输出字典hand的字母个数,先转换成列表再计算个数
def calculateHandlen(hand):
return sum(hand.values())
#或
#return sum([hand.get(i,0) for i in hand])
下面就是给玩家交互的代码了,这一块可能有一点复杂
def playHand(hand, wordList, n):
#这是玩一手牌的设计,仅玩一次
"""
Allows the user to play the given hand, as follows:
* The hand is displayed.
* The user may input a word or a single period (the string ".")
to indicate they're done playing
* Invalid words are rejected, and a message is displayed asking
the user to choose another word until they enter a valid word or "."
* 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 or the user
inputs a "."
hand: dictionary (string -> int)
wordList: list of lowercase strings
n: integer (HAND_SIZE; i.e., hand size required for additional points)
"""
total=0
while calculateHandlen(hand)!=0:
displayHand(hand)
word=input('Enter word, or a "." to indicate that you are finished: ')
if word=='.':
print('Goodbye! Total score:',total,'points.')
break
if isValidWord(word, hand, wordList)==False:
print('Invalid word, please try again.')
print(' ')
else:
total+=getWordScore(word, n)
print('"',word,'" earned ',getWordScore(word, n),'points. Total:',total,'points.')
print(' ')
hand=updateHand(hand, word)
if calculateHandlen(hand)==0:
print('Run out of letters. Total score:',total,'points.')
break
新增游戏模式的代码,上面是单一游戏模式,在这里我们升级到了可选择游戏模式
def playGame(wordList):
"""
Allow the user to play an arbitrary number of hands.
1) Asks the user to input 'n' or 'r' or 'e'.
* If the user inputs 'n', let the user play a new (random) hand.
* 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, tell them their input was invalid.
2) When done playing the hand, repeat from step 1
"""
pr=0
while True:
mode=input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if mode=='r':
if pr==0:
print('You have not played a hand yet. Please play a new hand first!')
continue
else:
playHand(hand,wordList,n)
continue
if mode=='n':
n=HAND_SIZE
hand=dealHand(n)
playHand(hand,wordList,n)
pr+=1
continue
if mode=='e':
break
else:
print('Invalid command.',end='')
#
# Build data structures used for entire session and play game
#
if __name__ == '__main__':
wordList = loadWords()
playGame(wordList)
剩下贴完整代码,也许能够在SoloLearnPython的控制台里面很容易开始玩
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 loadWords():
print ("Loading word list from file...")
inFile = open(WORDLIST_FILENAME, 'r')
wordList = []
for line in inFile:
wordList.append(line.strip().lower())
print (" ", len(wordList), "words loaded.")
print(' ')
return wordList
def getFrequencyDict(sequence):
freq = {}
for x in sequence:
freq[x] = freq.get(x,0) + 1
return freq
def getWordScore(word, n):
for i in word:
assert (i in string.ascii_lowercase or ''),'必须输入小写字母或空字符串'
score=0
for l in word:
SCRABBLE_LETTER_VALUES[l]
score+=SCRABBLE_LETTER_VALUES[l]
return score*len(word)+(len(word)==n)*50
def displayHand(hand):
print('Current Hand: ',end='')
for letter in hand.keys():
for j in range(hand[letter]):
print(letter,end=' ')
def dealHand(n):
hand={}
numVowels = n / 3
for i in range(int(numVowels)+1):
x = VOWELS[random.randrange(0,len(VOWELS))]
hand[x] = hand.get(x, 0) + 1
for i in range(int(numVowels)+1, n):
x = CONSONANTS[random.randrange(0,len(CONSONANTS))]
hand[x] = hand.get(x, 0) + 1
return hand
def updateHand(hand, word):
newhand={} #不能使用newhand=hand,因为这种赋值实际上是给了hand一个别名,在改动
#newhand的时候也会同时改动hand,从而不能满足要求
for i in hand:
newhand[i]=hand[i]
for i in word:
if newhand.get(i,0)!=0:
newhand[i]=newhand.get(i,0) - 1
return newhand
def isValidWord(word, hand, wordList):
newhand={}
for i in hand:
newhand[i]=hand[i]
for i in word:
if newhand.get(i,0)==0:
return False
else:
newhand[i]=newhand[i]-1
return word in wordList
def calculateHandlen(hand):
return sum([hand.get(i,0) for i in hand])
def playHand(hand, wordList, n):
total=0
while calculateHandlen(hand)!=0:
displayHand(hand)
word=input('Enter word, or a "." to indicate that you are finished: ')
if word=='.':
print('Goodbye! Total score:',total,'points.')
break
if isValidWord(word, hand, wordList)==False:
print('Invalid word, please try again.')
print(' ')
else:
total+=getWordScore(word, n)
print('"',word,'" earned ',getWordScore(word, n),'points. Total:',total,'points.')
print(' ')
hand=updateHand(hand, word)
if calculateHandlen(hand)==0:
print('Run out of letters. Total score:',total,'points.')
break
def playGame(wordList):
pr=0
while True:
mode=input('Enter n to deal a new hand, r to replay the last hand, or e to end game: ')
if mode=='r':
if pr==0:
print('You have not played a hand yet. Please play a new hand first!')
continue
else:
playHand(hand,wordList,n)
continue
if mode=='n':
n=HAND_SIZE
hand=dealHand(n)
playHand(hand,wordList,n)
pr+=1
continue
if mode=='e':
break
else:
print('Invalid command.',end='')
if __name__ == '__main__':
wordList = loadWords()
playGame(wordList)