From fb3f5d13949b174f9381247e5e440a4fa819b6bf Mon Sep 17 00:00:00 2001 From: jake Date: Fri, 24 Feb 2023 20:38:00 -0500 Subject: [PATCH] add ai movement based on 'points' gained/lost --- Main.gd | 158 +++++++++++++++++++++++++++++++++++++++++--------- project.godot | 8 +++ 2 files changed, 139 insertions(+), 27 deletions(-) diff --git a/Main.gd b/Main.gd index 636f9f9..5b4bd89 100644 --- a/Main.gd +++ b/Main.gd @@ -34,13 +34,18 @@ var team2 = 2 func _ready(): make_player1("green") - make_player2("red") + #make_player2("red") #checkmatet1() #checkmatet2() #spawn_piece("pawn", "teal", 2, 6, team1) - #spawn_piece("pawn", "red", 3, 4, team2) - #spawn_piece("rook", "red", 0, 5, team2) + #spawn_piece("pawn", "teal", 2, 1, team1) + #spawn_piece("knight", "teal", 4, 6, team1) + #spawn_piece("knight", "teal", 5, 4, team1) + #spawn_piece("rook", "teal", 7, 6, team1) + + #spawn_piece("queen", "red", 3, 5, team2) + #spawn_piece("pawn", "red", 7, 1, team2) var captures = update_capture_tables(board_to_text_board(board)) team1_capture = captures[0] @@ -73,10 +78,18 @@ func _process(_delta): if click_spot() == Vector2(0,0): print(history) if click_spot() == Vector2(1,0): + print("Queuing for team2...") + ai_move(team2, board_to_text_board(board), ai_modes.points, 1) + if click_spot() == Vector2(1,1): + print("Killing pawn: %s" % [evaluate_move([3,5], [2,6], board_to_text_board(board), team2, 1)]) + print("Killing knight: %s" % [evaluate_move([3,5], [4,6], board_to_text_board(board), team2, 1)]) + print("Going to (3,1): %s" % [evaluate_move([3,5], [3,1], board_to_text_board(board), team2, 1)]) + print("Going to (3,4) (enemy controlled): %s" % [evaluate_move([3,5], [3,4], board_to_text_board(board), team2, 1)]) + if click_spot() == Vector2(1,2): #print(team2_every_legal_move(board_to_text_board(board))) - print("whoops") - if click_spot() == Vector2(2,0): - print(board_to_text_board(board)) + print("Queuing for team1...") + ai_move(team1, board_to_text_board(board), ai_modes.points, 1) + #print("Killing queen: %s" % evaluate_move([2,6], [3,5], board_to_text_board(board), team1, 1)) if click_spot() == Vector2(4,0): color_tiles(team2_capture, "red") if click_spot() == Vector2(5,0): @@ -93,7 +106,7 @@ func _process(_delta): enum ai_modes { purely_random, weighted_random, - minimax_depth_2, + points, } var ai_weights = { @@ -101,30 +114,110 @@ var ai_weights = { knight = 30, bishop = 30, rook = 50, - queen = 80, + queen = 500, king = 1000, } -func ai_move(team, text_board, ai_mode=ai_modes.purely_random): +func ai_move(team, text_board, ai_mode=ai_modes.purely_random, depth=1): var legal_every_move = team_every_legal_move(text_board, team) + var the_move if ai_mode == ai_modes.purely_random: - ai_random_move(legal_every_move) + the_move = ai_random_move(team, text_board, legal_every_move) elif ai_mode == ai_modes.weighted_random: - ai_weighted_random(team, text_board, legal_every_move) - elif ai_mode == ai_modes.minimax_depth_2: - ai_minimax_depth_2(team, text_board, legal_every_move) + the_move = ai_weighted_random(team, text_board, legal_every_move) + elif ai_mode == ai_modes.points: + the_move = ai_points_system(team, legal_every_move, text_board, depth) + #print(the_move) + if the_move: + if the_move[1]: + ai_make_move(the_move[1], the_move[2]) new_turn() -func ai_minimax_depth_2(team, text_board, legal_every_move): - pass +func ai_points_system(team, legal_moves, text_board, depth=2): + var best = [-INF, null] + var alpha = -INF + var beta = -INF + legal_moves.shuffle() + for every_moves in legal_moves: + var piece = every_moves[0] + var moves = every_moves[1] + for move in moves: + var eval = evaluate_move(piece, move, text_board, team, depth) + #var eval = eval_move2(piece, move, text_board, team, depth) + if eval > best[0]: + best = [eval, piece, move] + print("This move is worth: %s" % best[0]) + return best + +func evaluate_move(piece, move, text_board, team, depth, add_points=false): + var p_board = generate_points_board(team, text_board) + var points = p_board[move[0]][move[1]] + if depth == 0 or depth <= 0: + return points + + # evaluate opposing team now + var eval_board + eval_board = ai_text_board_move(text_board.duplicate(true), piece, move) + var legal_moves + if team == team1: + legal_moves = team_every_legal_move(eval_board, team2) + else: # team2 + legal_moves = team_every_legal_move(eval_board, team1) + var highest_opposing_points = 0 + for every_moves in legal_moves: + var this_piece = every_moves[0] + for this_move in every_moves[1]: + var eval + if team == team1: + eval = evaluate_move(this_piece, this_move, eval_board.duplicate(true), team2, depth-1, !add_points) + else: # team2 + eval = evaluate_move(this_piece, this_move, eval_board.duplicate(true), team1, depth-1, !add_points) + if eval > highest_opposing_points: + #rint("Piece at (%s) moves to (%s), gaining %s points" % [this_piece, this_move, eval]) + highest_opposing_points = eval + if add_points: + points += highest_opposing_points + else: + points -= highest_opposing_points + + return points + +func ai_text_board_move(text_board, piece, move): + var new_board = text_board.duplicate(true) + var pos = new_board[piece[0]][piece[1]] + pos[text_board_ele.has_moved] = true + new_board[move[0]][move[1]] = pos + new_board[piece[0]][piece[1]] = 0 + + if move.size() == 3: + #rint(new_board[move[0]][move[1] - 1]) + if move[2] == movement_condition.en_passant_kill: + if move[1] + 1 < 8 and new_board[move[0]][move[1] + 1] is Array and new_board[move[0]][move[1] + 1][text_board_ele.en_passant]: + new_board[ move[0] ][(move[1] + 1)] = 0 + elif move[1] - 1 > 0 and new_board[move[0]][(move[1] - 1)] is Array and new_board[move[0]][move[1] - 1][text_board_ele.en_passant]: + new_board [move[0] ][(move[1] - 1)] = 0 + elif move[2] == movement_condition.king_side_castling: + # TODO hard coding rook positions like this seems bad + var rook = new_board[7][pos[1]] + new_board[5][pos[1]] = rook + new_board[7][pos[1]] = 0 + elif move[2] == movement_condition.queen_side_castling: + # TODO hard coding rook positions like this seems bad + var rook = new_board[0][pos[1]] + new_board[3][pos[1]] = rook + new_board[0][pos[1]] = 0 + return new_board func ai_make_move(piece, move): + #rint(piece) + #rint(move) var pos = position_to_board_cell(Vector2(piece[0] * board_cell, piece[1] * board_cell)) var board_piece = board[pos[0]][pos[1]] board_piece.position = in_square(Vector2(move[0] * board_cell, move[1] * board_cell)) if board[move[0]][move[1]]: board[move[0]][move[1]].kill() board[move[0]][move[1]] = board_piece + board[move[0]][move[1]].has_moved = true board[pos[0]][pos[1]] = 0 if move.size() == 3: @@ -143,7 +236,7 @@ func ai_make_move(piece, move): board[3][pos[1]] = board[0][pos[1]] board[0][pos[1]] = 0 -func ai_random_move(legal_every_move): +func ai_random_move(team, text_board, legal_every_move): legal_every_move.shuffle() while 1: var piece_and_moves = legal_every_move.pop_back() @@ -156,16 +249,14 @@ func ai_random_move(legal_every_move): #rint(moves) moves.shuffle() var move = moves.pop_back() - ai_make_move(piece, move) - return + #rint( ai_text_board_move(board_to_text_board(board), piece, move) ) + #ai_make_move(piece, move) + var p_board = generate_points_board(team, text_board) + return [p_board[move[0]][move[1]], piece, move] else: continue -func ai_weighted_random(team, text_board, legal_every_move): - # generate a board with 'points' on it. - # if move[x],move[y] corrispond over some points keep the move in memory. then, sort move by smallest to greatest points - # pop_back() to get 'best move'. if there are no moves, just do random movement. - var p_board = generate_points_board(team, text_board) +func get_moves_with_points(p_board, legal_every_move): var saved_moves = [] for every_move in legal_every_move: var piece = every_move[0] @@ -180,15 +271,28 @@ func ai_weighted_random(team, text_board, legal_every_move): saved_moves.append([p_board[move[0]][move[1]], piece, move]) else: continue + return saved_moves + +func ai_weighted_random(team, text_board, legal_every_move, dict = {"no_shuffle":false, "skip_amount":0}): + # generate a board with 'points' on it. + # if move[x],move[y] corrispond over some points keep the move in memory. then, sort move by smallest to greatest points + # pop_back() to get 'best move'. if there are no moves, just do random movement. + var p_board = generate_points_board(team, text_board) + var saved_moves = get_moves_with_points(p_board, legal_every_move) if saved_moves.size() > 0: - saved_moves.shuffle() + if ! dict.get("no_shuffle"): + saved_moves.shuffle() #rint(saved_moves) saved_moves.sort_custom(self, "sort_ascending") # sort, by smallest to greatest, then pop_back() print(saved_moves) - var the_move = saved_moves.pop_back() - ai_make_move(the_move[1], the_move[2]) + var the_move + the_move = saved_moves.pop_back() + for i in dict.get("skip_amount"): + the_move = saved_moves.pop_back() + #ai_make_move(the_move[1], the_move[2]) + return the_move else: - ai_random_move(legal_every_move) + return ai_random_move(team, text_board, legal_every_move) func sort_ascending(a, b): if a[0] < b[0]: diff --git a/project.godot b/project.godot index 91e12b7..af74602 100644 --- a/project.godot +++ b/project.godot @@ -34,6 +34,10 @@ window/stretch/aspect="expand" singletons=[ "res://addons/godot-git-plugin/git_api.gdnlib" ] +[global] + +limit=false + [input] mouse1={ @@ -47,6 +51,10 @@ mouse2={ ] } +[network] + +limits/debugger_stdout/max_chars_per_second=9999999999 + [physics] common/enable_pause_aware_picking=true