Jocul de X și 0 - TicTacToe - în Python și PySide - partea a III-a


 21 Oct, 2014  doru  730  
python pyside tic-tac-toe x-si-0

În această a treia parte a articolului despre "x și 0" am să prezint funcția principală a jocului - cea în care se decide fiecare mutare a calculatorului.

Fiecare mutare a calculatorului este declanșată de fiecare mutare a omului. Omul mută primul, când dă clic pe o celulă acest semnal este transmis funcției principale prin intermediul mecanismului semnal-slot (signal-slot) din PySide. Această conectare a semnalului cu slotul (de fapt funcția care trebuie să administreze/facă ceva cu acest semnal) se realizază într-o singură linie de cod:

#conectarea click-ului la functia principala
self.tabel.cellClicked.connect(self.functiaPrincipala)

Se vede că semnalul este de tipul cellClicked iar funcția care se ocupă de el este functiaPrincipala.

Întrucât functiaPrincipala este prea lungă am să o prezint pe bucăți, în funcție de a câta mutare este:

 #fct in care se deruleaza jocul in functie de nr de mutari facute de om   
def functiaPrincipala(self, a, b):
    self.tabel.item(a, b).setText("x")
    rowcolmutom = (a, b)
    self.mutariom.append(rowcolmutom)
    self.mutariramase.remove(rowcolmutom) 

În primul rând se vede că funcția principală primește două argumente - a, b: acestea sunt de fapt coordonatele (rândul și coloana) celulei în care a mutat omul. Apoi în acea celulă punem un "x"

self.tabel.item(a, b).setText("x")

, creăm un tuplu cu coordonatele mutării omului

rowcolmutom = (a, b)

, adăugăm acest tuplu la lista (de tupluri) cu mutările omului

self.mutariom.append(rowcolmutom)

și ștergem din lista cu mutări rămase mutarea omului

self.mutariramase.remove(rowcolmutom)

Aceste patru lucruri se execută de fiecare dată când omul mută.

Acum să vedem cum răspunde calculatorul.  În primul rând trebuie să știe despre a câta mutare e vorba și pentru a afla verifică la fiecare mutare a omului câte elemente (tupluri) conține lista cu mutările omului - mutariom : dacă conține un singur element - atunci e vorba de prima mutare, dacă conține două - de a doua ș.a.m.d până la cinci - cel care mută primul în "x și 0" poate face maxim cinci mutări. Numai primele patru din ele sunt importante pentru că cel care mută al doilea nu poate face decât patru mutări. Deci calculatorul verifică mai întâi despre a câta - din aceste prime patru - mutare a omului e vorba și face asta folosind un bloc condițional cu patru ramuri

if len(self.mutariom) == 1:
    .....
elif len(self.mutariom) == 2:
    ....
elif len(self.mutariom) == 3:
    ....
elif len(self.mutariom) == 4:
    ....

Acum să vedem în detaliu cum procedează calculatorul.

La prima mutare a omului calculatorul verifică dacă acesta a pus în centru: dacă a pus, atunci pune într-un colț (cel din stânga sus); dacă n-a pus, atunci pune el în centru

if len(self.mutariom) == 1:
    if self.mutariom[0] == (1,1):
        self.unu.setText("o")
        self.mutaricalc.append((0, 0))
        self.mutariramase.remove((0, 0))
    else:
        self.cinci.setText("o")
        self.mutariramase.remove((1, 1))
        self.mutaricalc.append((1, 1))

adică scrie "0" în celula respectivă

self.unu.setText("o")

, adaugă mutarea la lista cu mutările calculatorului

self.mutaricalc.append((0, 0))

și o șterge din lista cu mutări rămase

self.mutariramase.remove((0, 0))

Prima mutare a calculatorului este așadar ușor de făcut pentru că omul a mutat o singură dată, deci nu sunt încă posibile variante de câștig.

La mutarea a doua a omului calculatorul trebuie să verifice dacă acesta are vreo variantă imediată de câștig (la mutarea următoare) și să pună acolo. De asemenea trebuie să verifice dacă omul nu cumva folosește vreo încolțire (capcană) - pentru asta verifică mai întâi dacă calculatorul a pus în centru, dacă a pus atunci e posibilă o capcană și verifică dacă chiar acesta e cazul iar dacă nu e calculatorul pune într-unul din mijlocurile neocupate (mijlocuri numesc celulele care nu se află în colțuri exceptând de asemenea celula din centru tabelului). Dacă omul nu are nicio variantă de câștig la mutarea următoare și dacă calculatorul n-are pus în centru (deci nu e posibilă nicio încolțire - asta ține de felul cum am gândit eu jocul), atunci calculatorul pune în colțul din stânga jos (deși nu e cea mai bună mutare...)

elif len(self.mutariom) == 2:
    t = self.verVarianteWin(self.varianteWin, self.mutariom, self.mutariramase, self.mutaricalc)
    if t:
        #daca omul are vreo varianta de castig imediat calculatorul pune acolo
        self.tabel.item(t[0], t[1]).setText("o")
    else:
        #daca calc are pus in centru 
        if (1,1) in self.mutaricalc:
            i = self.verIncoltiri()
            #verifica daca e vorba de vreo incoltire...
            if i:
                self.tabel.item(i[0], i[1]).setText("o")
                self.mutaricalc.append((i[0], i[1]))
                self.mutariramase.remove(i)
            else:
                #daca nu e vorba de nicio incoltire pune intr-unul din mijlocurile ramase
                for i in self.mijlocuri:
                    if i not in self.mutariom and i in self.mutariramase:
                        self.tabel.item(i[0], i[1]).setText("o")
                        self.mutaricalc.append((i[0], i[1]))
                        self.mutariramase.remove((i[0], i[1]))
                        break
        #daca calc n-are pus in centru pune in coltul din stanga jos
        else:
            self.tabel.item(2, 0).setText("o")
            self.mutaricalc.append((2, 0))
            self.mutariramase.remove((2, 0))

Pentru a verifica dacă la mutarea următoare este vreo variantă de câștig am definit o funcție - verVarianteWin(), de asemenea am implementat o mică funcție pentru a verifica dacă este vorba de vreo încolțire din partea omului - verIncoltiri().

Se pare că articolul devine prea lung așa că am să termin expunerea despre partea de inteligență artificială (AI) a jocului în partea a IV-a. (Ro)cod beton!

P.S. Codul complet al jocului îl puteti descărca de pe GitHub, aici.

                                                                                                                                           Va urma