mastermind python

Un MasterMind en Python

  • Dernière modification de la publication :10 juin 2022
  • Temps de lecture :9 min de lecture
  • Commentaires de la publication :0 commentaire

Loading

Nous allons voir comment implémenter un MasterMind en Python, mais uniquement en mode console.

mastermind python

MasterMind en Python: le jeu

Le jeu du MasterMind consiste deviner une combinaison de couleurs.

À chaque proposition, votre adversaire doit vous dire:

  • combien de couleurs sont au(x) bon(s) endroit(s), sans indiquer lesquelles;
  • combien de couleurs sont bonnes mais pas au bon endroit.

Vous l’aurez compris, votre adversaire, ce sera l’ordinateur… C’est lui qui décidera la combinaison de couleurs à trouver.

MasterMind en Python: implémentation

Préliminaires

Nous allons décider du fait que les couleurs seront représentées par des lettres capitalisées de l’alphabet latin: A, B, C, D, …

Nous allons donc écrire une première fonction qui retourne l’alphabet sur lequel s’appuyer pour générer une combinaison de couleurs à trouver:

from string import ascii_uppercase

def gen_colors(code_size):
    if code_size <= 26:
        return ascii_uppercase[:code_size]
    else:
        return ascii_uppercase

Cette fonction retourne donc les n premières lettres de l’alphabet si n< 27, et retourne l’alphabet complet si n > 26.

>>> gen_colors(5)
'ABCDE'
>>> gen_colors(200)
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'

Il nous faut maintenant une fonction retournant une combinaison aléatoire de n couleurs prises parmi toutes celles de ce nouvel ensemble.

from random import choice
def gen_code(code_size, colors):
    r = ''
    for _ in range(code_size):
        r += choice(colors)
>>> gen_code(5,'ABCDEFGH')
'GCBAG'

Vérifications

Nous allons dans un premier temps écrire une fonction check_guess(guess, code_size, colors) qui vérifie si, d’une part, la longueur de « guess » est la même que code_size, et d’autre part si une couleur présente dans « guess » est aussi dans « colors »:

def check_guess(guess, code_size, colors):
    present_colors = [ i in colors for i in guess ]
    return len( guess ) == code_size and False not in present_colors

J’ai opté pour cette solution, mais il y a d’autres possibilités.

Ici, je construis une liste de booléens correspondants au fait que chaque élément de « guess » se trouve ou non dans « colors ». Si il n’y a aucun « False » dans cette liste, cela signifie que toutes les couleurs proposées sont dans l’alphabet autorisé.

Si la longueur de « guess » est la même que celle de « colors » ET si aucun « False » est dans la liste construite, la fonction renvoie « True ».

Renvoi du nombre de bonnes couleurs

def score_guess(code, guess):
    n_good_position = 0
    n_false_position = 0
    if len( code ) == len( guess ):
        for i in range( len(code) ):
            if code[i] == guess[i]:
                n_good_position += 1
            elif guess[i] in code:
                n_false_position += 1
        
        return n_good_position , n_false_position
>>> score_guess('ABCD' , 'AABC')
(1, 3)

Il y a en effet 1 bonne lettre (à sa place) et en tout 3 lettres correctes mais pas à la bonne place (le second ‘A’ est à la deuxième position et non à la 1ère, le ‘B’ et le ‘C’ sont bonnes mais pas au bon endroit).

Le jeu

def play(code_size, nb_colors):
    print(f'Les différentes couleurs possibles sont: {gen_colors(nb_colors)}.')
    print(f'Le code à trouver est de longueur {code_size}.')
    n = 0
    to_find = gen_code(code_size, gen_colors(nb_colors)) # combinaison à trouver
    while True:
        guess = input(f'{n} --> ').upper()
        if not check_guess(guess, code_size, gen_colors(nb_colors)):
            print('Mauvaise taille ou couleur...')
        elif guess != to_find:
            print( score_guess(to_find, guess) )
            n += 1
        else:
            print( f'Félicitations, vous avez trouvé après {n+1} essais!' )
            break
>>> play(4,4)
Les différentes couleurs possibles sont: ABCD.
Le code à trouver est de longueur 4.
0 --> ABCD
(1, 2)
1 --> ABBB
(0, 1)
2 --> CBCC
(1, 2)
3 --> BBDD
(1, 1)
4 --> DBCB
(0, 2)

Bon, je ne sais pas pour vous mais c’est assez frustrant de ne pas trouver après un certain nombre d’essais.

Je vais donc ajouter un argument à ma fonction pour limiter le nombre de coups maximum.

def play(code_size, nb_colors , nb_max = None):
    print(f'Possible colors are: {gen_colors(nb_colors)}.')
    print(f'Code size is {code_size}.')
    n = 0
    count = 0
    to_find = gen_code(code_size, gen_colors(nb_colors)) # combinaison à trouver
    while True:
        if nb_max != None and n <= nb_max or nb_max == None:
            guess = input(f'{n} --> ').upper()
            if not check_guess(guess, code_size, gen_colors(nb_colors)):
                print('Mauvaise taille ou couleur...')
            elif guess != to_find:
                print( score_guess(to_find, guess) )
                n += 1
            else:
                print( f'Félicitations, vous avez trouvé après {n+1} essais!' )
                break
        else:
            print(f'Il fallait trouver: {to_find}')
            break
>>> play(4,4,3)
Possible colors are: ABCD.
Code size is 4.
0 --> aaaa
(1, 3)
1 --> bbbb
(1, 3)
2 --> cccc
(1, 3)
3 --> abcd
(1, 3)
Il fallait trouver: DACB

Mémorisation des propositions

Dans la pratique, il est possible de s’y perdre avec toutes les propositions que l’on a faites.

Si l’on souhaite ne pas compter les coups identiques, on peut mémoriser tous les coups dans une liste L.

def play(code_size, nb_colors , nb_max = None):
    print(f'Possible colors are: {gen_colors(nb_colors)}.')
    print(f'Code size is {code_size}.')
    n = 0
    count = 0
    to_find = gen_code(code_size, gen_colors(nb_colors)) # combinaison à trouver
    L = []
    while True:
        if nb_max != None and n <= nb_max or nb_max == None:
            guess = input(f'{n} --> ').upper()
            if not check_guess(guess, code_size, gen_colors(nb_colors)):
                print('Mauvaise taille ou couleur...')
            elif  guess in L:
                print('Proposition déjà faite avant...')
            elif guess != to_find:
                print( score_guess(to_find, guess) )
                L.append( guess )
                n += 1
            else:
                print( f'Félicitations, vous avez trouvé après {n+1} essais!' )
                break
        else:
            print(f'Il fallait trouver: {to_find}')
            break
>>> play(4,4,3)
Possible colors are: ABCD.
Code size is 4.
0 --> abcd
(0, 4)
1 --> abcd
Proposition déjà faite avant...
1 --> aabb
(0, 4)
2 --> bbbb
(1, 3)
3 --> dcba
(2, 2)
Il fallait trouver: BCDA

Bon, là, on est pas mal non ?

0 0 votes
Évaluation de l'article
S’abonner
Notification pour
guest
0 Commentaires
Commentaires en ligne
Afficher tous les commentaires