<commit_before>IGRALEC_1 = 'igralec_1'
IGRALEC_2 = 'igralec_2'

class Igra():
    def __init__(self):
        # Naredi prazno igralno plosco.
        self.igralna_plosca = [None] * 24
        # na potezo postavi prvega igralca
        self.na_potezi = IGRALEC_1
        # na i-tem mestu v seznamu so sosedna polja i-tega polja na plosci
        self.sosedi = [[1, 9], [0, 2, 4], [1, 14], [4, 10], [1, 3, 5, 7], [4, 13], [7, 11], [4, 6, 8], [7, 12],
                       [0, 10, 21], [3, 9, 11, 18], [6, 10, 15], [8, 13, 17], [5, 12, 14, 20], [2, 13, 23], [11, 16],
                       [15, 17, 19], [12, 16], [10, 19], [16, 18, 20, 22], [13, 19], [9, 22], [19, 21, 23], [14, 22]]
        # polozaji vseh moznih trojk, ki lahko nastopijo na plosci
        self.trojke = [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}, {12, 13, 14}, {15, 16, 17}, {18, 19, 20},
                       {21, 22, 23}, {0, 9, 21}, {3, 10, 18}, {6, 11, 15}, {1, 4, 7}, {16, 19, 22}, {8, 12, 17},
                       {5, 13, 20}, {2, 14, 23}]
        # v slovarju self.manjkajoca so kljuci pari sosednih polj na plosci,
        # vrednost pa je polje, ki manjka do zakljucene trojke
        # slovar bomo potrebovali pri oceni postavitve
        self.manjkajoca = {}
        for trojka in self.trojke:
            a, b, c = sorted(trojka)
            self.manjkajoca[(a, b)] = c
            self.manjkajoca[(a, c)] = b
            self.manjkajoca[(b, c)] = a


        # v seznamu self.zetoni ustreza indeks i zetonu i: "zacetek" - ni se vstopil v igro,
        # "izlocen" - je ze izlocen iz igre, n - nahaja se na igralni plosci na mestu n
        # indeksi 0-8 so za zetone igralca 1, ostali za zetone igralca 2
        self.zetoni = ["zacetek"] * 18
        # faza_igre 1 pomeni, da se zetoni sele postavljajo na plosco
        # faza_igre 2 pomeni, da se zetoni prestavljajo po plosci
        self.faza_igre = 1
        # pove, ce se je zakljucila poteza
        self.konec_poteze = False
        # pove, ce se je igra koncala
        self.konec_igre = False
        # pove, kdo je zmagovalec igre
        self.zmagovalec = None
        # vsebuje vse podatke o trenutnem stanju:
        # self.igralna_plosca, self.zetoni, self.na_potezi, self.faza_igre, self.konec_igre , self.zmagovalec in self.ponovljene
        self.zgodovina = []
        # vsebuje število ponovljenih potez
        self.ponovljene = 0

    def shrani_zgodovino(self):
        """Doda trenutno stanje igre v zgodovino."""
        self.zgodovina.append((self.igralna_plosca[:], self.zetoni[:], self.na_potezi, self.faza_igre, self.konec_igre, self.zmagovalec, self.ponovljene))

    def razveljavi(self):
        """Odstrani zadnji vnos iz zgodovine, ponastavi igro na prejsnje stanje."""
        (self.igralna_plosca, self.zetoni, self.na_potezi, self.faza_igre, self.konec_igre, self.zmagovalec, self.ponovljene) = self.zgodovina.pop()

    def kopija_igre(self):
        """Ustvari kopijo igre, ki jo racunalnik uporablja pri algoritmu alfa-beta, da ne spreminja dejanske plosce."""
        k = Igra()
        k.igralna_plosca = self.igralna_plosca[:]
        k.zetoni = self.zetoni[:]
        k.na_potezi = self.na_potezi
        k.faza_igre = self.faza_igre
        k.konec_igre = self.konec_igre
        k.zmagovalec = self.zmagovalec
        k.ponovljene = self.ponovljene
        k.zgodovina = self.zgodovina
        return k

    def veljavna_poteza(self, zeton, zeljeno_polje):
        """Dobi index zetona, fazo igre (1 ali 2) in index polja, kamor zelimo zeton postaviti."""
        # zeton je ze izlocen iz igre
        if self.zetoni[zeton] is "izlocen":
            return False
        # Preveri, ce zeton ne pripada igralcu.
        if self.na_potezi is IGRALEC_1 and zeton >= 9 or self.na_potezi is IGRALEC_2 and zeton < 9:
            return False
        # v fazi 1 preverjamo, ce je zeljeno_polje prazno in zeton se ni vstopil v igro
        if self.faza_igre == 1:
            return self.igralna_plosca[zeljeno_polje] is None and self.zetoni[zeton] is "zacetek"
        elif self.faza_igre == 2:
            if self.na_potezi is IGRALEC_1:
                # preverimo, ce ima igralec samo se 2 ali 3 aktivne zetone - potem lahko skace po plosci
                if self.zetoni[:9].count("izlocen") >= 6:
                    # preverimo, ce je zeljeno_polje prazno
                    return self.igralna_plosca[zeljeno_polje] is None
                else:
                    # igralec ne sme skakati - torej mora biti polje prazno in sosednje
                    return self.igralna_plosca[zeljeno_polje] is None and zeljeno_polje in\
                                                                          self.sosedi[self.zetoni[zeton]]
            else:
                if self.zetoni[9:].count("izlocen") >= 6:
                    return self.igralna_plosca[zeljeno_polje] is None
                else:
                    return self.igralna_plosca[zeljeno_polje] is None and zeljeno_polje in\
                                                                          self.sosedi[self.zetoni[zeton]]
        else:
            return False

    def veljavni_zakljucek(self, zeton):
        """Dobi indeks zetona, ki ga zelimo vzeti in preveri, ce je to veljavno."""
        # Spremenljivka mesto je mesto v seznamu, pri katerem se zacnejo zetoni nasprotnega igralca
        if self.na_potezi is IGRALEC_1:
            mesto = 9
        else:
            mesto = 0

        # Indeksi nasprotnikovih zetonov, ki se nahajajo na plosci (nimajo statusa "zacetek" ali "izlocen")
        izbire = [i for i in range(mesto, mesto + 9) if self.zetoni[i] not in ["izlocen", "zacetek"]]
        if zeton not in izbire:
            return False
        # ce zeton ni vsebovan v trojki, ga lahko vzamemo
        elif not self.nova_trojka(zeton):
            return True
        else:
            for i in izbire:
                if not self.nova_trojka(i):
                    return False
        # ce bi obstajal nasprotnikov zeton, ki ni v trojki, bi pri prejsnjem else stavku ze vrnili False
        # torej so vsi naprotnikovi zetoni v trojkah - lahko vzamemo poljubnega
        return True

    def odigraj_potezo(self, zeton, polje):
        """Sprejme indeks zetona in polje, kamor ga zelimo prestaviti, ter odigra potezo.
        Privzamemo, da je poteza veljavna - veljavnost bo preveril objekt razreda Igralec ali Racunalnik, preden poklice to metodo"""
        self.shrani_zgodovino()
        if self.zetoni[zeton] is "zacetek":
            # zeton prvic vstopi v igro
            self.zetoni[zeton] = polje
            self.igralna_plosca[polje] = zeton
        else:
            # zeton premikamo po plosci
            self.igralna_plosca[self.zetoni[zeton]] = None
            self.igralna_plosca[polje] = zeton
            self.zetoni[zeton] = polje
        if not self.nova_trojka(zeton):
            # ni nastala nova trojka
            self.zakljucek_poteze(zeton=None)

    def nova_trojka(self, zeton):
        """Preveri, ce obstaja trojka, ki vsebuje dani zeton"""
        # v seznamu so vse trojke, ki vsebujejo pozicijo, na kateri se nahaja zeton
        moznosti = [trojka for trojka in self.trojke if self.zetoni[zeton] in trojka]
        # preverimo, ce potencialna trojka zares vsebuje vse 3 zetone istega igralca
        # zeton pripada igralcu 1
        if zeton < 9:
            for moznost in moznosti:
                if moznost <= set(self.zetoni[:9]):
                    return True
            return False
        # zeton pripada igralcu 2
        if zeton >= 9:
            for moznost in moznosti:
                if moznost <= set(self.zetoni[9:]):
                    return True
            return False

    def zakljucek_poteze(self, zeton=None):
        """Sprejme indeks zetona, ki ga zelimo vzeti in ustrezno odigra - veljavnost te poteze bo ze prej preveril objekt razreda Igralec ali Racunalnik.
        Privzeti parameter None pove, da ne bomo vzeli nobenega zetona."""
        if zeton is not None:
            self.shrani_zgodovino()
            self.igralna_plosca[self.zetoni[zeton]] = None
            self.zetoni[zeton] = "izlocen"
        # spremenimo igralca, ki je na potezi
        if self.na_potezi is IGRALEC_1:
            self.na_potezi = IGRALEC_2
        else:
            self.na_potezi = IGRALEC_1
        # povemo, da se je poteza zakljucila
        self.konec_poteze = True
        # poklicemo stanje igre
        self.stanje_igre()

    def veljavne_poteze(self):<commit_msg>Popravi komentar<commit_after>IGRALEC_1 = 'igralec_1'
IGRALEC_2 = 'igralec_2'

class Igra():
    def __init__(self):
        # Naredi prazno igralno plosco.
        self.igralna_plosca = [None] * 24
        # na potezo postavi prvega igralca
        self.na_potezi = IGRALEC_1
        # na i-tem mestu v seznamu so sosedna polja i-tega polja na plosci
        self.sosedi = [[1, 9], [0, 2, 4], [1, 14], [4, 10], [1, 3, 5, 7], [4, 13], [7, 11], [4, 6, 8], [7, 12],
                       [0, 10, 21], [3, 9, 11, 18], [6, 10, 15], [8, 13, 17], [5, 12, 14, 20], [2, 13, 23], [11, 16],
                       [15, 17, 19], [12, 16], [10, 19], [16, 18, 20, 22], [13, 19], [9, 22], [19, 21, 23], [14, 22]]
        # polozaji vseh moznih trojk, ki lahko nastopijo na plosci
        self.trojke = [{0, 1, 2}, {3, 4, 5}, {6, 7, 8}, {9, 10, 11}, {12, 13, 14}, {15, 16, 17}, {18, 19, 20},
                       {21, 22, 23}, {0, 9, 21}, {3, 10, 18}, {6, 11, 15}, {1, 4, 7}, {16, 19, 22}, {8, 12, 17},
                       {5, 13, 20}, {2, 14, 23}]
        # v slovarju self.manjkajoca so kljuci pari sosednih polj na plosci,
        # vrednost pa je polje, ki manjka do zakljucene trojke
        # slovar bomo potrebovali pri oceni postavitve
        self.manjkajoca = {}
        for trojka in self.trojke:
            a, b, c = sorted(trojka)
            self.manjkajoca[(a, b)] = c
            self.manjkajoca[(a, c)] = b
            self.manjkajoca[(b, c)] = a


        # v seznamu self.zetoni ustreza indeks i zetonu i: "zacetek" - ni se vstopil v igro,
        # "izlocen" - je ze izlocen iz igre, n - nahaja se na igralni plosci na mestu n
        # indeksi 0-8 so za zetone igralca 1, ostali za zetone igralca 2
        self.zetoni = ["zacetek"] * 18
        # faza_igre 1 pomeni, da se zetoni sele postavljajo na plosco
        # faza_igre 2 pomeni, da se zetoni prestavljajo po plosci
        self.faza_igre = 1
        # pove, ce se je zakljucila poteza
        self.konec_poteze = False
        # pove, ce se je igra koncala
        self.konec_igre = False
        # pove, kdo je zmagovalec igre
        self.zmagovalec = None
        # vsebuje vse podatke o trenutnem stanju:
        # self.igralna_plosca, self.zetoni, self.na_potezi, self.faza_igre, self.konec_igre , self.zmagovalec in self.ponovljene
        self.zgodovina = []
        # vsebuje število ponovljenih potez
        self.ponovljene = 0

    def shrani_zgodovino(self):
        """Doda trenutno stanje igre v zgodovino."""
        self.zgodovina.append((self.igralna_plosca[:], self.zetoni[:], self.na_potezi, self.faza_igre, self.konec_igre, self.zmagovalec, self.ponovljene))

    def razveljavi(self):
        """Odstrani zadnji vnos iz zgodovine, ponastavi igro na prejsnje stanje."""
        (self.igralna_plosca, self.zetoni, self.na_potezi, self.faza_igre, self.konec_igre, self.zmagovalec, self.ponovljene) = self.zgodovina.pop()

    def kopija_igre(self):
        """Ustvari kopijo igre, ki jo racunalnik uporablja pri algoritmu alfa-beta, da ne spreminja dejanske plosce."""
        k = Igra()
        k.igralna_plosca = self.igralna_plosca[:]
        k.zetoni = self.zetoni[:]
        k.na_potezi = self.na_potezi
        k.faza_igre = self.faza_igre
        k.konec_igre = self.konec_igre
        k.zmagovalec = self.zmagovalec
        k.ponovljene = self.ponovljene
        k.zgodovina = self.zgodovina
        return k

    def veljavna_poteza(self, zeton, zeljeno_polje):
        """Dobi index zetona, fazo igre (1 ali 2) in index polja, kamor zelimo zeton postaviti."""
        # zeton je ze izlocen iz igre
        if self.zetoni[zeton] is "izlocen":
            return False
        # Preveri, ce zeton ne pripada igralcu.
        if self.na_potezi is IGRALEC_1 and zeton >= 9 or self.na_potezi is IGRALEC_2 and zeton < 9:
            return False
        # v fazi 1 preverjamo, ce je zeljeno_polje prazno in zeton se ni vstopil v igro
        if self.faza_igre == 1:
            return self.igralna_plosca[zeljeno_polje] is None and self.zetoni[zeton] is "zacetek"
        elif self.faza_igre == 2:
            if self.na_potezi is IGRALEC_1:
                # preverimo, ce ima igralec samo se 2 ali 3 aktivne zetone - potem lahko skace po plosci
                if self.zetoni[:9].count("izlocen") >= 6:
                    # preverimo, ce je zeljeno_polje prazno
                    return self.igralna_plosca[zeljeno_polje] is None
                else:
                    # igralec ne sme skakati - torej mora biti polje prazno in sosednje
                    return self.igralna_plosca[zeljeno_polje] is None and zeljeno_polje in\
                                                                          self.sosedi[self.zetoni[zeton]]
            else:
                if self.zetoni[9:].count("izlocen") >= 6:
                    return self.igralna_plosca[zeljeno_polje] is None
                else:
                    return self.igralna_plosca[zeljeno_polje] is None and zeljeno_polje in\
                                                                          self.sosedi[self.zetoni[zeton]]
        else:
            return False

    def veljavni_zakljucek(self, zeton):
        """Dobi indeks zetona, ki ga zelimo vzeti in preveri, ce je to veljavno."""
        # Spremenljivka mesto je mesto v seznamu, pri katerem se zacnejo zetoni nasprotnega igralca
        if self.na_potezi is IGRALEC_1:
            mesto = 9
        else:
            mesto = 0

        # Indeksi nasprotnikovih zetonov, ki se nahajajo na plosci (nimajo statusa "zacetek" ali "izlocen")
        izbire = [i for i in range(mesto, mesto + 9) if self.zetoni[i] not in ["izlocen", "zacetek"]]
        if zeton not in izbire:
            return False
        # ce zeton ni vsebovan v trojki, ga lahko vzamemo
        elif not self.nova_trojka(zeton):
            return True
        else:
            for i in izbire:
                if not self.nova_trojka(i):
                    return False
        # ce bi obstajal nasprotnikov zeton, ki ni v trojki, bi pri prejsnjem else stavku ze vrnili False
        # torej so vsi naprotnikovi zetoni v trojkah - lahko vzamemo poljubnega
        return True

    def odigraj_potezo(self, zeton, polje):
        """Sprejme indeks zetona in polje, kamor ga zelimo prestaviti, ter odigra potezo.
        Privzamemo, da je poteza veljavna - veljavnost bo preveril objekt razreda Clovek ali Racunalnik, preden poklice to metodo"""
        self.shrani_zgodovino()
        if self.zetoni[zeton] is "zacetek":
            # zeton prvic vstopi v igro
            self.zetoni[zeton] = polje
            self.igralna_plosca[polje] = zeton
        else:
            # zeton premikamo po plosci
            self.igralna_plosca[self.zetoni[zeton]] = None
            self.igralna_plosca[polje] = zeton
            self.zetoni[zeton] = polje
        if not self.nova_trojka(zeton):
            # ni nastala nova trojka
            self.zakljucek_poteze(zeton=None)

    def nova_trojka(self, zeton):
        """Preveri, ce obstaja trojka, ki vsebuje dani zeton"""
        # v seznamu so vse trojke, ki vsebujejo pozicijo, na kateri se nahaja zeton
        moznosti = [trojka for trojka in self.trojke if self.zetoni[zeton] in trojka]
        # preverimo, ce potencialna trojka zares vsebuje vse 3 zetone istega igralca
        # zeton pripada igralcu 1
        if zeton < 9:
            for moznost in moznosti:
                if moznost <= set(self.zetoni[:9]):
                    return True
            return False
        # zeton pripada igralcu 2
        if zeton >= 9:
            for moznost in moznosti:
                if moznost <= set(self.zetoni[9:]):
                    return True
            return False

    def zakljucek_poteze(self, zeton=None):
        """Sprejme indeks zetona, ki ga zelimo vzeti in ustrezno odigra - veljavnost te poteze bo ze prej preveril objekt razreda Clovek ali Racunalnik.
        Privzeti parameter None pove, da ne bomo vzeli nobenega zetona."""
        if zeton is not None:
            self.shrani_zgodovino()
            self.igralna_plosca[self.zetoni[zeton]] = None
            self.zetoni[zeton] = "izlocen"
        # spremenimo igralca, ki je na potezi
        if self.na_potezi is IGRALEC_1:
            self.na_potezi = IGRALEC_2
        else:
            self.na_potezi = IGRALEC_1
        # povemo, da se je poteza zakljucila
        self.konec_poteze = True
        # poklicemo stanje igre
        self.stanje_igre()

    def veljavne_poteze(self):
{'fraction_non_alphanumeric': 0.09176788124156546, 'fraction_numerical': 0.02652115237927595, 'mean_word_length': 1.9912249912249913, 'pattern_counts': {'":': 4, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4388041', 'n_tokens_mistral': 6774, 'n_tokens_neox': 6357, 'n_words': 1762}