orlog.py

Created by florian-allard

Created on March 02, 2024

15.4 KB

Adaptation du jeu Orlog (jeu de dés et de jetons) à partir du mini-jeu éponyme dans le jeu Assassin’s Creed® : Valhalla.
Version avec une IA basique et un résumé du plateau affiché en bas lors du choix de la divinité pour la prochaine manche mais avec le nom des sorts réduit au nom de la divinité.
Une version avec le nom complet des sorts mais sans l’affichage du résumé du plateau est disponible ici : https://my.numworks.com/python/florian-allard/orlog2023


from random import choice
from kandinsky import set_pixel,fill_rect as fr,draw_string as ds
from ion import keydown as kd,KEY_EXE as KE,KEY_LEFT as KL,KEY_RIGHT as KR,KEY_DOWN as KD,KEY_UP as KU
from time import sleep as sp

inf={"Thrymr":(1,"Niveau d'invocation adverse\n   réduit.",3,6,9,"-",1,2,3," niv","  "),\
"Var":(1,"Soin par Jeton adverse\n   dépensé.",10,14,18,"+",1,2,3,"   /  ","<J"),\
"Freyja":(2,"Dés supplémentaires lancés.",2,4,6,"+",1,2,3,"   ","v "),\
"Frigg":(2,"Dés à soi et/ou adverses au\n   choix relancés.",2,3,4,"",2,3,4,"    ","v "),\
"Loki":(2,"Dés adverses au choix\n   bannis.",3,6,9,"-",1,2,3,"   ","v "),\

"Skuld":(3,"Jetons adverses détruits\n   par face flèche.",4,6,8,"-",2,3,4,"   /  ","Jf"),\
"Tyr":(3,"Jetons adverses détruits\n   par PV sacrifié.",4,6,8,"",-2,-3,-4,"   /  ","J<"),\
"Baldr":(4,"Multiplie casques et\n   boucliers.",3,6,9,"",2,3,4,"x(  &  )","cb"),\
"Bragi":(4,"Jetons gagnés par face main.",4,8,12,"+",2,3,4,"   /  ","Jm"),\
"Brunehilde":(4,"Multiplie les haches.",6,10,18," ",1.5,2,3,"x(    )"," h"),\

"Freyr":(4,"Ajout de faces majoritaires.",4,6,8,"+",2,3,4,"    majoritaire","v "),\
"Heimdal":(4,"Soin par attaque bloquée.",4,7,10,"+",1,2,3,"   /blocage","< "),\
"Hel":(4,"Soin par coup de hache\n   infligé.",6,12,18,"+",1,2,3,"   /  infligée","<h"),\
"Mimir":(4,"Jetons gagnés par coup subi.",3,5,7,"+",1,2,3,"   /coup subi","J "),\
"Skadi":(4,"Multiplie les flèches.",6,10,14,"",2,3,4,"x(  )","f "),\

"Ullr":(4,"Boucliers adverses ignorés.",2,3,4,"-",2,3,6,"   ","b "),\
"Vidar":(4,"Casques adverses enlevés.",2,4,6,"-",2,4,6,"   ","c "),\
"Thor":(8,"Dégâts infligés après la\n   phase de résolution.",4,8,12,"-",2,5,8,"   ","< "),\
"Idunn":(9,"Soin après la phase de\n   résolution.",4,7,10,"+",2,4,6,"   ","< "),\
"Odin":(9,"Gain de Jetons par PV\n   sacrifié.",6,8,10,"+",3,4,5,"   /  ","J<")}


def AffDv(Dv):
    fr(15,42,290,136,"w")
    fr(0,41,320,1,"purple")
    ds("<                             >",5,126,"b")
    if Dv=="aucune":
        ds("Ne pas choisir\n          de divinité.",90,80,"r")
    else:
        ds(Dv,160-5*len(Dv),45,"g") # nom
        ds(str(inf[Dv][0]),155,62,"r") # priorité
        ds(inf[Dv][1],29,76,"b") # description
        dess("d",305,5,"purple")
        for niv in (0,1,2):
            Y=115+22*niv
            Cout=inf[Dv][2+niv]
            ds(str(Cout)+"   : "+inf[Dv][5]+str(inf[Dv][6+niv])+inf[Dv][-2],55+10*(Cout<10),Y,"purple")
            ds(" >"[niv==NvDv[Jr]],40,Y,"r")
            dess("J",85,Y+3,dore,dore)
            for k in (2,1):
                dess(inf[Dv][-1][-k],220-30*k,Y+3,"brown","brown","brown")
    sp(0.2)

def cadre(x,y,l,h,clr):
    for k in (0,1):
        fr(x,y+h*k,l+1,1,clr)
        fr(x+l*k,y,1,h+1,clr)


mtfs={"<":(0,0,0,0,252,252,252,252),"":()," ":(),"v":(),"V":(),"h":(8,28,62,111,206,396,768,1536,1024),"f":(15,3,5,9,16,32,64,896,128,128),"c":(120,252,510,1023,1023,819,819,390,390),"b":(120,204,390,891,585,585,891,390,204,120),"m":(168,170,170,682,766,1022,508,248,120,120),"j":(0,462,330,510,72,72,510,330,462),"d":(1799,1022,260,340,260,396,626,1025,1539,1285,1161,1105,1105,1105,2047)}
dore=(200,150,0)

def dess(ltr,x,y,Mtf="b",Ctr="g",Lsr=dore):
    mtf=mtfs[ltr.lower()]
    for lig in range(len(mtf)):
        elt=mtf[lig]
        elt="0"*(12+(ltr in ("d","h"))-len(bin(elt)))+bin(elt)[2:]
        for col in range(len(elt)):
            set_pixel(x+col,y+lig,(("w",Mtf)[int(elt[col])],"g")[ltr=="<"])
    if ltr not in ("<",""," ","d"):
        cadre(x-4,y-4,17,17,Ctr)
        cadre(x-2,y-2,13,13,("w",Lsr)[ltr.isupper()])


def ChF(jr,n,DR,Affch,NB=9):
    L=len(DR)
    Verr=[0]*L
    pos=-1
    POS=(165-10*len(Affch),180-150*jr)[n>0]
    ch=1
    Num=102+100*jr
    if IA and not jr and n>0:
        Verr=[Affch[k] in ("BCFM",("hfF","bBcC")[Vie[0]<Vie[1]])[Jet[1]>5] for k in range(L)]
        sp(1)
    else:
        while not ((kd(KE) and n>0) or n==3 or L*NB==0 or (kd(KE) and n<1 and sum(Verr)<=NB)):
            ds("^ "[ch],20*pos+POS,Num,"b")
            sp(0.2*(ch!=0))
            pos=(pos+ch)%L
            while Affch[pos]==" " and ch:
                pos=(pos+ch)%L
            ds("^",20*pos+POS,Num,"b")
            ch=kd(KR)-kd(KL)

            if kd(KU) or kd(KD):
                while kd(KU) or kd(KD):1
                dess(Affch[pos],20*pos+POS,Num-15,"b","rg"[Verr[pos]])
                Verr[pos]=1-Verr[pos]
        while kd(KE) and n<3:1

    Nvl=tuple(Affch[i] for i in range(L) if (Verr[i] or n==3))*(n>0)
    chs[jr]=(chs[jr]+list(Nvl),list(Nvl)+chs[jr])[jr]
    fr(0,Num,320,16,"w")#ds(" "*32,0,102+100*jr) # efface les ^

    for i in range(L): # efface les faces des nouveaux dés choisis
        dess(Affch[i]*(Verr[i]>0 or n==3),20*i+POS,Num-15,"kw"[n>0],"kw"[n>0],"kw"[n>0])
        if n<1 and Verr[i]>0:
            chs[jr][i]=(" ",choice(choice(Des)))[n]

    return DR,Verr

def Duel(faces,jr,clrs=("b","r",dore)):
    symb(faces[jr],0,0,clrs)
    symb(faces[1-jr],1,faces[jr] in chs[0] or faces[jr].upper() in chs[0] or faces[1-jr] in chs[1] or faces[1-jr].upper() in chs[1],clrs)

def AV(Jr,ch):
    ch=min(max(ch,-Vie[Jr]),15-Vie[Jr])
    Vie[Jr]+=ch
    if ch:
        #for i in range(Vie[Jr]-ch*(ch>0)):
        #    affV(i,"g",Jr)
        for (clr1,clr2) in (("r","cyan"),("w","g")):
            for i in range(Vie[Jr]-ch*(ch>0),Vie[Jr]-ch*(ch<0)):
                affV(i,(clr1,clr2)[ch>0],Jr)
            sp(0.7)
    while min(Vie)==0:
        ds("Joueur "+"AB"[Vie.index(0)]+" a rejoint Odin...",10,105,"purple")

def affV(i,clr,j):
    fr(255-245*j+10*(i%5),32+100*j+8*(i//5),6,4,clr)

def symb(ltr,jr,pause=0,clrs=("b","g",dore),Nb=99,eff=0):
    L=len(chs[jr])
    for i in range(L):
        if ltr=="tout" or (chs[jr][i].lower()==ltr and Nb>0):
            dess(chs[jr][i],20*(i%16)+5+(L<17)*(160-10*L),87+100*jr-10*((L-1)//16)+20*(i//16),clrs[0],clrs[1],clrs[2])
            Nb -= 1
            chs[jr][i]=(chs[jr][i],"vV"[chs[jr][i].isupper()])[eff]
        if ltr=="tout" and Ulr[1-jr]:
            symb("b",jr,0,("cyan",clrs[1],clrs[2]),2+(NvDv[1-jr]-1)**2)
    sp(pause)


def calc(ok=True):
    if ok:
        (H[:],f[:],F[:],c[:],C[:],b[:],B[:],m[:],M[:],v[:],V[:])=tuple([chs[k].count(ltr) for k in (0,1)] for ltr in "hfFcCbBmMvV")
    #Sep=(max(H[J],c[K]+C[K]+v[K]+V[K]),max(f[J]+F[J],b[K]+B[K]),max(c[J]+C[J]+v[J]+V[J],H[K]),max(b[J]+B[J],f[K]+F[K]))
    chs[J]=list("h"*H[J]+" "*(c[K]+C[K]+v[K]+V[K]-H[J])+"f"*f[J]+"F"*F[J]+" "*(b[K]+B[K]-f[J]-F[J])+"v"*v[J]+"V"*V[J]+"c"*c[J]+"C"*C[J]+" "*(H[K]-c[J]-C[J]-v[J]-V[J])+"b"*b[J]+"B"*B[J]+" "*(f[K]+F[K]-b[J]-B[J])+"m"*m[J]+"M"*M[J]+" "*(m[K]+M[K]))
    chs[K]=list("v"*v[K]+"V"*V[K]+"c"*c[K]+"C"*C[K]+" "*(H[J]-c[K]-C[K]-v[K]-V[K])+"b"*b[K]+"B"*B[K]+" "*(f[J]+F[J]-b[K]-B[K])+"h"*H[K]+" "*(c[J]+C[J]+v[J]+V[J]-H[K])+"f"*f[K]+"F"*F[K]+" "*(b[J]+B[J]-f[K]-F[K])+" "*(m[J]+M[J])+"m"*m[K]+"M"*M[K])
    for Jr in (J,K):
        fr(0,65+100*Jr,320,49,"w")
        symb("tout",Jr)

def AJ(jr,nb=0):
    Jet[jr]=min(50,max(0,Jet[jr]+nb))
    if nb:
        for clr in ("r",dore):
            sp(0.7)
            affJ(jr,clr)

def affJ(jr,clr):
  ds(" "*jr*(Jet[jr]<10)+str(Jet[jr])+" "*(1-jr),32+235*jr,22+100*jr,clr)

def plt():
    fr(0,0,320,222,"w")
    for Jr in (J,K):
        Y=25+100*Jr
        ds("Joueur "+"AB"[Jr],120,Y+2,"g")
        for i in range(Vie[Jr]):
            affV(i,"g",Jr)
        dess("J",12+285*Jr,Y,dore,dore)
        affJ(Jr,dore)
        dess("d",10+285*Jr,Y+20,"purple")

def Tt(dv):
    if inf[dv][0]==NIV:
        co=inf[dv][NvDv[Jr]+1]
        ok=DvMch[Jr]==dv and Jet[Jr]>=co
        Ny=45+100*Jr
        dess("d"*(DvMch[Jr]==dv),10+285*Jr,Ny,"rb"[ok])
        if ok:
            chn=inf[dv][5]+str(Puiss)+inf[dv][-2]
            AJ(Jr,-co)
            AV(1-Jr,Vr[1-Jr]*co*NvDv[1-Jr])
            Nx=245*Jr-10*len(chn)*Jr
            ds(chn,30+Nx,Ny,"b")
            for k in (2,1):
                dess(inf[dv][-1][-k],125+Nx-30*k,3+Ny,"brown","brown","brown")
        sp(DvMch[Jr]==dv)
        return ok

def sacri():
    NbPV=Vie[Jr]-1
    while not kd(KE):
        NbPV=max(0,min(NbPV+kd(KR)-kd(KL),Vie[Jr]))
        for i in range(Vie[Jr]):
            affV(i,"kg"[i<NbPV],Jr)
        sp(0.2)
    #while kd(KE):1
    AJ((Jr,1-Jr)[DvMch[Jr]=="Tyr"],(Vie[Jr]-NbPV)*Puiss)
    AV(Jr,NbPV-Vie[Jr])

# Choix des divinités pour toute la partie
ds("Orlog",135,15,"g")
ds("Choisir le mode\n\n        Joueur vs Joueur\n          Joueur vs IA\n\n        Valider avec EXE",85,56,"purple")
IA=1
for k in range(6):
    fr(60,40+k//5*145,200,1,"b")
    dess("hCfbMF"[k],90+25*k,200)
while not kd(KE):
    IA=(IA,1-IA)[kd(KU)-kd(KD)]
    for k in (0,1):
        ds(" >"[k==IA],60,94+18*k,"r")
    sp(0.2)
while kd(KE):1
fr(0,0,320,240,"w")

DvCh,NvDv=[["Vidar"]*IA,[]],[-3,-3]
#DvCh=[[],[]]
J=choice((0,1))
K=1-J
for Jr in (J,K):
    if Jr or not IA:
        rg=-1
        ds("Joueur "+"AB"[Jr]+" : Choix des divinités\n                                ",2,5,"g")
        chgt=1
        while not kd(KE):
            rg=(rg+chgt)%20
            Dv=tuple(sorted(inf.keys()))[rg]
            if chgt:
                AffDv(Dv)
            chgt=kd(KR)-kd(KL)
            if kd(KU) or kd(KD):
                if Dv in DvCh[Jr]:
                    DvCh[Jr].remove(Dv)
                elif len(DvCh[Jr])<3:
                    DvCh[Jr].append(Dv)
                    DvCh[Jr].sort()
                ds("   ".join(DvCh[Jr])+"                                ",15,22,"purple")
                while kd(KU) or kd(KD):1
        while kd(KE):1
    DvCh[Jr].append("aucune")


# Initialisation

Vie=[15,15]
Jet=[0,0]

while 1:

    plt()

    # Phase de lancer

    Des=("ChhFbm","ChhfBm","ChhfbM","chhFBm","chhFbM","chhfBM")
    Rest=[Des[:]]*2

    chs,Vr,Ulr,Hl,Hmdl,Mmr,DvMch=[[],[]],[0,0],[0,0],[0,0],[0,0],[0,0],["",""]

    ds("   Phase de lancer      ",55,5,"orange")
    for n in (1,2,3):
        for jr in (J,K):
            DR=Rest[jr]
            R=range(len(DR))
            Affch=tuple(choice(DR[i]) for i in R)
            Y=87+100*jr
            ds("Phase "+str(n),125,Y-45,"g")
            fr(170-150*jr,Y-25,150,40,"w")

            for i in R:
                dess(Affch[i],20*i+180-150*jr,Y)
            sp(n==3)
            DR,Verr=ChF(jr,n,DR,Affch)

            for i in range(len(chs[jr])):
                dess(chs[jr][i],20*i+30+(270-20*len(chs[jr]))*jr,Y)
            sp(1)

            Rest[jr]=tuple(DR[i] for i in R if (Verr[i]==0)*(n<3))

    H,f,F,c,C,b,B,m,M,v,V=tuple([0,0] for k in range(11))
    calc()
    ds("    Phase de choix    ",50,5,"orange")

    #while not kd(KE):
    #    ds("Appuyer sur EXE",80,105,"purple")
    #while kd(KE):1
    sp(2)

    for Jr in (J,K):
        if IA and not Jr:
            DvMch[0]=("aucune","Vidar")[Jet[0]>=2]
            NvDv[0]=1+(Jet[0]>=3)
        else:
            fr(0,0,320,222,"w") # efface l'écran
            ds("Joueur "+"AB"[Jr]+" : Choisir la divinité \n   de la prochaine manche ",2,5,"g")
            fr(0,179,320,1,"purple")
            for jr in (J,K):
                Y=183+20*jr
                #ds("AB"[jr],-35,Y,"g")
                #for i in range(Vie[jr]):fr(67+8*(i%5),Y+6*(i//5),5,3,"g")
                dess("<",50,Y+5,"g")
                ds(str(Vie[jr]),63,Y,"g")
                dess("J",10,Y+3,dore,dore)
                ds(str(Jet[jr]),27,Y,dore)
                L=len(chs[jr])
                for i in range(L):
                    dess(chs[jr][i],93+(43-2*L)*i,Y+3)
            rg=-1
            chgt=1
            while not kd(KE):
                rg=(rg+chgt)%len(DvCh[Jr])
                Divi=DvCh[Jr][rg]
                if chgt or kd(KU)+kd(KD):
                    NvDv[Jr]=(NvDv[Jr]-kd(KU)+kd(KD))%3
                    AffDv(Divi)
                chgt=kd(KR)-kd(KL)


            while kd(KE):1
            DvMch[Jr]=DvCh[Jr][rg]
            NvDv[Jr]+=1 # pour avoir un niveau entre 1 et 3


    plt()
    ds("Phase de résolution    ",65,5,"orange")
    calc(False)


    for NIV in range(1,10):
        for Jr in (J,K):
            if DvMch[Jr]!="aucune":
                Puiss=inf[DvMch[Jr]][5+NvDv[Jr]]

    # divinité priorité 1
            if Tt("Var"):
                Vr[Jr]=1
            if Tt("Thrymr"):
                dess("d",295-285*Jr,145-100*Jr,"cyan")
                sp(1)
                NvDv[1-Jr]=max(0,NvDv[1-Jr]-NvDv[Jr])
                DvMch[1-Jr]=(DvMch[1-Jr],"aucune")[NvDv[1-Jr]==0]

    # divinité priorité 2
            if Tt("Freyja"):
                chs[Jr]+=[choice(choice(Des)) for k in range(NvDv[Jr])]
                calc()
            if DvMch[Jr] in ("Frigg","Loki") and Tt(DvMch[Jr]):
                Nb=sum(ChF(1-Jr,0-(DvMch[Jr]=="Frigg"),chs[1-Jr],chs[1-Jr],Puiss)[1])
                ChF(Jr,-1,chs[Jr],chs[Jr],(Puiss-Nb)*(DvMch[Jr]=="Frigg"))
                sp(1)
                calc()

    # divinité priorité 3
            if Tt("Skuld"):
                symb("f",Jr,1,("b","purple",dore))
                AJ(1-Jr,-(f[Jr]+F[Jr])*Puiss)
                #symb("f",Jr)
            if Tt("Tyr"):
                sacri()

    # divinité priorité 4
            if Tt("Vidar"):
                for effacer in (False,True):
                    symb("c",1-Jr,1,("rw"[effacer],"g",dore),Puiss,effacer)
                calc()
            if DvMch[Jr] in ("Ullr","Hel","Heimdal","Mimir") and Tt(DvMch[Jr]):
                (Ulr,Hl,Hmdl,Mmr)[("Ullr","Hel","Heimdal","Mimir").index(DvMch[Jr])][Jr]=1
            if DvMch[Jr] in ("Baldr","Brunehilde","Freyr","Skadi") and Tt(DvMch[Jr]):
                b[Jr]+=(DvMch[Jr]=="Baldr")*NvDv[Jr]*(b[Jr]+B[Jr])
                c[Jr]+=(DvMch[Jr]=="Baldr")*NvDv[Jr]*(c[Jr]+C[Jr])
                H[Jr]+=(DvMch[Jr]=="Brunehilde")*int((Puiss-1)*H[Jr]+0.51)
                Liste=(H[Jr],f[Jr]+F[Jr],c[Jr]+C[Jr],b[Jr]+B[Jr],m[Jr]+M[Jr])
                (H,f,c,b,m)[choice([k for k in range(5) if Liste[k]==max(Liste)])][Jr]+=(DvMch[Jr]=="Freyr")*int(Puiss)
                f[Jr]+=(DvMch[Jr]=="Skadi")*(f[Jr]+F[Jr])*NvDv[Jr]
                calc(False)
            if Tt("Bragi"):
                symb("m",Jr,0,("b","purple",dore))
                AJ(Jr,(m[Jr]+M[Jr])*Puiss)

    # action des liserés
            if F[Jr]+C[Jr]+B[Jr]+M[Jr]+V[Jr] and NIV==5:
                sp(0.7)
                symb("tout",Jr,1,"bgr")
                AJ(Jr,F[Jr]+C[Jr]+B[Jr]+M[Jr]+V[Jr])
                symb("tout",Jr,0.5)


    # Phase d'affrontement des dés
            k=Jr
            if NIV==6:
                Duel(".v",k,"www")
                Duel("hc",k)
                MAX=max(0,H[k]-c[1-k]-C[1-k])
                AV(1-k,Hmdl[1-k]*min(H[k],c[1-k]+C[1-k])*NvDv[1-k])
                AV(1-k,-MAX)
                AJ(1-k,Mmr[1-k]*MAX*NvDv[1-k])
                AV(k,Hl[k]*MAX*NvDv[k])
                Duel("hc",k,"www")

                Duel("fb",k)
                UU=Ulr[k]*(2+(NvDv[k]-1)**2)
                symb("b",1-k,0,("cyan","r",dore),UU)
                MAX=max(0,f[k]+F[k]-b[1-k]-B[1-k])
                MIN=min(f[k]+F[k],b[1-k]+B[1-k])
                AV(1-k,Hmdl[1-k]*MIN*NvDv[1-k])
                AV(1-k,-MAX-min(MIN,UU))
                AJ(1-k,Mmr[1-k]*MAX*NvDv[1-k])
                Duel("fb",k,"www")

            if NIV==7:
                Duel("m.",k)
                if (m[k]+M[k])*Jet[1-k]:
                    vol=min(m[k]+M[k],Jet[1-k])
                    AJ(1-k,-vol)
                    AJ(k,vol)
                Duel("m.",k,"www")


    # divinité de priorité 6+2
            if Tt("Thor"):
                AV(1-Jr,-Puiss)

    # divinité de priorité 7+2
            if Tt("Idunn"):
                AV(Jr,Puiss)
            if Tt("Odin"):
                sacri()

    J,K=K,J