Jeu de calcul mental

Objectifs

Le but de ce tutoriel est de programmer le "moteur logique" du jeu de calcul mental. On ne s'intéresse donc pas du tout à la création d'une interface graphique, mais il sera possible, en fin de tutoriel, de jouer avec le jeu dans la console Python (c'est-à-dire en mode texte).

1. Mise en place des fichiers du programme

L'éditeur utilisé pour programmer est le logiciel PyCharm (voir la page de mise en place des projets).

Ouvrir PyCharm et créer deux fichiers Python calcul_logique.py et calcul_console.py : le premier contiendra les définitions de fonctions et les constantes du jeu qui serviront pour le jeu en console et pour le jeu en interface graphique ; le second contiendra les instructions spécifiques (entrées, sorties) pour le jeu en console.

2. Tirage aléatoire du nombre cible

En Python, la fonction randint(a, b) retourne un nombre entier aléatoire compris (au sens large) entre les entiers a et b. Cette fonction se trouve dans la bibliothèque random qu'il faudra donc importer en début de fichier.

Dans le jeu, le nombre cible est un entier aléatoire compris entre 10 et 69.

Recopier tout le code ci-dessous dans le fichier calcul_logique.py et compléter la fonction choose_target() afin qu'elle retourne un nombre cible choisi au hasard. Ce nombre est stocké dans la variable target.

1
2
3
4
5
6
from random import randint

def choose_target():
    """cette fonction retourne le nombre cible compris entre 10 et 69"""
    # ecrire ici
    return target
Solution
1
2
3
4
5
6
from random import

def choose_target():
    """cette fonction retourne le nombre cible compris entre 10 et 69"""
    target = randint(10, 69)
    return target

Pour tester cette fonction, ouvrir le fichier calcul_console.py et recopier le code suivant :

1
2
3
4
from calcul_logique import *

cible = choose_target()
print(cible)

Explications : le ligne 1 importe toutes les fonctions définies dans le fichier calcul_logique.py. A la ligne 3, on appelle la fonction choose_target() et on stocke le nombre retourné dans la variable cible, que l'on affiche dans la console à la ligne 4.

Exécuter ce programme et vérifier qu'il réalise bien ce qui est attendu.

3. Tirage au hasard des nombres outils.

Dans le jeu de Mathador, les nombres outils sont obtenus en lançant des dés de différentes formes (dés blancs sur la photo ci-dessous).

image

Il s'agit donc de :

  • lancer un dé à 4 faces numérotées et 1 à 4 ;
  • lancer un dé à 6 faces numérotées et 1 à 6 ;
  • lancer un dé à 8 faces numérotées et 1 à 8 ;
  • lancer un dé à 12 faces numérotées et 1 à 12 ;
  • lancer un dé à 20 faces numérotées et 1 à 20.

Ajouter la fonction suivante dans le fichier calcul_logique.py, en la complétant convenablement.

1
2
3
4
5
def choose_numbers():
    """Cette fonction retourne les nombres outils"""
    de4 = ...
    ...
    return [de4, de6, de8, de12, de20]
Solution
1
2
3
4
5
6
7
8
def choose_numbers():
    """Cette fonction retourne les nombres outils"""
    de4 = randint(1,4)
    de6 = randint(1,6)
    de8 = randint(1,8)
    de12 = randint(1,12)
    de20 = randint(1,20)
    return [de4, de6, de8, de12, de20]

Tester cette fonction en modifiant le programme dans le fichier calcul_console.py.

Remarque

La fonction choose_numbers retourne les nombres tirés au hasard sous la forme d'une liste. En Python, une liste est délimitée par des crochets. Les éléments de la liste sont numérotés à partir de 0 et on y accède en utilisant aussi des crochets. Par exemple, si nombres = [2, 5, 4, 6, 12], alors nombres[2] retournera 4.

4. Validation de l'opération choisie par le joueur

Le joueur qui connaît maintenant le nombre cible et les nombres outils pour l'obtenir doit proposer une opération. Pour cela, il doit désigner deux nombres et une opération.

Voici une fonction qui va tester la validité de l'opération proposée et mettre à jour la liste des nombres disponibles en enlevant les nombres utilisés et en ajoutant le résultat de l'opération effectuée. Pour l'instant cette fonction est incomplète.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def valide_operation(a, b, op, nombres):
    """cette fonction verifie que l'operation proposee est possible
    et met a jour la liste des nombres disponibles"""
    ok = True
    if a not in nombres or b not in nombres:
        ok = False
    else:
        if op == "+":
            ...
            ...
            ...
        elif op == "-":
            ...
            ...
            ...
        elif op == "*":
            ...
            ...
            ...
        elif op == "/":
            if ...:
                ...
                ...
                ...
            else:
                ok = False
    return ok, nombres

Explications

  • ligne 1 : la fonction valide_operation prend quatre arguments : a et b sont les deux nombres à combiner, op est l'opération à effectuer, donnée sous la forme d'une chaîne de caractères, c'est-à-dire entre guillemets. op peut prendre les valeurs "+", "-", "*" ou "/". nombres est la liste des nombres outils disponibles.
  • ligne 27 : la fonction retourne deux éléments : une variable ok de type booléen qui ne peut prendre que deux valeurs : True si l'opération est valide, False sinon. Le deuxième élément est la liste des nombres disponibles mise à jour, le cas échéant.
  • lignes 5 et 6 : si les nombres proposés ne sont pas dans la liste des nombres disponibles, alors l'opération n'est pas valide.
  • lignes 8 à 26 : on traite le cas de chacune des opérations possibles. Compléter les pointillés présents sur ces lignes sachant que :
    • pour retirer un élément x d'une liste, on écrit : nombres.remove(x).
    • pour ajouter un élément x à la fin d'une liste, on écrit : nombres.append(x).
    • le cas de la division est plus délicat : on ne travaille qu'avec des nombres entiers, la division est donc valide seulement si b est un diviseur de a.
    • x % y calcule le reste dans la division euclidienne de x par y et x // y calcule le quotient (entier).

Le dernier nombre calculé sera toujours à la fin de la liste des nombres disponibles. On peut accéder au dernier terme d'une liste en entrant la commande nombres[-1].

Solution
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def valide_operation(a, b, op, nombres):
    """cette fonction verifie que l'operation proposee est possible
    et met a jour la liste des nombres disponibles"""
    ok = True
    if a not in nombres or b not in nombres:
        ok = False
    else:
        if op == "+":
            nombres.remove(a)
            nombres.remove(b)
            nombres.append(a+b)
        elif op == "-":
            nombres.remove(a)
            nombres.remove(b)
            nombres.append(a - b)
        elif op == "*":
            nombres.remove(a)
            nombres.remove(b)
            nombres.append(a * b)
        elif op == "/":
            if a%b == 0:
                nombres.remove(a)
                nombres.remove(b)
                nombres.append(a // b)
            else:
                ok = False
    return ok, nombres

Pour tester cette fonction, copier le code suivant dans le fichier calcul_console.py.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
from calcul_logique import *

print("Jeu Mathador ...")
cible = choose_target()
nombres = choose_numbers()
fini = False

while not fini:
    print("Vous devez obtenir le nombre : ", cible)
    print(nombres)
    a = int(input("Premier nombre choisi : "))
    b = int(input("Second nombre choisi : "))
    op = input("Opération à effectuer +, -, *, / : ")
    valide, nombres = valide_operation(a, b, op, nombres)
    if not valide:
        print("L'opération choisie n'est pas valide")
    elif nombres[-1]==cible:
        print(nombres)
        print("Bravo !")
        fini = True

Exécuter le programme, puis tenter d'analyser ce code pour expliquer le rôle de chaque ligne.