コード例 #1
0
ファイル: ai.py プロジェクト: samedb/Santorini
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
コード例 #2
0
ファイル: ai.py プロジェクト: samedb/Santorini
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
コード例 #3
0
ファイル: ai.py プロジェクト: samedb/Santorini
 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]
コード例 #4
0
def analizarDatos(anterior, actual):

    datos = Tabla(anterior, actual)

    tablaTranspuesta = datos.unirTablasXmes()

    nombre = 'MonthlyReport'

    reporte = Reporte(tablaTranspuesta, nombre)
    reporte.analizeReport()

    print('Reporte OK!')
コード例 #5
0
ファイル: ai.py プロジェクト: samedb/Santorini
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
コード例 #6
0
    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()
コード例 #7
0
ファイル: ai.py プロジェクト: samedb/Santorini
    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)
コード例 #8
0
ファイル: ai.py プロジェクト: samedb/Santorini
    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
コード例 #9
0
ファイル: ai.py プロジェクト: samedb/Santorini
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
コード例 #10
0
ファイル: ai.py プロジェクト: samedb/Santorini
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 
コード例 #11
0
ファイル: ai.py プロジェクト: samedb/Santorini
    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
コード例 #12
0
ファイル: analizador.py プロジェクト: rdonate/MiniCalc
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",
コード例 #13
0
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:
コード例 #14
0
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()