Joueur_g.py 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. ''' Programme Puissance 4 (IA !)
  4. '''
  5. import random
  6. nb_col = 7
  7. nb_li = 6
  8. vide = 0
  9. def detection_align(n, ligne, couleur):
  10. ''' Détecte une séquence de 4 contenant
  11. n pions de la couleur
  12. (n=1 ou 2 car 3 est à part...)
  13. et le reste vide.
  14. On renvoie les indices des cases vides.
  15. '''
  16. a_jouer = []
  17. for k in range(len(ligne)-n):
  18. if ligne[k:k+4].count(couleur)==n and ligne[k:k+4].count(vide)==4-n:
  19. for p,e in enumerate(ligne[k:k+4]):
  20. if e==vide:
  21. a_jouer.append(p+k)
  22. return a_jouer
  23. def diag_li(planche, i, j, sens):
  24. '''Retourne une liste des éléments de la diagonale
  25. qui part de (i,j)
  26. vers le bas à droite si sens vaut 1
  27. et vers le bas à gauche si sens vaut -1
  28. '''
  29. ligne = []
  30. ii, jj = i, j
  31. while ii<nb_li and 0<=jj<nb_col:
  32. ligne.append(planche[ii][jj])
  33. ii += 1
  34. jj = jj + sens
  35. return ligne
  36. def col_li(planche, j):
  37. ''' Transforme une colonne en ligne...'''
  38. return [planche[i][j] for i in range(nb_li)]
  39. def detection_coup_final(planche, couleur):
  40. """Différente des autres détection car il suffit de
  41. prendre la première qui vient en attaque puis
  42. sinon la première qui vient en défense,
  43. alors que pour les autres sont listées pour
  44. choisir les optimales...
  45. Le coup est donné dans un tuple d'un élément
  46. ou False sinon, ainsi on peut tester coup comme un booléen :
  47. 0 compterait comme faux mais (0,) compte comme vrai.
  48. """
  49. # Lignes de 3 :
  50. for i, ligne in enumerate(planche):
  51. detect_align = detection_align(3, ligne, couleur)
  52. for j in detect_align:
  53. if i==nb_li-1 or planche[i+1][j]!=vide:
  54. ## print('ligne 3, i, j couleur : ', i, j, couleur)
  55. return (j,)
  56. # Colonnes de 3 :
  57. for j in range(nb_col):
  58. detect_align = detection_align(3, col_li(planche, j), couleur)
  59. for i in detect_align:
  60. if i==nb_li-1 or planche[i+1][j]!=vide:
  61. ## print('colonne 3')
  62. return (j,)
  63. # Diagonales de 3 :
  64. for j in range(nb_col):
  65. for sens in (-1,1):
  66. detect_align = detection_align(3, diag_li(planche, 0, j, sens), couleur)
  67. for i in detect_align:
  68. k = j + sens*i
  69. if i==nb_li-1 or planche[i+1][k]!=vide:
  70. ## print('diag 3j', sens)
  71. return (k,)
  72. for i in range(nb_li):
  73. detect_align = detection_align(3, diag_li(planche, i, 0, 1), couleur)
  74. for j in detect_align:
  75. k = i + j
  76. if k==nb_li-1 or planche[k+1][j]!=vide:
  77. ## print('diag 3i', 1)
  78. return (j,)
  79. detect_align = detection_align(3, diag_li(planche, i, nb_col-1, -1), couleur)
  80. ## print('detect_align : ', detect_align)
  81. for j in detect_align:
  82. k = i + j
  83. ## print('k, j, i : ', k, j, i)
  84. if k==nb_li-1 or planche[k+1][nb_col-1-j]!=vide:
  85. ## print('diag 3i', -1)
  86. return (nb_col-1-j,)
  87. return False
  88. def detection(planche, couleur, nb, liste_a_jouer):
  89. ''' Détecte une position libre et possible qui amène à
  90. nb+1 l'effectif d'une séquence de nb parmi 4
  91. (pas nécessairement consécutifs).
  92. Ajoute les coups possibles dans liste_a_jouer (effet de bord).
  93. '''
  94. # Lignes de nb :
  95. for i, ligne in enumerate(planche):
  96. detect_align = detection_align(nb, ligne, couleur)
  97. for j in detect_align:
  98. if i==nb_li-1 or planche[i+1][j]!=vide:
  99. liste_a_jouer.append(j)
  100. # Colonnes de nb :
  101. for j in range(nb_col):
  102. detect_align = detection_align(nb, col_li(planche, j), couleur)
  103. for i in detect_align:
  104. if i==nb_li-1 or planche[i+1][j]!=vide:
  105. liste_a_jouer.append(j)
  106. # Diagonales de nb :
  107. for j in range(nb_col):
  108. for sens in (-1,1):
  109. detect_align = detection_align(nb, diag_li(planche, 0, j, sens), couleur)
  110. for i in detect_align:
  111. k = j + sens*i
  112. if i==nb_li-1 or planche[i+1][k]!=vide:
  113. liste_a_jouer.append(k)
  114. for i in range(nb_li):
  115. detect_align = detection_align(nb, diag_li(planche, i, 0, 1), couleur)
  116. for j in detect_align:
  117. k = i + j
  118. if k==nb_li-1 or planche[k+1][j]!=vide:
  119. liste_a_jouer.append(j)
  120. detect_align = detection_align(nb, diag_li(planche, i, nb_col-1, -1), couleur)
  121. for j in detect_align:
  122. k = i + j
  123. ## print('nb, k, j, i : ', nb, k, j, i)
  124. if k==nb_li-1 or planche[k+1][nb_col-1-j]!=vide:
  125. liste_a_jouer.append(nb_col-1-j)
  126. def duplique_planche(planche):
  127. copie_planche = []
  128. for ligne in planche:
  129. copie_planche.append([])
  130. for e in ligne:
  131. copie_planche[-1].append(e)
  132. ## print('copie_planche : ', copie_planche)
  133. return copie_planche
  134. def choix_coup_a_jouer(liste_a_jouer):
  135. """ Tire au sort une des colonnes de la liste
  136. dont la fréquence est maximale.
  137. """
  138. dico = {}
  139. for e in liste_a_jouer:
  140. dico[e] = dico.get(e,0) + 1
  141. maxi = 0
  142. liste_maxi = []
  143. for k, v in dico.items():
  144. if v>maxi:
  145. maxi = v
  146. liste_maxi = [k]
  147. elif v==maxi:
  148. liste_maxi.append(k)
  149. ## print('liste_a_jouer, dico, maxi : ', liste_a_jouer, dico, maxi)
  150. return random.choice(liste_maxi)
  151. def joueur_g(planche, couleur):
  152. couleur_adverse = 3 - couleur
  153. # Attaque ultime (3->4 !)
  154. coup = detection_coup_final(planche, couleur)
  155. if coup:
  156. return coup[0]
  157. # Défense ultime (3->4 !)
  158. coup = detection_coup_final(planche, couleur_adverse)
  159. if coup:
  160. ## print('défense')
  161. return coup[0]
  162. liste_a_jouer =[]
  163. # Attaque pour 2->3
  164. detection(planche, couleur, 2, liste_a_jouer)
  165. # Défense pour 2->3
  166. detection(planche, couleur_adverse, 2, liste_a_jouer)
  167. # On retire de la liste les coups
  168. # qui mèneraient à un coup de grâce par l'adversaire
  169. copie_liste_a_jouer = liste_a_jouer[:]
  170. for j in copie_liste_a_jouer:
  171. copie_planche = duplique_planche(planche)
  172. depot_jeton(copie_planche, j, couleur)
  173. coup = detection_coup_final(copie_planche, couleur_adverse)
  174. if coup:
  175. liste_a_jouer.remove(j)
  176. if liste_a_jouer:
  177. return choix_coup_a_jouer(liste_a_jouer)
  178. # Attaque pour 1->2
  179. detection(planche, couleur, 1, liste_a_jouer)
  180. # Défense pour 1->2
  181. detection(planche, couleur_adverse, 1, liste_a_jouer)
  182. # On retire encore de la liste les coups
  183. # qui mèneraient à un coup de grâce par l'adversaire
  184. # sauf le dernier car il faut bien jouer !
  185. # (on pourrait aussi encore essayer autre chose mais c'est compliqué)
  186. copie_liste_a_jouer = liste_a_jouer[:]
  187. for j in copie_liste_a_jouer:
  188. copie_planche = duplique_planche(planche)
  189. depot_jeton(copie_planche, j, couleur)
  190. coup = detection_coup_final(copie_planche, couleur_adverse)
  191. if coup:
  192. if len(liste_a_jouer)>1:
  193. liste_a_jouer.remove(j)
  194. else:
  195. break
  196. if liste_a_jouer:
  197. return choix_coup_a_jouer(liste_a_jouer)
  198. else: # Ici on pourrait essayer d'éviter les coups dangereux...
  199. return random.choice([i for i,e in enumerate(planche[0]) if e==vide])
  200. def depot_jeton(planche, j, couleur):
  201. ''' utilisée uniquement sur une copie de la planche !
  202. '''
  203. ## print('planche : ', planche)
  204. if not(planche[0][j]):
  205. i = nb_li-1
  206. ## print('i,j : ',i,j)
  207. while planche[i][j]:
  208. ## print('while, i, couleur : ', i, couleur)
  209. i = i-1
  210. ## print('i :', i)
  211. planche[i][j] = couleur
  212. deposer = True
  213. else:
  214. deposer = False
  215. return deposer