From 34ea6c821b5d1831c1f69f985f6073b178f113ee Mon Sep 17 00:00:00 2001 From: tzzzzzzzx <414850847@qq.com> Date: Sat, 3 Sep 2022 11:05:42 +0800 Subject: [PATCH] basic function realized --- SafariChess_Gamev1.0.py | 6 +- SafariChess_backend.py | 171 +++++++++++------- .../SafariChess_backend.cpython-39.pyc | Bin 6978 -> 8754 bytes 3 files changed, 111 insertions(+), 66 deletions(-) diff --git a/SafariChess_Gamev1.0.py b/SafariChess_Gamev1.0.py index c5894e1..69e3591 100644 --- a/SafariChess_Gamev1.0.py +++ b/SafariChess_Gamev1.0.py @@ -202,7 +202,7 @@ def main(): click_queue = []#点击队列,记录第一次点击和第二次点击位置,方便移动棋子 pg.display.update() startGamePage() - while True: + while running: for e in pg.event.get(): #接下来处理游戏中的事件 if e.type == pg.QUIT: @@ -240,7 +240,9 @@ def main(): if mademove: valid_moves = game_state.getAllMoves() ShowGameState(screen,game_state,valid_moves,square_selected) - + if game_state.conquer(): + showGameOverText(screen,"player "+game_state.win_person+" wins") + game_over = True clock.tick(60) pg.display.flip() diff --git a/SafariChess_backend.py b/SafariChess_backend.py index b34fffd..34a1259 100644 --- a/SafariChess_backend.py +++ b/SafariChess_backend.py @@ -1,6 +1,3 @@ - - - class GameState: def __init__(self): ''' @@ -33,13 +30,16 @@ class GameState: self.red_trap_loc=[(3,7),(2,8),(4,8)] self.blue_home=(3,0) self.red_home=(3,8) - + self.blue_pieces=[7,6,5,4,3,2,1] + self.red_pieces=[7,6,5,4,3,2,1] #蓝方(左)先行 self.red_to_move=False self.conquered=False + self.win_person='' self.MASSACRE=False - self.color = 'r' if self.red_to_move else 'b' + def color(self): + return 'r' if self.red_to_move else 'b' # 判断特殊位置 @@ -58,7 +58,7 @@ class GameState: return True return False - def inTrap(self,row,col,color): + def inTrap(self,row,col,color): #是否在color方的陷阱中 if color=="b": if (row,col) in self.blue_trap_loc: return True @@ -68,7 +68,10 @@ class GameState: return False def Eliminate(self,row,col,nxt_row,nxt_col):#下一步可吃对手的棋 - return self.board[nxt_row][nxt_col] == '00' or self.board[nxt_row][nxt_col][0] != self.board[row][col][0] and (eval(self.board[row][col][1]) >= eval(self.board[nxt_row][nxt_col][1]) and not (eval(self.board[row][col][1]) == 7 and eval(self.board[nxt_row][nxt_col][1]) == 1 ) or eval(self.board[row][col][1])==1 and eval(self.board[nxt_row][nxt_col][1])==7) + next_blank = self.board[nxt_row][nxt_col] == '00' + attack = self.board[nxt_row][nxt_col][0] != self.board[row][col][0] and (eval(self.board[row][col][1]) >= eval(self.board[nxt_row][nxt_col][1]) and not (eval(self.board[row][col][1]) == 7 and eval(self.board[nxt_row][nxt_col][1]) == 1 ) or eval(self.board[row][col][1])==1 and eval(self.board[nxt_row][nxt_col][1])==7) + other_in_trap = self.board[row][col][0] != self.board[nxt_row][nxt_col][0] and (self.board[nxt_row][nxt_col][0] == 'r' and self.inTrap(nxt_row,nxt_col,'b') or self.board[nxt_row][nxt_col][0] == 'b' and self.inTrap(nxt_row,nxt_col,'r')) + return next_blank or attack or other_in_trap # 定义移动方式 #---------------------------------- @@ -94,9 +97,9 @@ class GameState: new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] - if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color):#如果下一个位置是空的,则可以移动 + if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 moves.append(Move((row,col),(new_row,new_col),self.board)) - elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 + elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 moves.append(Move((row,col),(new_row,new_col),self.board)) return moves @@ -108,6 +111,7 @@ class GameState: new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] + if self.inHome(new_row,new_col,self.color()): continue if nxt_piece == '00': moves.append(Move((row,col),(new_row,new_col),self.board)) elif nxt_piece[0]==enemy_color and self.Eliminate(row,col,new_row,new_col) and not self.inWater(row,col): @@ -117,34 +121,45 @@ class GameState: def getEagMoves(self,row,col,moves): #可能存在一些问题,主要是移动方式的判断以及在陷阱的判断 enemy_color = 'b' if self.red_to_move else 'r' - moveNum_row = -6 - moveNum_col = -8 new_row = row new_col = col - while(moveNum_row <= 6 ): - new_row = row + moveNum_row - if 0<=new_row<=6: - nxt_piece = self.board[new_row][col] - if nxt_piece == '00': - moves.append(Move((row,col),(new_row,new_col),self.board)) - elif nxt_piece[0]==enemy_color and not self.inWater(new_row,col) and not self.inHome(row,new_col,self.color) and self.Eliminate(row,col,new_row,new_col): - moves.append(Move((row,col),(new_row,new_col),self.board)) - else : - break - moveNum_row += 1 - - while(moveNum_row <= 8): - new_col = col + moveNum_col - if 0 <= new_col <= 8: - nxt_piece = self.board[row][new_col] - if nxt_piece == '00' and not self.inWater(row,new_col) and not self.inHome(row,new_col,self.color): - moves.append(Move((row,col),(new_row,new_col),self.board)) - elif nxt_piece[0]==enemy_color and self.Eliminate(row,col,new_row,new_col): - moves.append(Move((row,col),(new_row,new_col),self.board)) - else : - break - moveNum_col += 1 + #U&D direction + while new_row >= 0: + nxt_piece = self.board[new_row][col] + if nxt_piece == '00' and not self.inTrap(new_row,col,enemy_color): + if not self.inHome(new_row,col,self.color()) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + else: + if self.Eliminate(row,col,new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + if new_row != row: break + new_row -= 1 + new_row = row + while new_row <= 6: + nxt_piece = self.board[new_row][col] + if nxt_piece == '00' and not self.inTrap(new_row,new_col,enemy_color): + if not self.inHome(new_row,col,self.color()) and not self.inWater(new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + else: + if self.Eliminate(row,col,new_row,col): moves.append(Move((row,col),(new_row,col),self.board)) + if new_row != row: break + new_row += 1 + #L&R Direction + while new_col >= 0: + nxt_piece = self.board[row][new_col] + if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color): + if not self.inHome(row,new_col,self.color()) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + else: + if self.Eliminate(row,col,row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + if new_col != col: break + new_col -= 1 + new_col = col + while new_col <= 8: + nxt_piece = self.board[row][new_col] + if nxt_piece == '00' and not self.inTrap(row,new_col,enemy_color): + if not self.inHome(row,new_col,self.color()) and not self.inWater(row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + else: + if self.Eliminate(row,col,row,new_col): moves.append(Move((row,col),(row,new_col),self.board)) + if new_col != col: break + new_col += 1 return moves @@ -157,51 +172,79 @@ class GameState: new_col = col + direction[1]*1 if 0<=new_row<=6 and 0<=new_col<=8 : nxt_piece = self.board[new_row][new_col] - if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color):#如果下一个位置是空的,则可以移动 + if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 moves.append(Move((row,col),(new_row,new_col),self.board)) - elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 + elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 moves.append(Move((row,col),(new_row,new_col),self.board)) return moves def getLionMoves(self,row,col,moves): - directions = ((-1, 0), (0, -1), (1, 0), (0, 1)) - enemy_color = "b" if self.red_to_move else "r" + directions = [(1,0),(0,1),(-1,0),(0,-1)] + enemy_color = 'b' if self.red_to_move else 'r' for direction in directions: - for i in range(1, 2): - end_row = row + direction[0] * 1 - end_col = col + direction[1] * 1 - if 0 <= end_row <= 6 and 0 <= end_col <= 8: # check for possible moves only in boundaries of the board - end_piece = self.board[end_row][end_col] - - if end_piece == "--" and not self.inWater(end_row,end_col) and self.moveNotOwnDen(end_row,end_col,enemy_color): # empty space is valid and Not in Water - moves.append(Move((row, col), (end_row, end_col), self.board)) - - elif end_piece == "--" and self.inWater(end_row,end_col): - jump_row = end_row - row #Vertical jump - jump_col = end_col - col #Horizontal jump - - if jump_row != 0 and self.jumpConditions(row,col,end_row,end_col,jump_row,jump_col,enemy_color): - moves.append(Move((row, col), (end_row+(3*jump_row), end_col), self.board)) - - elif jump_col != 0 and self.jumpConditions(row,col,end_row,end_col,jump_row,jump_col,enemy_color): - moves.append((end_row, end_col+(2*jump_col))) - - elif end_piece[0] == enemy_color and not self.inWater(end_row,end_col) and self.canAttack(row, col, end_row, end_col): # capture enemy piece - moves.append(Move((row, col), (end_row, end_col), self.board)) - break - else: # friendly piece - break - else: # off board - break + new_row = row + direction[0]*1 + new_col = col + direction[1]*1 + if 0<=new_row<=6 and 0<=new_col<=8 : + nxt_piece = self.board[new_row][new_col] + if nxt_piece == '00' and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()):#如果下一个位置是空的,则可以移动 + moves.append(Move((row,col),(new_row,new_col),self.board)) + elif nxt_piece[0]==enemy_color and not self.inWater(new_row,new_col) and not self.inHome(new_row,new_col,self.color()) and self.Eliminate(row,col,new_row,new_col):#如果是敌方棋子,且不在水里,且可以消除,则添加到可行路径中 + moves.append(Move((row,col),(new_row,new_col),self.board)) + jump_vert_loc=[(0,3),(0,4),(0,5),(3,3),(3,4),(3,5),(6,3),(6,4),(6,5)] + jump_hori_loc=[(1,2),(1,6),(2,2),(2,6),(4,2),(4,6),(5,2),(5,6)] + enemy_mouse = enemy_color + '1' + if (row,col) in jump_vert_loc: + if row == 0: + if self.board[1][col] != enemy_mouse and self.board[2][col] != enemy_mouse: + if self.Eliminate(row,col,3,col): moves.append(Move((row,col),(3,col),self.board)) + elif row == 3: + if self.board[1][col] != enemy_mouse and self.board[2][col] != enemy_mouse: + if self.Eliminate(row,col,0,col): moves.append(Move((row,col),(0,col),self.board)) + if self.board[4][col] != enemy_mouse and self.board[5][col] != enemy_mouse: + if self.Eliminate(row,col,6,col): moves.append(Move((row,col),(6,col),self.board)) + elif row == 6: + if self.board[4][col] != enemy_mouse and self.board[5][col] != enemy_mouse: + if self.Eliminate(row,col,3,col): moves.append(Move((row,col),(3,col),self.board)) + elif (row,col) in jump_hori_loc: + if col == 2: + lea = True + for i in range(3,6): + if self.board[row][i] == enemy_mouse: lea = False + if lea and self.Eliminate(row,col,row,6): moves.append(Move((row,col),(row,6),self.board)) + elif col == 6: + lea = True + for i in range(3,6): + if self.board[row][i] == enemy_mouse: lea = False + if lea and self.Eliminate(row,col,row,2): moves.append(Move((row,col),(row,2),self.board)) + return moves # 判断是否胜利 def conquer(self): if self.board[3][0][0] == 'r' or self.board[3][8][0] == 'b': self.conquered = True + if self.board[3][0][0] == 'r': + self.win_person = 'r' + else: self.win_person = 'b' + elif len(self.blue_pieces) == 0: + self.conquered = True + self.win_person = 'r' + elif len(self.red_pieces) == 0: + self.conquered = True + self.win_person = 'b' + elif len(self.getAllMoves()) == 0: + self.conquered = True + self.win_person = 'r' if self.color() == 'b' else 'b' return self.conquered #移动操作 def makeMove(self,move):#cur是当前位置,nxt是下一个位置,参数传入为元组 + # makeMove假设这个move一定是合法的 + if self.board[move.end_row][move.end_col] != '00': + nxt_piece = self.board[move.end_row][move.end_col] + if nxt_piece[0] == 'r': + self.red_pieces.remove(int(nxt_piece[1])) + else: + self.blue_pieces.remove(int(nxt_piece[1])) self.board[move.end_row][move.end_col] = self.board[move.start_row][move.start_col] self.board[move.start_row][move.start_col] = '00' self.red_to_move = not self.red_to_move diff --git a/__pycache__/SafariChess_backend.cpython-39.pyc b/__pycache__/SafariChess_backend.cpython-39.pyc index 2aa1243e7f0d36b5e1a4efa2a0fea19764d37602..c7d7effc4b051ed78fbe7eee5d1d9d349f644e14 100644 GIT binary patch literal 8754 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 GEBr5=mOmf> literal 6978 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