def staticka_funkcija_procene(tabla: Tabla, potez: Potez, na_potezu): """Ovo je jednostavna staticka funkcija procene f,koja se računa kao 𝑓 = 𝑛 + 𝑚, gde je 𝑛 broj pločica odredišnog polja, a 𝑚 broj nivoa na koje se dodaje plocica poomnozen razlikom rastojanja sopstvenih i protivnickih igraca od tog polja. Da bi se ova funkcija izracunala pored stanja/table potreban mi je i potez koji dovodi to tog novog stanja kao i igrac koji je trenutno na potezu. :param tabla: Tabla/stanje za koju treba izracunati staticku funkciju procene :type tabla: Tabla :param potez: Potez koji je doveo to tog stanja :type potez: Potez :param na_potezu: Igrac za kojeg se racuna staticka funkcija procene :type na_potezu: int :return: Vrednost staticke funkcije procene :rtype: int """ if tabla.pobeda(na_potezu): return 100 if tabla.poraz(na_potezu): return -100 # kupolu postavlja samo kada bas mora, postavljanje kupole se racuna kao -50 if tabla.matrica[potez.xg][potez.yg].broj_spratova == 4: return -50 n = tabla.matrica[potez.x2][potez.y2].broj_spratova rastojanja = 0 for i in range(5): for j in range(5): if tabla.matrica[i][j].igrac == na_potezu: rastojanja += tabla.rastojanje(i, j, potez.xg, potez.yg) elif tabla.matrica[i][j].igrac != na_potezu and tabla.matrica[i][j].igrac != Igrac.NIJEDAN: # ako je protivnik rastojanja -= tabla.rastojanje(i, j, potez.xg, potez.yg) m = tabla.matrica[potez.xg][potez.yg].broj_spratova * rastojanja return n + m
def nova_staticka_funkcija_procene(tabla: Tabla, potez: Potez, na_potezu): """Staticka funkcija procene stanja igre koja se racuna kao algebarski zbir visina figura na kvadrat. f = moja_figura1.broj_spratova^2 + moja_figura2.broj_spratova^2 - protivnikova_figura1.broj_spratova^2 - protivnikova_figura2.broj_spratova^2 :param tabla: Tabla/stanje za koju treba izracunati staticku funkciju procene :type tabla: Tabla :param potez: Potez koji je doveo to tog stanja :type potez: Potez :param na_potezu: Igrac za kojeg se racuna staticka funkcija procene :type na_potezu: int :return: Vrednost staticke funkcije procene :rtype: int """ if tabla.pobeda(na_potezu): return 100 if tabla.poraz(na_potezu): return -100 suma_visina = 0 for i in range(5): for j in range(5): if tabla.matrica[i][j].igrac == na_potezu: suma_visina += tabla.matrica[i][j].broj_spratova**2 elif tabla.matrica[i][j].igrac != na_potezu and tabla.matrica[i][j].igrac != Igrac.NIJEDAN: # ako je protivnik suma_visina -= tabla.matrica[i][j].broj_spratova**2 return suma_visina
def sledeci_potez(self, tabla, igrac, dubina): """Igra poziva ovu funkcija, prosledjuje joj stanje i igraca a ova funkija vraca sledeci potez. Ovde se koriti obicni minimax algoritam za nalazenje najboljeg poteza. Ovo je abstraktna funkcija tako da je moraju implementirati sve klase koje nasledjuju AI. :param tabla: Tabla za koju treba naci sledeci potez :type tabla: Tabla :param na_potezu: Igrac koji je na potezu i za kojeg treba naci sledeci potez :type na_potezu: int :param dubina: Dubina za koju treba izvrsiti pretrazivanje stabla :type dubina: int """ self.dubina = dubina svi_potezi = svi_moguci_potezi(tabla, igrac) vrednosti = [] # nadji vrednosti svih mogucih poteza for p in svi_potezi: nova_tabla = Tabla(tabla) nova_tabla.izvrsi_potez(p) vrednosti.append(self.minimax(nova_tabla, self.dubina - 1, igrac, False, p)) # stampaj vrednosti svih poteza ako treba if self.stampaj_vrednosti_svih_poteza: print(f"\n\n\nNa potezu je {igrac}, koristi se algoritam MiniMax NOVI NOVI i vrednsti svih mogucih poteza su:") for i in range(len(svi_potezi)): print(svi_potezi[i], vrednosti[i]) # nadji najbolji potez i vrati ga index_maximuma = vrednosti.index(max(vrednosti)) return svi_potezi[index_maximuma]
def analizarDatos(anterior, actual): datos = Tabla(anterior, actual) tablaTranspuesta = datos.unirTablasXmes() nombre = 'MonthlyReport' reporte = Reporte(tablaTranspuesta, nombre) reporte.analizeReport() print('Reporte OK!')
def optimizovana_nova_staticka_funkcija_procene_sa_rastojanjem(tabla: Tabla, potez: Potez, na_potezu): """Radi slicno kao funkcija iznad samo je malo optimizovana, brza je 40% Staticka funkcija procene stanja igre koja se racuna kao algebarski zbir visina figura na kvadrat. f = moja_figura1.broj_spratova^2 + moja_figura2.broj_spratova^2 - protivnikova_figura1.broj_spratova^2 - protivnikova_figura2.broj_spratova^2 + visina polja na kojem se gradi - kazna kod ove staticke funkcije procene kaznjava se preveliko rastojanje od protivnickih figura, tako se AI vise priblizava protivnickim figurama, nema vise izolovanja i gradnje u cosku da bi se pobedio AI :param tabla: Tabla/stanje za koju treba izracunati staticku funkciju procene :type tabla: Tabla :param potez: Potez koji je doveo to tog stanja :type potez: Potez :param na_potezu: Igrac za kojeg se racuna staticka funkcija procene :type na_potezu: int :return: Vrednost staticke funkcije procene :rtype: int """ if not tabla.ima_mogucih_poteza(na_potezu): return -100 elif not tabla.ima_mogucih_poteza(protivnik(na_potezu)): return 100 elif tabla.matrica[potez.xg][potez.yg].broj_spratova == 4: return -50 # nepotrebno postavljanje kupole se boduje sa -50 else: suma_visina = 0 brojac_figura = 0 # zbog ovoga imam 20% ubrzanje, jer prekidam petlje kad nadjem 4 figure nasi, njihovi = [], [] # pamtim pozicije mojih i protivnickih figura kazna = 0 for i in range(5): for j in range(5): if brojac_figura == 4: return suma_visina if tabla.matrica[i][j].igrac != Igrac.NIJEDAN: brojac_figura += 1 if tabla.matrica[i][j].igrac == na_potezu: if tabla.matrica[i][j].broj_spratova == 3: return 100 suma_visina += tabla.matrica[i][j].broj_spratova**2 nasi.append((i, j)) elif tabla.matrica[i][j].igrac != na_potezu: # protivnik if tabla.matrica[i][j].broj_spratova == 3: return -100 suma_visina -= tabla.matrica[i][j].broj_spratova**2 njihovi.append((i, j)) #preveliko rastojanje se kaznjava for nas in nasi: for njihov in njihovi: if tabla.rastojanje(nas[0], nas[1], njihov[0], njihov[1]) > 2: kazna += 2 # 2 sam lupio return suma_visina + tabla.matrica[potez.xg][potez.yg].broj_spratova - kazna
def __init__(self, parent, igrac1, igrac2, naziv_fajla, stampaj_vrednosti_svih_poteza, crtaj_svaki_korak=True): """Konstruktor klase IgraCanvas, inicijalizuje potrebne atribute. :param parent: Roditeljski widget u kojem se crta IgraCanvas :type parent: Widget :param igrac1: Tip prvog igraca :type igrac1: str :param igrac2: Tip drugog igraca :type igrac2: str :param naziv_fajla: Putanja do falja iz kojeg se citaju potezi ili u kojem se upisuju potezi :type naziv_fajla: str :param stampaj_vrednosti_svih_poteza: Da li treba stampati vrednosti svih mogucih poteza za AI :type stampaj_vrednosti_svih_poteza: bool :param crtaj_svaki_korak: Kad igraju AI vs AI da li treba prikazivati svaki potez ili samo rezultat njihovog meca, defaults to True :type crtaj_svaki_korak: bool, optional """ Canvas.__init__(self, parent) self.config(width=500, height=550) self.bind("<Button-1>", self.mouse_click) self.crtaj_svaki_korak = crtaj_svaki_korak # postavljanje tip igraca koji su prosledjeni kao parametri self.plavi_AI = self.odaberi_AI(igrac1, stampaj_vrednosti_svih_poteza) self.crveni_AI = self.odaberi_AI(igrac2, stampaj_vrednosti_svih_poteza) # inicijalizacije matrice self.tabla = Tabla() self.na_potezu = None # da napisem dobar komentar za ovo self.game_state = GameState.POSTAVLJANJE_FIGURA # u pocetku svi igraci postavljaju svoje figure na tablu self.broj_figura = 0 # treba mi za prvu fazu gde se postavljaju figure self.selektovana_figura = (-2, -2) # otvaranje fajla, citanje i izvrsavanje poteza ako ih ima u njemu self.procitaj_fajl_i_popuni_tabelu(naziv_fajla) # otvaranje fajla za pisanje sad, svaki put kad se izvrsi neki potez on se upisuje u fajl self.f = open(naziv_fajla, "a") self.crtaj() self.zameni_igraca()
def minimax(self, tabla, dubina, igrac, maximizing_player, potez): """Rekurzivna funkcija koja racuna (samo) vrednost koju ce minimax algoritam vratiti za prosledjenu tabelu/stanje. Ovaj algoritam je uradjen po ugledu na psudo kod minimax algoritma sa moodle-a. :param tabla: Tabla nad kojom treba izvrsavati poteze ili za koju treba racunati staticku funkciju procene :type tabla: Tabla :param dubina: Dubina razvijanja stabla :type dubina: int :param igrac: Igrac za kojeg se racuna staticka funkcija procene :type igrac: int :param maximizing_player: Da li treba uzimati max ili min vrednost od potomaka :type maximizing_player: bool :param potez: Potez koji je doveo do ovog stanja :type potez: Potez :return: Vrednost koji ce minimimax algoritam nadji za stablo koje nastaje iz prosledjene table :rtype: int """ # ako ne treba dalje razvijati stablo vracamo staticku funkciju procene if dubina == 0: return self.funkcija_procene(tabla, potez, igrac) # pronalazimo sve moguce poteze iz ovog stanja u zavisnosti od toga koji igrac je sada na potezu if maximizing_player: svi_potezi = svi_moguci_potezi(tabla, igrac) else: svi_potezi = svi_moguci_potezi(tabla, protivnik(igrac)) # ako nema mogucih poteza vrati vrednost tog cvora vracamo staticku funkciju procene if len(svi_potezi) == 0: return self.funkcija_procene(tabla, potez, igrac) else: # inace nadji vrednosti svih mogucih poteza iz ovog stanja vrednosti = [] for p in svi_potezi: nova_tabla = Tabla(tabla) nova_tabla.izvrsi_potez(p) vrednosti.append(self.minimax(nova_tabla, dubina - 1, igrac, not maximizing_player, p)) # nalazimo minimalnu ili maksimalu vrednost medju potomcima cvora i postavljamo je za vrednost tog cvora if maximizing_player: return max(vrednosti) else: return min(vrednosti)
def max_value(self, tabla, dubina, potez, alfa, beta): """Vraca maksimalnu vrednost podstabla uz upotrebu minimax algoritma sa alfa beta odsecanjem. :param tabla: Trenutna tabla/stanje igre, raspored figura i spratova :type tabla: Tabla :param dubina: Dubina do koje treba pretraziti stablo :type dubina: int :param potez: Potez koji je doveo do ove table/stanja :type potez: Potez :param alfa: Vrednost najboljeg izbora koji smo pronasli do sada tokom putanje za MAX :type alfa: int :param beta: Vrednost najboljeg izbofa (ovde je to najmanja vrednost) koju smo pronali do sada tokom putanja za MIN :type beta: int :return: Vraca maksimalu vrednost podstabla uz uptrebu minimax algoritma sa alfa beta odsecanjem :rtype: int """ if dubina == 0: return self.funkcija_procene(tabla, potez, self.na_potezu) v = -1000 svi_potezi = svi_moguci_potezi(tabla, self.na_potezu) # ako nema mogucih poteza vrati vrednost tog cvora if len(svi_potezi) == 0: return self.funkcija_procene(tabla, potez, self.na_potezu) else: for p in svi_potezi: nova_tabla = Tabla(tabla) nova_tabla.izvrsi_potez(p) nova_vrednost = self.min_value(nova_tabla, dubina - 1, p, alfa, beta) # sad upisujem sve poteze u self.lista_poteza da bih na kraju znao koji da uzmem if dubina == self.dubina: self.lista_poteza_i_njihovih_vrednosti.append((nova_vrednost, p)) v = max(v, nova_vrednost) if v >= beta: return v alfa = max(alfa, v) return v
def optimizovana_nova_staticka_funkcija_procene(tabla: Tabla, potez: Potez, na_potezu): """Radi slicno kao funkcija iznad samo je malo optimizovana, brza je 40% Staticka funkcija procene stanja igre koja se racuna kao algebarski zbir visina figura na kvadrat. f = moja_figura1.broj_spratova^2 + moja_figura2.broj_spratova^2 - protivnikova_figura1.broj_spratova^2 - protivnikova_figura2.broj_spratova^2 + visina polja na kojem se gradi :param tabla: Tabla/stanje za koju treba izracunati staticku funkciju procene :type tabla: Tabla :param potez: Potez koji je doveo to tog stanja :type potez: Potez :param na_potezu: Igrac za kojeg se racuna staticka funkcija procene :type na_potezu: int :return: Vrednost staticke funkcije procene :rtype: int """ if not tabla.ima_mogucih_poteza(na_potezu): return -100 elif not tabla.ima_mogucih_poteza(protivnik(na_potezu)): return 100 elif tabla.matrica[potez.xg][potez.yg].broj_spratova == 4: return -50 # nepotrebno postavljanje kupole se boduje sa -50 else: suma_visina = 0 brojac_figura = 0 # zbog ovoga imam 20% ubrzanje, jer prekidam petlje kad nadjem 4 figure for i in range(5): for j in range(5): if brojac_figura == 4: return suma_visina if tabla.matrica[i][j].igrac != Igrac.NIJEDAN: brojac_figura += 1 if tabla.matrica[i][j].igrac == na_potezu: if tabla.matrica[i][j].broj_spratova == 3: return 100 suma_visina += tabla.matrica[i][j].broj_spratova**2 elif tabla.matrica[i][j].igrac != na_potezu: # protivnik if tabla.matrica[i][j].broj_spratova == 3: return -100 suma_visina -= tabla.matrica[i][j].broj_spratova**2 return suma_visina + tabla.matrica[potez.xg][potez.yg].broj_spratova
def unapredjena_staticka_funkcija_procene(tabla: Tabla, potez: Potez, na_potezu): """Ovo je unapredjena staticka funkcija procene f,koja se računa kao 𝑓 = 3 * 𝑛 + 𝑚 + suma_visina + 5 * razlika_u_visini, gde je 𝑛 broj pločica odredišnog polja, a 𝑚 broj nivoa na koje se dodaje plocica poomnozen razlikom rastojanja sopstvenih i protivnickih igraca od tog polja, suma_visina je zbir visina spostvenih figura umanjen za zbir visina protivnickih figura,razlika_u_visini je razlika u visini izmedju prethodne i sadasnje pozicije figure koja se krece. Da bi se ova funkcija izracunala pored stanja/table potreban mi je i potez koji dovodi to tog novog stanja kao i igrac koji je trenutno na potezu. :param tabla: Tabla/stanje za koju treba izracunati staticku funkciju procene :type tabla: Tabla :param potez: Potez koji je doveo to tog stanja :type potez: Potez :param na_potezu: Igrac za kojeg se racuna staticka funkcija procene :type na_potezu: int :return: Vrednost staticke funkcije procene :rtype: int """ if tabla.pobeda(na_potezu): return 100 if tabla.poraz(na_potezu): return -100 # kupolu postavlja samo kada bas mora if tabla.matrica[potez.xg][potez.yg].broj_spratova == 4: return -50 n = tabla.matrica[potez.x2][potez.y2].broj_spratova rastojanja = 0 suma_visina = 0 for i in range(5): for j in range(5): if tabla.matrica[i][j].igrac == na_potezu: rastojanja += tabla.rastojanje(i, j, potez.xg, potez.yg)**2 suma_visina += tabla.matrica[i][j].broj_spratova**2 elif tabla.matrica[i][j].igrac != na_potezu and tabla.matrica[i][j].igrac != Igrac.NIJEDAN: # ako je protivnik rastojanja -= tabla.rastojanje(i, j, potez.xg, potez.yg)**2 suma_visina -= tabla.matrica[i][j].broj_spratova**2 m = tabla.matrica[potez.xg][potez.yg].broj_spratova * rastojanja razlika_u_visini = tabla.matrica[potez.x2][potez.y2].broj_spratova - tabla.matrica[potez.x1][potez.y1].broj_spratova return 3 * n + m + suma_visina + 5 * razlika_u_visini
def min_value(self, tabla, dubina, potez, alfa, beta): """Vraca minimalnu vrednost podstabla uz upotrebu minimax algoritma sa alfa beta odsecanjem. :param tabla: Trenutna tabla/stanje igre, raspored figura i spratova :type tabla: Tabla :param dubina: Dubina do koje treba pretraziti stablo :type dubina: int :param potez: Potez koji je doveo do ove table/stanja :type potez: Potez :param alfa: Vrednost najboljeg izbora koji smo pronasli do sada tokom putanje za MAX :type alfa: int :param beta: Vrednost najboljeg izbofa (ovde je to najmanja vrednost) koju smo pronali do sada tokom putanja za MIN :type beta: int :return: Vraca minimalnu vrednost podstabla uz uptrebu minimax algoritma sa alfa beta odsecanjem :rtype: int """ if dubina == 0: return self.funkcija_procene(tabla, potez, self.na_potezu) v = 1000 svi_potezi = svi_moguci_potezi(tabla, protivnik(self.na_potezu)) # ako nema mogucih poteza vrati vrednost tog cvora if len(svi_potezi) == 0: return self.funkcija_procene(tabla, potez, self.na_potezu) else: for p in svi_potezi: nova_tabla = Tabla(tabla) nova_tabla.izvrsi_potez(p) nova_vrednost = self.max_value(nova_tabla, dubina - 1, p, alfa, beta) v = min(v, nova_vrednost) if v <= alfa: return v beta = min(beta, v) return v
from analex import AnalizadorLexico # Código de usuario # # Módulos: # import generador import REParser import code from gramatica import * from tabla import Tabla from errores import errores, avisos # # Variables globales: # T = Tabla() # Tabla de símbolos directos = set() # Terminales directos encontrados enparentesis = False # Cierto si estamos dentro de paréntesis _nombre = { "abre": u"un paréntesis abierto", "accion": u"una acción semántica", "asterisco": "un asterisco", "barra": "una barra", "cierra": u"un paréntesis cerrado", "codigo": u"un segmento de código", "cruz": "una cruz", "errordos": "un tratamiento de error", "especificacion_lexica": u"una especificación léxica", "flecha": "una flecha", "interrogante": "un interrogante", "mc_EOF": "el fin de fichero",
RED = (255, 0, 0) BLACK = (0, 0, 0) light = (170, 170, 170) dark = (100, 100, 100) yellow = (252, 247, 135) size = (800, 800) screen_width = 800 screen_height = 800 screen = pygame.display.set_mode(size) clock = pygame.time.Clock() pygame.display.set_caption("Checkers") done = False QED = False GUI = True komp = False tabla = Tabla() font1 = pygame.font.SysFont('Corbel', 70) tabla.drawBoard(screen) font2 = None text3 = None DEPTH = 4 def btton(screen, x, y, text, color): pygame.draw.rect(screen, color, [x, y, 400, 100]) text_rect = text.get_rect(center=(screen_width // 2, y + 50)) screen.blit(text, text_rect) class main: while not done:
class IgraCanvas(Canvas): """Klasa ciji je zadatak da crta Tablu, da vodi racuna o GameStatu, trenutnom igracu, dozvoljenim potezima i AI. Prima inpute od korisnika i izvrsava odgovarajuce akcije.""" def __init__(self, parent, igrac1, igrac2, naziv_fajla, stampaj_vrednosti_svih_poteza, crtaj_svaki_korak=True): """Konstruktor klase IgraCanvas, inicijalizuje potrebne atribute. :param parent: Roditeljski widget u kojem se crta IgraCanvas :type parent: Widget :param igrac1: Tip prvog igraca :type igrac1: str :param igrac2: Tip drugog igraca :type igrac2: str :param naziv_fajla: Putanja do falja iz kojeg se citaju potezi ili u kojem se upisuju potezi :type naziv_fajla: str :param stampaj_vrednosti_svih_poteza: Da li treba stampati vrednosti svih mogucih poteza za AI :type stampaj_vrednosti_svih_poteza: bool :param crtaj_svaki_korak: Kad igraju AI vs AI da li treba prikazivati svaki potez ili samo rezultat njihovog meca, defaults to True :type crtaj_svaki_korak: bool, optional """ Canvas.__init__(self, parent) self.config(width=500, height=550) self.bind("<Button-1>", self.mouse_click) self.crtaj_svaki_korak = crtaj_svaki_korak # postavljanje tip igraca koji su prosledjeni kao parametri self.plavi_AI = self.odaberi_AI(igrac1, stampaj_vrednosti_svih_poteza) self.crveni_AI = self.odaberi_AI(igrac2, stampaj_vrednosti_svih_poteza) # inicijalizacije matrice self.tabla = Tabla() self.na_potezu = None # da napisem dobar komentar za ovo self.game_state = GameState.POSTAVLJANJE_FIGURA # u pocetku svi igraci postavljaju svoje figure na tablu self.broj_figura = 0 # treba mi za prvu fazu gde se postavljaju figure self.selektovana_figura = (-2, -2) # otvaranje fajla, citanje i izvrsavanje poteza ako ih ima u njemu self.procitaj_fajl_i_popuni_tabelu(naziv_fajla) # otvaranje fajla za pisanje sad, svaki put kad se izvrsi neki potez on se upisuje u fajl self.f = open(naziv_fajla, "a") self.crtaj() self.zameni_igraca() def procitaj_fajl_i_popuni_tabelu(self, naziv_fajla): """Funkcija koda otvara fajl, cita njegov sadrzaj, parsuje naredbe/poteze u tom fajlu i izvrsava ih nad trenutnom tablom. :param naziv_fajla: Putanja do fajla :type naziv_fajla: str """ # otvaranje fajla self.f = open(naziv_fajla, "r") lines = self.f.readlines() for i in range(len(lines)): # prva dva reda su za postavljanje figura if i < 2: line = lines[i].strip().split(" ") for l in line: x, y = Potez.string_u_koordinate(l) self.tabla.postavi_figuru(x, y, i) # ostalo su obicni potezi else: potez = Potez.iz_stringa(lines[i]) self.tabla.izvrsi_potez(potez) # ako txt fajl ima vise od dva reda onda to znaci da su figure postavljenje i # moze da se predje na sledecu fazu igre SELEKTOVANJE_FIGURE if len(lines) > 0: self.game_state = GameState.SELEKTOVANJE_FIGURE # broj linija takodje odredjuje ko je sad na potezu # paran broj poteza znaci da je sad na potezu plavi, a neparan znaci da je crveni if len(lines) % 2 == 0: self.na_potezu = Igrac.PLAVI else: self.na_potezu = Igrac.CRVENI # i to se sve jos jednom zameni jer se ispod poziva funkcija zameni_igraca() koja menja igraca i zapocinje igru self.na_potezu = protivnik(self.na_potezu) self.f.close() def odaberi_AI(self, tip_igraca, stampaj_vrednosti_svih_poteza): """Funkcija koja bira odgovarajuci tip AI-ja u zavisnosti od tipa igraca, instancira objekat odgovarajuce klase sa atributom za stampanje svih koraka, dubinom i odabranom statickom funkcijom procene i vraca taj objekat :param tip_igraca: Tip igraca na osnovu kojeg se bira AI ili se ostavlja Osoba :type tip_igraca: str :param stampaj_vrednosti_svih_poteza: Da li treba stampati vrednosti svih mogucih koraka AI-ja :type stampaj_vrednosti_svih_poteza: bool :return: Objekat odgovarajuce klase AI-ja :rtype: AI """ if tip_igraca == TIPOVI_IGRACA[0]: # Osoba return None elif tip_igraca == TIPOVI_IGRACA[1]: # AI easy return MiniMax(stampaj_vrednosti_svih_poteza, 5, staticka_funkcija_procene) elif tip_igraca == TIPOVI_IGRACA[2]: # AI medium return MiniMaxAlfaBeta(stampaj_vrednosti_svih_poteza, 7, staticka_funkcija_procene) elif tip_igraca == TIPOVI_IGRACA[3]: # AI hard return MiniMaxAlfaBeta( stampaj_vrednosti_svih_poteza, 20, optimizovana_nova_staticka_funkcija_procene_sa_rastojanjem) def crtaj(self): """Funkcija koja crta stanje table na Canvas-u uzimajuci u obzir i dozvoljena polja koja se crtaju zelenom bojom, i selektovanu figuru cije polje ima zutu boju pozadine.""" self.delete("all") for i in range(0, 5): for j in range(0, 5): # izracunaj koordinate tog polja x1 = i * 100 y1 = j * 100 + 50 # nacrtaj pozadinu # ako je to polje na kojem se nalazi selektovana figura onda oboji zutom bojom if self.selektovana_figura == (i, j): boja = "yellow" # ako je to polje dozvoljeno u sledecem potezu onda zelenom bojom elif (i, j) in self.tabla.pronadji_dozvoljena_polja( self.game_state, self.selektovana_figura[0], self.selektovana_figura[1], self.na_potezu): boja = "green" # ako nije nista od toga onda siva boja else: boja = "grey" self.create_rectangle(x1 + 2, y1 + 2, x1 + 98, y1 + 98, fill=boja) # nacrtaj spratove, spratovi se crtaju kao "koncentricni" kvadrati sve manjih dimenzija stepen = self.tabla.matrica[i][j].broj_spratova if stepen >= 1: self.create_rectangle(x1 + 8, y1 + 8, x1 + 92, y1 + 92, width=3) if stepen >= 2: self.create_rectangle(x1 + 15, y1 + 15, x1 + 85, y1 + 85, width=3) if stepen >= 3: self.create_rectangle(x1 + 25, y1 + 25, x1 + 75, y1 + 75, width=3) if stepen >= 4: self.create_oval(x1 + 30, y1 + 30, x1 + 70, y1 + 70, fill="black") # nacrtaj igraca if self.tabla.matrica[i][ j].igrac == Igrac.PLAVI: # 1 znaci plavi igrac self.create_oval(x1 + 30, y1 + 30, x1 + 70, y1 + 70, fill="blue") elif self.tabla.matrica[i][ j].igrac == Igrac.CRVENI: # 2 znaci crveni igrac self.create_oval(x1 + 30, y1 + 30, x1 + 70, y1 + 70, fill="red") self.create_text(250, 25, text=self.sastavi_poruku(), font="Airal 12") self.update_idletasks() def mouse_click(self, e): """Funkcija koja upravlja inputom korisnika, prima x i y koordinate mouse click eventa, praracunava ih u polje table i izvrsava neku akciju (pomeranje, gradnja...) ako je ona moguca. :param e: Mouse click event :type e: idk """ # print(e.x, e.y) # koordinate piksela na koji je klikuo mis u ovom canvasu # ako je kliknuo vam table ili je kraj meca if e.y < 50 or self.game_state == GameState.KRAJ_IGRE: return # preracunavanje tih kooridnata u indekse polja tabele x = int(e.x / 100) y = int((e.y - 50) / 100) #print(f"Polje koje je pritisnuto je: {x}, {y}") # nalazenje svih dozvoljenih polja dozvoljena_polja = self.tabla.pronadji_dozvoljena_polja( self.game_state, self.selektovana_figura[0], self.selektovana_figura[1], self.na_potezu) #print("Dozvoljena polja: ", dozvoljena_polja) # ako pritisnuto polje ne pripada dozvoljenim poljima onda se prikazuje greska i zavrsava ova funkcija if (x, y) not in dozvoljena_polja: print("Neispravan potez!") return # u zavisnosti od gamestate-a vrse se razlicite akcije, postavlje figure, pomeranje, gradnja if self.game_state == GameState.POSTAVLJANJE_FIGURA: self.tabla.postavi_figuru(x, y, self.na_potezu) self.f.write(Potez.koordinate_u_string(x, y) + " ") self.broj_figura += 1 if self.broj_figura == 2: self.f.write("\n") self.zameni_igraca() elif self.broj_figura == 4: self.game_state = GameState.SELEKTOVANJE_FIGURE #self.f.write("\n") self.zameni_igraca() print("Sad pocinje prava igra") elif self.game_state == GameState.SELEKTOVANJE_FIGURE: self.selektuj_figuru(x, y) self.game_state = GameState.POMERANJE_FIGURE elif self.game_state == GameState.POMERANJE_FIGURE: # ako klikne na istu figuru ili na svoju drugu figuru if self.tabla.matrica[x][y].igrac == self.na_potezu: self.selektuj_figuru(x, y) else: x1, y1 = self.selektovana_figura self.tabla.pomeri_figuru(x1, y1, x, y) self.trenutni_potez_osobe = Potez(x1, y1, x, y, 0, 0) self.selektovana_figura = (x, y) self.game_state = GameState.GRADNJA elif self.game_state == GameState.GRADNJA: self.tabla.gradi(x, y) self.trenutni_potez_osobe.xg = x self.trenutni_potez_osobe.yg = y self.f.write( "\n" + str(self.trenutni_potez_osobe)) # zapisi ovaj potez u fajlu self.game_state = GameState.SELEKTOVANJE_FIGURE self.after(1, self.zameni_igraca) self.crtaj() self.da_li_je_kraj() def selektuj_figuru(self, x, y): """Postavlja koordinate selektovane figure na x i y :param x: x koordinata selektovane figure :type x: int :param y: y koordinata selektovane figure :type y: int """ self.selektovana_figura = (x, y) def AI_je_na_potezu(self): """Proverava da li je AI na potezu :return: True ako je AI na potezu, inace false :rtype: bool """ return (self.na_potezu == Igrac.PLAVI and self.plavi_AI != None) or (self.na_potezu == Igrac.CRVENI and self.crveni_AI != None) def AI_izvrsi_potez(self, pravi_pauzu: bool): """Funkcija koja poziva AI koji je trenutno na potezu, prosledjuje mu trenutno stanje table i dobija novi potez Taj potez onda izvrsava nad tablom i to crta. Ova funkcija moze da pravi pauzu da potezi AI ne bi bili previse brzi :param pravi_pauzu: Da li treba praviti pauzu za potez AI da se on ne bi previse brzo izvrsio :type pravi_pauzu: bool """ if self.game_state == GameState.KRAJ_IGRE: return # minimalno trajanje poteza AI, da se ne bi momentalno izvrsio potez, potez moze da traje i duze ako treba DOZVOLJENO_VREME = 1 # koliko vremena AI moze da trazi potez pocetak = time.time() # AI odredi sledeci potez ai = None potez = None dubina = 2 # dubina od koje pocinje iterativno produbljivanje if self.na_potezu == Igrac.PLAVI: ai = self.plavi_AI else: ai = self.crveni_AI #sve dok ima vremena i dubina nije presla max_dubinu tog ai-ja, povecavaj dubinu i ponovo trazi potez while time.time( ) - pocetak < DOZVOLJENO_VREME and dubina <= ai.max_dubina: print("Iterativno produbljivanje, dubina", dubina) potez = ai.sledeci_potez(self.tabla, self.na_potezu, dubina) dubina += 1 print("Na potezu je " + str(self.na_potezu) + " i on je odgirao sledeci potez: " + str(potez)) self.tabla.izvrsi_potez(potez) self.f.write("\n" + str(potez)) self.game_state = GameState.SELEKTOVANJE_FIGURE self.da_li_je_kraj() def postavi_figure_na_slucajno_izabrana_mesta(self): """Postavlja dve figure na slucajno izabrana slobodna polja u tabli, ovo se koristi u pocetnoj fazi igre za AI """ dozvoljena_polja = self.tabla.pronadji_dozvoljena_polja( self.game_state, -2, -2, self.na_potezu) # uzimamo 2 slucajna polja iz liste dozvoljenih random_polja = random.sample(range(len(dozvoljena_polja)), 2) # nadjemo x i y koordinate tih polja x1, y1 = dozvoljena_polja[random_polja[0]][0], dozvoljena_polja[ random_polja[0]][1] x2, y2 = dozvoljena_polja[random_polja[1]][0], dozvoljena_polja[ random_polja[1]][1] # i postavimo figure u tim poljima, i zapisemo sve to u fajlu self.tabla.postavi_figuru(x1, y1, self.na_potezu) self.f.write(Potez.koordinate_u_string(x1, y1) + " ") self.tabla.postavi_figuru(x2, y2, self.na_potezu) self.f.write(Potez.koordinate_u_string(x2, y2) + "\n") # povecamo broj figura self.broj_figura += 2 # ako imamo 4 figure na tabli onda je faza postavljanja figura gotova i prelazimo na fazu selektovanje figure if self.broj_figura == 4: self.game_state = GameState.SELEKTOVANJE_FIGURE def zameni_igraca(self): """Funkcija menja trenutnog igraca, prebacuje kontrolu protivniku. Ako je AI na potezu onda izvrsava njegov potez i ponovo menja igraca. Ako igraju AI vs Ai onda je ovo rekurzivna funkcija koja menja igrace i izvrsava njihove poteze sve dok neko od njih ne pobedi. """ if self.game_state == GameState.KRAJ_IGRE: return if self.na_potezu == None: self.na_potezu = Igrac.PLAVI else: self.na_potezu = protivnik(self.na_potezu) self.selektovana_figura = (-2, -2) self.after(100, self.crtaj) # ovde treba da proverava da li igra AI sad if self.AI_je_na_potezu(): if self.game_state == GameState.SELEKTOVANJE_FIGURE: pravi_pauzu_izmedju_poteza_AI = self.crtaj_svaki_korak self.AI_izvrsi_potez(pravi_pauzu_izmedju_poteza_AI) elif self.game_state == GameState.POSTAVLJANJE_FIGURA: self.postavi_figure_na_slucajno_izabrana_mesta() if self.crtaj_svaki_korak: # veoma vazna stvar, kreira pauzu i omogucava GUI-u da se updateuje, inace blokira self.after(100, self.zameni_igraca) else: # ovo treba da ide kod implemetiranja algoritma do kraja, # koristim bug kao feature :D, blokiram gui namerno self.zameni_igraca() def sastavi_poruku(self): """Sastavlja poruku o trenutnom stanju igre i igracu koji je na potezu""" igrac = "PLAVI" if self.na_potezu == Igrac.CRVENI: igrac = "CRVENI" return f"Na potezu je {igrac} \na gamestate je {self.game_state}" def da_li_je_kraj(self): """Proverava da li je kra igre, u zavisnosti od toga da li je neko dostigao 3 nivo ili neko nema mogucih poteza prikazuje odgovarajucu poruku, gamestat postavlja na KRAJ_IGRE i prikazuje messagebox sa porukom o pobedniku """ if self.game_state == GameState.POSTAVLJANJE_FIGURA: return # proveri da li je kraj meca, tj da li ima mogucih poteza za igraca na potezu if not self.tabla.ima_mogucih_poteza(self.na_potezu): self.game_state = GameState.KRAJ_IGRE self.zatovori_fajl() self.crtaj() messagebox.showinfo( "Pobeda", f"Pobedio je {protivnik(self.na_potezu)} jer {self.na_potezu} nema mogucih poteza!" ) if self.tabla.zauzeo_treci_sprat(self.na_potezu): self.game_state = GameState.KRAJ_IGRE if not self.AI_je_na_potezu(): self.f.write(str(self.trenutni_potez_osobe) + "\n") self.zatovori_fajl() self.crtaj() messagebox.showinfo( "Pobeda", f"Pobedio je {self.na_potezu} jer je zauzeo polje sa nivoom 3!" ) def zatovori_fajl(self): """Zatvara fajl self.f""" self.f.close()