28/05/2009

Mastermind, a little more refined...

J'avais posté ici un petit jeu de Mastermind, un furieux premier jet né d'un film trop peu intéressant à la TV et d'une envie de coder "quelque chose". D'une manière ou d'une autre ça valait la peine de faire quelque chose d'un peu plus peaufiné un jour.

Voici qui est un peu mieux. Toujours une interface textuelle sans fioritures, mais le jeu est paramétrable (voir le menu options) et offre le mode de jeu classique et le mode de jeu facile qu'implémentait ma version "quick and dirty".

Au niveau du code c'est du plus propre sans pour autant être de l'objet-pour-faire-de-l'objet. Hack away, have fun!

Ah oui, pour que ce soit un peu plus lisible il n'y a pas de contrôle aux entrées clavier. Si on tape n'importe quoi ça plante de façon insultante, soyez prévenu :)

#! /usr/bin/env python

# Game of Mastermind, with some niceties
# Jean Karim Bockstael - jkb@jkbockstael.be


# Import
from random import randint

# Gameplay constants
CODE_LENGTH = 4   # Length of the code (1-16)
CODE_COLORS = 10  # Number of different colors in the code (2-10)
MAX_GUESSES = 5   # Max number of guesses to find the correct code (1-50)
SHOW_MENU = True  # Show main menu before playing a first game
EASY_MODE = True  # Braindead mode

# String constants
STR_GUESS_PROMPT = 'Guess'
STR_WHITE_PEG = 'o'
STR_BLACK_PEG = 'x'
STR_EMPTY_PEG = '_'
STR_OUTCOME_WIN = 'Won!'
STR_OUTCOME_LOSS = 'Lost!'
STR_OUTCOME_REVEAL = 'The secret code was: '
STR_HELP = """
{codelength} digits long code, each between 0 and {codecolors} included, you have a maximum of {maxguesses} guesses to find it.
    {whitepeg} : right digit, right position
    {blackpeg} : right digit, wrong position
    {emptypeg} : wrong digit
"""
STR_OPT_CODELENGTH = 'Number of digits in code (min 1 max 16): '
STR_OPT_CODECOLORS = 'Number of possible digits in code (min 2 max 10): '
STR_OPT_MAXGUESSES = 'Maximum number of guesses before giving up (min 1 max 50): '
STR_OPT_SHOWMENU = 'Show main menu on program startup? (False/True): '
STR_OPT_EASYMODE = 'Play in easy mode? (False/True): '
STR_MENU_MAIN  = """
----------------
-- Mastermind --
----------------
   A)bout
   O)ptions
   P)lay
   Q)uit
"""
STR_MENU_MAINPROMPT = "Choice: "
STR_MENU_OPTIONS	 = """
------------------
-- Game Options --
------------------
"""
STR_ABOUT = """
----------------------
-- About Mastermind --

A simple and time-honored game, brought to your console using Python.

2009 - Jean Karim Bockstael - jkb@virus1984.com
"""


# And now, let the fun begin!
# (__)
# ( @@
# /\_| MOOH!


# Create a code of set length and number of colors, as a list of ints
def set_secret_code():
    tmp_code = []
    for i in range(0, CODE_LENGTH):
        tmp_code.append(randint(0, CODE_COLORS - 1))
    return tmp_code


# Read a code from the user
def get_guess_code():
    tmp_guess = []
    padding_spaces = ''
    if (len(STR_GUESS_PROMPT) < CODE_LENGTH):
        padding_spaces = " " * (CODE_LENGTH - len(STR_GUESS_PROMPT))
    guess_prompt = STR_GUESS_PROMPT + padding_spaces + " : "
    str_guess = raw_input(guess_prompt)
    for i in range(0, CODE_LENGTH):
        tmp_guess.append(int(str_guess[i]))
    return tmp_guess


# Print a help message
def print_help():
    print STR_HELP.format(codelength=CODE_LENGTH, codecolors=(CODE_COLORS-1), \
      maxguesses=MAX_GUESSES, whitepeg=STR_WHITE_PEG, blackpeg=STR_BLACK_PEG, \
      emptypeg=STR_EMPTY_PEG)
    

# Returns a code formatted for printing
def format_code(code):
    formatted_code = ''
    for i in range(0, CODE_LENGTH):
        formatted_code += str(code[i])
    return formatted_code


# Print a hint based on the player's guess
def print_hint(secret_code, guess_code):
    hint = ''
    if (EASY_MODE):
        for i in range(0, CODE_LENGTH):
            if (guess_code[i] == secret_code[i]):
                hint += STR_WHITE_PEG
            elif (guess_code[i] in secret_code):
                hint += STR_BLACK_PEG
            else:
                hint += STR_EMPTY_PEG
    else: # Badass mode
        white_pegs = 0
        black_pegs = 0
        dupes = [False] * CODE_LENGTH
        for i in range(0, CODE_LENGTH):
            if (guess_code[i] == secret_code[i]):
                white_pegs += 1
                dupes[i] = True
            else:
                for j in range(0, CODE_LENGTH):
                    if (secret_code[j] == guess_code[i] and not dupes[j]):
                        black_pegs += 1
        if (white_pegs != 0):
            hint += str(white_pegs) + ' ' + STR_WHITE_PEG + ' '
        if (black_pegs != 0):
            hint += str(black_pegs) + ' ' + STR_BLACK_PEG
        if (white_pegs == 0 and black_pegs == 0):
            hint += STR_EMPTY_PEG
    padding_spaces = ''
    if (CODE_LENGTH < len(STR_GUESS_PROMPT)):
        padding_spaces = " " * (len(STR_GUESS_PROMPT) - CODE_LENGTH)
    print format_code(guess_code), padding_spaces + ':', hint


# Print the game outcome
def print_outcome(code_found, secret_code):
    if (code_found):
        print STR_OUTCOME_WIN
    else:
        print STR_OUTCOME_LOSS
        print STR_OUTCOME_REVEAL, format_code(secret_code)
   
   
# Play a game of Mastermind
def play_game():
    print_help()
    secret_code = set_secret_code()
    guess_num = 0
    code_found = False
    while (guess_num < MAX_GUESSES):
        guess_code = get_guess_code()
        guess_num += 1
        code_found = (guess_code == secret_code)
        if (code_found):
            break	   # Avoid printing a hint if the code is found
        print_hint(secret_code, guess_code)
    print_outcome(code_found, secret_code)
        
    
# Options menu
def menu_options():
    global CODE_LENGTH
    global CODE_COLORS
    global MAX_GUESSES
    global SHOW_MENU
    global EASY_MODE
    print STR_MENU_OPTIONS
    print STR_OPT_CODELENGTH
    CODE_LENGTH = int(input("[" + str(CODE_LENGTH) + "] "))
    print STR_OPT_CODECOLORS
    CODE_COLORS = int(input("[" + str(CODE_COLORS) + "] "))
    print STR_OPT_MAXGUESSES
    MAX_GUESSES = int(input("[" + str(MAX_GUESSES) + "] "))
    print STR_OPT_SHOWMENU
    SHOW_MENU = input("[" + str(SHOW_MENU) + "] ")
    print STR_OPT_EASYMODE
    EASY_MODE = input("[" + str(EASY_MODE) + "] ")
    

# Main menu
def menu_main():
    menu_main_choices = { "A" : show_about,
                          "O" : menu_options,
                          "P" : play_game,
                          "Q" : None }
    usr_choice = ''
    while (True):
        print STR_MENU_MAIN
        while (not usr_choice in menu_main_choices):
            usr_choice = raw_input(STR_MENU_MAINPROMPT)
        if (usr_choice == 'Q'):
            return None
        else:
            menu_main_choices[usr_choice]()
            usr_choice = ''

  
# Show "about" screen
def show_about():
    print STR_ABOUT
    raw_input()


# Main
if (SHOW_MENU):
    menu_main()
else:
    play_game()

# End

Tags:

cc-by-nc | code (python) | jeux


Tiens j'avais oublié ça... (16/06/2009)"I know the pieces fit" (14/05/2009)