Projet AWALE



1.1. Contraintes

Langage de programmation : Python.

1.2. Groupes

1.3. Sujet

Le jeu de l'awalé, ou awélé ou encore kalaha, est un jeu de société africain à deux joueurs. On peut trouver les règles de ce jeu sur Wikipédia mais on va les simplifier ici. Le but est de récolter le plus de billes possibles en en prenant à son adversaire.

Initialement, chaque joueur dispose de 6 cases de jeu qui contiennent 4 billes et d'un grenier qui permet de stocker les billes gagnées, comme sur la figure suivante :

Awalé

A chaque tour, un joueur choisit une de ses cases non vides et égraine les billes dans le sens inverse des aiguilles d'une montre en déposant une bille s'il passe par son grenier. Il ne peut pas déposer de bille dans le grenier de son adversaire.

S'il dépose la dernière bille dans l'une de ses cases et que celle-ci ne contient qu'une seule bille, il ramasse les billes de son adversaire dans la case en regard de la sienne mais laisse sa bille dans la case où il termine de jouer.

Si un joueur n'a plus de billes dans ses cases, la partie se termine et le joueur qui possède encore des billes les place dans son grenier.

1.3.1. Prise des billes de l'adversaire

Voici un exemple ou le joueur orange, joue les 3 billes dans la première de ses cases. Il termine en case 4 avec une seule bille, il peut donc prendre les 7 billes en regard de cette case chez son adversaire.

Awalé

1.4. Spécificités

Pour ce jeu, on va opposer un être humain à l'ordinateur et on réalisera un tournoi qui verra chaque équipe s'affronter. On établira un classement en fonction du nombre de victoires.

On vous demande :

  1. de mettre en place des structures de données et fonctions communes à tous les groupes de manière à pouvoir réaliser une compétition entre groupes de projet
  2. de développer une fonction de jeu pour l'ordinateur qui prendra les mêmes paramètres pour tous les groupes de projet et retournera la case à jouer à partir d'une situation de jeu
  3. de tester que la fonction de jeu pour l'ordinateur fonctionne correctement

Il n’est pas nécessaire de développer une interface graphique.

1.5. Implantation

1.5.1. Modules

On va utiliser trois modules / fichiers comme suit :

1.5.2. Structures de données

On va utiliser une simple liste qui contient le nombre de billes / graines dans chaque trou. Le premier élément d'indice 0 ne sera pas utilisé :

1.5.3. Fonctions à implanter

Pour awale.py :

  1. import numpy as np
  2.  
  3. # premier joueur
  4. JOUEUR_1 = 1
  5. # second joueur
  6. JOUEUR_2 = 2
  7. # nombre de trous / cases
  8. MAX_TROUS = 14
  9.  
  10. #
  11. # Initialisation du jeu sous forme de tableau numpy
  12. # dont le premier indice ne sert à rien
  13. # On peut également utiliser une simple liste
  14. #
  15. def jeu_initialiser():
  16.     return np.array( [ 0, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4, 4, 4, 4, 0 ] )
  17.  
  18. #
  19. # Retourne l'adversaire du joueur passé en paramètre
  20. # - joueur (int)
  21. def adversaire( joueur ):
  22. # à compléter
  23.  
  24. #
  25. # Retourne le trou suivant accessible en fonction du trou
  26. # d'où on commence et du joueur. On rappelle qu'un joueur
  27. # ne peut pas jouer dans le grenier de son adversaire
  28. # - trou (int) variant entre 1 et 14
  29. # - joueur (int) soit JOUEUR_1, soit JOUEUR_2
  30. def trou_suivant( trou,  joueur ):
  31. # à compléter
  32.  
  33. #
  34. # Afficher le plateau de jeu
  35. # - jeu (liste ou numpy array)
  36. def jeu_afficher( jeu ):
  37. # à compléter
  38.  
  39. #
  40. # Indique si le jeu est terminé (True), c'est à dire si l'un des
  41. # joueurs ne peut pas jouer
  42. # - jeu (liste ou numpy array)
  43. #
  44. def jeu_est_termine( jeu ):
  45. # à compléter
  46.  
  47. #
  48. # Si on termine le jeu on ramasse les billes restantes
  49. # et on les place dans le grenier du joueur concerné
  50. # - jeu (liste ou numpy array)
  51. #
  52. def jeu_ramasser_billes( jeu ):
  53.  
  54. # à compléter
  55.  
  56. #
  57. # Indique si un joueur peut jouer, c'est à dire qu'il possède
  58. # des billes dans au moins une de ses cases
  59. # - jeu (liste ou numpy array)
  60. # - joueur (int) soit JOUEUR_1, soit JOUEUR_2
  61. #
  62. def joueur_peut_jouer( jeu, joueur ):
  63. # à compléter
  64.  
  65.  
  66. #
  67. # Indique si le joueur peut jouer la case/trou indiqué
  68. # - jeu (liste ou numpy array)
  69. # - joueur (int) soit JOUEUR_1, soit JOUEUR_2
  70. # - trou (int) valeur entre 1 et 6
  71. def joueur_peut_jouer_trou( jeu, joueur, trou ):
  72. # à compléter
  73.    
  74.    
  75. #
  76. # Joue pour le joueur donné, le coup donné
  77. # - jeu (liste ou numpy array)
  78. # - joueur (int) soit JOUEUR_1, soit JOUEUR_2
  79. # - trou (int) valeur entre 1 et 6
  80. #
  81. def joue( jeu, joueur, trou ):
  82. # à compléter
  83.    
  84.  
  85. #
  86. # Retourne le nombre de billes dans le grenier du joueur donné
  87. # - jeu (liste ou numpy array)
  88. # - joueur (int) soit JOUEUR_1, soit JOUEUR_2
  89. #
  90. def jeu_grenier( jeu, joueur ):
  91. # à compléter
  92.  

Pour appli_awale.py :

  1. import numpy as np
  2. import awale as aw
  3.  
  4.  
  5. le_joueur_courant = aw.JOUEUR_1
  6. le_jeu = aw.jeu_initialiser()
  7.  
  8. def demande( jeu, joueur ):
  9.     n = 0
  10.     while True:
  11.         print( "quel trou jouer joueur ", joueur, " ? ", end='')
  12.         n = int(input())
  13.         if aw.joueur_peut_jouer_trou( jeu, joueur, n):
  14.             break
  15.     return n
  16.  
  17. tour = 1
  18.  
  19.  
  20. #
  21. # Boucle principale
  22. #
  23. while not aw.jeu_est_termine( le_jeu ):
  24.  
  25.     aw.jeu_afficher( le_jeu )
  26.  
  27.     if aw.joueur_peut_jouer( le_jeu, le_joueur_courant ):
  28.  
  29.         if le_joueur_courant == aw.JOUEUR_1:
  30.             trou = demande( le_jeu, le_joueur_courant )
  31.             print("joue")
  32.             aw.joue( le_jeu, le_joueur_courant, trou )
  33.  
  34.         if le_joueur_courant == aw.JOUEUR_2:
  35.             trou = demande( le_jeu, le_joueur_courant )
  36.             print("joue")
  37.             aw.joue( le_jeu, le_joueur_courant, trou )
  38.            
  39.  
  40.     else:
  41.         print("Le joueur ", le_joueur_courant," ne peut pas jouer")
  42.  
  43.     le_joueur_courant = aw.adversaire( le_joueur_courant )
  44.    
  45.     print( le_jeu )
  46.  
  47. #
  48. # Fin de partie, au moins un des joueurs ne peut pas jouer
  49. #
  50. aw.jeu_ramasser_billes( le_jeu )
  51. aw.jeu_afficher( le_jeu )
  52. grenier_1 = jeu_grenier( le_jeu, aw.JOUEUR_1 )
  53. grenier_2 = jeu_grenier( le_jeu, aw.JOUEUR_2 )
  54. if grenier_1 > grenier_2:
  55.     print("Joueur 1 a gagné !")
  56. elif grenier_2 > grenier_1:
  57.     print("Joueur 2 a gagné !")
  58. else:
  59.     print("Match nul")
  60.  

Pour ia0.py :

  1. import awale as aw
  2.  
  3. #
  4. # Trouve le meilleur coup à jouer en fonction du
  5. # jeu et du joueur
  6. # Retourne une valeur entre 1 et 6 quelque soit le joueur
  7. #
  8. def ia( jeu, joueur ):
  9. # à compléter
  10.  

1.6. Tests

Vérifier que les sous-programmes que vous avez écrits sont capable de donner le résultat final à partir de le jeu suivant. Pour rappel le premier élément est 0.

0  0  0  3  3  0  1  14  0  0  0  0  2  10  15

C'est le joueur 1 qui commence. On a donc :

 Tour   Joueur   Trou à jouer 
 36   1   4 
 37   2   5 
 38   1   3 
 39   2   6 
 40   1   2 
 41   2   1 
 42   1   3 
 43   2   2 
 44   1   4 
 45   2   3 
 46   1   1 
 47   2   4 
 48   1   2 
 49   2   5 
 50   1   3 
 51   2   6 
Séquence de jeu

Situation initiale
          Joueur 2             
    10  2  0  0  0  0 
15                    14
     0  0  3  3  0  1 
          Joueur 1             
Joueur  1 joue trou 4
tour= 36


-------------------------------
         Joueur 2             
    10  2  0  0  0  0 
15                    15
     0  0  3  0  1  2 
          Joueur 1             
Joueur  2 joue trou 5
tour= 37
-------------------------------
          Joueur 2             
    11  0  0  0  0  0 
16                    15
     0  0  3  0  1  2 
          Joueur 1             
Joueur  1 joue trou 3
tour= 38
-------------------------------
          Joueur 2             
    11  0  0  0  0  0 
16                    15
     0  0  0  1  2  3 
          Joueur 1             
Joueur  2 joue trou 6
tour= 39
-------------------------------
          Joueur 2             
     0  0  1  1  1  1 
18                    15
     1  1  0  2  3  4 
          Joueur 1             
Joueur  1 joue trou 2
tour= 40
-------------------------------
          Joueur 2             
     0  0  0  1  1  1 
18                    16
     1  0  1  2  3  4 
          Joueur 1             
Joueur  2 joue trou 1
tour= 41
-------------------------------
          Joueur 2             
     0  0  0  1  2  0 
18                    16
     1  0  1  2  3  4 
          Joueur 1             
Joueur  1 joue trou 3
tour= 42
-------------------------------
          Joueur 2             
     0  0  0  1  2  0 
18                    16
     1  0  0  3  3  4 
          Joueur 1             
Joueur  2 joue trou 2
tour= 43
-------------------------------
          Joueur 2             
     0  0  1  2  0  0 
18                    16
     1  0  0  3  3  4 
          Joueur 1             
Joueur  1 joue trou 4
tour= 44
-------------------------------
          Joueur 2             
     0  0  1  2  0  0 
18                    17
     1  0  0  0  4  5 
          Joueur 1             
Joueur  2 joue trou 3
tour= 45
-------------------------------
          Joueur 2             
     0  1  2  0  0  0 
18                    17
     1  0  0  0  4  5 
          Joueur 1             
Joueur  1 joue trou 1
tour= 46
-------------------------------
          Joueur 2             
     0  0  2  0  0  0 
18                    18
     0  1  0  0  4  5 
          Joueur 1             
Joueur  2 joue trou 4
tour= 47
-------------------------------
          Joueur 2             
     1  1  0  0  0  0 
18                    18
     0  1  0  0  4  5 
          Joueur 1             
Joueur  1 joue trou 2
tour= 48
-------------------------------
          Joueur 2             
     1  1  0  0  0  0 
18                    18
     0  0  1  0  4  5 
          Joueur 1             
Joueur  2 joue trou 5
tour= 49
-------------------------------
          Joueur 2             
     2  0  0  0  0  0 
18                    18
     0  0  1  0  4  5 
          Joueur 1             
Joueur  1 joue trou 3
tour= 50
-------------------------------
          Joueur 2             
     2  0  0  0  0  0 
18                    18
     0  0  0  1  4  5 
          Joueur 1             
Joueur  2 joue trou 6

Situation finale
-------------------------------
          Joueur 2             
     0  0  0  0  0  0 
19                    29
     0  0  0  0  0  0 
          Joueur 1             
Joueur 1 a gagné !

Au final c'est le joueur 1 qui gagne avec 29 billes contre 19.

1.7. Tournoi

1.7.1. Règles

Chaque groupe doit proposer un fichier Python qui comporte une fonction qui retourne le prochain coup à jouer.

Chaque groupe affronte un adversaire 10 fois et on comptabilise le nombre de victoires, défaites ou matchs nuls.

Si le code fourni par un groupe :

alors la partie est considérée perdue par ce groupe.

1.7.2. Résultats

 Groupe   Victoires   Défaites   Matchs nuls 
 1   -   -   - 
 2   -   -   - 
 3   -   -   - 
 4   -   -   - 
 5   -   -   - 
Résultats du tournoi