@TOC
使用偽代碼,來(lái)檢查你的錯(cuò)誤,使得設(shè)計(jì)變得更簡(jiǎn)單
為什么要使用偽代碼?
這是學(xué)堂在線的幫助文件
http://www.xuetangx.com/asset-v1:MITx+6_00_1x+sp+type@asset+block/files_ps04_files_WhyPseudocode.pdf
學(xué)習(xí)問(wèn)題的好方法,讀別人的代碼
<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'] #這種方式可能會(huì)導(dǎo)致錯(cuò)誤發(fā)生
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'e'
>>> hand.get('e', 0) #這種方式就沒(méi)有錯(cuò)誤
0
</kbd>
設(shè)計(jì)playHand游戲
第一部分模塊,已經(jīng)給了你,幫助你獲得詞頻和讀取單詞列表以待查詢
# 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
分值是按照字母出現(xiàn)的頻率來(lái)計(jì)分,字母出現(xiàn)的頻率越頻繁,分值越低
'''
'''
你可以假設(shè)輸入總是小寫字母串或者空串 "".
'''
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個(gè)元音字母,使用了int方法,并且修改了一部分代碼以使得能夠使用,為下一個(gè)部分模塊的刪改和游戲運(yùn)行模塊打基礎(chǔ)
這里涉及到,怎么讓多個(gè)零散在不同位置的print輸出到同一行??
事實(shí)上,print('')不僅會(huì)輸出空字符串,而且自帶換行符
如果我們改成print('',end='')那么它就會(huì)以end里面的屬性結(jié)尾,從而不換行!
#
# 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
#
下面的模塊能夠給你隨機(jī)發(fā)n個(gè)牌組成的一手牌
# 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刪減模塊,在這里使用了字典操作語(yǔ)言,注意使用hand.get(i,0)不會(huì)在字典沒(méi)有i鍵的時(shí)候報(bào)錯(cuò),并且在不存在i鍵的時(shí)候自動(dòng)生成該鍵并且賦值為0(不會(huì)修改字典,只是會(huì)返回0值或者設(shè)定好的值)
a={}
a.get('s',0)
Out[41]: 0
--------------------------
a
Out[42]: {}
--------------------------
a.get('s',23124)
Out[43]: 23124
updateHand模塊,注意使用的時(shí)候它并不會(huì)修改hand的值,所以還要使用hand=updataHand(hand,word)來(lái)修改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,因?yàn)檫@種賦值實(shí)際上是給了hand一個(gè)別名,在改動(dòng)
#newhand的時(shí)候也會(huì)同時(shí)改動(dòng)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的字母?jìng)€(gè)數(shù),先轉(zhuǎn)換成列表再計(jì)算個(gè)數(shù)
def calculateHandlen(hand):
return sum(hand.values())
#或
#return sum([hand.get(i,0) for i in hand])
下面就是給玩家交互的代碼了,這一塊可能有一點(diǎn)復(fù)雜
def playHand(hand, wordList, n):
#這是玩一手牌的設(shè)計(jì),僅玩一次
"""
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
新增游戲模式的代碼,上面是單一游戲模式,在這里我們升級(jí)到了可選擇游戲模式
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的控制臺(tái)里面很容易開(kāi)始玩
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,因?yàn)檫@種賦值實(shí)際上是給了hand一個(gè)別名,在改動(dòng)
#newhand的時(shí)候也會(huì)同時(shí)改動(dòng)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)