checkers.py

Created by laigna

Created on March 14, 2026

8.71 KB

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)

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.