Plateau.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. from Outils.Moteur_de_jeu.Pathfinding import *
  2. from Outils.Moteur_de_jeu.Barriere import *
  3. from Outils.Moteur_de_jeu.Coup import *
  4. def suppr (t, a) : #Elric et Baptiste 09/2016
  5. """ On supprime tout les elements valant a dans le tableau t """
  6. for i in t :
  7. if i == a :
  8. t.remove(i)
  9. """
  10. Conventions :
  11. - Les coordonnées vont de 0 à lg - 1 horizontalement et ht - 1 verticalement
  12. - L'origine des axes est en haut à gauche
  13. - Le barycentre d'une barrière est reperé par les coordonnées de la case en haut à gauche
  14. --- ---
  15. |ici| |
  16. ---B--- B = milieu de la barrière
  17. | | |
  18. --- ---
  19. - Le joueur 0 commence sur la ligne 0, le joueur 1 sur la ligne ht - 1
  20. - D'accord ici
  21. """
  22. class Plateau : # Jovian : 18 octobre 2016
  23. """
  24. On dispose des méthodes suivantes :
  25. .copie(self)
  26. .joueur_sur_case(self, num, x, y)
  27. .cases_voisines(self, x, y)
  28. .cases_accessibles(self, x, y)
  29. .cases_accessibles_depuis(self, x, y, num)
  30. .cases_accessibles_joueur(self, num)
  31. .point_libre(plateau, x, y)
  32. .point_barrieres_possibles(self, x, y)
  33. .rangee_desiree(self, num)
  34. .barriere_possible(self, barriere)
  35. .liste_barrieres_possibles(plateau, num)
  36. .liste_coups_possibles(self, num)
  37. .executer_coup(self, coup, num)
  38. .gagnant(self)
  39. .longueur_chemin(self, num)
  40. .barrieres_adjacentes
  41. .pions_voisins
  42. .bord_adjacent
  43. .contact (self,num)
  44. """
  45. def __init__(self, lg, ht, nombre_barrieres) : # Quentin 06/10/2016
  46. self.pions = [[(lg-1)//2, 0], [(lg-1)//2, ht - 1]]
  47. self.barrieres_restantes = [nombre_barrieres, nombre_barrieres]
  48. self.liste_barrieres = []
  49. self.lg = lg
  50. self.ht = ht
  51. self.tour = 0 # Joueur dont c'est le tour
  52. def copie(self) : #Quentin 06/10/2016
  53. """ Retourne un nouveau plateau, copie de celui passé en paramètre. """
  54. nouveau = Plateau(self.lg, self.ht, 0)
  55. nouveau.pions = [list(self.pions[0]),list(self.pions[1])]
  56. nouveau.barrieres_restantes = list(self.barrieres_restantes)
  57. nouveau.liste_barrieres = list(self.liste_barrieres)
  58. nouveau.tour = self.tour
  59. return nouveau
  60. def copie_complete(self) :
  61. """ Copie également les barrières """
  62. nouveau = Plateau(self.lg, self.ht, 0)
  63. nouveau.pions = [list(self.pions[0]),list(self.pions[1])]
  64. nouveau.barrieres_restantes = list(self.barrieres_restantes)
  65. for b in self.liste_barrieres :
  66. nouveau.liste_barrieres.append(b.copie())
  67. nouveau.tour = self.tour
  68. return nouveau
  69. def joueur_sur_case(self, num, x, y) : #Elric et Baptiste 10/2016
  70. """ Retourne True si le joueur num est sur la case (x,y) """
  71. return self.pions[num] == [x,y]
  72. def cases_accessibles_depuis(self, x0, y0, num) : #Elric et Baptiste, 11/10
  73. """Cases accessibles depuis la case (x0, y0) par le joueur num s'il était placé sur cette case. Prend en compte la possibilité de saut et les barrières."""
  74. liste = cases_accessibles(self, x0, y0)
  75. for c in liste :
  76. (x, y) = c
  77. if self.joueur_sur_case(1-num, x, y) :#Si l'adversaire est présent sur une case voisine,
  78. suppr(liste,c)
  79. liste2 = cases_accessibles(self, x, y)
  80. for i in liste2 :
  81. liste.append(i)
  82. suppr(liste,(x0,y0))
  83. return liste
  84. def cases_accessibles_joueur(self, num) : #Quentin 06/10/2016
  85. """ Cases accessibles par le joueur num depuis la case où il est réellement placé """
  86. return self.cases_accessibles_depuis(self.pions[num][0], self.pions[num][1], num)
  87. def point_libre(self, x, y) : #Elric et Baptiste 09/2016
  88. """
  89. Retourne une chaîne de caractères correspondant aux barrières pouvant être placées en (x, y)
  90. "" : aucune
  91. "h" : horizontale
  92. "v" : verticale
  93. "vh" : les deux
  94. """
  95. b = self.liste_barrieres
  96. t = ["v", "h"]
  97. for bar in b :
  98. if bar.x == x-1 and bar.y == y and bar.orientation == "h" :
  99. suppr (t, "h")
  100. elif bar.x == x+1 and bar.y == y and bar.orientation == "h" :
  101. suppr (t, "h")
  102. elif bar.x == x and bar.y == y-1 and bar.orientation == "v" :
  103. suppr (t, "v")
  104. if bar.x == x and bar.y == y+1 and bar.orientation == "v" :
  105. suppr (t, "v")
  106. elif bar.x == x and bar.y == y :
  107. t = []
  108. while len(t) < 2 :
  109. t.append(" ")
  110. return(t[0] + t[1])
  111. def pourri_chemin (self , t ) :
  112. """
  113. prend un plateau et un chemin en entrée
  114. retourne la liste des barrières permettant de pourrir le chemin entré
  115. """
  116. n = len(t)
  117. tab = []
  118. for k in range (n - 1) :
  119. x1 = t[k][0]
  120. x2 = t[k+1][0]
  121. y1 = t[k][1]
  122. y2 = t[k+1][1]
  123. if x1 == x2 :
  124. if y1 == y2 + 1 :
  125. tab.append ( Barriere("h", x1, y2) )
  126. tab.append (Barriere("h", x1 - 1, y2) )
  127. else:
  128. tab.append ( Barriere("h", x1, y1) )
  129. tab.append ( Barriere("h", x1 - 1, y1) )
  130. else :
  131. if x1 == x2 + 1 :
  132. tab.append ( Barriere("v", x1 - 1, y1 - 1) )
  133. tab.append ( Barriere("v", x1 - 1, y1) )
  134. else :
  135. tab.append ( Barriere("v", x1, y1 ) )
  136. tab.append ( Barriere("v", x1, y1 - 1) )
  137. return tab
  138. def point_barrieres_possibles(self, x, y) : #Elric et Baptiste 09/2016
  139. """Retourne la liste des barrières pouvant être placées en (x, y)"""
  140. p = self.point_libre(x, y)
  141. if " " == p :
  142. return []
  143. elif p == "h " :
  144. return [Barriere("h", x, y)]
  145. elif p == "v " :
  146. return [Barriere("v", x, y)]
  147. else :
  148. return [Barriere("h", x, y), Barriere("v", x, y)]
  149. def rangee_desiree(self, num) : #Quentin 04/10/2016
  150. """ Retourne la rangée que doit atteindre le joueur num """
  151. return (self.ht - 1)*(1 - num)
  152. def barriere_possible (self, barriere) : # Jovian 18/10/16 : optimisation
  153. """
  154. Permet de savoir si une barrière peut être placée sans isoler un pion du bord qu'il cherche à atteindre.
  155. Argument self : le plateau qui lance la méthode.
  156. Argument barriere : objet barrière supposée posable sans collision.
  157. Retour : un booléen qui retourne True si la barrière est valide.
  158. """
  159. # Si la barrière a moins de deux contacts, elle ne peut pas fermer de contour. Il n'est donc pas nécessaire de la vérifier.
  160. if self.nombre_contacts(barriere) < 2 :
  161. return True
  162. # Mise en place de la barrière pour l'expérience
  163. self.liste_barrieres.append( barriere )
  164. # Pathfinding joueur A
  165. joueurA = self.pions[0]
  166. trajetA = path_finding( self, joueurA[0], joueurA[1], self.rangee_desiree(0) )
  167. if trajetA == [] :
  168. # Arrivée non joignable dans ce cas
  169. self.liste_barrieres.pop()
  170. return False
  171. # Pathfinding joueur B
  172. joueurB = self.pions[1]
  173. trajetB = path_finding( self, joueurB[0], joueurB[1], self.rangee_desiree(1) )
  174. if trajetB == [] :
  175. # Arrivée non joignable dans ce cas
  176. self.liste_barrieres.pop()
  177. return False
  178. # L'arrivée est joignable
  179. self.liste_barrieres.pop()
  180. return True
  181. ## def liste_barrieres_possibles (self) : #Elric et Baptiste 04/10/2016 #accélération Elric 25/11
  182. ## """
  183. ## Retourne la liste de toutes les barrières pouvant être placées ce tour-ci en tenant compte de toutes les contraintes existantes.
  184. ## """
  185. ##
  186. ## if self.barrieres_restantes[self.tour] == 0 :
  187. ## return []
  188. ## tab = []
  189. ##
  190. ## for y in range (self.ht - 1) :
  191. ## for x in range (self.lg - 1) :
  192. ## bar = self.point_barrieres_possibles (x, y)
  193. ## for i in bar :
  194. ## if self.barriere_possible (i) :
  195. ## tab.append(i)
  196. ##
  197. ##
  198. ## """joueurA = self.pions[0]
  199. ## trajetA = path_finding( self, joueurA[0], joueurA[1], self.rangee_desiree(0) )
  200. ## t = self.pourri_chemin(trajetA)
  201. ## joueurB = self.pions[1]
  202. ## trajetB = path_finding( self, joueurB[0], joueurB[1], self.rangee_desiree(1) )
  203. ##
  204. ## t += self.pourri_chemin(trajetB)
  205. ##
  206. ## for i in t :
  207. ## if self.barriere_possible (i) :
  208. ## tab.append(i)"""
  209. ##
  210. ## return tab
  211. def liste_barrieres_possibles (self) : #Elric et Baptiste 04/10/2016 #accélération Elric 25/11
  212. """
  213. Retourne la liste de toutes les barrières pouvant être placées ce tour-ci en tenant compte de toutes les contraintes existantes.
  214. """
  215. if self.barrieres_restantes[self.tour] == 0 :
  216. return []
  217. tab = []
  218. joueurA = self.pions[0]
  219. trajetA = path_finding( self, joueurA[0], joueurA[1], self.rangee_desiree(0) )
  220. t = self.pourri_chemin(trajetA)
  221. joueurB = self.pions[1]
  222. trajetB = path_finding( self, joueurB[0], joueurB[1], self.rangee_desiree(1) )
  223. t += self.pourri_chemin(trajetB)
  224. for x in range ( self.lg -1):
  225. for y in range (self.ht -1) :
  226. bar = self.point_barrieres_possibles( x, y)
  227. for i in bar :
  228. if i in t :
  229. if self.barriere_possible (i) :
  230. tab.append(i)
  231. else :
  232. tab.append(i)
  233. return tab
  234. def liste_coups_possibles(self) :
  235. """
  236. Liste des coups possibles à disposition du joueur actuel
  237. """
  238. t = []
  239. mouvements = self.cases_accessibles_joueur(self.tour)
  240. barrieres = self.liste_barrieres_possibles()
  241. #On met les mouvements
  242. for m in mouvements :
  243. t.append(Coup("M",case = m))
  244. # On met les barrières
  245. for b in barrieres :
  246. t.append(Coup("B",barriere = b))
  247. return t
  248. def executer_coup(self, coup) : #Quentin 06/10/2016
  249. """ Exécute un coup de la part du joueur dont c'est le tour"""
  250. if coup.type == "M" :
  251. self.pions[self.tour][0] = coup.case[0]
  252. self.pions[self.tour][1] = coup.case[1]
  253. else :
  254. self.liste_barrieres.append(coup.barriere)
  255. self.barrieres_restantes[self.tour] -= 1
  256. self.tour = 1 - self.tour
  257. def gagnant(self) :
  258. """
  259. Détermine si un plateau correpsond à une partie terminée. Retourne :
  260. > -1 si la partie est toujours en cours
  261. > le numéro du gagannt sinon
  262. """
  263. if self.pions[0][1] == self.rangee_desiree(0) :
  264. return 0
  265. elif self.pions[1][1] == self.rangee_desiree(1) :
  266. return 1
  267. else :
  268. return -1
  269. def chemin(self,num) :
  270. return path_finding(self, self.pions[num][0], self.pions[num][1], self.rangee_desiree(num))
  271. def longueur_chemin(self, num) : # Quentin 08/11/2016
  272. """ Retourne la longueur du chemin le plus court entre un joueur et le bord recherché """
  273. return len( path_finding(self, self.pions[num][0], self.pions[num][1], self.rangee_desiree(num)) ) - 1
  274. def bord_adjacent (self, bar) : # Elric, 09/11/2016
  275. """
  276. Prend un barrière en entrée, et retourne le tableau contenant les bords la touchant
  277. RETOURNE un tableau de booléens
  278. """
  279. if bar.orientation == "h" :
  280. return [bar.x == 0, False, bar.x == self.lg - 2]
  281. else :
  282. return [bar.y == 0, False, bar.y == self.ht - 2]
  283. def pions_voisins(self, bar) : # Elric, 19/11/2016
  284. """
  285. Prend une barrière en entrée, donne s'il y a un pion qui colle la barrière ou pas.
  286. RETOURNE un booléen
  287. """
  288. position1 = self.pions[0]
  289. position2 = self.pions[1]
  290. t = [[bar.x,bar.y] , [bar.x + 1 , bar.y + 1] ,
  291. [bar.x , bar.y + 1 ] , [bar.x +1, bar.y ]]
  292. return ( position1 in t or position2 in t )
  293. def barrieres_adjacentes(self, bar) :
  294. """
  295. Prend une barrière en entrée, et retourne le tableau contenant les barrières la touchant
  296. """
  297. if bar.orientation == "h" :
  298. b1 = Barriere ("v", bar.x, bar.y + 1)
  299. b2 = Barriere ("v", bar.x - 1, bar.y + 1)
  300. b3 = Barriere ("v", bar.x + 1, bar.y + 1)
  301. b4 = Barriere ("v", bar.x, bar.y - 1)
  302. b5 = Barriere ("v", bar.x + 1, bar.y - 1)
  303. b6 = Barriere ("v", bar.x - 1, bar.y - 1)
  304. b7 = Barriere ("h", bar.x - 2, bar.y)
  305. b8 = Barriere ("h", bar.x + 2, bar.y)
  306. b9 = Barriere ("v", bar.x - 1, bar.y)
  307. b10 = Barriere ("v", bar.x + 1, bar.y)
  308. t = [b1, b2, b3, b4, b5, b6, b7, b8, b9, b10 ]
  309. res = []
  310. for a in self.liste_barrieres :
  311. if a in t :
  312. res.append(a)
  313. else :
  314. b1 = Barriere ("v", bar.x, bar.y + 2)
  315. b2 = Barriere ("v", bar.x, bar.y - 2)
  316. b3 = Barriere ("h", bar.x + 1, bar.y + 1)
  317. b4 = Barriere ("h", bar.x + 1, bar.y - 1)
  318. b5 = Barriere ("h", bar.x + 1, bar.y)
  319. b6 = Barriere ("h", bar.x - 1, bar.y - 1)
  320. b7 = Barriere ("h", bar.x - 1, bar.y)
  321. b8 = Barriere ("h", bar.x - 1, bar.y + 1)
  322. b9 = Barriere ("h", bar.x , bar.y - 1)
  323. b10 = Barriere ("h", bar.x , bar.y + 1)
  324. res = []
  325. t = [b1, b2, b3, b4, b5, b6, b7, b8, b9, b10 ]
  326. for a in self.liste_barrieres :
  327. if a in t :
  328. res.append(a)
  329. return res
  330. def barrieres_adjacentes_precis(self, b0) : # Quentin 15/11/2016
  331. """
  332. b0 est une barrière, qui peut être vue comme un triplet de trois noeuds.
  333. Cette fonction retourne la liste des barrières et des bords (représentés par des None) qui touchent chaque noeud, sous forme d'un tableau de tableaux.
  334. Le sens de lecture est de gauche à droite si b0 est horizontale, et de haut en bas si b0 est verticale.
  335. """
  336. tab_final = [[],[],[]]
  337. if b0.orientation == "h" :
  338. tab_potentiel = [[Barriere ("v", b0.x - 1, b0.y - 1), Barriere ("v", b0.x - 1, b0.y), Barriere ("v", b0.x - 1, b0.y + 1), Barriere ("h", b0.x - 2, b0.y)],
  339. [Barriere ("v", b0.x, b0.y - 1), Barriere ("v", b0.x, b0.y + 1)],
  340. [Barriere ("v", b0.x + 1, b0.y - 1), Barriere ("v", b0.x + 1, b0.y), Barriere ("v", b0.x + 1, b0.y + 1), Barriere ("h", b0.x + 2, b0.y)]]
  341. if b0.x == 0 :
  342. tab_final[0].append(None)
  343. if b0.x == self.lg - 2 :
  344. tab_final[2].append(None)
  345. else :
  346. tab_potentiel = [[Barriere ("h", b0.x - 1, b0.y - 1), Barriere ("h", b0.x, b0.y - 1), Barriere ("h", b0.x + 1, b0.y - 1), Barriere ("v", b0.x, b0.y - 2)],
  347. [Barriere ("h", b0.x - 1, b0.y), Barriere ("h", b0.x + 1, b0.y)],
  348. [Barriere ("h", b0.x - 1, b0.y + 1), Barriere ("h", b0.x, b0.y + 1), Barriere ("h", b0.x + 1, b0.y + 1), Barriere ("v", b0.x, b0.y + 2)]]
  349. if b0.y == 0 :
  350. tab_final[0].append(None)
  351. if b0.y == self.ht - 2 :
  352. tab_final[2].append(None)
  353. for b in self.liste_barrieres :
  354. for i in range(3) :
  355. if b in tab_potentiel[i] :
  356. tab_final[i].append(b)
  357. return tab_final
  358. def nombre_contacts(self, b) :
  359. """ Retourne le nombre de noeuds de la barrière b ayant un contact avec une barrière du plateau """
  360. tab = self.barrieres_adjacentes_precis(b)
  361. nb = 0
  362. for i in range(3) :
  363. if tab[i] != [] :
  364. nb += 1
  365. return nb
  366. def contact (self, x, y) :#Elric, 25/11
  367. """
  368. Si une barrière touche le pion num. C'est un booléen
  369. """
  370. for i in self.liste_barrieres :
  371. if (i.x == x and i.y == y ) or (i.x == x-1 and i.y == y ) or (i.x == x and i.y == y-1 ) or (i.x == x-1 and i.y == y-1 ) :
  372. return True
  373. return False