Python Mastermind Game Troubles

I’m a beginner to Python programming and have come upon an issue with my current assignment. The assignment reads as follows…

  • Your program should secretly generate a 4-digit number (or a string containing only digits, 4 characters long) which has no digits repeated.
  • Your program should then ask the user to enter a guess for the code. The user’s guess should be 4 characters long, consisting only of digits, with no digits repeated. Your program should verify the input is valid before scoring it, and prompting the user to re-enter input if necessary. Invalid input does not count against the codebreaker’s number of guesses. Your code may ignore (strip off) leading or trailing whitespace from the input, but should count internal spaces as incorrect input.
  • On each turn, print the turn number and get the user’s guess. If the input is valid, the output for the turn should be the user’s guess, followed by the feedback. Feedback is a 4-character string: ‘X’ for each digit in the right position; ‘O’ for each digit that is in the code but not in the right position; ‘-‘ for all others. Note that the X’s and O’s should be together; feedback is only how many pegs of each type, not which ones or where they are.
  • Maintain a history of all guesses and the feedback, so it can be printed for the user on each turn.

Right now I am just focusing on the “Feedback” portion of the assignment. My code is currently:

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:")
        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:") 

            return numberList



while guessesRemaining > 0:
     guessesRemaining -= 1
     if guess[0] == code[0]:
     if guess[1] == code[1]:
     if guess[2] == code[2]:
     if guess[3] == code[3]:


     if tempCode[0]==tempGuess[0]:
     if tempCode[1]==tempGuess[1]:
     if tempCode[2]==tempGuess[2]:
     if tempCode[3]==tempGuess[3]:



For example, if the user guess 1879 and the code is 1234, I receive “X O –” but I want to receive “X—“. Also, any advice on streamlining my code would be awesome. For simplicity, I made the “random code” just [1,2,3,4] for now.

Enquirer: Bob


Solution #1:

You can solve your problem very elegantly with the Python function map(). (Not quite as elegantly as I originally thought, but still pretty nicely.)

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

map() works like this: you give it a function as its first argument, and one or more sequences as arguments following that. It then takes takes that function and applies it first to both the first elements, then to both the second elements, and so on. For instance:

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

[ 11, 22, 33, 44 ]

Now, you have two sequence of characters, “guess” and “answer”. You could write a function that returns X if they’re equal and – otherwise like this:

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

That’s not quite enough, you also need to put in the ‘O’s. For this you need to use the entire “answer” sequence at once:

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

Using map, we can apply that to the sequences you have:

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

Now, right now we’re giving away more information than we’re supposed to because the positions of our hints correspond to the positions of the guess characters. A simple way to hide this information is to sort the sequence. Python has a sorted() function which does this:

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

All that remains is to join this into a single string:

>>> "".join( sorted( map( mastermind_hint, guess, answer ) ) )
Respondent: svk

Solution #2:

Very interesting homework I must say. I wish I’d get homework like this one.

Normally I don’t provide full answers to homework but I solved this one for fun and you have tried to solve this on your own so here you go:

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!'
        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]
        answer += digit
    return answer

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

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

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

I hope you’ll find your answer in this piece of code.

Respondent: Ionut Hulub

Solution #3:

Here is an example that uses some more advance python idioms to improve readability and succinctness. This also makes it easier to make a more general solution such as for n digit answers for m base.

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
                print 'Congratulations, you won in %d turns!' % turn
        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)

def guess(base, size):
    '''Uses duck typing for error detection'''
    while True:
        guess = raw_input('>> Guess: ').strip()
            if int(guess, base) < base**size and len(set(guess)) == size:
                return guess
        except ValueError:
        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: 0123
  Hint 2: XX-0
>> Guess: 0135
Congratulations, you won in 3 turns!
Respondent: dansalmo

The answers/resolutions are collected from stackoverflow, are licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0 .

Leave a Reply

Your email address will not be published.