Simple checkers game
# Checkers 10x10 NumWorks # Created by Alvar Laigna - https://alvarlaigna.com # Arrows:move OK/EXE:select /:resign -:draw from kandinsky import fill_rect as F,draw_string as D from ion import keydown as K from time import sleep as Z,monotonic as M N=10;pl=1;S=222//N;Q=2;R=(S-2*Q-2)//2;J=(S-2*R)//2 cr=[] for _a in range(R*2): a=b=-1 for _b in range(R*2+1): if(_b-R)**2+(_a-R)**2<=R*R: if a<0:a=_b b=_b cr.append((a,b-a+1)if a>=0 else None) UI=(255,181,59);C0,C1=(0,85,66),(231,227,206) LT,DK=(223,175,121),(74,41,51) RE,GR,BL=(255,0,0),(48,246,49),(0,0,255) BX=S*N;tl=lambda a,b:BX+(320-BX-(len(str(a))+b)*10)//2 ww=wb=0 CL={1:LT,2:(255,)*3,6:DK,7:(0,)*3} okv=1 if K(4)or K(52) else 0 def okd():return K(4)or K(52) def okp(): global okv d=okd() if d and not okv: okv=1 return True if not d:okv=0 return False def dp(cx,cy): p=bd[cy][cx] if not p:return c=CL[p];px,py=cx*S+J,cy*S+J for i in range(len(cr)): s=cr[i] if s:F(px+s[0],py+i,s[1],1,c) def ac(x,y,p,r,bj): a1,a2,e1,e2=(1,2,6,7)if p<4 else(6,7,1,2) if p in(1,6): for dx in(-1,1): for dy in(-1,1): px,py=x+dx,y+dy if 0<=px<N and 0<=py<N and bj[py][px]in(e1,e2): nx,ny=x+2*dx,y+2*dy if 0<=nx<N and 0<=ny<N and bj[ny][nx]==0: if r==0:tp.append([x,y,0,r]) tp.append([px,py,2,r+1]);tp.append([nx,ny,1,r+1]) nb=[w[:]for w in bj] nb[py][px],nb[ny][nx],nb[y][x]=0,nb[y][x],0 ac(nx,ny,p,r+1,nb) else: for dx in(-1,1): for dy in(-1,1): for d in range(1,N): px,py=x+dx*d,y+dy*d if not(0<=px<N and 0<=py<N)or bj[py][px]in(a1,a2):break if bj[py][px]in(e1,e2): for i in range(1,N): nx,ny=px+dx*i,py+dy*i if not(0<=nx<N and 0<=ny<N)or bj[ny][nx]!=0:break if r==0:tp.append([x,y,0,r]) tp.append([px,py,2,r+1]);tp.append([nx,ny,1,r+1]) nb=[w[:]for w in bj] nb[py][px],nb[ny][nx],nb[y][x]=0,nb[y][x],0 ac(nx,ny,p,r+1,nb) break def fc(): global tp,og,np tp=[] for a in range(N): for b in range(N): p=bd[b][a] if(pl==1 and p>3)or(pl==2 and p<4):continue if p:ac(a,b,p,0,bd) if len(tp)>1: og,np,hv=1,[],0 for vx,vy,ch,r in tp: if r>hv:hv=r rp=0 for i,(vx,vy,ch,r)in enumerate(tp): if r==hv and ch==1: ok2,na,pb2=False,hv,[] np.append([]) for ni,(nx,ny,nc,nr)in enumerate(reversed(tp)): if not ok2 and ni>=len(tp)-1-i and(nx,ny,nc,r)==(vx,vy,ch,r):ok2=True if ok2 and nr==na: pb2.append([nx,ny,nc]) if nc==2:na-=1 if nr==0:break for v in reversed(pb2):np[rp].append(v) rp+=1 def sm(xm,ym,l=0): for i in range(2): mx,my=(xp,yp)if i==0 else(xm,ym) p=bd[my][mx] if(pl==1 and p>4)or(pl==2 and p<3):continue if og==1 and l==2:return True if og==i==1 or(i==0 and l==2):continue if p in(1,6): py=my-1 if p==1 else my+1 for dx in(-1,1): px=mx+dx if 0<=px<N and bd[py][px]==0: if l==2:return True if i==1: F(px*S,py*S,S,S,GR) if l==0:F(px*S+Q,py*S+Q,S-Q*2,S-Q*2,fl[py][px]) else:bf.append([px,py,1]) else:F(px*S,py*S,S,S,fl[py][px]) dp(px,py) elif p in(2,7): for dd in range(4): for d in range(1,N): px,py=mx+(-d if dd>1 else d),my+(d if dd%2==0 else-d) if 0<=px<N and 0<=py<N: if bd[py][px]==0: if l==2:return True if i==1: F(px*S,py*S,S,S,GR) if l==0:F(px*S+Q,py*S+Q,S-Q*2,S-Q*2,fl[py][px]) else:bf.append([px,py,1]) else:F(px*S,py*S,S,S,fl[py][px]) else:break def ok(): global pl,vp,bf,new,sh,pw,pb,bx,by,og,it if og: for ps in np: if ps[0][0]==x and ps[0][1]==y:bf.append(ps[1]);bf.append(ps[2]) for vx,vy,ch in bf:F(vx*S,vy*S,S,S,fl[vy][vx]);dp(vx,vy) if vp==0 and((pl==1 and bd[y][x]in(1,2))or(pl==2 and bd[y][x]in(6,7))): if og: ag=False for ps in np: if ps[0][0]==x and ps[0][1]==y:ag=True if not ag:return vp,bx,by=1,x,y if not og:sm(x,y,1) else: for vx,vy,ch in bf: if ch==1:F(vx*S,vy*S,S,S,GR) elif ch==2:F(vx*S,vy*S,S,S,RE) elif vp==1 and x==bx and y==by and it==0:vp,bf,bx,by=0,[],0,0 elif vp==1 and[x,y,1]in bf: bd[y][x],bd[by][bx],it=bd[by][bx],0,1 F(bx*S,by*S,S,S,fl[by][bx]);dp(bx,by) rm=False if og==1: for i,(vx,vy,ch)in enumerate(bf):rp=i-1 if vx==x and vy==y else 0 px,py=bf[rp][0],bf[rp][1] if bd[py][px]>4:pw=pw+1 if bd[py][px]==6 else pw+5 elif bd[py][px]<3:pb=pb+1 if bd[py][px]==1 else pb+5 D("Pts:"+str(pw),tl(pw,4),143,LT);D("Pts:"+str(pb),tl(pb,4),62,DK) bd[py][px]=0;F(px*S,py*S,S,S,fl[py][px]) dl=[] for i,ps in enumerate(np): if ps[0][0]!=bx or ps[0][1]!=by or ps[1][0]!=px or ps[1][1]!=py or ps[2][0]!=x or ps[2][1]!=y:dl.append(ps) else: np[i].remove(ps[0]);np[i].remove(ps[0]) if len(ps)>1:rm=True for i in dl:np.remove(i) bf=[] if not rm: ck() if(bd[y][x]==1 and y==0)or(bd[y][x]==6 and y==N-1):bd[y][x]+=1;dp(x,y) vp,xp,yp,og,it=0,bx,by,0,0 sh=sh+1 if pl==2 else sh;pl=2 if pl==1 else 1 D("Turn:"+str(sh),tl(sh,5),89,BL);D("P"+str(pl),tl(pl,2),116,BL) fc();ce() else: bx,by,it=x,y,1 for ps in np: if ps[0][0]==x and ps[0][1]==y: bf.append(ps[1]);bf.append(ps[2]) if ps[0][2]==1:F(vx*S,vy*S,S,S,GR) elif ps[0][2]==2:F(vx*S,vy*S,S,S,RE) new=True def dt(): global pl,tm,tw,tb if M()-tm>=1: for i in(1,2): if pl!=i:continue t=tw if i==1 else tb t-=M()-tm if i==1:tw=t else:tb=t m,s=str(int(t//60)),str(int(t%60)) c=RE if t<TM/10 else(LT if i==1 else DK) if len(m)==1:m="0"+m if len(s)==1:s="0"+s D(m+":"+s,tl(m+s,1),196 if i==1 else 8,c) if m=="00"and s=="01":gw(pl) tm=M() def sc(xm,ym,i): for cp in np: at=0 for ni,(vx,vy,ch)in enumerate(cp): if ni==0 and vx==xm and vy==ym:at=1 if ch==0 and not(vx==xm and vy==ym):break if ni==0:continue if at: if i==0: if ch==1:F(vx*S,vy*S,S,S,GR) elif ch==2:F(vx*S,vy*S,S,S,RE) F(vx*S+Q,vy*S+Q,S-Q*2,S-Q*2,fl[vy][vx]);dp(vx,vy) else:F(vx*S,vy*S,S,S,fl[vy][vx]);dp(vx,vy) def sp(): if vp==0: for i in range(2): xm,ym=(x,y)if i==0 else(xp,yp) if og==0:sm(x,y) else:sc(xm,ym,i) elif vp==1: if og==0: for vx,vy,ch in bf: if ch==1:F(vx*S,vy*S,S,S,GR) elif ch==2:F(vx*S,vy*S,S,S,RE) dp(vx,vy) else: sc(bx,by,0) for vx,vy,ch in bf: if ch==1:F(vx*S,vy*S,S,S,GR) elif ch==2:F(vx*S,vy*S,S,S,RE) dp(vx,vy) def ck(): global hh,hc,hc2 hh.append([[bx,by],[x,y]]) if og:hh=[] if len(hh)==6: rt=True for a,b in((0,2),(1,3)): if hh[a]!=hh[b+2]:rt=False;break for c in range(2): if hh[a][c]!=hh[b][1-c]:rt=False;break if rt:gt() else:hh.pop(0) if not og and bd[y][x]not in(1,6):hc+=1 else:hc=0 if hc==50:gt() pn={0:0,1:0,2:0,6:0,7:0} for a in range(N): for b in range(N):pn[bd[b][a]]+=1 if pn[1]==pn[6]==0 and[pn[2],pn[7]]in([2,1],[1,1],[1,2]):gt() if hc2==0: for a,b in((2,7),(7,2)): if pn[a-1]==0 and pn[a]==1 and pn[b-1]+pn[b]==3 and pn[b]>0:hc2+=1 else:hc2+=1 if hc2==32:gt() def ce(): for a in range(N): for b in range(N): if sm(a,b,2):return gw(pl) def msg(t,fn): F(0,0,BX,BX,CL[7]) D(t,BX//2-len(t)*5,82);D("3",BX//2-5,112) D("Back=cancel",BX//2-55,142);Z(1) rt=M()+3 while True: D(str(max(0,int(rt-M()))),BX//2-5,112) if K(17):Z(0.3);break elif M()-rt>0:fn();return for a in range(N): for b in range(N):F(a*S,b*S,S,S,fl[b][a]);dp(a,b) def gw(p): dp(x,y) global game,ww,wb Z(2);F(0,0,320,222,(255,)*3) if p==1:wb+=1;t="Black wins!" else:ww+=1;t="White wins!" D(t,160-len(t)*5,102);Z(4);game=False def gt(): dp(x,y) global game Z(2);F(0,0,320,222,(255,)*3) D("Draw!",135,96);D("Nobody wins",80,126) Z(4);game=False while True: F(0,0,320,222,UI) fl=[[C1]*N for i in range(N)] for a in range(N): for b in range(N): if(N*2-a+b)%2==1:fl[a][b]=C0 F(a*S,b*S,S,S,fl[a][b]) bd=[[0]*N for i in range(N)] v=0 if N%2 else 1 for a in range(N): for b in range(N): if(N*2-a+b)%2==1: if b<N//2-v:bd[b][a]=6 elif b>N//2:bd[b][a]=1 dp(a,b) x=y=xp=yp=mv=vp=og=bx=by=it=0;bf=[] hh,hc,hc2=[],0,0;TM=600;tw=tb=TM;tm=M() pw=pb=sh=0 D("Turn:"+str(sh),tl(sh,5),89,BL);D("P"+str(pl),tl(pl,2),116,BL) D("Pts:"+str(pw),tl(pw,4),143,LT);D("Pts:"+str(pb),tl(pb,4),62,DK) D("W:"+str(ww),tl(ww,2),169,LT);D("W:"+str(wb),tl(wb,2),35,DK) for i in(1,2): t=tw if i==1 else tb m,s=str(int(t//60)),str(int(t%60)) if len(m)==1:m="0"+m if len(s)==1:s="0"+s D(m+":"+s,tl(m+s,1),196 if i==1 else 8,LT if i==1 else DK) game=new=True while game: if new: new,mv=False,0 F(xp*S,yp*S,S,S,fl[yp][xp]);dp(xp,yp) sp();F(x*S,y*S,S,S,BL);dp(x,y);Z(0.15) dt() if K(1)and y>0:xp,yp,y,new,mv=x,y,y-1,True,1 elif K(2)and y<N-1:xp,yp,y,new,mv=x,y,y+1,True,1 if K(0)and x>0:xp,yp,x,new=x,y if mv==0 else yp,x-1,True elif K(3)and x<N-1:xp,yp,x,new=x,y if mv==0 else yp,x+1,True elif okp():ok() elif K(12):msg("Resign?",lambda:gw(pl)) elif K(13):msg("Draw?",gt)