Sat, 30th Aug 2008 09:04:09
Never fear, this site is here

#Mastermind

Language: Python
Written by ben on 2008-01-01 11:46:56

#!/usr/bin/env python
#encoding:utf-8
#tab:4 spaces
"""
mastermind.py
coded by dbr, 2008-01-01

# Description.
Simple computerification of a boardgame called "Mastermind" (http://en.wikipedia.org/wiki/Mastermind_%28board_game%29 )

# The game.
- A secret 4 digit code is created.
The code consists of the numbers 0 to 9.
- The player makes a guess at the code and it told the following:
-- How many numbers are the right number in the right place.
-- How many numbers are the right number, but in the wrong place.

- From there, the player attempts to deduce the code from these scores.

# Usage.
Run the script.
To input guesses, enter the values seperated by commans, followed by return/enter, for example:
3,5,2,4[return]

When you guess the correct code, it will display "Vicory", confirm the code and exit.

# Difficulty levels.
It is possible to make the game more challanging, either by increasing the code size - for example, to an 8 digit code:
Change the line:
code = gencode()
..to:
code = gencode(clen=8)

Or a larger character set - for example, the numbers 0 through 19:
code = gencode(charset=range(20))
Note: you can specify specific numbers with (charset=[1,2,6,7], or use the range() command)

Or you can combine the two:
code = gencode(clen=8,charset=range(20))

# Possible improvements.
Currently the code will only work with numeric codes. It would be fairly simple to allow letters into the code (instead of running int() on the users input, run str() on the numeric values when comparing in compare())
I suppose an easier way to configure the code size/character set would be preferable to editing the code as well.

# Dev Notes.
elif sum([guess.count(x)-1 for x in guess]) > 0:
This code looks slightly odd, but it was the simplest way I could figure out to only allow unique numbers in the code - without creating another function.
Count the number of times each value appears the array. Subtract one from this value (the current one) 
If all values are unique, this will run sum([0,0,0,0]), and thus return 0. If a value appears twice, it will run sum([1,1,0,0]), and thus return 2. Non-zero returns ==  non-unqiue inputs.

I may clean this up in future versions. Ideally a validate_input() function, that checks for unqiueness and length, and has the abilty to to deal with different deliminators (to allow 3 4 5 6, or 4.5.6.7 to be entered)
"""
import sys,random

def compare(code,guess):
    code = map(lambda x:int(x),code)
    guess = map(lambda x:int(x),guess)
    exact=0
    place=0
    # Get exact matches:
    for i in range(len(code)):
        if code[i] == guess[i]:
            exact+=1
        # Not exact match, find correct match in wrong place
        elif guess[i] in code:
            place+=1    
    return exact,place

def result(exact,place,code):
    if exact == len(code):
        print "Victory!"
        print "Code was:",code
        sys.exit(1)
    else:
        print """   Try number:\t%d
    Right number, right place:%d
    Right number, wrong place:%d""" % (try_co,exact,guess)
        return True

def gencode(clen=4,charset=[0,1,2,3,4,5,6,7,8,9]):
    return random.sample(charset,clen)
# end all functions.

# Generate the code
code = gencode()

try_co=1
while True:
    # Get the user-input and process it
    print ">",
    guess = raw_input().split(",")
    
    if len(guess) != len(code):
        print "\tInvalid input, must be in the format 1,2,3,4"
    elif sum([guess.count(x)-1 for x in guess]) > 0:
        print "\tValues must be unique"
    else:
        # Valid input, compare guess to code, 
        # and display results.
        exact, guess = compare(code,guess)
        result(exact,guess,code)
        try_co+=1
Powered by Debian, Jack Daniels, Guinness, and excessive quantities of caffeine and sugar.