Advertisement
Guest User

TestConnect4

a guest
Mar 31st, 2020
118
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 16.73 KB | None | 0 0
  1. import time
  2. #
  3. #
  4. # def elem_identice(lista):
  5. # """ Primeste o lista si returneaza
  6. # -> simbolul jucatorului castigator (daca lista contine doar acel simbol repetat)
  7. # -> sau False (daca a fost remiza sau daca nu s-a terminat jocul)
  8. # """
  9. # mt = set(lista)
  10. # if len(mt) == 1:
  11. # castigator = list(mt)[0]
  12. # if castigator != Joc.GOL:
  13. # return castigator
  14. # else:
  15. # return False
  16. # else:
  17. # return False
  18. #
  19.  
  20. class Joc:
  21. """
  22. Clasa care defineste jocul. Se va schimba de la un joc la altul.
  23. """
  24. NR_COLOANE = 7
  25. NR_LINII = 6
  26. NR_CONNECT = 4 # cu cate simboluri adiacente se castiga
  27. SIMBOLURI_JUC = ['X', '0'] # ['G', 'R'] sau ['X', '0']
  28. JMIN = None # 'R'
  29. JMAX = None # 'G'
  30. GOL = '.'
  31. def __init__(self, tabla=None):
  32. self.matr = tabla or [Joc.GOL]*(Joc.NR_COLOANE * Joc.NR_LINII)
  33.  
  34.  
  35. def final(self):
  36. # returnam simbolul jucatorului castigator daca are 4 piese adiacente
  37. # pe linie, coloana, diagonala \ sau diagonala /
  38. # sau returnam 'remiza'
  39. # sau 'False' daca nu s-a terminat jocul
  40. rez = False
  41.  
  42. # verificam linii
  43. # TO DO ..........
  44. #pass
  45. for i in range(self.NR_LINII):
  46. for j in range(self.NR_COLOANE - 4):
  47. start = 0
  48. for k in range(4):
  49. if k == 0:
  50. start = self.matr[i*self.NR_COLOANE + j + k]
  51. if start == '.':
  52. break
  53. elif self.matr[i*self.NR_COLOANE + j +k] != start:
  54. rasp = 0
  55. break
  56. if k == 3:
  57. rasp = 1
  58. return start
  59.  
  60.  
  61.  
  62. # verificam coloane
  63. # T0 DO ..........
  64. #pass
  65.  
  66. for i in range(self.NR_LINII - 4):
  67. for j in range(self.NR_COLOANE):
  68. start = 0
  69. for k in range(4):
  70. if k == 0:
  71. start = self.matr[(i + k)*self.NR_COLOANE + j]
  72. if start == '.':
  73. break
  74. elif self.matr[(i + k)*self.NR_COLOANE + j] != start:
  75. rasp = 0
  76. break
  77. if k == 3:
  78. rasp = 1
  79. return start
  80.  
  81.  
  82.  
  83. # verificam diagonale \
  84. # TO DO..........
  85. #pass
  86.  
  87. for i in range(self.NR_LINII - 1, 2, -1):
  88. for j in range(self.NR_COLOANE - 1, 2, -1):
  89. start = 0
  90. for k in range(4):
  91. if k == 0:
  92. start = self.matr[(i - k)*self.NR_COLOANE + j - k]
  93. if start == '.':
  94. break
  95. elif self.matr[(i - k)*self.NR_COLOANE + j - k] != start:
  96. rasp = 0
  97. break
  98. if k == 3:
  99. rasp = 1
  100. return start
  101.  
  102.  
  103. # verificam diagonale /
  104. # TO DO..........
  105. #pass
  106.  
  107. for i in range(self.NR_LINII - 4):
  108. for j in range(self.NR_COLOANE - 4):
  109. start = 0
  110. for k in range(4):
  111. if k == 0:
  112. start = self.matr[(i + k)*self.NR_COLOANE + j + k]
  113. if start == '.':
  114. break
  115. elif self.matr[(i + k)*self.NR_COLOANE + j + k] != start:
  116. rasp = 0
  117. break
  118. if k == 3:
  119. rasp = 1
  120. return start
  121.  
  122.  
  123. if rez==False and Joc.GOL not in self.matr:
  124. return 'remiza'
  125. else:
  126. return False
  127.  
  128.  
  129. def mutari(self, jucator_opus):
  130. l_mutari=[]
  131.  
  132. # TO DO..........
  133. # folosim:
  134. # matr_tabla_noua = list(self.matr)
  135. # .... "jucator_opus" (parametrul functiei) adauga o mutare in "matr_tabla_noua"
  136. # l_mutari.append(Joc(matr_tabla_noua))
  137.  
  138. config = self.matr
  139. print(config)
  140. # for i in range(self.NR_LINII):
  141. for j in range(self.NR_COLOANE):
  142. linie = 0
  143. # print(len(config))
  144. # print(linie * self.NR_COLOANE + j)
  145. # print('\n')
  146. while config[linie * self.NR_COLOANE + j] == '.' and linie < self.NR_LINII - 1:
  147. linie += 1
  148. if config[linie * self.NR_COLOANE + j] == '.':
  149. print((linie,j))
  150. print('\n')
  151. copie = [config[x] for x in range(len(config))]
  152. copie[linie * self.NR_COLOANE + j] = jucator_opus
  153. mutare = Joc(copie)
  154. l_mutari.append(mutare)
  155.  
  156. return l_mutari
  157.  
  158.  
  159. def nr_intervale_deschise(self, jucator):
  160. # un interval de 4 pozitii adiacente (pe linie, coloana, diag \ sau diag /)
  161. # este deschis pt "jucator" daca nu contine "juc_opus"
  162.  
  163. juc_opus = Joc.JMIN if jucator == Joc.JMAX else Joc.JMAX
  164. rez = 0
  165.  
  166. # linii
  167. for i in range(self.NR_LINII):
  168. for j in range(self.NR_COLOANE - 4):
  169. for k in range(4):
  170. if k == 0 and self.matr[i * self.NR_COLOANE + j + k] != jucator:
  171. break
  172. elif self.matr[i * self.NR_COLOANE + j + k] != jucator:
  173. break
  174. if k == 3:
  175. rez += 1
  176.  
  177. # coloane
  178.  
  179. for i in range(self.NR_LINII - 4):
  180. for j in range(self.NR_COLOANE):
  181. for k in range(4):
  182. if k == 0 and self.matr[(i + k) * self.NR_COLOANE + j] != jucator:
  183. break
  184. elif self.matr[(i + k) * self.NR_COLOANE + j] != jucator:
  185. break
  186. if k == 3:
  187. rez += 1
  188.  
  189. # diagonale \
  190.  
  191. for i in range(self.NR_LINII - 1, 2, -1):
  192. for j in range(self.NR_COLOANE - 1, 2, -1):
  193. for k in range(4):
  194. if k == 0 and self.matr[(i - k) * self.NR_COLOANE + j - k] != jucator:
  195. break
  196. elif self.matr[(i - k) * self.NR_COLOANE + j - k] != jucator:
  197. break
  198. if k == 3:
  199. rez += 1
  200.  
  201. # diagonale /
  202.  
  203. for i in range(self.NR_LINII - 4):
  204. for j in range(self.NR_COLOANE - 4):
  205. start = 0
  206. for k in range(4):
  207. if k == 0 and self.matr[(i + k) * self.NR_COLOANE + j + k] != jucator:
  208. break
  209. elif self.matr[(i + k) * self.NR_COLOANE + j + k] != jucator:
  210. break
  211. if k == 3:
  212. rez += 1
  213.  
  214. return rez
  215.  
  216.  
  217. def fct_euristica(self):
  218. # TO DO: alte variante de euristici? .....
  219.  
  220. # intervale_deschisa(juc) = cate intervale de 4 pozitii
  221. # (pe linii, coloane, diagonale) nu contin juc_opus
  222. return self.nr_intervale_deschise(Joc.JMAX) - self.nr_intervale_deschise(Joc.JMIN)
  223.  
  224.  
  225.  
  226. def estimeaza_scor(self, adancime):
  227. t_final = self.final()
  228. if t_final == Joc.JMAX :
  229. return (999+adancime)
  230. elif t_final == Joc.JMIN:
  231. return (-999-adancime)
  232. elif t_final == 'remiza':
  233. return 0
  234. else:
  235. return self.fct_euristica()
  236.  
  237.  
  238. def __str__(self):
  239. sir = ''
  240. for nr_col in range(self.NR_COLOANE):
  241. sir += str(nr_col) + ' '
  242. sir += '\n'
  243.  
  244. for lin in range(self.NR_LINII):
  245. k = lin * self.NR_COLOANE
  246. sir += (" ".join([str(x) for x in self.matr[k : k+self.NR_COLOANE]])+"\n")
  247. return sir
  248.  
  249.  
  250. class Stare:
  251. """
  252. Clasa folosita de algoritmii minimax si alpha-beta
  253. Are ca proprietate tabla de joc
  254. Functioneaza cu conditia ca in cadrul clasei Joc sa fie definiti JMIN si JMAX (cei doi jucatori posibili)
  255. De asemenea cere ca in clasa Joc sa fie definita si o metoda numita mutari() care ofera lista cu
  256. configuratiile posibile in urma mutarii unui jucator
  257. """
  258.  
  259. ADANCIME_MAX = None
  260.  
  261. def __init__(self, tabla_joc, j_curent, adancime, parinte=None, scor=None):
  262. self.tabla_joc = tabla_joc
  263. self.j_curent = j_curent
  264.  
  265. #adancimea in arborele de stari
  266. self.adancime=adancime
  267.  
  268. #scorul starii (daca e finala) sau al celei mai bune stari-fiice (pentru jucatorul curent)
  269. self.scor=scor
  270.  
  271. #lista de mutari posibile din starea curenta
  272. self.mutari_posibile=[]
  273.  
  274. #cea mai buna mutare din lista de mutari posibile pentru jucatorul curent
  275. self.stare_aleasa=None
  276.  
  277. def jucator_opus(self):
  278. if self.j_curent==Joc.JMIN:
  279. return Joc.JMAX
  280. else:
  281. return Joc.JMIN
  282.  
  283. def mutari(self):
  284. l_mutari=self.tabla_joc.mutari(self.j_curent)
  285. juc_opus=self.jucator_opus()
  286. l_stari_mutari=[Stare(mutare, juc_opus, self.adancime-1, parinte=self) for mutare in l_mutari]
  287.  
  288. return l_stari_mutari
  289.  
  290.  
  291. def __str__(self):
  292. sir= str(self.tabla_joc) + "(Juc curent: "+self.j_curent+")\n"
  293. return sir
  294.  
  295.  
  296.  
  297. """ Algoritmul MinMax """
  298.  
  299. def min_max(stare):
  300.  
  301. if stare.adancime==0 or stare.tabla_joc.final() :
  302. stare.scor=stare.tabla_joc.estimeaza_scor(stare.adancime)
  303. return stare
  304.  
  305. #calculez toate mutarile posibile din starea curenta
  306. stare.mutari_posibile=stare.mutari()
  307.  
  308. #aplic algoritmul minimax pe toate mutarile posibile (calculand astfel subarborii lor)
  309. mutari_scor=[min_max(mutare) for mutare in stare.mutari_posibile]
  310.  
  311. if stare.j_curent==Joc.JMAX :
  312. #daca jucatorul e JMAX aleg starea-fiica cu scorul maxim
  313. stare.stare_aleasa = max(mutari_scor, key=lambda x: x.scor)
  314. else:
  315. #daca jucatorul e JMIN aleg starea-fiica cu scorul minim
  316. stare.stare_aleasa = min(mutari_scor, key=lambda x: x.scor)
  317.  
  318. stare.scor=stare.stare_aleasa.scor
  319. return stare
  320.  
  321.  
  322.  
  323. def alpha_beta(alpha, beta, stare):
  324. if stare.adancime==0 or stare.tabla_joc.final() :
  325. stare.scor = stare.tabla_joc.estimeaza_scor(stare.adancime)
  326. return stare
  327.  
  328. if alpha >= beta:
  329. return stare #este intr-un interval invalid deci nu o mai procesez
  330.  
  331. stare.mutari_posibile = stare.mutari()
  332.  
  333. if stare.j_curent == Joc.JMAX :
  334. scor_curent = float('-inf')
  335.  
  336. for mutare in stare.mutari_posibile:
  337. #calculeaza scorul
  338. stare_noua = alpha_beta(alpha, beta, mutare)
  339.  
  340. if (scor_curent < stare_noua.scor):
  341. stare.stare_aleasa = stare_noua
  342. scor_curent = stare_noua.scor
  343. if(alpha < stare_noua.scor):
  344. alpha = stare_noua.scor
  345. if alpha >= beta:
  346. break
  347.  
  348. elif stare.j_curent == Joc.JMIN :
  349. scor_curent = float('inf')
  350.  
  351. for mutare in stare.mutari_posibile:
  352. stare_noua = alpha_beta(alpha, beta, mutare)
  353.  
  354. if (scor_curent > stare_noua.scor):
  355. stare.stare_aleasa = stare_noua
  356. scor_curent = stare_noua.scor
  357.  
  358. if(beta > stare_noua.scor):
  359. beta = stare_noua.scor
  360. if alpha >= beta:
  361. break
  362.  
  363. stare.scor = stare.stare_aleasa.scor
  364.  
  365. return stare
  366.  
  367.  
  368.  
  369. def afis_daca_final(stare_curenta):
  370. # ?? TO DO:
  371. # de adagat parametru "pozitie", ca sa nu verifice mereu toata tabla,
  372. # ci doar linia, coloana, 2 diagonale pt elementul nou, de pe "pozitie"
  373.  
  374. final = stare_curenta.tabla_joc.final()
  375. if(final):
  376. if (final=="remiza"):
  377. print("Remiza!")
  378. else:
  379. print("A castigat "+final)
  380.  
  381. return True
  382.  
  383. return False
  384.  
  385.  
  386.  
  387. def main():
  388. #initializare algoritm
  389. raspuns_valid=False
  390. while not raspuns_valid:
  391. tip_algoritm=input("Algorimul folosit? (raspundeti cu 1 sau 2)\n 1.Minimax\n 2.Alpha-beta\n ")
  392. if tip_algoritm in ['1','2']:
  393. raspuns_valid=True
  394. else:
  395. print("Nu ati ales o varianta corecta.")
  396.  
  397. # initializare ADANCIME_MAX
  398. raspuns_valid = False
  399. while not raspuns_valid:
  400. n = input("Adancime maxima a arborelui: ")
  401. if n.isdigit():
  402. Stare.ADANCIME_MAX = int(n)
  403. raspuns_valid = True
  404. else:
  405. print("Trebuie sa introduceti un numar natural nenul.")
  406.  
  407.  
  408. # initializare jucatori
  409. [s1, s2] = Joc.SIMBOLURI_JUC.copy() # lista de simboluri posibile
  410. raspuns_valid = False
  411. while not raspuns_valid:
  412. Joc.JMIN = str(input("Doriti sa jucati cu {} sau cu {}? ".format(s1, s2))).upper()
  413. if (Joc.JMIN in Joc.SIMBOLURI_JUC):
  414. raspuns_valid = True
  415. else:
  416. print("Raspunsul trebuie sa fie {} sau {}.".format(s1, s2))
  417. Joc.JMAX = s1 if Joc.JMIN == s2 else s2
  418.  
  419. #initializare tabla
  420. tabla_curenta = Joc()
  421. print("Tabla initiala")
  422. print(str(tabla_curenta))
  423.  
  424. #creare stare initiala
  425. stare_curenta = Stare(tabla_curenta, Joc.SIMBOLURI_JUC[0], Stare.ADANCIME_MAX)
  426.  
  427. linie = -1
  428. coloana = -1
  429. while True :
  430. if (stare_curenta.j_curent == Joc.JMIN):
  431. #muta jucatorul
  432. raspuns_valid=False
  433. while not raspuns_valid:
  434. try:
  435. coloana = int(input("coloana = "))
  436.  
  437. # TO DO......
  438. # de verificat daca "coloana" este in intervalul corect,
  439. # apoi de gasit pe ce "linie" este cea mai de jos
  440. # casuta goala de pe acea "coloana"
  441.  
  442. #if ........
  443. # ..........
  444.  
  445. #if ......
  446. # print("Toata coloana este ocupata.")
  447. #else:
  448. # print("Coloana invalida (trebuie sa fie un numar intre 0 si {}).".format(Joc.NR_COLOANE - 1))
  449. if coloana >= 0 and coloana < tabla_curenta.NR_COLOANE:
  450. for i in range(tabla_curenta.NR_LINII):
  451. if tabla_curenta.matr[i*tabla_curenta.NR_COLOANE + coloana] == '.':
  452. linie = i
  453. raspuns_valid = True
  454. if linie == -1:
  455. print("Toata coloana este ocupata.")
  456. else:
  457. print("Coloana invalida (trebuie sa fie un numar intre 0 si {}).".format(Joc.NR_COLOANE - 1))
  458.  
  459. except ValueError:
  460. print("Coloana trebuie sa fie un numar intreg.")
  461.  
  462. #dupa iesirea din while sigur am valida coloana
  463. #deci pot plasa simbolul pe "tabla de joc"
  464. print(linie)
  465. pozitie = (linie-1) * Joc.NR_COLOANE + coloana
  466. stare_curenta.tabla_joc.matr[pozitie] = Joc.JMIN
  467.  
  468. #afisarea starii jocului in urma mutarii utilizatorului
  469. print("\nTabla dupa mutarea jucatorului")
  470. print(str(stare_curenta))
  471.  
  472. #testez daca jocul a ajuns intr-o stare finala
  473. #si afisez un mesaj corespunzator in caz ca da
  474. if (afis_daca_final(stare_curenta)):
  475. break
  476.  
  477.  
  478. #S-a realizat o mutare. Schimb jucatorul cu cel opus
  479. stare_curenta.j_curent = stare_curenta.jucator_opus()
  480.  
  481. #--------------------------------
  482. else: #jucatorul e JMAX (calculatorul)
  483. #Mutare calculator
  484.  
  485. #preiau timpul in milisecunde de dinainte de mutare
  486. t_inainte=int(round(time.time() * 1000))
  487. if tip_algoritm=='1':
  488. stare_actualizata = min_max(stare_curenta)
  489. else: #tip_algoritm==2
  490. stare_actualizata = alpha_beta(-5000, 5000, stare_curenta)
  491. stare_curenta.tabla_joc = stare_actualizata.stare_aleasa.tabla_joc
  492. print("Tabla dupa mutarea calculatorului")
  493. print(str(stare_curenta))
  494.  
  495. #preiau timpul in milisecunde de dupa mutare
  496. t_dupa=int(round(time.time() * 1000))
  497. print("Calculatorul a \"gandit\" timp de "+str(t_dupa-t_inainte)+" milisecunde.")
  498.  
  499. if (afis_daca_final(stare_curenta)):
  500. break
  501.  
  502. #S-a realizat o mutare. Schimb jucatorul cu cel opus
  503. stare_curenta.j_curent = stare_curenta.jucator_opus()
  504.  
  505.  
  506. if __name__ == "__main__" :
  507. main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement