2013-03-26 70 views
1

我是Python編程的初學者,並且遇到了與我當前任務相關的問題。作業內容如下:Python大師遊戲難題

  • 您的程序應該暗中生成一個4位數的數字(或只包含數字,4個字符長的字符串),其中沒有數字重複。
  • 然後,程序應該要求用戶輸入代碼猜測。用戶的猜測應該是4個字符長,僅包含數字,不重複任何數字。評分前,您的程序應驗證輸入是否有效,並在必要時提示用戶重新輸入。無效輸入不計入代碼破解器的猜測次數。您的代碼可能會忽略(剝離)輸入中的前導空白或尾隨空白,但應將內部空間計爲不正確的輸入。
  • 在每一回閤中,打印轉數並得到用戶的猜測。如果輸入有效,回合的輸出應該是用戶的猜測,然後是反饋。反饋是一個4個字符的字符串:'X'表示每個數字在正確的位置; 'O'表示代碼中的每個數字,但不在正確的位置; ' - '爲所有其他人。請注意,X和O應該在一起;反饋只是每種類型有多少釘,而不是哪些釘或哪些釘。
  • 保持所有猜測和反饋的歷史記錄,因此可以在每一回閤中爲用戶打印。

現在我只關注作業的「反饋」部分。我的代碼是目前:

import random 

def validateInput(): 
inputGuess = input("Enter your guess as 4 numbers:") 

while True: 
    if len(inputGuess) != 4: 
     inputGuess = input("Enter your guess as 4 numbers:") 
    else: 
     numberList = list(inputGuess) ## 

     invalidNumbers = False 
     for number in numberList: 
      if number not in ['1','2','3','4','5','6','7','8','9']: 
       invalidNumbers = True 

     if invalidNumbers == True: 
      print ("Possible numbers are 1, 2, 3, 4, 5, 6, 7, 8, 9.") 
      inputGuess = input("Enter your guess as 4 numbers:") 

     else: 
      return numberList 

guessesRemaining=10 

code=['1','2','3','4'] 



while guessesRemaining > 0: 
    report=[] 
    guess=validateInput() 
    guessesRemaining -= 1 
    if guess[0] == code[0]: 
     report.append("X") 
    if guess[1] == code[1]: 
     report.append("X") 
    if guess[2] == code[2]: 
     report.append("X") 
    if guess[3] == code[3]: 
     report.append("X") 

    tempCode=sorted(code) 
    tempGuess=sorted(guess) 

    if tempCode[0]==tempGuess[0]: 
     report.append("O") 
    if tempCode[1]==tempGuess[1]: 
     report.append("O") 
    if tempCode[2]==tempGuess[2]: 
     report.append("O") 
    if tempCode[3]==tempGuess[3]: 
     report.append("O") 

    report2=report[0:4] 
    dash=["-","-","-","-"] 
    report3=report2+dash 
    report4=report3[0:5] 



    print(report4) 

例如,如果用戶想1879的代碼是1234,我收到「×○ - 」但我想收到「X ---」。此外,任何關於精簡我的代碼的建議都會很棒。爲了簡單起見,我現在只是[1,2,3,4]製作了「隨機代碼」。

回答

3

你可以用Python函數map()非常優雅地解決你的問題。 (沒有這麼優雅,因爲我原本以爲,但還是蠻漂亮。)

guess = "1879" # or [ '1', '8', '7', '9' ] 
answer = "1234" 

地圖()的工作原理是這樣的:你給它一個函數作爲第一個參數,並遵循一個或多個序列作爲參數。然後它接受該函數並將其首先應用於第一個元素,然後應用於第二個元素,依此類推。例如:

>>> def f(a,b): 
>>> return a + b 
>>> map(f, [1,2,3,4], [ 10, 20, 30, 40 ]) 

[ 11, 22, 33, 44 ] 

現在,你有兩個字符序列,「猜測」和「答案」。你可以寫,如果他們是平等的,返回X的功能 - 否則像這樣:

>>> def mastermind_hint(a, b): 
>>> return "X" if a == b else "-" 

這還遠遠不夠,還需要放在「0'。爲此,您需要同時使用整個「答案」序列:

>>> def mastermind_hint(a, b): 
>>> if a == b: return "X" 
>>> if a in answer: return "O" 
>>> return "-" 

使用地圖,我們可以應用到你的序列:

>>> map(mastermind_hint, guess, answer) 
[ "X", "-", "-", "-" ] 

現在,現在我們正在給因爲我們提示的位置與猜測字符的位置相對應,所以我們可以得到比我們預期更多的信息。隱藏這些信息的簡單方法是對序列進行排序。Python有一個排序()函數做到這一點:

>>> sorted(map(mastermind_hint, guess, answer)) 
[ "-", "-", "-", "X" ] 

剩下的工作就是加入到這個單一的字符串:

>>> "".join(sorted(map(mastermind_hint, guess, answer))) 
"---X" 
+0

這不正確處理案件[1,2,3,4] [2,7,8,9]。 – Jerome 2013-03-26 22:33:33

+0

哦,對不起。自從我玩過Mastermind已經很久了。我會刪除/審查/可能取消刪除。 – svk 2013-03-26 22:36:04

+0

編輯,應該現在工作。作爲lambda表達式將不再是非常漂亮的。 – svk 2013-03-26 22:44:24

2

非常有趣的功課,我必須說。我希望我能像這樣做作業。

通常我不提供完整的答案作業,但我解決了這個一個有趣的和你試圖解決這個你自己那麼在這裏你去:

import random 

def main(): 
    print '>> New game started.\n>> Good luck!\n' 
    answer = generateAnswer() 
    while True: 
     userGuess = getUserGuess() 
     if userGuess == answer: 
      print '>> Congratulations, you won!' 
      return 
     print '>> The answer you provided is incorrect.\n>> Perhaps this hint will help you: ' 
     giveFeedback(answer, userGuess) 

def generateAnswer(): 
    digits = [str(x) for x in range(10)] 
    answer = '' 
    for i in range(4): 
     digit = random.sample(digits, 1)[0] 
     digits.remove(digit) 
     answer += digit 
    return answer 

def getUserGuess(): 
    while True: 
     guess = raw_input('>> Please enter a 4-digit number: ').strip() 
     if len(guess) != 4: 
      continue 
     guessIsValid = True 
     for x in guess: 
      if guess.count(x) != 1 or ord(x) not in range(48, 58): 
       guessIsValid = False 
       break 
     if guessIsValid: 
      return guess 

def giveFeedback(answer, guess): 
    for i in range(4): 
     if guess[i] == answer[i]: 
      print 'X', 
      continue 
     if guess[i] in answer: 
      print 'O', 
      continue 
     print '-', 
    print '\n' 

if __name__ == '__main__': 
    try: 
     main() 
    except Exception, e: 
     print '>> Fatal error: %s' % e 

我希望你會發現你的在這段代碼中回答。

+0

我在想'giveFeedback'是否處理重複項,如答案:'[1,2,3,4]'guess:'[1,1,1,1]''。這可能會返回'['X','O','O','O']'。根據維基百科:如果在猜測中有重複的顏色,他們不能被授予關鍵掛鉤,除非它們對應於隱藏代碼中相同數量的重複顏色。 – Bastian 2017-08-21 15:41:26

1

這是一個使用一些更高級的python習語來提高可讀性和簡潔性的例子。這也使得製作一個更通用的解決方案變得更容易,例如m base的n位數答案。

import random 
from itertools import permutations # for "lucky guess" Easter egg 

def main(base=10, size=4): 
    print 'New game started.\nGood luck!\n' 
    answer, turn = list(genAnswer(range(base), size)), 1 
    while True: 
     hint = ['X' if a == g 
      else '0' if g in answer 
      else '-' for a, g in zip(answer, guess(base, size))] 
     if set(hint) == set(['X']): 
      if turn == 1: 
       choices = len(list(permutations(range(base), size))) 
       print 'You won, lucky guess out of %d possible choices' % choices 
      else: 
       print 'Congratulations, you won in %d turns!' % turn 
      return 
     print ' Hint %d: %s' % (turn, ''.join(hint)) 
     turn += 1 

def genAnswer(digits, size): 
    '''Python generator function''' 
    for i in range(size): 
     choice = random.choice(digits) 
     yield str(choice) 
     digits.remove(choice) 

def guess(base, size): 
    '''Uses duck typing for error detection''' 
    while True: 
     guess = raw_input('>> Guess: ').strip() 
     try: 
      if int(guess, base) < base**size and len(set(guess)) == size: 
       return guess 
     except ValueError: 
      pass 
     print 'Enter %d unique digits from 0 to %d' % (size, base -1) 

>>> main(6, 4) 
New game started. 
Good luck! 

>> Guess: 1234 
    Hint 1: 0-X- 
>> Guess: 12345 
Enter 4 unique digits from 0 to 5 
>> Guess: 01227 
Enter 4 unique digits from 0 to 5 
>> Guess:
    Hint 2: XX-0 
>> Guess: 0135 
Congratulations, you won in 3 turns!