def remove_moves_that_give_opponent_a_winning_move_in_two_moves( self, board, potential_moves): new_moves = [] for col in potential_moves: row = utils.find_first_empty_row(board, col) if row == None: continue # If we play here board[row][col] = self.mark # If we are at the top of the board, it can't hurt if row == 0: # Reset board board[row][col] = None new_moves.append(col) continue # If opponent plays above us: board[row - 1][col] = self.other_player # can the opponent have two winning moves? winning_moves = self.count_winning_moves( board, self.other_player, "remove_moves_that_give_opponent_a_winning_move_in_two_moves") if winning_moves > 1: # If so, skip this move # Reset board board[row][col] = None board[row - 1][col] = None continue if winning_moves == 1: # If there is one winning move, and we block it, does that give opponent a winning move? opponent_win_col = self.check_for_opponent_winning_move( board, "remove_moves_that_give_opponent_a_winning_move_in_two_moves" ) opponent_win_row = utils.find_first_empty_row( board, opponent_win_col) board[opponent_win_row][opponent_win_col] = self.mark opponent_second_win = self.check_for_opponent_winning_move( board, "remove_moves_that_give_opponent_a_winning_move_in_two_moves second_move" ) if opponent_second_win != None: # The opponent can win, skip this move board[opponent_win_row][opponent_win_col] = None board[row][col] = None board[row - 1][col] = None continue # If we've made it this far, the move is safe new_moves.append(col) # Reset board and continue to next col board[row][col] = None board[row - 1][col] = None log.info( "remove_moves_that_give_opponent_a_winning_move_in_two_moves: player {} keeps moves: {}" .format(self.mark, new_moves)) return new_moves
def check_for_move_that_blocks_opponent_in_two_moves(self, board): block_it = None for col in range(0, constants.num_cols): row = utils.find_first_empty_row(board, col) if row == None: continue # If we play here board[row][col] = self.mark # Can the opponent win? opponent_win = self.check_for_opponent_winning_move( board, "check_for_move_that_blocks_opponent_in_two_moves") # Reset board board[row][col] = None # If the opponent can win, skip this move if opponent_win != None: continue # If opponent plays here board[row][col] = self.other_player # can the opponent have two winning moves? winning_moves = self.count_winning_moves( board, self.other_player, "check_for_move_that_blocks_opponent_in_two_moves") if winning_moves > 1: block_it = col if winning_moves == 1: # If there is one winning move, and we block it, does that give opponent a winning move? opponent_win_col = self.check_for_opponent_winning_move( board, "check_for_move_that_blocks_opponent_in_two_moves") opponent_win_row = utils.find_first_empty_row( board, opponent_win_col) board[opponent_win_row][opponent_win_col] = self.mark opponent_second_win = self.check_for_opponent_winning_move( board, "check_for_move_that_blocks_opponent_in_two_moves second_move" ) if opponent_second_win != None: # The opponent can win, block this move block_it = col board[opponent_win_row][opponent_win_col] = None # reset move for next col board[row][col] = None if block_it is not None: log.info( "check_for_move_that_blocks_opponent_in_two_moves: player {} finds move in column {} that prevents the computer from winning in two moves" .format(self.mark, col)) break return block_it
def remove_full_columns(self, board, potential_moves): new_moves = [] for col in potential_moves: row = utils.find_first_empty_row(board, col) if row == None: continue else: new_moves.append(col) log.info("remove_full_columns: player {} keeps moves {}".format( self.mark, new_moves)) return new_moves
def check_for_move_that_wins_in_two_moves(self, board): best_move = None for col in range(0, constants.num_cols): row = utils.find_first_empty_row(board, col) if row == None: continue # If we play here board[row][col] = self.mark opponent_win = self.check_for_opponent_winning_move( board, "check_for_move_that_wins_in_two_moves") # If the opponent can win, skip this move if opponent_win != None: board[row][col] = None continue # Otherwise count how many winning moves there are for me winning_moves = self.count_winning_moves( board, self.mark, "check_for_move_that_wins_in_two_moves") if winning_moves > 1: best_move = col elif winning_moves == 1: # If there is one winning move, and opponent blocks it, does that give us a winning move? win_col = self.check_for_winning_move( board, "check_for_move_that_wins_in_two_moves") win_row = utils.find_first_empty_row(board, win_col) board[win_row][win_col] = self.other_player second_win = self.check_for_winning_move( board, "check_for_move_that_wins_in_two_moves second_move") if second_win != None: # This will guarantee victory, play it! best_move = col board[win_row][win_col] = None # reset move for next col board[row][col] = None if best_move is not None: log.info( "check_for_move_that_wins_in_two_moves: player {} finds move in column {} that allows them to win in two moves" .format(self.mark, col)) break return best_move
def check_for_move_that_wins_eventually(self, board): winning_move = None for col in range(0, constants.num_cols): row = utils.find_first_empty_row(board, col) if row == None: continue if self.check_for_iterative_winning_move(board, row, col): winning_move = col break if winning_move is not None: log.info( "check_for_move_that_wins_eventually: player {} finds move in column {} that allows them to win eventually" .format(self.mark, col)) return winning_move
def check_for_iterative_winning_move(self, board, row, col): forced_win = False i = 0 win_cols = [] win_rows = [] move_cols = [] move_rows = [] while forced_win == False: # If we play here board[row][col] = self.mark move_rows.append(row) move_cols.append(col) opponent_win = self.check_for_opponent_winning_move( board, "check_for_iterative_winning_move-{}".format(i)) # If the opponent can win, skip this move if opponent_win != None: break win_col = self.check_for_winning_move( board, "check_for_iterative_winning_move-{}".format(i)) if win_col == None: # No winning moves, break break # If there is a winning move, and opponent blocks it, does that still give us a winning move? win_row = utils.find_first_empty_row(board, win_col) win_cols.append(win_col) win_rows.append(win_row) board[win_row][win_col] = self.other_player second_win = self.check_for_winning_move( board, "check_for_iterative_winning_move-{} second_move".format(i)) if second_win != None: # Yes, there is a winning move force_win = True break else: # If there is no winning move, play above the opponent and check again row = win_row - 1 if row < 0: break col = win_col i += 1 # Clean up for i in range(0, len(win_cols)): board[win_rows[i]][win_cols[i]] = None for i in range(0, len(move_cols)): board[move_rows[i]][move_cols[i]] = None return forced_win
def remove_moves_that_give_opponent_an_immediate_winning_move( self, board, potential_moves): new_moves = [] for col in potential_moves: row = utils.find_first_empty_row(board, col) if row == None: # Should not happen, but keeping this just in case continue if self.other_could_win_after_this_move(board, col, row): continue else: new_moves.append(col) log.info( "remove_moves_that_give_opponent_an_immediate_winning_move: player {} keeps moves: {}" .format(self.mark, new_moves)) return new_moves
def count_winning_moves(self, board, mark, caller=None): caller_str = "" if caller != None: caller_str = " (for {})".format(caller) winning_moves = 0 winning_move_cols = [] for col in range(0, constants.num_cols): row = utils.find_first_empty_row(board, col) if row == None: continue if utils.check_for_winner(board, col, row, mark): winning_moves += 1 winning_move_cols.append(col) log.info( "count_winning_moves{}: player {} has {} winning moves in columns {}" .format(caller_str, mark, winning_moves, winning_move_cols)) return winning_moves
def check_for_opponent_winning_move(self, board, caller=None): caller_str = "" if caller != None: caller_str = " (for {})".format(caller) move = None for col in range(0, constants.num_cols): row = utils.find_first_empty_row(board, col) if row == None: continue if utils.check_for_winner(board, col, row, self.other_player): log.info( "check_for_opponent_winning_move{}: player {} finds opponents winning move in column {}" .format(caller_str, self.mark, col)) move = col break log.debug("check_for_opponent_winning_move returning {}".format(move)) return move