def vrednost_pozicije(self): """Ocena vrednosti pozicije: sešteje vrednosti vseh štiric na plošči.""" # Slovar, ki pove, koliko so vredne posamezne štirke, kjer "(x,y) : v" pomeni: # če imamo v stirici x znakov igralca in y znakov nasprotnika (in 4-x-y praznih polj), # potem je taka štirka za self.jaz vredna v. # Štirke, ki se ne pojavljajo v slovarju, so vredne 0. vrednost_stirice = { (4, 0): Minimax.ZMAGA, (0, 4): -Minimax.ZMAGA, (3, 0): Minimax.ZMAGA // 100, (0, 3): -Minimax.ZMAGA // 100, (2, 0): Minimax.ZMAGA // 10000, (0, 2): -Minimax.ZMAGA // 10000, (1, 0): Minimax.ZMAGA // 100000, (0, 1): -Minimax.ZMAGA // 100000 } vrednost = 0 for t in self.igra.stirice: x = 0 # Koliko jih imam jaz v štirici t y = 0 # Koliko jih ima nasprotnik v štirici t for (i, j) in t: if self.igra.stolpci[i][j] == self.jaz: x += 1 elif self.igra.stolpci[i][j] == nasprotnik(self.jaz): y += 1 vrednost += vrednost_stirice.get((x, y), 0) return vrednost
def vrednost_pozicije(self): """Ocena vrednosti pozicije: sešteje vrednosti vseh trojk na plošči.""" # Slovar, ki pove, koliko so vredne posamezne trojke, kjer "(x,y) : v" pomeni: # če imamo v trojki x znakov igralca in y znakov nasprotnika (in 3-x-y praznih polj), # potem je taka trojka za self.jaz vredna v. # Trojke, ki se ne pojavljajo v slovarju, so vredne 0. vrednost_trojke = { (4,0) : ZMAGA, (0,4) : -ZMAGA//10, (3,0) : ZMAGA//100, (0,3) : -ZMAGA//1000, (2,0) : ZMAGA//10000, (0,2) : -ZMAGA//100000, (1,0) : ZMAGA//1000000, (0,1) : -ZMAGA//10000000 } vrednost = 0 for t in self.igra.trojke: x = 0 y = 0 for (j,i) in t: if self.igra.polje[j][i] == self.jaz: x += 1 elif self.igra.polje[j][i] == nasprotnik(self.jaz): y += 1 vrednost += vrednost_trojke.get((x,y), 0) return vrednost
def minimax(self, globina, maksimiziramo, alfa = -NESKONCNO, beta = NESKONCNO): """Glavna metoda minimax.""" if self.prekinitev: # Sporočili so nam, da moramo prekiniti logging.debug ("Minimax prekinja, globina = {0}".format(globina)) return (None, 0) (zmagovalec, lst) = self.igra.stanje_igre() if zmagovalec in (IGRALEC_M, IGRALEC_R, NEODLOCENO): # Igre je konec, vrnemo njeno vrednost if zmagovalec == self.jaz: return (None, ZMAGA) elif zmagovalec == nasprotnik(self.jaz): return (None, -ZMAGA) else: return (None, 0) elif zmagovalec == NI_KONEC: # Igre ni konec if globina == 0: return (None, self.vrednost_pozicije()) else: # Naredimo eno stopnjo minimax if maksimiziramo: # Maksimiziramo najboljsa_poteza = None vrednost = -NESKONCNO #print(self.igra.veljavne_poteze()) for i, j in self.igra.veljavne_poteze()[::random.choice([1,-1])]: #######UPORABI PRAVO POLJE, DA BO VEDELO V KATERO VRSTICO POVLEČTI POTEZO!!!!####### self.igra.povleci_potezo(i) if vrednost < self.minimax(globina-1, not maksimiziramo, alfa, beta)[1]: najboljsa_poteza = (j, i) vrednost = self.minimax(globina-1, not maksimiziramo, alfa, beta)[1] self.igra.razveljavi() alfa = max(alfa, vrednost) if beta <= alfa: break else: # Minimiziramo najboljsa_poteza = None vrednost = NESKONCNO #print(self.igra.veljavne_poteze()) for i, j in self.igra.veljavne_poteze()[::random.choice([1,-1])]: self.igra.povleci_potezo(i) if vrednost > self.minimax(globina-1, maksimiziramo, alfa, beta)[1]: najboljsa_poteza = (j, i) vrednost = self.minimax(globina-1, maksimiziramo, alfa, beta)[1] self.igra.razveljavi() beta = min(beta, vrednost) if beta <= alfa: break assert (najboljsa_poteza is not None), "minimax: izračunana poteza je None" return (najboljsa_poteza, vrednost) else: assert False, "minimax: nedefinirano stanje igre"
def alfabeta(self, globina, alfa, beta, maksimiziramo): if self.prekinitev: logging.debug("Alfabeta prekinja, globina = {0}".format(globina)) return (None, 0) (zmagovalec, stirica) = self.igra.stanje_igre() if zmagovalec in (MODRI, RDECI, NEODLOCENO): # Igre je konec, vrnemo njeno vrednost if zmagovalec == self.jaz: return (None, Alfabeta.ZMAGA) elif zmagovalec == nasprotnik(self.jaz): return (None, -Alfabeta.ZMAGA) else: return (None, 0) elif zmagovalec == NI_KONEC: # Igre ni konec if globina == 0: return (None, self.vrednost_pozicije()) else: # Naredimo eno stopnjo alfabeta if maksimiziramo: # Maksimiziramo najboljsa_poteza = None veljavne_poteze = self.igra.veljavne_poteze() shuffle(veljavne_poteze) for p in veljavne_poteze: self.igra.povleci_potezo(p) vrednost = self.alfabeta(globina - 1, alfa, beta, not maksimiziramo)[1] self.igra.razveljavi() if vrednost > alfa: alfa = vrednost najboljsa_poteza = p if alfa >= beta: break return (najboljsa_poteza, alfa) else: # Minimiziramo najboljsa_poteza = None veljavne_poteze = self.igra.veljavne_poteze() shuffle(veljavne_poteze) for p in veljavne_poteze: self.igra.povleci_potezo(p) vrednost = self.alfabeta(globina - 1, alfa, beta, not maksimiziramo)[1] self.igra.razveljavi() if vrednost < beta: beta = vrednost najboljsa_poteza = p if alfa >= beta: break return (najboljsa_poteza, beta) assert (najboljsa_poteza is not None), "alfabeta: izračunana poteza je None" else: assert False, "alfabeta: nedefinirano stanje igre"
def minimax(self, globina, maksimiziramo): if self.prekinitev: logging.debug("Minimax prekinja, globina = {0}".format(globina)) return (None, 0) (zmagovalec, stirica) = self.igra.stanje_igre() if zmagovalec in (MODRI, RDECI, NEODLOCENO): # Igre je konec, vrnemo njeno vrednost if zmagovalec == self.jaz: return (None, Minimax.ZMAGA) elif zmagovalec == nasprotnik(self.jaz): return (None, -Minimax.ZMAGA) else: return (None, 0) elif zmagovalec == NI_KONEC: # Igre ni konec if globina == 0: return (None, self.vrednost_pozicije()) else: # Naredimo eno stopnjo minimax if maksimiziramo: # Maksimiziramo najboljsa_poteza = None vrednost_najboljse = -Minimax.NESKONCNO veljavne_poteze = self.igra.veljavne_poteze() # Veljavne poteze random premešamo, da ne bo računalnik v enaki sitauaciji vedno odigral enako shuffle(veljavne_poteze) for p in veljavne_poteze: self.igra.povleci_potezo(p) vrednost = self.minimax(globina - 1, not maksimiziramo)[1] self.igra.razveljavi() if vrednost > vrednost_najboljse: vrednost_najboljse = vrednost najboljsa_poteza = p else: # Minimiziramo najboljsa_poteza = None vrednost_najboljse = Minimax.NESKONCNO veljavne_poteze = self.igra.veljavne_poteze() # Veljavne poteze random premešamo, da ne bo računalnik v enaki sitauaciji vedno odigral enako shuffle(veljavne_poteze) for p in veljavne_poteze: self.igra.povleci_potezo(p) vrednost = self.minimax(globina - 1, not maksimiziramo)[1] self.igra.razveljavi() if vrednost < vrednost_najboljse: vrednost_najboljse = vrednost najboljsa_poteza = p assert (najboljsa_poteza is not None), "minimax: izračunana poteza je None" return (najboljsa_poteza, vrednost_najboljse) else: assert False, "minimax: nedefinirano stanje igre"
def neumna_cenilka(self): """Vsem potezam priredi enako vrednost, razen, če je konec igre.""" (konec_ali_ne, na_vrsti) = self.igra.trenutno_stanje() if konec_ali_ne == KONEC_IGRE: # Igre je konec, vrnemo njeno vrednost if na_vrsti == self.jaz: return ZMAGA elif na_vrsti == nasprotnik(self.jaz): return -ZMAGA elif na_vrsti is None: return -ZMAGA + 1 # remi else: return 3 # naključno izbrana vrednost, važno da je za vse enaka
def minimax(self, globina, maksimiziramo): '''Glavna metoda Minimax.''' if self.prekinitev: # Sporočili so nam, da moramo prekiniti return (None, 0) (zmagovalec, stirka) = self.igra.stanje_igre() if zmagovalec in (IGRALEC_R, IGRALEC_Y, NEODLOCENO): k = 1 - self.igra.stevilo_zetonov() / (2 * 6 * 7) # Igre je konec, vrnemo njeno vrednost if zmagovalec == self.jaz: return (None, Minimax.ZMAGA * k) elif zmagovalec == nasprotnik(self.jaz): return (None, -Minimax.ZMAGA * k) else: return (None, 0) elif zmagovalec == NI_KONEC: # Igre ni konec if globina == 0: return (None, self.vrednost_pozicije()) else: # Naredimo en korak minimax metode if maksimiziramo: # Maksimiziramo najboljsa_poteza = None sez_naj_potez = [] vrednost_najboljse = -Minimax.NESKONCNO for p in self.igra.veljavne_poteze(): self.igra.povleci_potezo(p) vrednost = self.minimax(globina - 1, not maksimiziramo)[1] self.igra.razveljavi() if vrednost > vrednost_najboljse: sez_naj_potez = [p] vrednost_najboljse = vrednost elif vrednost == vrednost_najboljse: sez_naj_potez.append(p) if len(sez_naj_potez) == 1: najboljsa_poteza = sez_naj_potez[0] elif len(sez_naj_potez) > 1: rand_st = int(random.random() * len(sez_naj_potez)) najboljsa_poteza = sez_naj_potez[rand_st] else: # Minimiziramo najboljsa_poteza = None sez_naj_potez = [] vrednost_najboljse = Minimax.NESKONCNO for p in self.igra.veljavne_poteze(): self.igra.povleci_potezo(p) vrednost = self.minimax(globina - 1, not maksimiziramo)[1] self.igra.razveljavi() if vrednost < vrednost_najboljse: sez_naj_potez = [p] vrednost_najboljse = vrednost elif vrednost == vrednost_najboljse: sez_naj_potez.append(p) if len(sez_naj_potez) == 1: najboljsa_poteza = sez_naj_potez[0] elif len(sez_naj_potez) > 1: rand_st = int(random.random() * len(sez_naj_potez)) najboljsa_poteza = sez_naj_potez[rand_st] assert (najboljsa_poteza is not None), 'minimax: izračunana poteza je None' return (najboljsa_poteza, vrednost_najboljse) else: assert False, 'minimax: nedefinirano stanje igre'
def alfabeta(self, globina, maksimiziramo, alfa=-NESKONCNO, beta=NESKONCNO): """Glavna metoda alfabeta.""" if self.prekinitev: # Sporočili so nam, da moramo prekiniti logging.debug("Alfabeta prekinja, globina = {0}".format(globina)) return None, 0 (konec_ali_ne, na_vrsti) = self.igra.trenutno_stanje() if konec_ali_ne == KONEC_IGRE: # Igre je konec, vrnemo njeno vrednost if na_vrsti == self.jaz: return None, ZMAGA elif na_vrsti == nasprotnik(self.jaz): return None, -ZMAGA elif na_vrsti is None: return None, -ZMAGA + 1 # remi else: assert False, 'stanje_igre vrne čudnega igralca, alfabeta' elif konec_ali_ne != KONEC_IGRE: # Igre ni konec if globina == -1: # v primeru, da imamo nastavljeno najlažjo težavnost # računalnik naredi en korak alfabeta z neumno cenilko: najboljsa_poteza = None vrednost_najboljse = -NESKONCNO for p in self.uredi_poteze(self.igra.mozne_poteze(), maksimiziramo): poteza = [self.igra.polozaj_zoge] + p self.igra.naredi_potezo(poteza) vrednost = self.neumna_cenilka() self.igra.razveljavi_potezo(poteza) if vrednost > vrednost_najboljse: vrednost_najboljse = vrednost najboljsa_poteza = poteza assert (najboljsa_poteza is not None), \ "alfabeta: izračunana poteza je None" return najboljsa_poteza, vrednost_najboljse elif globina == 0: # print("konec rekurzije, globina 0") return None, self.pametna_cenilka() else: # Naredimo eno stopnjo alfabeta if maksimiziramo: # Maksimiziramo najboljsa_poteza = None vrednost_najboljse = -NESKONCNO for p in self.uredi_poteze(self.igra.mozne_poteze(), maksimiziramo): poteza = [self.igra.polozaj_zoge] + p self.igra.naredi_potezo(poteza) vrednost = self.alfabeta( globina - 1, not maksimiziramo, alfa, beta)[1] self.igra.razveljavi_potezo(poteza) if vrednost > vrednost_najboljse: vrednost_najboljse = vrednost najboljsa_poteza = poteza alfa = max(alfa, vrednost_najboljse) if beta <= alfa: break else: # Minimiziramo najboljsa_poteza = None vrednost_najboljse = NESKONCNO for p in self.uredi_poteze(self.igra.mozne_poteze(), maksimiziramo): poteza = [self.igra.polozaj_zoge] + p self.igra.naredi_potezo(poteza) vrednost = self.alfabeta( globina - 1, not maksimiziramo, alfa, beta)[1] self.igra.razveljavi_potezo(poteza) if vrednost < vrednost_najboljse: vrednost_najboljse = vrednost najboljsa_poteza = poteza beta = min(beta, vrednost_najboljse) if beta <= alfa: break assert (najboljsa_poteza is not None), \ "alfabeta: izračunana poteza je None" return najboljsa_poteza, vrednost_najboljse else: assert False, "alfabeta: ni vrnil cele poteze, ampak korak"