Outils pour utilisateurs

Outils du site


nsi:jeu:puissance4

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Prochaine révision
Révision précédente
nsi:jeu:puissance4 [2021/09/04 10:47] – créée goupillwikinsi:jeu:puissance4 [2022/12/09 12:14] (Version actuelle) goupillwiki
Ligne 34: Ligne 34:
 <code python> <code python>
 """ """
-module fonctions_puissance4+module fonctionspuissance4
 """ """
  
Ligne 60: Ligne 60:
 Voici un exemple. Ici le joueur 1 a les jeton jaunes et le joueur 2 a les jetons rouges. Voici un exemple. Ici le joueur 1 a les jeton jaunes et le joueur 2 a les jetons rouges.
  
 +{{:nsi:jeu:puissance4_2.png?direct&400 |}}
  
 +<code python>
 +# tableau correspondant
 +[0, 0, 0, 0, 0, 0, 0,
 + 0, 0, 0, 0, 0, 0, 0,
 + 0, 0, 1, 0, 0, 0, 0,
 + 0, 0, 2, 1, 2, 0, 0,
 + 0, 1, 2, 2, 1, 0, 0,
 + 2, 1, 1, 1, 2, 2, 0]
 +</code>
  
 +//Bien que j'ai noté ce tableau sur plusieurs lignes, il s'agit bien d'un tableau à une dimension puisqu'il n'y a qu'une paire de crochets.//
  
 +<code python>
 +# c'est exactement le même tableau du point de vue de Python :
 +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 1, 2, 2, 1, 0, 0, 2, 1, 1, 1, 2, 2, 0]
 +</code>
  
 +=== Créer une grille vide ===
  
 +<code python linenums:9>
 +def make_empty_grid() -> list:
 +    """
 +    Renvoie un tableau de LIGNES * COLS cases et ne contenant que des 0
 +    """
 +    # à vous de compléter
 +</code>
 +
 +=== Lire le contenu d'une case d'une grille donnée ===
 +
 +<code python linenums:15>
 +def read(grid:list, lig:int, col:int) -> int:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    lig: entier dans [0;LIGNES[, indice de ligne
 +    col: entier dans [0;COLS[, indice de colonne
 +    Renvoie le contenu de grid correspondant à la ligne lig et colonne col
 +    """
 +    assert 0 <= lig < LIGNES
 +    assert 0 <= col < COLS
 +    assert len(grid) == LIGNES * COLS
 +    return # Complétez !
 +</code>
 +
 +=== Afficher une grille ===
 +
 +Il pourra être utile de donner une version lisible du contenu de la grille.
 +Je propose la solution suivante.
 +
 +<code python linenums:27>
 +SYMBOLS = " OX" # symboles pour les différents joueurs.
 +# SYMBOLS[0] correspond à une case vide.
 +
 +def grid_to_str(grid:list) -> str:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    renvoie une version texte de la grille.
 +    """
 +    # création d'une grille avec les symboles au lieu des numéros
 +    symb_grid = [SYMBOLS[joueur] for joueur in grid]
 +    # création d'une grille de ligne
 +    symb_lignes = ["|"+"|".join(symb_grid[lig*COLS:(lig+1)*COLS])+"|" for lig in range(LIGNES)]
 +    return "\n".join(symb_lignes)
 +</code>
 +
 +C'est un peu compliqué. Quelques détails pour les plus curieux :
 +  * ''%%symb_grid = [SYMBOLS[joueur] for joueur in grid]%%'' utilise un tableau en compréhension : On crée directement un tableau dont les éléments sont obtenus par exécution de la boucle.
 +  * ''%%symb_grid[lig*COLS:(lig+1)*COLS]%%'' permet d'extraire un tronçon correspondant à une ligne ''lig'' donnée,
 +  * ''%%"|".join(symb_grid[lig*COLS:(lig+1)*COLS])%%'' permet de coller les éléments de ce tronçon avec un trait de séparation de colonne,
 +  * ''%%"|"+"|".join(symb_grid[lig*COLS:(lig+1)*COLS])+"|"%%'' permet d'ajouter des traits de colonnes au début et à la fin,
 +  * ''%%[... for lig in range(LIGNES)]%%'' permet de faire cela pour toutes les lignes et de mettre l'ensemble des résultats dans un tableau,
 +  * ''%%"\n".join(symb_lignes)%%'' permet de coller les lignes obtenus par un symbole de retour chariot -- retour à la ligne -- que l'on note ''%%"\n"%%''.
 +
 +=== Vérifier si une colonne est pleine ===
 +
 +Une colonne si la case du haut de cette colonne est occupée. Pour une colonne ''%%col%%'' il nous suffit de lire le contenu de cette colonne et de la ligne ''0'' et de voir si le contenu est occupé.
 +
 +<code python linenums:41>
 +def col_is_full(grid:list, col:int) -> bool:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    col: indice de la colonne
 +    renvoie True si la colonne est pleine, False sinon
 +    """
 +    # à vous...
 +</code>
 +
 +=== Vérifier si la grille est pleine ===
 +
 +Il faut vérifier chaque colonne. Si au moins une n'est pas pleine, c'est que la grille n'est pas pleine.
 +
 +<code python linenums:49>
 +def grid_is_full(grid:list) -> bool:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    renvoie True si la grille est pleine, False sinon
 +    """
 +    # à vous...
 +</code>
 +
 +=== insérer jeton ===
 +
 +Ajoute un jeton du joueur donné dans la plus haute case libre de la colonne.
 +
 +<code python linenums:56>
 +def insert(grid:list, col:int, player:int):
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    col: indice de la colonne
 +    player: numéro du joueur
 +    """
 +    assert not col_is_full(grid, col)
 +    # À vous !
 +</code>    
 +
 +=== Vérifier un alignement ===
 +
 +Cette partie est plus difficile. L'humain reconnaît d'un coup d'œil la présence ou l'absence d'alignement. Je vous propose l'approche suivante :
 +
 +  * On choisit une orientation -- diagonale ↘, diagonale ↗, verticale, horizontale
 +  * On choisit un point de départ, par exemple le coin supérieur gauche
 +  * On parcourt cet alignement du point de départ jusqu'à atteindre un bord. On relève les valeurs rencontrées.
 +
 +<code lang-none>
 +FONCTION get_line
 +ENTRÉES
 +    grille
 +    pas: déplacement à faire d'un case à l'autre
 +    depart: position de départ
 +SORTIE: une chaîne de caractères line valeurs de l'alignement
 +DÉBUT
 +    soit position en cours définie par la position de depart
 +    soit line une chaine vide
 +    TANT QUE position en cours à l'intérieur de la grille RÉPÉTER
 +        lire le contenu de la grille en position,
 +        ajouter ce qui a été lu au bout de line
 +        modifier position selon le pas
 +    FIN
 +    RENVOYER line
 +FIN
 +</code>
 +
 +//Exemple ://
 +<code lang-none>
 +0000000
 +0000000
 +0010000
 +0022200
 +0012120
 +1121211
 +</code>
 +Si on se donne ''depart= (0,0)'', cela désigne le coin supérieur gauche. ''pas = (1,1)'' fait se déplacer en diagonale ↘. L'appel ''get_line(grille, pas, depart)'' doit renvoyer ''%%"001211"%%''.
 +
 +Exemple d'utilisation :
 +  * ''%%get_line(grid, (1,1), (0,0))%%'' renvoie la diagonale ↘ partant du coin supérieur droit,
 +  * ''%%get_line(grid, (1,1), (0,1))%%'' renvoie la diagonale ↘ partant de la deuxième case de la première ligne,
 +  * ''%%get_line(grid, (-1,1), (0,3))%%'' renvoie la diagonale ↙ partant de la quatrième case de la première ligne,
 +  * ''%%get_line(grid, (0,1), (0,3))%%'' renvoie la colonne partant de la quatrième case de la première ligne,
 +  * ''%%get_line(grid, (1,0), (2,0))%%'' renvoie la troisième ligne.
 +
 +On ajoute une deuxième fonction pour compter le nombre max de répétitions d'un symbole :
 +
 +<code python>
 +def line_has_victory(line:str, valeur:int) -> bool:
 +    '''
 +    line: chaîne représentant un alignement. ex : "012111"
 +    valeur: valeur recherchée. ex : 1
 +    renvoie True si line contient un alignement assez long
 +      ex: ici non, il n'y a que 3 fois le 1 à la suite
 +    '''
 +</code>
 +
 +Et maintenant vous pouvez envisager une fonction qui parcours toutes les lignes possibles à la recherche d'une victoire.
 +
 +<code python linenums:74>
 +def grid_has_victory(grid:list) -> bool:
 +    """
 +    grid: grille de jeu
 +    renvoie True si un alignement gagnant a été trouvé, False sinon
 +    """
 +    # À vous !
 +</code>
 +
 +=== Fichier complet ===
 +
 +À placer dans un fichier ''%%fonctionspuissance4.py%%''.
 +
 +<code python linenums>
 +"""
 +module fonctionspuissance4
 +"""
 +
 +COLS = 7   # Nombre de colonnes de la grille
 +LIGNES = 6 # Nombre de lignes de la grille
 +TO_WIN = 4 # Nombre de jetons à aligner pour gagner
 +
 +def make_empty_grid() -> list:
 +    """
 +    Renvoie un tableau de LIGNES * COLS cases et ne contenant que des 0
 +    """
 +    # à vous de compléter
 +    
 +def read(grid:list, lig:int, col:int) -> int:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    lig: entier dans [0;LIGNES[, indice de ligne
 +    col: entier dans [0;COLS[, indice de colonne
 +    Renvoie le contenu de grid correspondant à la ligne lig et colonne col
 +    """
 +    assert 0 <= lig < LIGNES
 +    assert 0 <= col < COLS
 +    assert len(grid) == LIGNES * COLS
 +    return # Complétez !
 +
 +SYMBOLS = " OX" # symboles pour les différents joueurs.
 +# SYMBOLS[0] correspond à une case vide.
 +
 +def grid_to_str(grid:list) -> str:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    renvoie une version texte de la grille.
 +    """
 +    # création d'une grille avec les symboles au lieu des numéros
 +    symb_grid = [SYMBOLS[joueur] for joueur in grid]
 +    # création d'une grille de ligne
 +    symb_lignes = ["|"+"|".join(symb_grid[lig*COLS:(lig+1)*COLS])+"|" for lig in range(LIGNES)]
 +    return "\n".join(symb_lignes)
 +
 +def col_is_full(grid:list, col:int) -> bool:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    col: indice de la colonne
 +    renvoie True si la colonne est pleine, False sinon
 +    """
 +    # à vous...
 +
 +def grid_is_full(grid:list) -> bool:
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    renvoie True si la grille est pleine, False sinon
 +    """
 +    # à vous...
 +
 +def insert(grid:list, col:int, player:int):
 +    """
 +    grid: tableau de LIGNES * COLS éléments
 +    col: indice de la colonne
 +    player: numéro du joueur
 +    """
 +    assert not col_is_full(grid, col)
 +    # À vous !
 +
 +def get_line(grid:list, step:tuple, start:tuple) -> str:
 +    """
 +    grid: grille de jeu
 +    step: paire (step_lig,step_col) indiquant le déplacement d'une case à la suivante
 +    start: paire (start_lig, start_col) indiquant la position de départ
 +    renvoie une chaîne correspondant à l'alignement demandé
 +    """
 +    # À vous !
 +
 +def line_has_victory(line:str, valeur:int) -> bool:
 +    '''
 +    line: chaîne représentant un alignement. ex : "012111"
 +    valeur: valeur recherchée. ex : 1
 +    renvoie True si line contient un alignement assez long
 +      ex: ici non, il n'y a que 3 fois le 1 à la suite
 +    '''
 +
 +def grid_has_victory(grid:list) -> bool:
 +    """
 +    grid: grille de jeu
 +    renvoie True si un alignement gagnant a été trouvé, False sinon
 +    """
 +    # À vous !
 +</code>
 +
 +==== Fichier principal ====
 +
 +Il faut importer les fonctions définies précédemment.
 +
 +<code python linenums>
 +# main.py
 +
 +from fonctionspuissance4 import *
 +</code>
 +
 +Ensuite le jeu suit l'algorithme suivant :
 +
 +<code lang-none>
 +DÉBUT
 +    créer une grille vide
 +    afficher la grille
 +    joueur en cours est 1
 +    partie_finie est faux
 +    TANT QUE partie finie est faux RÉPÉTER
 +        demander au joueur en quelle colonne il souhaite jouer
 +        jouer le coup pour le joueur en cours
 +        afficher la grille
 +        SI la grille contient une victoire ALORS
 +            partie_finie passe à vrai
 +            afficher un message indiquant la victoire du joueur
 +        SINON SI la grille est pleine ALORS
 +            partie_finie passe à vrai
 +            afficher un message indiquant le match nul
 +        SINON
 +            changer de joueur
 +        FIN
 +    FIN
 +FIN
 +</code>
  
-# **Important :** plutôt que d'écrire les valeurs 4, 7, 6 dans le programme, nous utiliserons des constantes. Cela rend le programme plus clair et permet, si on le souhaite, de modifier facilement les règles en passant à une grille plus grande par exemple.+À vous de compléter le fichier ''main.py''
nsi/jeu/puissance4.1630745254.txt.gz · Dernière modification : de goupillwiki