def start_game(game_type): game = Game() ai = AI() while (game.game_finished is False): #clear board so output is not too messy os.system('cls' if os.name == "nt" else 'clear') #print the current board state for the players print_board_state(game.board) #if the game has an AI player get AI to move if it's their turn if (game_type == AI_PLAYS_BLUE or game_type == AI_PLAYS_RED): #if it's the AI's turn call the AI to make a move, else player is prompted for a move if (game.current_player_turn == RED_PLAYER and game_type == AI_PLAYS_RED): game.player_move(ai.get_move(game)) elif (game.current_player_turn == BLUE_PLAYER and game_type == AI_PLAYS_BLUE): game.player_move(ai.get_move(game)) else: game.player_move(get_user_column_input()) #get player move if no AI player or it's still player turn else: game.player_move(get_user_column_input()) #if the game is finished print the board state and let the player know who has won if (game.game_finished): os.system('cls' if os.name == "nt" else 'clear') print_board_state(game.board) print print str(game.winner) + " has won the game!"
class Game: def __init__(self): self.browser = Browser() self.app = QApplication(sys.argv) self.timer = QTimer() self.timer.timeout.connect(self.updateEvent) self.ai = AI() self.last_score = 1 def run(self, delay): self.timer.start(delay) self.browser.run() return self.app.exec_() def updateEvent(self): self.timer.stop() (score, board) = self.browser.extractData() if self.last_score > score: self.ai.restart_game() self.last_score = score self.browser.sendMove(self.ai.get_move(score, board)) self.timer.start() # restart the event loop
def test_get_move(): # get_move() should return the move with the maximum value test_ai = AI('B') test_board = Board([Piece('9WN'), Piece('17BN'), Piece('21BN')], 'B') assert test_ai.get_move(test_board) in [{ "position_from": "17", "position_to": "13" }, { "position_from": "21", "position_to": "18" }]
def run_game(): """ runs the game :D """ game_board = Board() player1 = Human("1") player2 = AI("2") print(player1, "vs", player2) # players_turn = 1 while not game_board.has_winner: col = player1.get_move(game_board) game_board.add_piece(col, player1.piece) col = player2.get_move(game_board) game_board.add_piece(col, player2.piece) game_board.print_board()
def brain_turn(): if pp.terminateAI: return global myAI if myAI.turnChecked: opp_move = myAI.get_opponent_move(board) myAI.set(opp_move, 2) else: myAI = AI(board) if myAI.white_or_black(): myAI.searchDeep = config.searchDeep_black else: myAI.searchDeep = config.searchDeep_white myAI.searchDeep_ = myAI.searchDeep myAI.turnChecked = True if myAI.turnChecked and len(myAI.theBoard.allSteps) <= 4: myAI.searchDeep = myAI.searchDeep_ - 2 else: myAI.searchDeep = myAI.searchDeep_ myAI.theBoard.startTime = time.clock() if_only = False if not myAI.if_found_vcx: # 如果之前已经找到,之后就不需要再搜了 move, if_only = myAI.get_move() if not if_only: move_vcx = myAI.get_move_vcx() if move_vcx: myAI.if_found_vcx = True # print('HHHHHHH') move = move_vcx myAI.set(move, 1) x, y = move pp.do_mymove(x, y)
class AbstractBoard(object): '''A class that keeps track of the board logic; piece positions, legal moves etc.''' def __init__(self, shape=None): self.ai = None self.man_coords = set() self.ball_coords = (0, 0) self.shape = (15, 19) self.legal_moves = {} # Speculative attributes will hold data about the move the # player is currently making, without disrupting the full # logical state. self.speculative_ball_coords = (0, 0) self.speculative_man_coords = set() self.speculative_legal_moves = {} self.speculative_step_removals = [] self.speculative_steps = [] self.message = '' self.current_player = 'top' if 'shape' is not None: self.shape = shape def initialise_ai(self): if not self.ai: self.ai = AI(self) def check_for_win(self): '''Checks if either player has won.''' ball_coords = self.ball_coords if ball_coords[1] <= 1: return 'bottom' elif ball_coords[1] >= self.shape[1] - 2: return 'top' else: return 'none' def speculative_move_ball_to(self, coords): '''Tries to move the ball to the given coordinates. Returns appropriate instructions for how the board should change in response.''' coords = tuple(coords) speculative_legal_moves = self.speculative_legal_moves if coords in self.speculative_legal_moves: possible_paths = self.speculative_legal_moves[coords] if len(possible_paths) > 1: short_paths = list( filter(lambda j: len(j) == 1, possible_paths)) if not short_paths: return {'conflicting_paths': (coords, possible_paths)} steps = short_paths[0] else: steps = possible_paths[0] self.speculative_ball_coords = coords newly_removed_coords = removed_coords_from_steps(coords, steps) remove_coords_lists_from_set(newly_removed_coords, self.speculative_man_coords) self.speculative_step_removals.extend(newly_removed_coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) self.speculative_steps.extend(list(map(tuple, steps))) return { 'speculative_marker': get_speculative_move_identifiers(coords, self.speculative_steps) } if coords in self.speculative_steps: i = index = self.speculative_steps.index(coords) added_stones = self.speculative_step_removals[index:] self.speculative_ball_coords = coords self.speculative_steps = self.speculative_steps[:index] self.speculative_step_removals = self.speculative_step_removals[:i] add_coords_lists_to_set(added_stones, self.speculative_man_coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) return { 'speculative_marker': get_speculative_move_identifiers(coords, self.speculative_steps) } return None def speculative_play_man_at(self, coords): '''Speculatively plays a man at the given coordinates.''' coords = tuple(coords) self.speculative_man_coords.add(coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) def confirm_speculation(self): '''Sets the current speculation state to the real board state. Returns a list of permanent instructions.''' if (not self.speculative_step_removals and self.speculative_man_coords - self.man_coords == set()): return None new_men = self.speculative_man_coords - self.man_coords self.ball_coords = self.speculative_ball_coords self.man_coords = self.speculative_man_coords self.legal_moves = self.speculative_legal_moves if new_men: instructions = {'add': list(new_men)} else: removals = [] for coords in self.speculative_step_removals: removals.extend(coords) instructions = { 'move_ball_to': self.ball_coords, 'move_ball_via': get_speculative_move_identifiers(tuple(self.ball_coords), self.speculative_steps), 'remove': removals, 'clear_transient': None } self.reset_speculation() return instructions def reset_speculation(self): self.speculative_ball_coords = self.ball_coords self.speculative_man_coords = self.man_coords.copy() self.speculative_legal_moves = self.legal_moves self.speculative_step_removals = [] self.speculative_steps = [] def reset(self, *args): self.man_coords = set() self.ball_coords = (0, 0) self.legal_moves = [] self.reset_speculation() def add_man(self, coords): coords = tuple(coords) if coords in self.man_coords: return None self.man_coords.add(coords) return {'add': [coords]} def remove_man(self, coords): coords = tuple(coords) if coords not in self.man_coords: return None self.man_coords.remove(coords) return {'remove': [coords]} def toggle_man(self, coords): coords = tuple(coords) if coords in self.man_coords: instructions = self.remove_man(coords) else: instructions = self.add_man(coords) self.update_legal_moves() return instructions def play_man_at(self, coords): '''Method for attempting to play a man piece. Adds the man, and updates internal move state if necessary. ''' instructions = self.add_man(coords) if instructions: self.update_legal_moves() self.reset_speculation() return instructions def do_ai_move(self): if not self.ai: self.initialise_ai() self.reset_speculation() move_type, coords = self.ai.get_move() print('ai wants to move at', coords, move_type) if move_type == 'move': self.speculative_move_ball_to(coords) elif move_type == 'play': self.speculative_play_man_at(coords) # legal_moves[current_pos] = def update_legal_moves(self): moves = get_legal_moves(self.ball_coords, self.man_coords, self.shape) self.legal_moves = moves return self.legal_moves def as_ascii(self, speculative=False, *args): '''Returns an ascii representation of the board.''' string_elements = [] if not speculative: ball_coords = self.ball_coords man_coords = self.man_coords legal_moves = self.legal_moves else: ball_coords = self.speculative_ball_coords man_coords = self.speculative_man_coords legal_moves = self.speculative_legal_moves for y in range(self.shape[1])[::-1]: for x in range(self.shape[0]): coords = (x, y) if (coords[0] == ball_coords[0] and coords[1] == ball_coords[1]): string_elements.append('O') elif coords in man_coords: string_elements.append('X') elif coords in legal_moves: string_elements.append('@') elif coords[1] <= 1 or coords[1] >= self.shape[1] - 2: string_elements.append(',') else: string_elements.append(',') string_elements.append('\n') return ''.join(string_elements) def serialise(self): '''Serialises the board position (all stones, including speculative moves) as json. ''' return json.dumps({ 'shape': self.shape, 'ball_coords': self.ball_coords, 'man_coords': list(self.man_coords), 'current_player': self.current_player, 'legal_moves': list(self.legal_moves.items()), 'speculative_ball_coords': self.speculative_ball_coords, 'speculative_man_coords': list(self.speculative_man_coords), 'speculative_legal_moves': list(self.speculative_legal_moves.items()), 'speculative_step_removals': self.speculative_step_removals, 'speculative_steps': self.speculative_steps, 'message': '', 'other': '', }) def save_state(self, filen): '''Saves the state of self in the given file.''' with open(filen, 'w') as fileh: fileh.write(self.serialise()) def load_dict(self, d): '''Sets the properties of self according to the dictionary.''' if ('shape' not in d or 'ball_coords' not in d or 'man_coords' not in d or 'current_player' not in d): raise Exception('Not enough information to load.') print('loading from', d) self.shape = tuple(d['shape']) self.ball_coords = tuple(d['ball_coords']) print('ball coords set to', self.ball_coords) self.man_coords = set([tuple(coords) for coords in d['man_coords']]) self.current_player = d['current_player'] self.legal_moves = get_legal_moves(self.ball_coords, self.man_coords, self.shape) # Speculative saving not implemented yet. self.reset_speculation() if 'message' in d: self.message = d['message'] def load_file(self, filen): '''Loads json data from filen and sets the properties of self appropriately.''' with open(filen, 'r') as fileh: data = json.load(fileh) self.load_dict(data)
class Game: def __init__(self): # get user input for board size and number of ships, if input is invalid it gets re-asked while True: try: size = raw_input("Please enter a size for the board [10]: ") if size == "": size = 10 else: size = int(size) if size < 1: raise ValueError break except ValueError: continue while True: try: ships2 = raw_input("Please enter the amount of size 2 ships [1]: ") if ships2 == "": ships2 = 1 else: ships2 = int(ships2) if ships2 < 0: raise ValueError # preliminary check for whether the ships will fit on the board # if the total area of ships is greater than the area of the board # than there is no chance of the ships fitting and a new value is asked for # this check is done for all ships and does not take into account previously # added ships if ships2 > size * size / 2: print "The ships will not fit on the board" raise ValueError break except ValueError: continue while True: try: ships3 = raw_input("Please enter the amount of size 3 ships [2]: ") if ships3 == "": ships3 = 2 else: ships3 = int(ships3) if ships3 < 0: raise ValueError if ships3 > size * size / 3: print "The ships will not fit on the board" raise ValueError break except ValueError: continue while True: try: ships4 = raw_input("Please enter the amount of size 4 ships [1]: ") if ships4 == "": ships4 = 1 else: ships4 = int(ships4) if ships4 < 0: raise ValueError if ships4 > size * size / 4: print "The ships will not fit on the board" raise ValueError break except ValueError: continue while True: try: ships5 = raw_input("Please enter the amount of size 5 ships [1]: ") if ships5 == "": ships5 = 1 else: ships5 = int(ships5) if ships5 < 0: raise ValueError if ships5 > size * size / 5: print "The ships will not fit on the board" raise ValueError break except ValueError: continue # get user input for type of game if enhancements: while True: try: game_type = raw_input("Please enter game type:\n\t0:Human vs. Human\n\t1:Human vs. Computer\n\t2:Computer vs. Computer\n[1]:\n") if game_type == "": game_type = 1 else: game_type = int(game_type) if game_type < 0 or game_type > 2: raise ValueError break except ValueError: continue else: while True: try: game_type = raw_input("Please enter game type:\n\t0:Human vs. Human\n\t1:Human vs. Computer\n[1]:\n") if game_type == "": game_type = 1 else: game_type = int(game_type) if game_type < 0 or game_type > 1: raise ValueError break except ValueError: continue # create the players, their boards and ships, also ask for AI difficulty if enhancements are enabled # and a user is AI if game_type == 0: self._player1 = User(Board(size, ships2, ships3, ships4, ships5), 0) self._player2 = User(Board(size, ships2, ships3, ships4, ships5), 1) elif game_type == 1: difficulty = 0 if enhancements: while True: try: difficulty = raw_input("Please enter a computer difficulty:\n\t0:Easy\n\t1:Hard\n[0]:\n") if difficulty == "": difficulty = 0 else: difficulty = int(difficulty) if difficulty < 0 or difficulty > 1: raise ValueError break except ValueError: continue self._player1 = User(Board(size, ships2, ships3, ships4, ships5), 0) self._player2 = AI(Board(size, ships2, ships3, ships4, ships5), difficulty) elif game_type == 2: difficulty = 0 if enhancements: while True: try: difficulty = raw_input("Please enter a computer difficulty:\n\t0:Easy\n\t1:Hard\n[0]:\n") if difficulty == "": difficulty = 0 else: difficulty = int(difficulty) if difficulty < 0 or difficulty > 1: raise ValueError break except ValueError: continue self._player1 = AI(Board(size, ships2, ships3, ships4, ships5), difficulty) difficulty = 0 if enhancements: while True: try: difficulty = raw_input("Please enter a computer difficulty:\n\t0:Easy\n\t1:Hard\n[0]:\n") if difficulty == "": difficulty = 0 else: difficulty = int(difficulty) if difficulty < 0 or difficulty > 1: raise ValueError break except ValueError: continue self._player2 = AI(Board(size, ships2, ships3, ships4, ships5), difficulty) else: print "Game type was incorrent" # if enhancements are enabled initialize and setup variables for the GUI display if enhancements: pygame.init() self._screen1 = pygame.display.set_mode(((size * 22) + 1,(size * 11) + 50)) self._screen1.fill((0,0,0)) self._font = pygame.font.Font(None, 30) self._ship_font = pygame.font.Font(None, 20) def start(self): # continue playing the game as long as someone has not lost turn_count = 0 draw_ships = False while(not self._player1.is_defeated() and not self._player2.is_defeated()): # if enhancements are enabled generate the images to display for the GUI and display them if enhancements: for event in pygame.event.get(pygame.QUIT): pygame.quit() sys.exit() self._screen1.fill((0,0,0)) image, imagerect = self._player1.get_board().draw_board(draw_ships) imagerect.top += 50 image1, imagerect1 = self._player2.get_board().draw_board(draw_ships) imagerect1.top += 50 imagerect1.left = imagerect.width + 1 self._screen1.blit(image, imagerect) self._screen1.blit(image1, imagerect1) # create the 'scoreboard' for the GUI with the player name highlighted for # whoever's turn it currently is if turn_count % 2 == 0: self._font.set_bold(True) else: self._font.set_bold(False) font_image = self._font.render("Player 1", False, (255,255,255)) self._screen1.blit(font_image, pygame.Rect(0,0,self._font.size("Player 1")[0], self._font.size("Player 1")[1])) ship_image = self._ship_font.render("ships left = " + str(self._player1.get_ships_left()), False, (255,255,255)) self._screen1.blit(ship_image, pygame.Rect(0,30,self._ship_font.size("ships left = " + str(self._player1.get_ships_left()))[0], self._ship_font.size("ships left = " + str(self._player1.get_ships_left()))[1])) if turn_count % 2 != 0: self._font.set_bold(True) else: self._font.set_bold(False) font_image = self._font.render("Player 2", False, (255,255,255)) self._screen1.blit(font_image, pygame.Rect(self._screen1.get_width() - self._font.size("Player 2")[0],0,self._font.size("Player 2")[0], self._font.size("Player 2")[1])) ship_image = self._ship_font.render("ships left = " + str(self._player2.get_ships_left()), False, (255,255,255)) self._screen1.blit(ship_image, pygame.Rect(self._screen1.get_width() - self._ship_font.size("ships left = " + str(self._player2.get_ships_left()))[0],30,self._ship_font.size("ships left = " + str(self._player2.get_ships_left()))[0], self._ship_font.size("ships left = " + str(self._player2.get_ships_left()))[1])) pygame.display.update() # get player 1 or player 2 move and check for hit and update board if turn_count % 2 == 0: if not enhancements: print self._player1.get_board() value = self._player2.is_hit(Point(0, self._player1.get_move())) if value: self._player1.set_prev_was_hit(True) elif self._player1.get_prev_was_hit() and not value: self._player1.next_direction() else: if not enhancements: print self._player2.get_board() value = self._player1.is_hit(Point(0, self._player2.get_move())) if value: self._player2.set_prev_was_hit(True) elif self._player2.get_prev_was_hit() and not value: self._player2.next_direction() # change players turn turn_count += 1 # if enhancements are enabled display the final display after a player has won if enhancements: self._screen1.fill((0,0,0)) self._font.set_bold(False) font_image = self._font.render("Player 1", False, (255,255,255)) self._screen1.blit(font_image, pygame.Rect(0,0,self._font.size("Player 1")[0], self._font.size("Player 1")[1])) font_image = self._font.render("Player 2", False, (255,255,255)) self._screen1.blit(font_image, pygame.Rect(self._screen1.get_width() - self._font.size("Player 2")[0],0,self._font.size("Player 2")[0], self._font.size("Player 2")[1])) # display who was the winner of the game if self._player1.is_defeated(): if not enhancements: print "Player 2 Wins." print self._player1.get_board() else: end_image = self._ship_font.render("Player 2 Wins.", False, (255,255,255)) self._screen1.blit(end_image, pygame.Rect(0,30, self._ship_font.size("Player 2 Wins.")[0], self._ship_font.size("Player 2 Wins.")[1])) elif self._player2.is_defeated(): if not enhancements: print "Player 1 Wins." print self._player2.get_board() else: end_image = self._ship_font.render("Player 1 Wins.", False, (255,255,255)) self._screen1.blit(end_image, pygame.Rect(0,30, self._ship_font.size("Player 1 Wins.")[0], self._ship_font.size("Player 1 Wins.")[1])) # if enhancements are enabled display the actual boards of the players after one has won if enhancements: image, imagerect = self._player1.get_board().draw_board(draw_ships) imagerect.top += 50 image1, imagerect1 = self._player2.get_board().draw_board(draw_ships) imagerect1.top += 50 imagerect1.left = imagerect.width + 1 self._screen1.blit(image, imagerect) self._screen1.blit(image1, imagerect1) pygame.display.update() # wait for a mouse click to allow the users to see the outcome of the game while len(pygame.event.get(pygame.MOUSEBUTTONUP)) == 0: continue
class GameGrid(Frame): def __init__(self): Frame.__init__(self) self.grid() self.master.title('2048') self.grid_cells = [] self.init_grid() self.init_matrix() self.update_grid_cells() self.AI = AI() self.run_game() self.mainloop() def run_game(self): while True: self.board.move(self.AI.get_move(self.board)) self.update_grid_cells() self.add_random_tile() self.update_grid_cells() if len(self.board.get_available_moves()) == 0: self.game_over_display() break self.update() def game_over_display(self): for i in range(4): for j in range(4): self.grid_cells[i][j].configure(text="", bg=BACKGROUND_COLOR_CELL_EMPTY) self.grid_cells[1][1].configure(text="TOP", bg=BACKGROUND_COLOR_CELL_EMPTY) self.grid_cells[1][2].configure(text="4 TILES:", bg=BACKGROUND_COLOR_CELL_EMPTY) top_4 = list( map(int, reversed(sorted(list(self.board.grid.flatten()))))) self.grid_cells[2][0].configure(text=str(top_4[0]), bg=BACKGROUND_COLOR_DICT[2048], fg=CELL_COLOR_DICT[2048]) self.grid_cells[2][1].configure(text=str(top_4[1]), bg=BACKGROUND_COLOR_DICT[2048], fg=CELL_COLOR_DICT[2048]) self.grid_cells[2][2].configure(text=str(top_4[2]), bg=BACKGROUND_COLOR_DICT[2048], fg=CELL_COLOR_DICT[2048]) self.grid_cells[2][3].configure(text=str(top_4[3]), bg=BACKGROUND_COLOR_DICT[2048], fg=CELL_COLOR_DICT[2048]) self.update() def init_grid(self): background = Frame(self, bg=BACKGROUND_COLOR_GAME, width=SIZE, height=SIZE) background.grid() for i in range(GRID_LEN): grid_row = [] for j in range(GRID_LEN): cell = Frame(background, bg=BACKGROUND_COLOR_CELL_EMPTY, width=SIZE / GRID_LEN, height=SIZE / GRID_LEN) cell.grid(row=i, column=j, padx=GRID_PADDING, pady=GRID_PADDING) # font = Font(size=FONT_SIZE, family=FONT_FAMILY, weight=FONT_WEIGHT) t = Label(master=cell, text="", bg=BACKGROUND_COLOR_CELL_EMPTY, justify=CENTER, font=FONT, width=4, height=2) t.grid() grid_row.append(t) self.grid_cells.append(grid_row) def gen(self): return randint(0, GRID_LEN - 1) def init_matrix(self): self.board = GameBoard() self.add_random_tile() self.add_random_tile() def update_grid_cells(self): for i in range(GRID_LEN): for j in range(GRID_LEN): new_number = int(self.board.grid[i][j]) if new_number == 0: self.grid_cells[i][j].configure( text="", bg=BACKGROUND_COLOR_CELL_EMPTY) else: n = new_number if new_number > 2048: c = 2048 else: c = new_number self.grid_cells[i][j].configure( text=str(n), bg=BACKGROUND_COLOR_DICT[c], fg=CELL_COLOR_DICT[c]) self.update_idletasks() def add_random_tile(self): if randint(0, 99) < 100 * 0.9: value = 2 else: value = 4 cells = self.board.get_available_cells() pos = cells[randint(0, len(cells) - 1)] if cells else None if pos is None: return None else: self.board.insert_tile(pos, value) return pos
class GameControl: def __init__(self, player_color, is_computer_opponent): self.turn = player_color self.winner = None self.board = None self.board_draw = None self.held_piece = None self.ai_control = None if is_computer_opponent: self.ai_control = AI("B") if player_color == "W" else AI("W") self.setup() def get_turn(self): return self.turn def get_winner(self): return self.winner def setup(self): # Initial setup pieces = [] for opponent_piece in range(0, 12): pieces.append(Piece(str(opponent_piece) + 'BN')) for player_piece in range(20, 32): pieces.append(Piece(str(player_piece) + 'WN')) self.board = Board(pieces, self.turn) self.board_draw = BoardGUI(self.board) pass def draw_screen(self, display_surface): self.board_draw.draw_board(display_surface) self.board_draw.draw_pieces(display_surface) if self.held_piece is not None: self.held_piece.draw_piece(display_surface) def hold_piece(self, mouse_pos): piece_clicked = self.board_draw.get_piece_on_mouse(mouse_pos) board_pieces = self.board.get_pieces() has_jump_restraint = False # True if any piece can jump in one of its moves, forcing the player to jump if piece_clicked is None: return if piece_clicked["piece"]["color"] != self.turn: return # Determines if player has a jump restraint for piece in board_pieces: for move in piece.get_moves(self.board): if move["eats_piece"]: if piece.get_color() == piece_clicked["piece"]["color"]: has_jump_restraint = True else: continue break piece_moves = board_pieces[piece_clicked["index"]].get_moves( self.board) if has_jump_restraint: piece_moves = list( filter(lambda move: move["eats_piece"] == True, piece_moves)) move_marks = [] # Gets possible moving positions and tells BoardGUI to draw them for possible_move in piece_moves: row = self.board.get_row_number(int(possible_move["position"])) column = self.board.get_col_number(int(possible_move["position"])) move_marks.append((row, column)) self.board_draw.set_move_marks(move_marks) self.board_draw.hide_piece(piece_clicked["index"]) self.set_held_piece(piece_clicked["index"], board_pieces[piece_clicked["index"]], mouse_pos) def release_piece(self): if self.held_piece is None: return position_released = self.held_piece.check_collision( self.board_draw.get_move_marks()) moved_index = self.board_draw.show_piece() piece_moved = self.board.get_piece_by_index(moved_index) # Only moves the piece if dropped in a proper move mark if position_released is not None: self.board.move_piece( moved_index, self.board_draw.get_position_by_rect(position_released)) self.board_draw.set_pieces( self.board_draw.get_piece_properties(self.board)) self.winner = self.board.get_winner() # Check if player can eat another piece, granting an extra turn. jump_moves = list( filter(lambda move: move["eats_piece"] == True, piece_moved.get_moves(self.board))) if len(jump_moves) == 0 or piece_moved.get_has_eaten() == False: self.turn = "B" if self.turn == "W" else "W" self.held_piece = None self.board_draw.set_move_marks([]) def set_held_piece(self, index, piece, mouse_pos): # Creates a HeldPiece object to follow the mouse surface = self.board_draw.get_surface(piece) offset = get_surface_mouse_offset( self.board_draw.get_piece_by_index(index)["rect"], mouse_pos) self.held_piece = HeldPiece(surface, offset) def move_ai(self): # Gets best move from an AI instance and moves it. if self.turn == "W": return optimal_move = self.ai_control.get_move(self.board) index_moved = -1 piece_moved = None for index, piece in enumerate(self.board.get_pieces()): if piece.get_position() == optimal_move["position_from"]: index_moved = index piece_moved = piece break else: raise RuntimeError( "AI was supposed to return a move from an existing piece but found none." ) self.board.move_piece(index_moved, int(optimal_move["position_to"])) self.board_draw.set_pieces( self.board_draw.get_piece_properties(self.board)) self.winner = self.board.get_winner() # Check if AI can eat another piece, granting an extra turn. jump_moves = list( filter(lambda move: move["eats_piece"] == True, piece_moved.get_moves(self.board))) if len(jump_moves) == 0 or piece_moved.get_has_eaten() == False: self.turn = "B" if self.turn == "W" else "W"
class AbstractBoard(object): '''A class that keeps track of the board logic; piece positions, legal moves etc.''' def __init__(self, shape=None): self.ai = None self.man_coords = set() self.ball_coords = (0, 0) self.shape = (15, 19) self.legal_moves = {} # Speculative attributes will hold data about the move the # player is currently making, without disrupting the full # logical state. self.speculative_ball_coords = (0, 0) self.speculative_man_coords = set() self.speculative_legal_moves = {} self.speculative_step_removals = [] self.speculative_steps = [] self.message = '' self.current_player = 'top' if 'shape' is not None: self.shape = shape def initialise_ai(self): if not self.ai: self.ai = AI(self) def check_for_win(self): '''Checks if either player has won.''' ball_coords = self.ball_coords if ball_coords[1] <= 1: return 'bottom' elif ball_coords[1] >= self.shape[1]-2: return 'top' else: return 'none' def speculative_move_ball_to(self, coords): '''Tries to move the ball to the given coordinates. Returns appropriate instructions for how the board should change in response.''' coords = tuple(coords) speculative_legal_moves = self.speculative_legal_moves if coords in self.speculative_legal_moves: possible_paths = self.speculative_legal_moves[coords] if len(possible_paths) > 1: short_paths = list(filter(lambda j: len(j) == 1, possible_paths)) if not short_paths: return {'conflicting_paths': (coords, possible_paths)} steps = short_paths[0] else: steps = possible_paths[0] self.speculative_ball_coords = coords newly_removed_coords = removed_coords_from_steps(coords, steps) remove_coords_lists_from_set(newly_removed_coords, self.speculative_man_coords) self.speculative_step_removals.extend(newly_removed_coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) self.speculative_steps.extend(list(map(tuple, steps))) return {'speculative_marker': get_speculative_move_identifiers( coords, self.speculative_steps)} if coords in self.speculative_steps: i = index = self.speculative_steps.index(coords) added_stones = self.speculative_step_removals[index:] self.speculative_ball_coords = coords self.speculative_steps = self.speculative_steps[:index] self.speculative_step_removals = self.speculative_step_removals[:i] add_coords_lists_to_set(added_stones, self.speculative_man_coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) return {'speculative_marker': get_speculative_move_identifiers( coords, self.speculative_steps)} return None def speculative_play_man_at(self, coords): '''Speculatively plays a man at the given coordinates.''' coords = tuple(coords) self.speculative_man_coords.add(coords) self.speculative_legal_moves = get_legal_moves( self.speculative_ball_coords, self.speculative_man_coords, self.shape) def confirm_speculation(self): '''Sets the current speculation state to the real board state. Returns a list of permanent instructions.''' if (not self.speculative_step_removals and self.speculative_man_coords - self.man_coords == set()): return None new_men = self.speculative_man_coords - self.man_coords self.ball_coords = self.speculative_ball_coords self.man_coords = self.speculative_man_coords self.legal_moves = self.speculative_legal_moves if new_men: instructions = {'add': list(new_men)} else: removals = [] for coords in self.speculative_step_removals: removals.extend(coords) instructions = {'move_ball_to': self.ball_coords, 'move_ball_via': get_speculative_move_identifiers( tuple(self.ball_coords), self.speculative_steps), 'remove': removals, 'clear_transient': None} self.reset_speculation() return instructions def reset_speculation(self): self.speculative_ball_coords = self.ball_coords self.speculative_man_coords = self.man_coords.copy() self.speculative_legal_moves = self.legal_moves self.speculative_step_removals = [] self.speculative_steps = [] def reset(self, *args): self.man_coords = set() self.ball_coords = (0, 0) self.legal_moves = [] self.reset_speculation() def add_man(self, coords): coords = tuple(coords) if coords in self.man_coords: return None self.man_coords.add(coords) return {'add': [coords]} def remove_man(self, coords): coords = tuple(coords) if coords not in self.man_coords: return None self.man_coords.remove(coords) return {'remove': [coords]} def toggle_man(self, coords): coords = tuple(coords) if coords in self.man_coords: instructions = self.remove_man(coords) else: instructions = self.add_man(coords) self.update_legal_moves() return instructions def play_man_at(self, coords): '''Method for attempting to play a man piece. Adds the man, and updates internal move state if necessary. ''' instructions = self.add_man(coords) if instructions: self.update_legal_moves() self.reset_speculation() return instructions def do_ai_move(self): if not self.ai: self.initialise_ai() self.reset_speculation() move_type, coords = self.ai.get_move() print('ai wants to move at', coords, move_type) if move_type == 'move': self.speculative_move_ball_to(coords) elif move_type == 'play': self.speculative_play_man_at(coords) # legal_moves[current_pos] = def update_legal_moves(self): moves = get_legal_moves(self.ball_coords, self.man_coords, self.shape) self.legal_moves = moves return self.legal_moves def as_ascii(self, speculative=False, *args): '''Returns an ascii representation of the board.''' string_elements = [] if not speculative: ball_coords = self.ball_coords man_coords = self.man_coords legal_moves = self.legal_moves else: ball_coords = self.speculative_ball_coords man_coords = self.speculative_man_coords legal_moves = self.speculative_legal_moves for y in range(self.shape[1])[::-1]: for x in range(self.shape[0]): coords = (x, y) if (coords[0] == ball_coords[0] and coords[1] == ball_coords[1]): string_elements.append('O') elif coords in man_coords: string_elements.append('X') elif coords in legal_moves: string_elements.append('@') elif coords[1] <= 1 or coords[1] >= self.shape[1]-2: string_elements.append(',') else: string_elements.append(',') string_elements.append('\n') return ''.join(string_elements) def serialise(self): '''Serialises the board position (all stones, including speculative moves) as json. ''' return json.dumps( {'shape': self.shape, 'ball_coords': self.ball_coords, 'man_coords': list(self.man_coords), 'current_player': self.current_player, 'legal_moves': list(self.legal_moves.items()), 'speculative_ball_coords': self.speculative_ball_coords, 'speculative_man_coords': list(self.speculative_man_coords), 'speculative_legal_moves': list( self.speculative_legal_moves.items()), 'speculative_step_removals': self.speculative_step_removals, 'speculative_steps': self.speculative_steps, 'message': '', 'other': '', }) def save_state(self, filen): '''Saves the state of self in the given file.''' with open(filen, 'w') as fileh: fileh.write(self.serialise()) def load_dict(self, d): '''Sets the properties of self according to the dictionary.''' if ('shape' not in d or 'ball_coords' not in d or 'man_coords' not in d or 'current_player' not in d): raise Exception('Not enough information to load.') print('loading from', d) self.shape = tuple(d['shape']) self.ball_coords = tuple(d['ball_coords']) print('ball coords set to', self.ball_coords) self.man_coords = set([tuple(coords) for coords in d['man_coords']]) self.current_player = d['current_player'] self.legal_moves = get_legal_moves( self.ball_coords, self.man_coords, self.shape) # Speculative saving not implemented yet. self.reset_speculation() if 'message' in d: self.message = d['message'] def load_file(self, filen): '''Loads json data from filen and sets the properties of self appropriately.''' with open(filen, 'r') as fileh: data = json.load(fileh) self.load_dict(data)