Skip to content

Instantly share code, notes, and snippets.

@Kaki-In
Created January 10, 2024 16:28
Show Gist options
  • Save Kaki-In/def1ac3551622ef43df557a7012917ae to your computer and use it in GitHub Desktop.
Save Kaki-In/def1ac3551622ef43df557a7012917ae to your computer and use it in GitHub Desktop.
Puis4
class Grid():
def __init__(self,x,y,grid=None):
if grid:self._grid=grid
else:self._grid=[None for i in range(x*y)]
self._dims=[x,y]
def setAt(self,x,y,value):
if not x in range(self._dims[0]) or not y in range(self._dims[1]):raise ValueError("invalid dimensions")
self._grid[x+y*self._dims[0]]=value
def getAt(self,x,y):
if not x in range(self._dims[0]) or not y in range(self._dims[1]):raise ValueError("invalid dimensions")
return self._grid[x+y*self._dims[0]]
def lines(self,number,max=None):
l=[]
a=[1,self._dims[0]-1,self._dims[0],self._dims[0]+1]
e=[(1,0),(-1,1),(0,1),(1,1)]
rp=range(1,number)
rd=range(4)
for i in range(len(self._grid)):
x,y=i%self._dims[0],i//self._dims[0]
piece=self._grid[i]
if piece is None:continue
for d in rd:
da=a[d]
de=e[d]
v=True
for p in rp:
nx,ny=x+de[0]*p,y+de[1]*p
if nx<0 or nx>=self._dims[0] or ny<0 or ny>=self._dims[1]:
v=False
break
elif self._grid[i+da*p]!=piece:
v=False
break
if v:
l.append(((x,y),de))
if max:
if len(l)==max:return l
return l
def row(self,y):
return self._grid[self._dims[0]*y:self._dims[0]*(y+1)]
def column(self,x):
return [self._grid[x+self._dims[0]*y] for y in range(self._dims[1])]
def copy(self):
g=Grid(self._dims[0],self._dims[1],self._grid.copy())
return g
class Puissance4Grid(Grid):
def __init__(self,grid=None,turn=True):
super().__init__(7,6,grid)
self._turn=turn
self._sel=3
def placePiece(self):
n=5
c=self.column(self._sel)
while not c[n] is None:n-=1
self.setAt(self._sel,n,self._turn)
self._turn=not self._turn
if None in self._grid:
while self.column(self._sel)[0] is not None:self._sel=(self._sel+1)%7
def placePieceAt(self,x):
n=5
c=self.column(x)
while not c[n] is None:n-=1
self.setAt(x,n,self._turn)
self._turn=not self._turn
def selectNext(self):
while True:
self._sel=(self._sel+1)%7
if self.column(self._sel)[0] is None:break
def selectPrevious(self):
while True:
self._sel=(self._sel-1)%7
if self.column(self._sel)[0] is None:break
def selected(self):
return self._sel
def playerTurn(self):
return self._turn
def hasFinished(self):
return (not None in self._grid) or self.lines(4)
def copy(self):
g=Puissance4Grid(self._grid.copy(),self._turn)
return g
class Puissance4Display():
def __init__(self,grid):
self._grid=grid
def piecePlace(self,x,y):
return x*30+57,y*30+32
def drawPiece(self,x,y):
piece=self._grid.getAt(x,y)
x,y=self.piecePlace(x,y)
if piece is not None:
if piece:c=(255,0,0)
else:c=(255,200,0)
fill_rect(x,y,27,27,c)
def drawLine(self,x,y,w,h,c):
fill_rect(x,y,w,h,c)
c2=[255-(255-i)/2 for i in c]
fill_rect(x-1,y-1,w+2,1,c2)
fill_rect(x-1,y-1,1,h+2,c2)
c3=[i/2 for i in c]
fill_rect(x+w,y-1,1,h+2,c3)
fill_rect(x-1,y+h,w+2,1,c3)
def drawGrid(self):
for i in range(8):
self.drawLine(55+i*30,10,1,200,GRID_COLOR)
for i in range(7):
self.drawLine(55,30+i*30,210,1,GRID_COLOR)
for i in range(6):
for j in range(7):
self.drawPiece(j,i)
def draw(self):
self.drawGrid()
fill_rect(0,0,320,8,(255,255,255))
if self._grid.hasFinished():
l=self._grid.lines(4)
for k in l:
a=list(k[0])
for i in range(4):
x,y=self.piecePlace(*a)
fill_rect(x+6,y+6,15,15,(255,255,255))
a[0]+=k[1][0]
a[1]+=k[1][1]
else:
if self._grid.playerTurn():c=(255,0,0)
else:c=(255,200,0)
col=self._grid.selected()
x,y=self.piecePlace(col,-1)
for i in range(3):
fill_rect(x+10+i,y+i,5-i*2,1,c)
def playAnimation(self):
piece=self._grid.playerTurn()
n=5
c=self._grid.column(self._grid.selected())
while not c[n] is None:n-=1
if piece:col=(255,0,0)
else:col=(255,200,0)
for i in range(n+2):
x,y=self.piecePlace(self._grid.selected(),i-1)
for j in range(27):
fill_rect(x,y-30+j,27,1,(255,255,255))
fill_rect(x,y+j,27,1,col)
sleep(0.002)
class Puissance4Game():
def __init__(self,p1,p2):
self._players=p1,p2
for i in self._players:
if hasattr(i,"restart"):i.restart()
self._grid=Puissance4Grid()
self._disp=Puissance4Display(self._grid)
self._n=0
def ChuckNorris(self):
try:return [type(i) for i in self._players].index(ChuckNorrisPlayer)
except:return None
def main(self):
self._disp.draw()
while not self._grid.hasFinished():
a=self.ChuckNorris()
self._players[self._grid.playerTurn()].play(self._grid,self._disp)
if a is 0 and self._n==6:
g=self._grid.lines(3)
if g:
for i in g:
if self._grid.getAt(*i[0])==True:
self._grid._turn=not self._grid.playerTurn()
break
self._disp.playAnimation()
self._grid.placePiece()
self._disp.draw()
self._n+=1
def winner(self):
a=self._grid.lines(4)
if a:
return self._grid.getAt(*a[0][0])
def play(self):
try:self.main()
except KeyboardInterrupt:pass
class Puissance4PhysicPlayer:
def play(grid,disp):
k=-1
while True:
r=False
if keydown(KEY_LEFT) and k!=KEY_LEFT:
grid.selectPrevious()
k=KEY_LEFT
r=True
if keydown(KEY_RIGHT) and k!=KEY_RIGHT:
grid.selectNext()
k=KEY_RIGHT
r=True
if keydown(KEY_OK) and k!=KEY_OK:return
if r:disp.draw()
elif not keydown(k):k=-1
class Puissance4RandomizedPlayer():
def play(grid,disp):
import random
n=random.randrange(7)
while grid.column(n)[0] is not None:n=random.randrange(7)
while grid.selected()>n:
grid.selectPrevious()
disp.draw()
sleep(0.1)
while grid.selected()<n:
grid.selectNext()
disp.draw()
sleep(0.1)
class Puissance4VirtualPlayer():
def __init__(self,depth):
self.depth=depth
def betterPlace(self,grid,depth):
if depth<0:return [(0,0)]
if grid._grid.count(not grid.playerTurn())<2:return [(0,3)]
bl=[]
for i in range(7):
gcopy=grid.copy()
if gcopy.column(i)[0] is not None:continue
gcopy.placePieceAt(i)
if gcopy.lines(4,1):ps=1
else:
a=self.betterPlace(gcopy,depth-1)
ps=-sum([i[0] for i in a])
bl.append((ps,i))
bl.sort()
bl.reverse()
return bl
def play(self,grid,disp):
from random import choice
n=monotonic()
l=self.betterPlace(grid,self.depth)
f=l[0][0]
for i in l.copy():
if i[0]!=f:l.remove(i)
l=choice(l)[1]
g=grid.selected()
while g!=l:
if l>g:grid.selectNext()
else:grid.selectPrevious()
disp.draw()
g=grid.selected()
sleep(0.1)
class ChuckNorrisPlayer():
def __init__(self):
self._piecePlaying=0
def restart(self):
self._piecePlaying=0
def play(self,grid,disp):
grid.setAt(self._piecePlaying,5,None)
while grid.selected()!=self._piecePlaying:
grid.selectNext()
disp.draw()
self._piecePlaying+=1
GRID_COLOR=(0,0,255)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment