from mycolors import * from pieces import * from copy import deepcopy from math import sqrt,atan,cos,sin import pygame import random import time sign=lambda x:x>=0 class Board: def __init__(self): self.orientation=1 #Off self.flipping=0 #Off self.size=(8,8) self.state=0 self.won=False self.draw=False self.winner=None self.historic=[] self.grid_historic=[] self.action=None self.moves_selecter=[] self.piece_selecter=None self.message="" self.promoted=[Queen,Tower,Bishop,Horse] self.alphabet="abcdefghijklmnopqrstuvwxyz" self.last_action_shown=True self.colors=["White","Black"] self.time=time.time() self.moving_shown=False self.moving=None self.moving_time=0 self.moving_max_time=2 self.moving_position=None self.wait=False self.generate() def generate(self): self.grid= [["t1","h1","b1","g1","q1","b1","h1","t1"], ["k1","k1","k1","k1","k1","k1","k1","k1"], ["nn","nn","nn","nn","nn","nn","nn","nn"], ["nn","nn","nn","nn","nn","nn","nn","nn"], ["nn","nn","nn","nn","nn","nn","nn","nn"], ["nn","nn","nn","nn","nn","nn","nn","nn"], ["k2","k2","k2","k2","k2","k2","k2","k2"], ["t2","h2","b2","g2","q2","b2","h2","t2"]] sx,sy=self.size for y in range(sy): for x in range(sx): p=(x,y) small_id=self.grid[y][x] if small_id=="k1": entity=Pawn(1,p) elif small_id=="k2": entity=Pawn(2,p) elif small_id=="h1": entity=Horse(1,p) elif small_id=="h2": entity=Horse(2,p) elif small_id=="b1": entity=Bishop(1,p) elif small_id=="b2": entity=Bishop(2,p) elif small_id=="b1": entity=Bishop(1,p) elif small_id=="b2": entity=Bishop(2,p) elif small_id=="t1": entity=Tower(1,p) elif small_id=="t2": entity=Tower(2,p) elif small_id=="g1": entity=King(1,p) elif small_id=="g2": entity=King(2,p) elif small_id=="q1": entity=Queen(1,p) elif small_id=="q2": entity=Queen(2,p) else: entity=None self.grid[y][x]=entity def __repr__(self): sx,sy=self.size presentation="" for y in range(sy): presentation+="|" for x in range(sx): entity=self.grid[y][x] if not entity: presentation+=" " else: nature=entity.id nature=nature+str(entity.side)+" "*(6-len(nature)) presentation+=nature presentation+="|" presentation+="\n" return presentation def debug(self): pass #print("DEBUG:") #print(self.state) #print(self.piece_selecter) #print(self.moves_selecter) #print("") def getPresentation(self,state,action): sx,sy=self.size piece,position,move=action name=piece.name side=piece.side x,y=move spot=self.alphabet[x%sx]+str(sy-y) text="|"+str(state)+"| : "+str(self.colors[side-1])+" "+name+" moved in "+spot return text def summarize(self,historic): for state in range(len(historic)): action=historic[state] self.message+=self.getPresentation(state,action) def isAlive(self,id,side): if self.locateById(id,side) is not None: return True else: return False def locateChoices(self,side): ##print(side) output=[] sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity is None: continue if entity.side!=side: continue moves=self.getMoves(entity,(x,y)) if len(moves)==0: continue for move in moves: output.append((entity,(x,y),move)) #print(output) return output def locateById(self,id,side): sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity is not None: if entity.side is side and entity.id is id: return (x,y) return None def locateByEntity(self,piece): sx,sy=self.size for y in range(sy): for x in range(sx): if self.grid[y][x] is piece: return (x,y) return None def locateSidePieces(self,side): positions=[] sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity: if entity.side==side: positions.append((x,y)) return positions def locateAllPieces(self): positions=[] sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity: positions.append((x,y)) return positions def getSidePieces(self,side): pieces=[] sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity: if entity.side==side: pieces.append(entity) return pieces def getAllPieces(self): pieces=[] sx,sy=self.size for y in range(sy): for x in range(sx): entity=self.grid[y][x] if entity: pieces.append(entity) return pieces def correctMoves(self,moves): new_moves=[] for move in moves: x,y=move if self.inGrid(x,y): new_moves.append(move) return new_moves def getSideMoves(self,side,raw=True): pieces=self.getSidePieces(side) moves=[] for piece in pieces: moves+=self.getMoves(piece,piece.position,raw) return moves def removeFromSets(self,set1,set2): #Remove all the elements of set1 that are in set2 new_set=[] for e1 in set1: if not e1 in set2: new_set.append(e1) return new_set def getSuicideMoves(self,piece,moves): enemy_side=self.otherSide(piece.side) all_enemy_moves=self.getSideMoves(enemy_side) new_moves=[] for move in moves: if move in all_enemy_moves: new_moves.append(move) return new_moves def oldRemoveSuicideMoves(self,piece,moves): #Prevent the king's player from dying on the next turn by removing moves that will get it killed enemy_side=self.otherSide(piece.side) all_enemy_moves=self.getSideMoves(enemy_side) moves=self.removeFromSets(moves,all_enemy_moves) return moves def removeSuicideMoves(self,dying_piece,choosed_piece,moves): new_moves=[] #print("In removeSuicideMoves:") #print("moves:",moves) #print("dying:",dying) #print("dying_piece:",dying_piece) #print("choosed_piece:",choosed_piece) #print("") for move in moves: dying=self.canDieNextTurn(dying_piece,choosed_piece,move) if not dying: new_moves.append(move) return new_moves def canDieNextTurn(self,dying_piece,choosed_piece,choosed_move): new_board=deepcopy(self) new_board.choose(choosed_piece,choosed_piece.position,choosed_move) enemy_side=new_board.otherSide(dying_piece.side) all_enemy_moves=new_board.getSideMoves(enemy_side,1) #print("In canDieNextTurn:") #print("choosed_piece and choosed_move:",choosed_piece,choosed_move) #print("dying_piece:",dying_piece) #print("enemy_move:",all_enemy_moves) #print("new_board:") #print(new_board) #print("") for enemy_move in all_enemy_moves: if enemy_move==dying_piece.position: return True return False def otherSide(self,side): return side%2+1 def getMoves(self,piece,position,raw=False): #print("In getMoves") #print("piece:",piece) #print("position:",position) moves=self.extractMoves(piece,position) #print("normal moves",normal_moves) if isinstance(piece,King) or isinstance(piece,Pawn): moves+=self.extractSpecialMoves(piece,position) #print("special moves",special_moves) #print("") #moves=normal_moves+special_moves #moves=self.correctMoves(moves) if not raw: king=self.getById("King",piece.side) #moves=self.removeSuicideMoves(king,piece,moves) random.shuffle(moves) print(moves) return moves def getRawMoves(self,piece): moves=self.extractMoves(piece,piece.position) if isinstance(piece,King) or isinstance(piece,Pawn): moves+=self.extractSpecialMoves(piece,position) random.shuffle(moves) return moves def extractMoves(self,piece,position): vectors,norm=piece.moves px,py=position sx,sy=self.size moves=[] orientation=piece.side%2*2-1 for vector in vectors: vx,vy=vector n=1 while n<=norm: x=px+vx*n y=py+orientation*vy*n if 0<=x and x0: piece,position,move=self.historic[-1] if isinstance(piece,Pawn): ex,ey=position emx,emy=move x,y=(px-1,py) if self.inGrid(x,y): if (x,y)==(emx,emy) and (ex,ey-o)==(emx,emy): moves.append((x,y+o)) x,y=(px+1,py) if self.inGrid(x,y): if (x,y)==(emx,emy) and (ex,ey-o)==(emx,emy): moves.append((x,y+o)) return moves def getRoqueMoves(self,piece): o=((self.state+1)%2)*2-1 moves=[] px,py=piece.position if piece.state==0 and not piece.check: neighbours=self.getNeighbours(piece) for neighbour in neighbours: if isinstance(neighbour,Tower): if neighbour.state==0: if neighbour.side is piece.side: nx,ny=neighbour.position px,py=piece.position dx=int((nx-px)/abs(nx-px)) position=(px+2*dx,py) moves.append(position) return moves def getTowerMoveFromRoque(self,piece,move): px,py=piece.position mx,my=move if abs(mx-px)!=2: return None else: o=int((mx-px)/(abs(mx-px))) print("o:",o) tower_move=(px+o,py) x=px+o while abs(x)<10: print("x:",x) print("entity:",self.grid[py][x]) tower=self.grid[py][x] if tower: return (tower,tower_move) x+=o return None def getNeighbours(self,piece): vectors,norm=piece.moves sx,sy=self.size m=max(sx,sy) norm=m px,py=piece.position neighbours=[] orientation=((self.state+1)%2)*2-1 for vector in vectors: vx,vy=vector n=1 while n<=norm: x=px+vx*n y=py+orientation*vy*n if self.inGrid(x,y): if self.grid[y][x]: entity=self.grid[y][x] if entity.side is piece.side: neighbours.append(entity) break else: break n=n+1 return neighbours def getById(self,id,side): position=self.locateById(id,side) if position: x,y=position entity=self.grid[y][x] return entity else: return None def updateCheck(self): player_side=(self.state+1)%2+1 enemy_side=self.state%2+1 #print("State and sides:",self.state,player_side,enemy_side) king=self.getById("King",player_side) king.check=self.isInCheck(king) def isInCheck(self,king): enemy_side=king.side%2+1 pieces=self.getSidePieces(enemy_side) for piece in pieces: if king in self.canKill(piece): return True return False def canKill(self,killer): moves=self.getMoves(killer,killer.position) #print("moves:",moves) victims=[] for move in moves: x,y=move #print("canKill move:",move) entity=self.grid[y][x] if entity: victims.append(entity) #print("killer:",killer) #print("victims:",victims) #print("") return victims def inGrid(self,x,y): sx,sy=self.size return (0<=x and x1 and len(self.grid_historic)>1: self.state-=1 del self.historic[-1] self.action=self.historic[-1] del self.grid_historic[-1] self.grid=self.grid_historic[-1] piece,position,move=self.historic[-1] x,y=position self.piece_selecter=self.grid[y][x] def updateHistoric(self): #self.state+=1 self.historic.append(self.action) self.grid_historic.append(deepcopy(self.grid)) self.piece_selecter=None self.moves_selecter=[] self.moving=self.action[0] self.moving_time=0 self.time=time.time() def check(self): sx,sy=self.size player1_alive=self.isAlive(King,1) player2_alive=self.isAlive(King,2) if player1_alive and player2_alive: self.won=False else: self.won=True def checkPromotion(self,action): sx,sy=self.size piece,position,move=action x,y=move orientation=((self.state+1)%2)*2-1 if isinstance(piece,Pawn): if orientation==1 and y==sy-1: self.promote(piece,move) if orientation==-1 and y==0: self.promote(piece,move) def promote(self,piece,move): x,y=move self.grid[y][x]=self.promoted[0](piece.side,move) def point(self,window): sx,sy=self.size wsx,wsy=window.size wx,wy=window.point() x,y=int(sx*wx/wsx),int(sy*wy/wsy) return (x,y) def getEntity(self,position): sx,sy=self.size x,y=position if 0<=x and x0 and self.last_action_shown: self.showLastPieceSelecter(window) self.showLastMoveSelecter(window) if self.piece_selecter is not None: self.showPieceSelecter(window) if self.moves_selecter!=[]: self.showMovesSelecter(window) self.showPieces(grid,window) if self.moving_shown and self.moving is not None and self.moving_position is not None: ##print(self.moving_shown,self.moving,self.moving_position) self.showMovingPiece(window) window.flip() def showGrid(self,window): i=1 wsx,wsy=window.size sx,sy=self.size for y in range(sy): i=(i+1)%len(self.case_colors) for x in range(sx): i=(i+1)%len(self.case_colors) coordonnates=[float(x*wsx)/sx,float(y*wsy)/sy,float(wsx)/sx+1,float(wsy)/sy+1] pygame.draw.rect(window.screen,self.case_colors[i],coordonnates,0) for x in range(sx+1): start= (float(x*wsx)/sx,0) end= (float(x*wsx)/sx,wsx) pygame.draw.line(window.screen,self.line_color,start,end,1) for y in range(sy+1): start= (0,float(y*wsy)/sy) end= (wsy,float(y*wsy)/sy) pygame.draw.line(window.screen,self.line_color,start,end,1) def showPieces(self,grid,window): wsx,wsy=window.size sx,sy=self.size for y in range(sy): for x in range(sx): entity=grid[y][x] if entity is not None: if entity is not self.moving or not self.moving_shown: position=[x*wsx/sx,y*wsy/sy] size=[wsx/sx,wsy/sy] coordonnates=position+size entity.show(window,coordonnates,self.pieces_colors) def showMovingPiece(self,window): x,y=self.moving_position wsx,wsy=window.size sx,sy=self.size position=[int(x*wsx/sx),(y*wsy/sy)] size=[wsx/sx,wsy/sy] coordonnates=position+size self.moving.show(window,coordonnates,self.pieces_colors) def showMovesSelecter(self,window): moves=self.moves_selecter wsx,wsy=window.size sx,sy=self.size sm=min(sx,sy) wsm=min(wsx,wsy) raw_radius=int(wsm/(sm*4)) for move in moves: x,y=move raw_position=(int(wsx*(x+0.5)/sx),int(wsy*(y+0.5)/sy)) pygame.draw.circle(window.screen, self.moves_selecter_colors[1], raw_position, raw_radius+2, 0) pygame.draw.circle(window.screen, self.moves_selecter_colors[0], raw_position, raw_radius, 0) def showLastMoveSelecter(self,window): pawn,position,move=self.historic[-1] wsx,wsy=window.size sx,sy=self.size sm=min(sx,sy) wsm=min(wsx,wsy) raw_radius=int(wsm/(sm*4)) x,y=position raw_position=(int(wsx*(x+0.5)/sx),int(wsy*(y+0.5)/sy)) pygame.draw.circle(window.screen, self.last_move_selecter_colors[1], raw_position, raw_radius+2, 0) pygame.draw.circle(window.screen, self.last_move_selecter_colors[0], raw_position, raw_radius, 0) def showPieceSelecter(self,window): x,y=self.locateByEntity(self.piece_selecter) wsx,wsy=window.size sx,sy=self.size sm=min(sx,sy) wsm=min(wsx,wsy) raw_radius=int(wsm/(sm*3)) raw_position=(int(wsx*(x+0.5)/sx),int(wsy*(y+0.5)/sy)) pygame.draw.circle(window.screen, self.piece_selecter_colors[1], raw_position, raw_radius+2, 0) pygame.draw.circle(window.screen, self.piece_selecter_colors[0], raw_position, raw_radius, 0) def showLastPieceSelecter(self,window): pawn,position,move=self.historic[-1] self.time x,y=move wsx,wsy=window.size sx,sy=self.size sm=min(sx,sy) wsm=min(wsx,wsy) raw_radius=int(wsm/(sm*3)) raw_position=(int(wsx*(x+0.5)/sx),int(wsy*(y+0.5)/sy)) pygame.draw.circle(window.screen, self.last_piece_selecter_colors[1], raw_position, raw_radius+2, 0) pygame.draw.circle(window.screen, self.last_piece_selecter_colors[0], raw_position, raw_radius, 0) def getOldTrajectory(self,A,B,moving_time,moving_max_time): xa,ya=A xb,yb=B height=yb-ya width=xb-xa angle=atan(height/width) delta=moving_max_time c=moving_time/moving_max_time ##print(1-c**2,c,moving_time,moving_max_time) z=sqrt((1-c**2)) x=width*z*cos(angle) y=height*z*sin(angle) return (x,y) def getTrajectory(self): piece,old_position,new_position=self.historic[-1] xa,ya=old_position xb,yb=new_position height=yb-ya width=xb-xa t=self.moving_time mt=self.moving_max_time ##print("time: ",t,mt) x=xa+width*t/mt y=ya+height*t/mt ##print("trajectory:",x,y) return (x,y) def updateMoving(self,window,colors): piece,old_position,new_position=self.historic[-1] dt=time.time()-self.time self.moving_time=dt ox,oy=old_position nx,ny=new_position x,y=self.getTrajectory() if min(ox,nx)<=x and x<=max(ox,nx) and min(oy,ny)<=y and y<=max(oy,ny) and self.moving_time