Kryziuku nuliuku pavyzdys

Iš wiki.angis.net.
Jump to navigation Jump to search


Kryžiukų-nuliukų žaidimo pavyzdys Angies platformoje. Žaisti Kryžiukus nuliukus

Kompiuterio ėjimams paskaičiuoti naudojamas rekursiškas Minimax algoritmas.

Žaidimo sudėtingumui sumažinti reikia pakeisti paieškos gylį objektui MinimaxAlgoritmas.


Kad programa veiktų, reikia failų tictactoe.jpg , o.png ir x.png tavo paskyroje.

Žaidimo išvaizda.
reikalinga angis
reikalingas žaidimas

"""
sutartinės reikšmės (konstantos).
Ir modelyje, ir algoritmuose laikome, kad žmogaus ėjimai žymimi -1, o kompiuterio +1
"""
ŽMOGUS = -1
KOMPIUTERIS = +1

class Modelis:
    """
    Kryžiukų-nuliukų žaidimo modelis. Žino apie galimus ėjimus, moka žymėti žaidėjo ėjimą, ir nustatyti laimėtoją.
    """

    VISI_LANGELIAI = [[0,0], [1,0], [2,0], [0,1], [1,1], [2,1], [0,2], [1,2], [2,2]]

    komanda __init__(mano):
        mano.išNaujo()

    komanda išNaujo(mano):
        mano.langeliai = [ [0, 0, 0],
                           [0, 0, 0],
                           [0, 0, 0] ]

    komanda sukurkKloną(mano):
        """
        grąžina šios lentos kloną
        """
        klonas = Modelis()
        klonas.langeliai = []
        kiekvienam eil  mano.langeliai:
            klonas.langeliai.append(eil[:])
        grąžink klonas

    komanda duokTuščiusLangelius(mano):
        """
        išrenka tuščius langelius iš lentos (t.y. galimus ėjimus).
        """
        ats = []

        kiekvienam eil  intervalo(3):
            kiekvienam st  intervalo(3):
                jei mano.langeliai[eil][st] == 0:
                    ats.append([eil, st])

        grąžink ats

    komanda duokLaiminčiusLangelius(mano, žaidėjas):
        """
        grąžina laiminčių langelių sąrašą jei žaidimą laimėjo nurodytas žaidėjas
                arba None, jei niekas nelaimėjo
        """
        kiekvienam eil  intervalo(0, 3):
            jei mano.langeliai[eil][0] == mano.langeliai[eil][1] == mano.langeliai[eil][2] == žaidėjas:
                grąžink [ [eil, 0], [eil, 1], [eil, 2] ]

        kiekvienam st  intervalo(0, 3):
            jei mano.langeliai[0][st] == mano.langeliai[1][st] == mano.langeliai[2][st] == žaidėjas:
                grąžink [ [0, st], [1, st], [2, st] ]

        jei mano.langeliai[0][0] == mano.langeliai[1][1] == mano.langeliai[2][2] == žaidėjas:
            grąžink [ [0,0], [1,1], [2,2] ] 

        jei mano.langeliai[0][2] == mano.langeliai[1][1] == mano.langeliai[2][0] == žaidėjas:
            grąžink [ [0,2], [1,1], [2,0] ] 

        grąžink None

    komanda yraLangelisTuščias(mano, eilutė, stulpelis):
        """
        pasako, ar nurodytas langelis tuščias
        """
        grąžink mano.langeliai[eilutė][stulpelis] == 0

    komanda žymėkĖjimą(mano, eilutė, stulpelis, žaidėjas):
        """
        pažymi nurodytą langelį žaidėjui
        """
        mano.langeliai[eilutė][stulpelis] = žaidėjas

    komanda yraŽaidimasBaigtas(mano):
        """
        grąžina True, jei laimėjo kuris nors žaidėjas arba baigėsi langeliai
        """
        langeliai = mano.duokLaiminčiusLangelius(1)
        jei langeliai != None:
            grąžink True
            
        langeliai = mano.duokLaiminčiusLangelius(-1)
        jei langeliai != None:
            grąžink True

        jei len(mano.duokTuščiusLangelius()) == 0 :
            grąžink True

        grąžink False


class Interfeisas:
    """
    Moka vizualiai nupiešti 3x3 langelius, žymėti žaidėjų ėjimus, ir laiminčią simbolių liniją.
    Taip pat moka konvertuoti tarp ekrano koordinačių X,Y ir modelio koordinačių EILUTĖ,STULPELIS
    """

    komanda __init__(mano):
        angis.naudosiuFailus(['pav/efektai/sprogimas.json',
                              'tictactoe.jpg', 'o.png', 'x.png'])

        žaidimas.duokSceną().fonas('tictactoe.jpg')

        mano.figūros = []

    komanda išNaujo(mano):
        kiekvienam f  mano.figūros:
            f.išnyk()

        mano.figūros = []

    komanda paskaičiuokEilStulp(mano, x, y):
        eilutė = -1
        stulpelis = -1
        jei x > 10 ir x <= 267:
            stulpelis = 0
        ojei x > 267  ir x <= 524:
            stulpelis = 1
        ojei x > 524 ir x <=699:
            stulpelis = 2

        jei  y > 10 ir y <= 200:
            eilutė = 0
        ojei y > 200  ir y <= 400:
            eilutė = 1
        ojei y > 400 ir y <=600:
            eilutė = 2

        grąžink eilutė, stulpelis

    komanda paskaičiuokXY(mano, eilutė, stulpelis):
        grąžink stulpelis * 240 + 80, eilutė * 200 + 40

    komanda pieškFigūrą(mano, eilutė, stulpelis, žaidėjas):
        x, y = mano.paskaičiuokXY(eilutė, stulpelis)
        failovardas = "o.png" jei žaidėjas == KOMPIUTERIS kituatveju "x.png"
        figūra = žaidimas.Daiktas(failovardas, x, y)

        mano.figūros.append(figūra)

    komanda sprogdink(mano, langeliai):
        kiekvienam eil, stulp  langeliai:
            mano.rodykSprogimą(eil, stulp)

    komanda rodykSprogimą (mano, eilutė, stulpelis):
        x, y = mano.paskaičiuokXY(eilutė, stulpelis)
        sprogimas = žaidimas.Animacija(failoVardas = "pav/efektai/sprogimas.json", pavadinimas="sprogimas", greitis=0.5)
        sprogimas.atsirask(x, y)
        sprogimas.grokFone()

class Švieslentė:
    """
    Moka vizualiai ekrane parodyti žaidėjų surinktus taškus
    """
    komanda __init__(mano):
        mano.žmogausTaškai = 0
        mano.kompiuterioTaškai = 0

        mano.tekstas = žaidimas.Tekstas("kryžiukai 0 : nuliukai 0")

        mano.tekstas.atsirask (10, 10)
        mano.tekstas.spalva("#AAAAAA")
        mano.tekstas.dydis(15)

    komanda žymėkLaimėjimą(mano, laimėtojas):
        jei laimėtojas == ŽMOGUS:
            mano.žmogausTaškai = mano.žmogausTaškai + 1
        ojei laimėtojas == KOMPIUTERIS:
            mano.kompiuterioTaškai = mano.kompiuterioTaškai + 1
        mano.perpiešk()

    komanda perpiešk(mano):
        mano.tekstas.užrašas("kryžiukai "
                            + str(mano.žmogausTaškai)
                            + " : nuliukai "
                            + str(mano.kompiuterioTaškai) )

class MinimaxAlgoritmas:
    """
    Moka rasti geriausią žaidėjo ėjimą pagal Minimax algoritmą.
    """
    komanda __init__(mano, modelis, paieškosGylis):
        mano.modelis = modelis
        mano.gylis = paieškosGylis

    komanda raskĖjimą(mano, žaidėjas):
        grąžink mano.__raskĖjimąRekursiškai(mano.modelis, žaidėjas, mano.gylis)

    komanda __raskĖjimąRekursiškai(mano, modelis, žaidėjas, gylis):

        jei modelis.yraLangelisTuščias(1, 1):
            grąžink [1, 1, žaidėjas] # centrinis langelis yra strategiškai svarbus

        tuštiLangeliai = modelis.duokTuščiusLangelius()
        jei len(tuštiLangeliai) == 0:
            grąžink [-1, -1, 0] # taip neturi būti

        jei len(tuštiLangeliai) == 8:
            grąžink [0, 0, žaidėjas] # jei užimtas tik vienas langelis, ir jis centre, tai užsiimam kampą.

        ats = None

        kiekvienam eil, st  tuštiLangeliai:

            jei ats == None:
                ats = [eil, st, -žaidėjas]

            # bandom modeliuoti žaidėjo ėjimą į eil, st
            modelioKopija = modelis.sukurkKloną()
            modelioKopija.žymėkĖjimą(eil, st, žaidėjas)

            jei modelioKopija.duokLaiminčiusLangelius(žaidėjas) != None:
                grąžink [eil, st, žaidėjas] # garantuotas laimėjimas

            jei gylis <= 0:
                ats = [eil, st, 0] # garantuotos lygiosios, įsiminkim dėl viso pikto
                tęsk

            # rekursiškai modeliuojam tolimesnius žingsnius, pradedant nuo priešininko
            e, s, rezultatas = mano.__raskĖjimąRekursiškai(modelioKopija, -žaidėjas, gylis-1)

            jei rezultatas == žaidėjas:
                grąžink [eil, st, rezultatas] # galimas laimėjimas!

            jei rezultatas == 0:
                ats = [eil, st, 0] # galimos lygiosios, įsiminkim dėl viso pikto

        grąžink ats


class Taisyklės:
    """
    Užtikrina žaidimo taisykles: ėjimų eiliškumą, komponentų tarpusavio sąveiką
    """

    komanda __init__(mano, modelis, interfeisas, švieslentė, algoritmas):
        mano.modelis = modelis
        mano.interfeisas = interfeisas
        mano.švieslentė = švieslentė
        mano.algoritmas = algoritmas
        mano.žmogausĖjimas = True

    komanda išNaujo(mano):
        mano.modelis.išNaujo()
        mano.interfeisas.išNaujo()
        mano.žmogausĖjimas = True

    komanda žymėkŽmogausĖjimą(mano, eilutė, stulpelis):
        jei mano.žmogausĖjimas == False:
            grįžk

        jei mano.modelis.yraLangelisTuščias(eilutė, stulpelis) == False:
            grįžk

        mano.žmogausĖjimas = False

        mano.modelis.žymėkĖjimą(eilutė, stulpelis, ŽMOGUS)
        mano.interfeisas.pieškFigūrą(eilutė, stulpelis, ŽMOGUS)
        
        jei modelis.yraŽaidimasBaigtas():
            mano.__užbaikŽaidimą()
            grįžk

        eil, st, rezultatas = mano.algoritmas.raskĖjimą(KOMPIUTERIS)

        mano.modelis.žymėkĖjimą(eil, st, KOMPIUTERIS)
        mano.interfeisas.pieškFigūrą(eil, st, KOMPIUTERIS)

        jei mano.modelis.yraŽaidimasBaigtas():
            mano.__užbaikŽaidimą()
            grįžk

        mano.žmogausĖjimas = True

    komanda __užbaikŽaidimą(mano):
        laimintysLangeliai, laimėtojas = mano.__duokLaimėtoją()
       
        mano.švieslentė.žymėkLaimėjimą(laimėtojas)
        mano.interfeisas.sprogdink(laimintysLangeliai)

        mano.išNaujo()

    komanda __duokLaimėtoją(mano):
        ats = mano.modelis.duokLaiminčiusLangelius(ŽMOGUS)
        jei ats != None:
            grąžink ats, ŽMOGUS

        ats = mano.modelis.duokLaiminčiusLangelius(KOMPIUTERIS)
        jei ats != None:
            grąžink ats, KOMPIUTERIS

        grąžink mano.modelis.VISI_LANGELIAI, 0


modelis = Modelis()
interfeisas = Interfeisas()
švieslentė = Švieslentė()
algoritmas = MinimaxAlgoritmas(modelis, paieškosGylis = 3)
taisyklės = Taisyklės(modelis, interfeisas, švieslentė, algoritmas)

komanda pelėsPaspaudimas(pelėsX, pelėsY):
    eilutė, stulpelis = interfeisas.paskaičiuokEilStulp(pelėsX, pelėsY)
    jei eilutė >= 0 ir stulpelis >= 0:
        taisyklės.žymėkŽmogausĖjimą(eilutė, stulpelis)
      
žaidimas.pelęPaspaudus(pelėsPaspaudimas)