Created
January 10, 2024 16:28
-
-
Save Kaki-In/def1ac3551622ef43df557a7012917ae to your computer and use it in GitHub Desktop.
Puis4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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