def basic_movement_test(): # Leaper currentState = BC.BC_state(t6[0], BC.WHITE) moves = available_moves(currentState) check(t6, len(moves)) # King currentState = BC.BC_state(t7[0], BC.WHITE) moves = available_moves(currentState) check(t7, len(moves)) # Freezer currentState = BC.BC_state(t8[0], BC.WHITE) moves = available_moves(currentState) check(t8, len(moves)) # Imitator currentState = BC.BC_state(t9[0], BC.WHITE) moves = available_moves(currentState) check(t9, len(moves)) # Withdrawer currentState = BC.BC_state(t10[0], BC.WHITE) moves = available_moves(currentState) check(t10, len(moves))
def basicStaticEval(state): '''Use the simple method for state evaluation described in the spec. This is typically used in parameterized_minimax calls to verify that minimax and alpha-beta pruning work correctly.''' board = state.board value = 0 if winTester.winTester(state) == "No win": for row in range(8): for col in range(8): piece = board[row][col] if piece != EMPTY and BC.who(piece) == WHITE: if piece == WHITE_KING: value += 100 elif piece == WHITE_PINCER: value += 1 else: value += 2 if piece != EMPTY and BC.who(piece) == BLACK: if piece == BLACK_KING: value -= 100 elif piece == BLACK_PINCER: value -= 1 else: value -= 2 return value
def makeMove(currentState, currentRemark, timelimit): global ALPHA_BETA_CUTOFFS ALPHA_BETA_CUTOFFS = 0 # Compute the new state for a move. # This is a placeholder that just copies the current state. hash = Z.zhash(currentState.board) #print(hash) current_state = BC.BC_state(currentState.board, currentState.whose_move, hash) #print(current_state.hash) newState = BC.BC_state(currentState.board) board = newState.board # Fix up whose turn it will be. newState.whose_move = 1 - currentState.whose_move # Construct a representation of the move that goes from the # currentState to the newState. # Here is a placeholder in the right format but with made-up # numbers: score, move = iterative_deepening_alpha_beta(current_state, current_state.whose_move, 3) new_state = PM.move(move[0], move[1], current_state, move[2]) #print(move) move = move[0:2] #print(score) #print(newState) # Make up a new remark newRemark = "I'll think harder in some future game. Here's my move" print(ALPHA_BETA_CUTOFFS) print(score) print(STATES_EXPANDED) print(STATIC_EVALS_PERFORMED) return [[move, new_state], newRemark]
def coordCapMove(dest_row, dest_col, board, cur_player): # intersection of king's rank and coordinator's file and coordinator's file # and king's rank are captured # pieces captured is initialized to an empty list captured_pieces = [] (row_king, col_king) = findAllyKing(board, cur_player) # possible captured pieces cap_piece1 = board[row_king][dest_col] cap_piece2 = board[dest_row][col_king] #print("captured_piece1: " + str(cap_piece1)) #print("captured_piece2: " + str(cap_piece2)) # side of captured pieces piece1_side = BC.who(cap_piece1) piece2_side = BC.who(cap_piece2) # if captured piece 1 is an enemy, capture it! if not piece1_side == cur_player and not cap_piece1 == 0: captured_pieces.append(cap_piece1) board[row_king][dest_col] = 0 # if captured piece 2 is an enemy, capture it! if not piece2_side == cur_player and not cap_piece2 == 0: captured_pieces.append(cap_piece2) board[dest_row][col_king] = 0 return captured_pieces
def coordinator(board, move, turn): next_turn = 1- turn capture = [] if BC.who(WHITE_KING) == next_turn: king = WHITE_KING else: king = BLACK_KING row_king = None col_king = None coor_row = move[0] coor_col = move[1] for row in range(8): for col in range(8): if board[row][col] == king: row_king = row col_king = col if row_king != None and col_king != None: first_corner = board[row_king][coor_col] second_corner = board[coor_row][col_king] if first_corner != EMPTY and BC.who(first_corner) != next_turn: capture.append([row_king, coor_col]) if second_corner != EMPTY and BC.who(second_corner) != next_turn: capture.append([coor_row, col_king]) if capture != []: return capture else: return None
def pincer(board, location, turn): next_turn = 1 - turn capture = [] # Checks in the 4 directions a pincer can move for direction in range(4): next_space = can_move(location, direction) if next_space != None: next_row = next_space[0] next_column = next_space[1] next_piece = board[next_row][next_column] # if the next location is not empty and is an enemy piece if next_piece != EMPTY and BC.who(next_piece) == next_turn: if next_piece not in [BLACK_PINCER, WHITE_PINCER]: next_next_space = can_move(next_space, direction) # expands move in the given direction if next_next_space != None: next_next_row = next_next_space[0] next_next_col = next_next_space[1] next_next_piece = board[next_next_row][next_next_col] # If the piece behind the enemy is on our team, then this # piece will be captured if next_next_piece != EMPTY and BC.who(next_next_piece) == turn: capture.append(next_space) if capture != []: return capture else: return None
def test_coordinator_capture(self): test1 = bcs.BC_state(BOARD1C, 0) result = pm.coordinator_capture((3, 2), test1.board, 0) self.assertTrue(result == [(3, 4)]) test2 = bcs.BC_state(BOARD2C, 0) result = pm.coordinator_capture((3, 5), test2.board, 1) self.assertTrue(result == [(3, 4)]) print("Coordinator capture Passed")
def test_move_with_imitator_capture(self): test1 = bcs.BC_state(BOARD_I_CAPTURE1, 0) goal1 = bcs.BC_state(BOARD_I_CAPTURE2, 1) self.assertTrue(pm.can_move((3, 4), (3, 0), test1, 2)) self.assertFalse(pm.can_move((3, 4), (4, 4), test1, 2)) result_state = pm.move((3, 4), (3, 0), test1, 2) self.assertTrue(result_state == goal1) #print(result_state) print("Move with imitator capture passed.")
def test_move_with_withdrawer_capture(self): test1 = bcs.BC_state(BOARD_W_CAPTURE1, 1) goal1 = bcs.BC_state(BOARD_W_CAPTURE2, 0) self.assertFalse(pm.can_move((4, 4), (2, 0), test1, 5)) self.assertTrue(pm.can_move((4, 4), (3, 5), test1, 5)) result_state = pm.move((4, 4), (3, 5), test1, 5) #print(result_state) self.assertTrue(result_state == goal1) print("Move with withdrawer_capture passed")
def test_moves_with_leaper_capture(self): test1 = bcs.BC_state(BOARD_L_CAPTURE1, 0) goal1 = bcs.BC_state(BOARD_L_CAPTURE2, 1) self.assertFalse(pm.can_move((2, 6), (6, 2), test1, 6)) self.assertTrue(pm.can_move((2, 6), (5, 3), test1, 6)) result_state = pm.move((2, 6), (5, 3), test1, 6) #print(result_state) self.assertTrue(result_state == goal1) print("Moves with leaper capture passed")
def freezer_search(board, whose_move): frozen = [[], []] for x in range(0, len(board)): for y in range(0, len(board[x])): if board[x][y] - BC.who(board[x][y]) == BC.INIT_TO_CODE['f']: for i, j in value: if x + i >= 0 and y + j >= 0 and x + i <= 7 and y + j <= 7: frozen[BC.who(board[x][y])].append((x + i, y + j)) return frozen
def legal_move(board, current, move, direction): # Initializes current piece piece = board[current[0]][current[1]] next_piece = board[move[0]][move[1]] turn = BC.who(piece) next_turn = 1 - turn # Gets all the space in between the current and move empty_spots, spots = inbetween(board, current, move, direction) # If the piece isn't frozen, find the legal moves if not frozen(board, current): if spots != []: if piece not in [BLACK_IMITATOR, WHITE_IMITATOR, BLACK_KING, WHITE_KING, BLACK_LEAPER, WHITE_LEAPER]: if direction > 3 and piece in [BLACK_PINCER and WHITE_PINCER]: return False else: return empty_spots # if the piece is a leaper, returns whether the leaper is moving # across only empty spaces, or can legally capture an enemy piece elif piece == BLACK_LEAPER or piece == WHITE_LEAPER: can_capture, captured = leaper(board, current, move, spots, empty_spots) if empty_spots: return True else: return can_capture # legal moves for the king elif piece == BLACK_KING or piece == WHITE_KING: # ensures the length of the move is one, and the space # being moved into is either an empty space and not a suicidal # move if len(spots) != 1: return False if spots[0] == EMPTY: return True if BC.who(next_piece) == next_turn: return True else: return False else: opponent = WHITE_KING if next_turn else BLACK_KING can_capture, captured = leaper(board, current, move, spots, empty_spots) return empty_spots or spots[0] == opponent and \ len(spots) == 1 or \ can_capture return False
def test_basic_move(self): test1 = bcs.BC_state(INITIAL, 1) goal1 = bcs.BC_state(BOARD_ONE_MOVE, 0) result_state = pm.move((6, 7), (2, 7), test1, 1) #print(result_state) self.assertTrue(result_state == goal1) test2 = bcs.BC_state(BOARD_ONE_MOVE, 0) goal2 = bcs.BC_state(BOARD_TWO_MOVES, 1) #print(test2.board) result_state = pm.move((1, 6), (2, 6), test2, 1) #print(result_state) self.assertTrue(result_state == goal2) print("basic move passed.")
def test_imitator_capture(self): test1 = bcs.BC_state(BOARD1I, 0) result = pm.chameleon_captures((0, 5), (4, 5), test1.board, 0, 1) self.assertTrue(result == [(4, 4)]) test2 = bcs.BC_state(BOARD2I, 0) result = pm.chameleon_captures((4, 5), (4, 4), test2.board, 0, 2) #print(result) self.assertTrue(result == [(4, 6), (4, 3)]) test3 = bcs.BC_state(BOARD3I, 0) result = pm.chameleon_captures((4, 4), (1, 4), test3.board, 1, 0) #print(result) self.assertTrue(result == (2, 4)) print("Imitator capture passed.")
def makeMove(currentState, currentRemark, timelimit): # Compute the new state for a move. # This is a placeholder that just copies the current state. newState = BC.BC_state(currentState.board) curr_player = newState.whose_move gameBoard = newState.board all_moves = [] for row in range(8): for col in range(8): piece = gameBoard[row][col] piece_side = BC.who(piece) if piece_side == curr_player and not piece == 0: # test if piece is immobilized immobile = isPieceImmobilized(row, col, gameBoard, curr_player) if not immobile: if piece == BC.BLACK_PINCER or piece == BC.WHITE_PINCER: p_moves = findPincerMoves(newState, (row, col)) for move in p_moves: all_moves.append(move) elif piece == BC.BLACK_KING or piece == BC.WHITE_KING: k_moves = findKingMoves(newState, (row, col)) for move in k_moves: all_moves.append(move) else: q_moves = findQueenStyleMoves(newState, (row, col)) for move in q_moves: all_moves.append(move) #findPincerMoves(newState, (1,0)) #findQueenStyleMoves(newState, (3, 2)) #findQueenStyleMoves(newState, (3, 4)) tup = random.choice(all_moves) #print("tuple: " + str(tup)) move = tup[0] newState = tup[1] # Fix up whose turn it will be. newState.whose_move = 1 - currentState.whose_move # Construct a representation of the move that goes from the # currentState to the newState. # Here is a placeholder in the right format but with made-up # numbers: #move = ((6, 4), (3, 4)) # Make up a new remark newRemark = "I'll think harder in some future game. Here's my move" return [[move, newState], newRemark]
def test_king_in_check(self): test1 = bcs.BC_state(BOARD1K, 0) result = pm.is_king_in_check(test1.board, (0, 4), 0) self.assertTrue(result == True) test2 = bcs.BC_state(BOARD2K, 0) result = pm.is_king_in_check(test2.board, (1, 3), 0) self.assertTrue(result == True) test3 = bcs.BC_state(BOARD3K, 0) result = pm.is_king_in_check(test3.board, (2, 4), 0) self.assertTrue(result == True) test4 = bcs.BC_state(BOARD1P, 0) result = pm.is_king_in_check(test4.board, (0, 4), 0) self.assertTrue(result == False) print("Test king is in check passed.")
def test_pincer_capture(self): test1 = bcs.BC_state(BOARD1P, 0) result = pm.pincer_capture((3, 7), BOARD1P, 1) #print(result) self.assertTrue(result == [(3, 6)]) test2 = bcs.BC_state(BOARD2P, 0) result = pm.pincer_capture((3, 2), BOARD2P, 0) #print(result) self.assertTrue(result == [(4, 2)]) test3 = bcs.BC_state(BOARD3P, 0) result = pm.pincer_capture((3, 2), BOARD3P, 0) #print(result) self.assertTrue(result == None) print("Test pincer capture passed.")
def pincher_function(state, x, y, z_h): global ZOBRIST_M piece = state.board[x][y] for i, j in value[0:4]: if on_board_or_not( x, y) and on_board_or_not(x + i, y + j) and on_board_or_not( x + 2 * i, y + 2 * j) and BC.who(state.board[x + i][y + j]) != BC.who( piece) and state.board[x + 2 * i][y + 2 * j] == piece: z_h ^= ZOBRIST_N[8 * (x + i) + y + j][state.board[x + i][y + j]] state.board[x + i][y + j] = 0 state.static_eval() ZOBRIST_M[z_h] = z_node(state) return state
def successors(state, turn): board = state.board next_turn = 1 - turn moves = [] # Search through every piece by row-major order if winTester.winTester(state) == 'No win': for row in range(0, 8): for column in range(0, 8): piece = board[row][column] square = row, column # If the piece is friendly if piece != EMPTY and BC.who(piece) == turn: # If the piece is a pincer it can only move up # and down, else it can go in all 8 directions if piece == BLACK_PINCER or piece == WHITE_PINCER: direction = 4 else: direction = 8 for dir in range(direction): # Finds whether this movement is actually on the board possible_square = can_move(square, dir) # Keeps looking to find the legal moves of given piece # in all the directions it can move while possible_square != None: next_row = possible_square[0] next_col = possible_square[1] next_piece = board[next_row][next_col] # A piece can't go on top of a friendly piece if next_piece != EMPTY and BC.who(next_piece) == state.whose_move: break # A piece cannot go past another piece or land on another piece if # they are not an imitator, leaper, or king. if piece not in [BLACK_IMITATOR, WHITE_IMITATOR, \ BLACK_LEAPER, WHITE_LEAPER, BLACK_KING, WHITE_KING] and \ next_piece != EMPTY and BC.who(next_piece) == next_turn: break # If the move is considered legal given the piece, then you can # add this move to the given successors list if legal_move(board, square, possible_square, dir): move = [square[0], square[1], possible_square[0], possible_square[1], dir] moves.append(move) possible_square = can_move(possible_square, dir) return moves
def coordinator_function(state, x, y, z_h): global ZOBRIST_M newx, newy = state.kingP[state.whose_move] if on_board_or_not(x, y) and on_board_or_not(x, newy) and BC.who( state.board[x][y]) != BC.who(state.board[x][newy]): z_h ^= ZOBRIST_N[8 * x + newy][state.board[x][newy]] state.board[x][newy] = 0 if on_board_or_not(x, y) and on_board_or_not( newx, y) and BC.who(state.board[x][y]) != BC.who(state.board[newx][y]): z_h ^= ZOBRIST_N[8 * newx + y][state.board[newx][y]] state.board[newx][y] = 0 state.static_eval() ZOBRIST_M[z_h] = z_node(state) return state
def king_function(state, x, y, x1, y1, z_h): global ZOBRIST_M if on_board_or_not(x, y) and on_board_or_not( x1, y1) and BC.who(state.board[x1][y1]) != BC.who( state.board[x][y]) or state.board[x1][y1] == 0: if state.board[x1][y1] != 0: z_h ^= ZOBRIST_N[8 * x1 + y1][state.board[x1][y1]] z_h ^= ZOBRIST_N[8 * x1 + y1][state.board[x][y]] z_h ^= ZOBRIST_N[8 * x + y][state.board[x][y]] state.board[x1][y1] = state.board[x][y] state.board[x][y] = 0 state.kingP[state.whose_move] = (x1, y1) state.static_eval() ZOBRIST_M[z_h] = z_node(state) return state
def loadInfo(): global Q_VALUE_FILE, POLICY f = open(Q_VALUE_FILE, "r") policy = {} while True: state = f.read(64) action = f.read(4) if not state or not action: break # create state board = [[0, 0, 0, 0, 0, 0, 0, 0] for r in range(8)] for v in range(64): i = int(v / 8) j = v % 8 board[i][j] = int(state[v], 16) state = BC.BC_state(board, BC.WHITE) # craete move start_i = int(action[0], 16) start_j = int(action[1], 16) end_i = int(action[2], 16) end_j = int(action[3], 16) move = ((start_i, start_j), (end_i, end_j)) # add policy policy[state] = move f.close() POLICY = policy
def hasLost(state, side=BC.WHITE): board = state.board for row in board: for piece in row: if (piece == 12 or piece == 13) and BC.who(piece) == side: return False return True
def withd_move(currentState, posx, posy): State = [] side = currentState.whose_move direction_x = [-1, -1, 0, 1, 1, 1, 0, -1] direction_y = [0, 1, 1, 1, 0, -1, -1, -1] if non_freezer(currentState, posx, posy): for i in range(8): for length in range(1, 8): posx_new = posx + direction_x[i] * length posy_new = posy + direction_y[i] * length if outofrange(posx_new, posy_new) or ( currentState.board[posx_new][posy_new] != 0): break else: newState = BC.BC_state(currentState.board) newState.whose_move = 1 - currentState.whose_move newState.board[posx_new][posy_new] = newState.board[posx][ posy] newState.board[posx][posy] = 0 if not (outofrange(posx + direction_x[(i + 4) % 8], posy + direction_y[(i + 4) % 8])): if notsameside( newState.board[posx + direction_x[(i + 4) % 8]] [posy + direction_y[(i + 4) % 8]], currentState.board[posx][posy]): newState.board[posx + direction_x[(i + 4) % 8]][ posy + direction_y[(i + 4) % 8]] = 0 State.append( [newState, [posx, posy], [posx_new, posy_new]]) return (State)
def coord_move(currentState, posx, posy): State = [] side = currentState.whose_move direction_x = [-1, -1, 0, 1, 1, 1, 0, -1] direction_y = [0, 1, 1, 1, 0, -1, -1, -1] if non_freezer(currentState, posx, posy): for i in range(8): for length in range(1, 8): posx_new = posx + direction_x[i] * length posy_new = posy + direction_y[i] * length if outofrange(posx_new, posy_new) or ( currentState.board[posx_new][posy_new] != 0): break else: newState = BC.BC_state(currentState.board) newState.whose_move = 1 - currentState.whose_move newState.board[posx_new][posy_new] = newState.board[posx][ posy] newState.board[posx][posy] = 0 #Search king j = [j for j in newState.board if (12 + side) in j][0] king_pos_x = newState.board.index(j) king_pos_y = j.index(12 + side) if (newState.board[posx_new][king_pos_y] != 0) and ( newState.board[posx_new][king_pos_y] % 2) != side: newState.board[posx_new][king_pos_y] = 0 if (newState.board[posx_new][king_pos_y] != 0) and ( newState.board[king_pos_x][posy_new] % 2) != side: newState.board[king_pos_x][posy_new] = 0 State.append( [newState, [posx, posy], [posx_new, posy_new]]) return (State)
def pawn_move(currentState, posx, posy): State = [] side = currentState.whose_move direction_x = [-1, 0, 1, 0] direction_y = [0, -1, 0, 1] if non_freezer(currentState, posx, posy): for i in range(4): for length in range(1, 8): posx_new = posx + direction_x[i] * length posy_new = posy + direction_y[i] * length if outofrange(posx_new, posy_new) or ( currentState.board[posx_new][posy_new] != 0): break else: newState = BC.BC_state(currentState.board) newState.whose_move = 1 - currentState.whose_move newState.board[posx_new][posy_new] = newState.board[posx][ posy] newState.board[posx][posy] = 0 for j in range(4): if not (outofrange(posx_new + 2 * direction_x[j], posy_new + 2 * direction_y[j])): if pawn_capture(newState, posx_new, posy_new, posx_new + direction_x[j], posy_new + direction_y[j]): newState.board[posx_new + direction_x[j]][ posy_new + direction_y[j]] = 0 State.append( [newState, [posx, posy], [posx_new, posy_new]]) return (State)
def alpha_beta_pruning(current_depth, max_ply, current_state, turn, alpha, beta, start_time, time_limit): global states_evaluated, retrieved, min_eval, max_eval # instantly return if it exceeds time limit if time.time() - start_time >= time_limit * 0.9: return current_state moves = valid_moves(current_state) best_move = BC.BC_state(current_state.board, current_state.whose_move) # instantly return if there's no move or reached depth if not moves or current_depth == max_ply: return current_state # check each valid move for move in moves: state = alpha_beta_pruning( current_depth + 1, max_ply, move, turn, alpha, beta, start_time, time_limit) eval_val = staticEval(state) move_value = eval_val min_eval = min(min_eval, move_value) max_eval = max(move_value, max_eval) print("--------------") print(alpha) print(beta) if turn == 1: if eval_val > alpha: alpha = eval_val best_move = state else: if eval_val < beta: beta = eval_val best_move = state if alpha >= beta: return best_move return best_move
def pincer_capture(state, cur_pos): ''' check if pincer moves capture any pieces and return a new state :param state: state of the board :param cur_pos: tuple of the position :return: new state of after pincer captures ''' new_state=BC.BC_state(state.board, state.whose_move) new_row = cur_pos[0] new_col = cur_pos[1] for dir_key in range(4): dire = ALL_DIRECTION[dir_key] possible_enemy_pos = (new_row+dire[0], new_col+dire[1]) possible_firendly_pos = (new_row + dire[0] * 2, new_col + dire[1] * 2) hasEnemy = False hasFirendly = False hasSpace = possible_firendly_pos[0] >= 0 and possible_firendly_pos[ 0] < NUM_COLS and possible_firendly_pos[1] >= 0 and possible_firendly_pos[1] < NUM_ROWS if hasSpace: possible_enemy_tile = new_state.board[possible_enemy_pos[0]][possible_enemy_pos[1]] hasEnemy = possible_enemy_tile != 0 and possible_enemy_tile % 2 != new_state.whose_move possible_firendly_tile = new_state.board[possible_firendly_pos[0]][possible_firendly_pos[1]] hasFirendly = possible_firendly_tile != 0 and possible_firendly_tile % 2 == new_state.whose_move # check if there's enemy piece in between pincer and other friendly piece if hasEnemy and hasFirendly and hasSpace: # new_state = BC.BC_state(state.board, state.whose_move) new_state.board[possible_enemy_pos[0]][possible_enemy_pos[1]] = 0 return new_state
def valid_moves(state): # check for invalid state if state is None: return [] board = BC.BC_state(state.board, state.whose_move) moves = [] for i, row in enumerate(board.board): for j, tile in enumerate(row): # make sure the cell is nonempty and is occupied by a piece owned by whoever's turn current turn if tile != 0 and tile % 2 == board.whose_move and not_frozen(board, i, j): if tile // 2 == 1: # pincer movement moves += pincer_moves(board, i, j) elif tile // 2 == 2: # coordiantor movement moves += coordinator_moves(board, i, j) elif tile // 2 == 3: # eaper movement moves += leaper_moves(board, i, j) elif tile // 2 == 4: # IMITATOR movement moves += imitator_moves(board, i, j) elif tile // 2 == 5: # WITHDRAWER movement moves += withdrawer_moves(board, i, j) elif tile // 2 == 6: # King movement moves += king_moves(board, i, j) else: # freezer movement moves += freezer_moves(board, i, j) return moves
def withdrawer_capture(state, pre_pos, dir): ''' :param state: :param pre_pos: :param dir: :return: ''' oppo_dir = (-1*dir[0], dir[1]*-1) if oppo_dir[0]+pre_pos[0] >= 0 and oppo_dir[0]+pre_pos[0] < NUM_COLS and oppo_dir[1]+pre_pos[1] >= 0 and \ oppo_dir[1]+pre_pos[1] < NUM_ROWS and state.board[oppo_dir[0]][oppo_dir[1]] != 0 and \ state.board[oppo_dir[0]][oppo_dir[1]] % 2 != state.whose_move: new_state = BC.BC_state(state.board, state.whose_move) new_state.board[oppo_dir[0]+pre_pos[0]][oppo_dir[1]+pre_pos[1]] = 0 return new_state return BC.BC_state(state.board, state.whose_move)