extends Node export (PackedScene) var piece_scene export (PackedScene) var movetile_scene var board = new_board() var board_cell = 128 const BOARD_WIDTH = 7 # starting at 0..7 const BOARD_HEIGHT = 7 var history = [] var team1_capture = new_board() var team2_capture = new_board() var game_over = false var movement_layer = false var movement_layer_piece = null var en_passant_pawn = null var en_passant_wait = 0 # how many times any piece on the board must move before en_passant_pawn gets set to null var team1_king = null var team2_king = null # hack to prevent 'clicking' on a killed piece var safely_handle_movement = false var turn = 0 var team1 = 1 var team2 = 2 func _ready(): make_player1("green") #make_player2("red") #checkmatet1() #checkmatet2() #spawn_piece("pawn", "teal", 2, 6, team1) #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] team2_capture = captures[1] save_turn() OS.set_window_size(Vector2(700,700)) randomize() #OS.set_window_always_on_top(true) func checkmatet1(): team1_king = spawn_piece('king', 'orange', 4, 7, team1) spawn_piece('bishop', 'orange', 3, 7, team1) spawn_piece('pawn', 'orange', 5, 6, team1) spawn_piece('pawn', 'orange', 3, 6, team1) spawn_piece('pawn', 'orange', 4, 6, team1) spawn_piece('rook', 'teal', 7, 3, team2) func checkmatet2(): team2_king = spawn_piece('king', 'teal', 4, 0, team2) spawn_piece('bishop', 'teal', 3, 0, team2) spawn_piece('pawn', 'teal', 5, 1, team2) spawn_piece('pawn', 'teal', 3, 1, team2) spawn_piece('pawn', 'teal', 4, 1, team2) spawn_piece('rook', 'orange', 7, 2, team1) func _process(_delta): safely_handle_movement = false if Input.is_action_just_pressed("mouse2"): 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("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): color_tiles(team1_capture, "green") if click_spot() == Vector2(7,0): ai_move(team2, board_to_text_board(board)) if click_spot() == Vector2(7,1): ai_move(team1, board_to_text_board(board)) if click_spot() == Vector2(6,0): ai_move(team2, board_to_text_board(board), ai_modes.weighted_random) if click_spot() == Vector2(6,1): ai_move(team1, board_to_text_board(board), ai_modes.weighted_random) enum ai_modes { purely_random, weighted_random, points, } var ai_weights = { pawn = 10, knight = 30, bishop = 30, rook = 50, queen = 500, king = 1000, } 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: the_move = ai_random_move(team, text_board, legal_every_move) elif ai_mode == ai_modes.weighted_random: 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_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: if move[2] == movement_condition.en_passant_kill: kill_en_passant_pawn([move[0], move[1]]) elif move[2] == movement_condition.king_side_castling: # TODO hard coding rook positions like this seems bad var rook = board[7][pos[1]] rook.position = in_square(Vector2(5 * board_cell, pos[1] * board_cell)) board[5][pos[1]] = board[7][pos[1]] board[7][pos[1]] = 0 elif move[2] == movement_condition.queen_side_castling: # TODO hard coding rook positions like this seems bad var rook = board[0][pos[1]] rook.position = in_square(Vector2(3 * board_cell, pos[1] * board_cell)) board[3][pos[1]] = board[0][pos[1]] board[0][pos[1]] = 0 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() if ! piece_and_moves: if ! legal_every_move: break # AI literally cannot move this turn, game should be offically over before this occurs var piece = piece_and_moves[0] var moves = piece_and_moves[1] if moves: #rint(moves) moves.shuffle() var move = moves.pop_back() #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 get_moves_with_points(p_board, legal_every_move): var saved_moves = [] for every_move in legal_every_move: var piece = every_move[0] var moves = every_move[1] if moves: for move in moves: if p_board[move[0]][move[1]] is Array: # en passant 'move' specifically does array if piece[2] == piece_names.pawn: saved_moves.append([p_board[move[0]][move[1]], piece, move]) elif p_board[move[0]][move[1]] > 0: 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: 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 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: return ai_random_move(team, text_board, legal_every_move) func sort_ascending(a, b): if a[0] < b[0]: return true return false func generate_points_board(team, text_board): var p_board = new_board() for i in 8: for k in 8: var piece = text_board[i][k] if piece: match piece[text_board_ele.piece_enum]: piece_names.pawn: if piece[text_board_ele.team] == team: # our pawn p_board[i][k] = -1 * ai_weights.pawn if piece[text_board_ele.en_passant]: print("this teams (%s) pawn is en passant, on our team" % piece[text_board_ele.team]) pass else: # their pawn p_board[i][k] = ai_weights.pawn if piece[text_board_ele.en_passant]: print("this teams (%s) pawn is en passant, on enemy team" % piece[text_board_ele.team]) if team == team1: # they'll be team2 here p_board[i][(k - 1)] = [ai_weights.pawn, true] else: # they'll be team1 here # team1 pawn goes 'up' -1 or -2 each movement, so the space behind it will be +1 p_board[i][(k + 1)] = [ai_weights.pawn, true] piece_names.rook: if piece[text_board_ele.team] == team: p_board[i][k] = -1 * ai_weights.rook else: p_board[i][k] = ai_weights.rook piece_names.knight: if piece[text_board_ele.team] == team: p_board[i][k] = -1 * ai_weights.knight else: p_board[i][k] = ai_weights.knight piece_names.bishop: if piece[text_board_ele.team] == team: p_board[i][k] = -1 * ai_weights.bishop else: p_board[i][k] = ai_weights.bishop piece_names.queen: if piece[text_board_ele.team] == team: p_board[i][k] = -1 * ai_weights.queen else: p_board[i][k] = ai_weights.queen piece_names.king: if piece[text_board_ele.team] == team: p_board[i][k] = -1 * ai_weights.king else: p_board[i][k] = ai_weights.king else: if ! p_board[i][k]: # don't clobber en passant points p_board[i][k] = 0 return p_board func new_turn(): check_for_promotion() var text_board = board_to_text_board(board) var captures = update_capture_tables(text_board) team1_capture = captures[0] team2_capture = captures[1] #print(captures) is_king_team1_checked(text_board, true, team2_capture) is_king_team2_checked(text_board, true, team1_capture) turn += 1 print("Turn: %s" % turn) save_turn() print("-------------------") func save_turn(): var text_board = board_to_text_board(board) history.append(text_board) enum piece_names { pawn, rook, knight, bishop, king, queen } enum text_board_ele { piece_enum, team, en_passant, has_moved, in_check } func board_to_text_board(boarde): var text_board = new_board() for i in 8: for k in 8: if boarde[i][k] is Object: var curr_piece = boarde[i][k] var piece_name = curr_piece.get_piece() var piece_enum = piece_names.get(piece_name) var team = curr_piece.get_team() var has_moved = curr_piece.has_moved var in_check = curr_piece.in_check var en_passant = null if curr_piece == en_passant_pawn: en_passant = 1 #var color = curr_piece.get_piece_color_by_region() text_board[i][k] = [piece_enum, team, en_passant, has_moved, in_check] else: text_board[i][k] = 0 return text_board enum movement_condition { not_attacking, must_attack, en_passant_kill, king_side_castling, queen_side_castling, } func update_capture_tables(text_board, setting=tile_setting.hide_tiles_and_cover_allies): var t1_capture = new_board() var t2_capture = new_board() var pieces = get_pieces(text_board) for e in pieces: var coords = e[chess_enum.pos] if e[chess_enum.team] == team1: t1_capture[coords[0]][coords[1]] = 2 else: # team2 t2_capture[coords[0]][coords[1]] = 2 for e in pieces: var coords = e[chess_enum.pos] var pattern = get_move_pattern(e, coords) var captured = can_chess_move(pattern, coords, text_board, setting) if e[chess_enum.team] == team1: for c in captured: if c.size() == 3: if c[2] == movement_condition.not_attacking: continue t1_capture[c[0]][c[1]] = 1 else: # team2 for c in captured: if c.size() == 3: if c[2] == movement_condition.not_attacking: continue t2_capture[c[0]][c[1]] = 1 #print(team1_capture) #print(team2_capture) #color_tiles(t2_capture, "red") #color_tiles(t1_capture, "green") return [t1_capture, t2_capture] func color_tiles(capture, color): for i in 8: for k in 8: if capture[i][k] == 1: var move_tile = movetile_scene.instance() add_child(move_tile) move_tile.set_color(color) move_tile.position = in_square(Vector2(i * board_cell, k * board_cell)) func check_for_promotion(): var pieces = get_tree().get_nodes_in_group("piece") for e in pieces: if e.get_piece() == "pawn": var y = position_to_board_cell(e.position)[1] if y == 0 or y == 7: print("pawn is elligable for promotion") # TODO: player option e.set_piece("queen", e.get_piece_color_by_region()) func is_king_team2_checked(text_board, enumerate=true, capture_table=[]): if team2_king: for i in 8: for k in 8: if text_board[i][k] and text_board[i][k][chess_enum.piece_enum] == piece_names["king"] and text_board[i][k][chess_enum.team] == team2: if capture_table[i][k] >= 1: if enumerate: print("Aye, team2 in check.") team2_king.in_check = true if enumerate_checkmate(text_board, 2): print("Game over: Checkmate! Team 1 wins!") game_over = true return true else: team2_king.in_check = false return false func is_king_team1_checked(text_board, enumerate=true, capture_table=[]): if team1_king: for i in 8: for k in 8: if text_board[i][k] and text_board[i][k][chess_enum.piece_enum] == piece_names["king"] and text_board[i][k][chess_enum.team] == team1: if capture_table[i][k] >= 1: if enumerate: print("Aye, team1 in check.") team1_king.in_check = true if enumerate_checkmate(text_board, 1): print("Game over: Checkmate! Team 2 wins!") game_over = true return true else: team1_king.in_check = false return false func enumerate_checkmate(text_board, which_king=1): var checkmate = true var legal_every_move = team_every_legal_move(text_board, which_king) for every_move in legal_every_move: var piece = every_move[0] #rint("piece at (%s,%s)" % [piece[0],piece[1]]) for move in every_move[1]: #print("can move to: (%s,%s)" % [move[0],move[1]]) var fake_board = pretend_text_board_movement(text_board.duplicate(true), piece, move) #print(text_board) #print(fake_board) var fake_captures = update_capture_tables(fake_board.duplicate(true)) var t1_captures = fake_captures[0] var t2_captures = fake_captures[1] if which_king == 1: if is_king_team1_checked(fake_board, false, t2_captures): pass else: checkmate = false else: # team2 if is_king_team2_checked(fake_board, false, t1_captures): pass else: checkmate = false return checkmate func get_pieces(text_board): var pieces = [] var deepcopy = text_board.duplicate(true) for i in 8: for k in 8: if deepcopy[i][k] is Array: deepcopy[i][k].append([i,k]) pieces.append(deepcopy[i][k]) # 6 return pieces func team_every_legal_move(text_board, team): var every_legal_move = [] for i in 8: for k in 8: if text_board[i][k] is Array and text_board[i][k][chess_enum.team] == team: var piece_name = text_board[i][k][chess_enum.piece_enum] var coords = [i,k] var move_pattern #var name_of_this = match_piece_names_enums(piece_name) move_pattern = get_move_pattern([piece_name, team], coords) every_legal_move.append([[i,k, piece_name], can_chess_move(move_pattern, coords, text_board, tile_setting.hide_tiles_no_cover_allies)]) #rint(every_legal_move) return every_legal_move func match_piece_names_enums(piece_name): if piece_names["pawn"] == piece_name: return "pawn" elif piece_names["rook"] == piece_name: return "rook" elif piece_names["knight"] == piece_name: return "knight" elif piece_names["bishop"] == piece_name: return "bishop" elif piece_names["queen"] == piece_name: return "queen" elif piece_names["king"] == piece_name: return "king" else: print("unknown piece: %s" % piece_name) func pretend_text_board_movement(text_board, old_coords, new_coords): #print("old coords: (%s , %s)" % old_coords) #print("new coords: (%s , %s)" % [new_coords[0], new_coords[1]]) #print(text_board) var new_text_board = text_board.duplicate(true) new_text_board[new_coords[0]][new_coords[1]] = new_text_board[old_coords[0]][old_coords[1]] new_text_board[old_coords[0]][old_coords[1]] = 0 #print(new_text_board) return new_text_board func remove_movement_layer(): movement_layer = false movement_layer_piece = null var movement_tiles = get_tree().get_nodes_in_group("tile") for e in movement_tiles: e.queue_free() func piece_clicked(piece): if movement_layer: print("I was clicked on, but the movement layer is toggled") if movement_layer_piece == click_spot(): remove_movement_layer() else: if ! safely_handle_movement: #var piece_name = piece.get_piece() #rint("You clicked on a %s, team %s" % [piece_name, piece.get_team()]) var location = click_spot() #rint("Spot: %s " % location) var pattern = get_move_pattern(piece, location) if can_chess_move(pattern, location, board_to_text_board(board)): movement_layer = true movement_layer_piece = location func click_spot(): var square = get_viewport().get_mouse_position() square[0] = floor(square[0] / board_cell) square[1] = floor(square[1] / board_cell) return square func make_player2(color): spawn_piece('rook', color, 0, 0, team2) spawn_piece('knight', color, 1, 0, team2) spawn_piece('bishop', color, 2, 0, team2) spawn_piece('queen', color, 3, 0, team2) team2_king = spawn_piece('king', color, 4, 0, team2) spawn_piece('bishop', color, 5, 0, team2) spawn_piece('knight', color, 6, 0, team2) spawn_piece('rook', color, 7, 0, team2) for i in BOARD_WIDTH + 1: spawn_piece('pawn', color, i , 1, team2) func make_player1(color): spawn_piece('rook', color, 0, 7, team1) spawn_piece('knight', color, 1, 7, team1) spawn_piece('bishop', color, 2, 7, team1) spawn_piece('queen', color, 3, 7, team1) team1_king = spawn_piece('king', color, 4, 7, team1) spawn_piece('bishop', color, 5, 7, team1) spawn_piece('knight', color, 6, 7, team1) spawn_piece('rook', color, 7, 7, team1) for i in BOARD_WIDTH + 1: spawn_piece('pawn', color, i , 6, team1) func spawn_piece(piece_name, color, x=0, y=0, team=0): var piece = piece_scene.instance() piece.init(piece.piece_map.get(piece_name), piece.piece_color.get(color), team) add_child(piece) piece.connect("clicked", self, "piece_clicked", [piece]) board_add_piece(piece, x, y) piece.position = in_square(Vector2(x * board_cell, y * board_cell)) return piece func rand_pos(): return Vector2(rand_range(0, get_viewport().size.x),rand_range(0, get_viewport().size.y)) # needs to be Vector2 as that is what object.position takes func in_square(vect2): #rint(vect2) vect2.x = ceil(vect2.x / board_cell) #rint(vect2.x) vect2.x *= board_cell vect2.x += board_cell / 2 vect2.y = ceil(vect2.y / board_cell) #rint(vect2.y) vect2.y *= board_cell vect2.y += board_cell / 2 #rint(vect2) return vect2 func new_board(): # x → # y # ↓ # [0][0] = top left, [0][7] = bottom left, [7][0] = top right, [7][7] = bottom right var new_board = [] for i in BOARD_HEIGHT + 1: new_board.append([]) new_board[i].resize(BOARD_WIDTH + 1) for j in BOARD_WIDTH + 1: new_board[i][j] = 0 return new_board func board_add_piece(piece, x, y): board[x][y] = piece enum { move_2_up_pawn, move_1_up_pawn, attack_1_nw, attack_1_ne, en_passant_nw, en_passant_ne, move_2_down_pawn, move_1_down_pawn, attack_1_sw, attack_1_se, en_passant_sw, en_passant_se, move_1_up, move_1_down, move_1_left, move_1_right, move_1_nw, move_1_ne, move_1_sw, move_1_se, move_up_inf, move_down_inf, move_left_inf, move_right_inf, castling, move_nw_inf, move_ne_inf, move_sw_inf, move_se_inf, knight, } func get_move_pattern(piece, coords): var piece_name var team if piece is Object: piece_name = piece.get_piece() team = piece.get_team() else: piece_name = match_piece_names_enums(piece[chess_enum.piece_enum]) #print(piece_name) team = piece[1] #rint("Array: %s, %s" % [piece_name, team]) match (piece_name): "pawn": if team == team1: if coords[1] == 6: return [attack_1_nw, move_2_up_pawn, attack_1_ne, en_passant_ne, en_passant_nw] else: return [attack_1_nw, move_1_up_pawn, attack_1_ne, en_passant_ne, en_passant_nw] else: if coords[1] == 1: return [attack_1_sw, move_2_down_pawn, attack_1_se, en_passant_se, en_passant_sw] else: return [attack_1_sw, move_1_down_pawn, attack_1_se, en_passant_se, en_passant_sw] "rook": return [move_up_inf, move_left_inf, move_right_inf, move_down_inf] "knight": return [knight] "bishop": return [move_ne_inf, move_nw_inf, move_sw_inf, move_se_inf] "queen": return [move_up_inf, move_down_inf, move_left_inf, move_right_inf, move_ne_inf, move_nw_inf, move_sw_inf, move_se_inf] "king": return [move_1_down, move_1_left, move_1_right, move_1_up, move_1_ne, move_1_nw, move_1_se, move_1_sw, castling] _: return [] enum chess_enum { piece_enum = 0, team = 1, en_passant = 2, has_moved = 3, in_check = 4, pos = 5 } enum tile_setting { hide_tiles_and_cover_allies = 0 show_tiles = 1 hide_tiles_no_cover_allies = 2 } func can_chess_move(pattern, coords, text_board, create_tiles=tile_setting.show_tiles): var can_move = [] #rint(text_board[coords[0]][coords[1]]) var curr_piece = text_board[coords[0]][coords[1]] var curr_team = curr_piece[chess_enum.team] for e in pattern: match (e): move_1_down_pawn: var test = make_tiles(coords, [0,1], 1, true, curr_team, {}, create_tiles, text_board) if test: test[0].push_back(movement_condition.not_attacking) can_move.append_array(test) move_2_down_pawn: var test = make_tiles(coords, [0,1], 1, true, curr_team, {}, create_tiles, text_board) if test: test[0].push_back(movement_condition.not_attacking) can_move.append_array(test) var test2 = make_tiles(coords, [0,2], 1, true, curr_team, {'tile_is_en_passant': true}, create_tiles, text_board) if test2: test2[0].push_back(movement_condition.not_attacking) can_move.append_array(test2) attack_1_sw: var test = make_tiles(coords, [-1,1], 1, false, curr_team, {"must_attack": true}, create_tiles, text_board) if test: test[0].push_back(movement_condition.must_attack) can_move.append_array(test) attack_1_se: var test = make_tiles(coords, [1,1], 1, false, curr_team, {"must_attack": true}, create_tiles, text_board) if test: test[0].push_back(movement_condition.must_attack) can_move.append_array(test) en_passant_sw: var pawn_maybe = text_board[coords[0]-1][coords[1]] if pawn_maybe and pawn_maybe[chess_enum.piece_enum] == piece_names["pawn"] and pawn_maybe[chess_enum.en_passant] == 1 and pawn_maybe[chess_enum.team] != curr_team: var test = make_tiles(coords, [-1,1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles, text_board) if test: test[0].push_back(movement_condition.en_passant_kill) can_move.append_array(test) en_passant_se: if ! coords[0] + 1 > BOARD_WIDTH: var pawn_maybe = text_board[coords[0]+1][coords[1]] if pawn_maybe and pawn_maybe[chess_enum.piece_enum] == piece_names["pawn"] and pawn_maybe[chess_enum.en_passant] == 1 and pawn_maybe[chess_enum.team] != curr_team: var test = make_tiles(coords, [1,1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles, text_board) if test: test[0].push_back(movement_condition.en_passant_kill) can_move.append_array(test) move_1_up_pawn: var test = make_tiles(coords, [0,-1], 1, true, curr_team, {}, create_tiles, text_board) if test: test[0].push_back(movement_condition.not_attacking) can_move.append_array(test) move_2_up_pawn: var test = make_tiles(coords, [0,-1], 1, true, curr_team, {}, create_tiles, text_board) if test: test[0].push_back(movement_condition.not_attacking) can_move.append_array(test) var test2 = make_tiles(coords, [0,-2], 1, true, curr_team, {'tile_is_en_passant': true}, create_tiles, text_board) if test2: test2[0].push_back(movement_condition.not_attacking) can_move.append_array(test2) attack_1_nw: var test = make_tiles(coords, [-1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles, text_board) if test: test[0].push_back(movement_condition.must_attack) can_move.append_array(test) attack_1_ne: var test = make_tiles(coords, [1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles, text_board) if test: test[0].push_back(movement_condition.must_attack) can_move.append_array(test) en_passant_nw: var pawn_maybe = text_board[coords[0]-1][coords[1]] if pawn_maybe and pawn_maybe[chess_enum.piece_enum] == piece_names["pawn"] and pawn_maybe[chess_enum.en_passant] == 1 and pawn_maybe[chess_enum.team] != curr_team: var test = make_tiles(coords, [-1,-1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles, text_board) if test: test[0].push_back(movement_condition.en_passant_kill) can_move.append_array(test) en_passant_ne: if ! coords[0] + 1 > BOARD_WIDTH: var pawn_maybe = text_board[coords[0]+1][coords[1]] if pawn_maybe and pawn_maybe[chess_enum.piece_enum] == piece_names["pawn"] and pawn_maybe[chess_enum.en_passant] == 1 and pawn_maybe[chess_enum.team] != curr_team: var test = make_tiles(coords, [1,-1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles, text_board) if test: test[0].push_back(movement_condition.en_passant_kill) can_move.append_array(test) move_up_inf: can_move.append_array(make_tiles(coords, [0,-1], BOARD_HEIGHT, false, curr_team, {}, create_tiles, text_board)) move_down_inf: can_move.append_array(make_tiles(coords, [0,1], BOARD_HEIGHT, false, curr_team, {}, create_tiles, text_board)) move_left_inf: can_move.append_array(make_tiles(coords, [-1,0], BOARD_WIDTH, false, curr_team, {}, create_tiles, text_board)) move_right_inf: can_move.append_array(make_tiles(coords, [1,0], BOARD_WIDTH, false, curr_team, {}, create_tiles, text_board)) castling: if ! curr_piece[chess_enum.has_moved] and ! curr_piece[chess_enum.in_check]: var y = coords[1] var king_x = coords[0] #var pieces = get_tree().get_nodes_in_group("piece") var pieces = get_pieces(text_board) for ele in pieces: if ele[chess_enum.team] == curr_team and ele[chess_enum.piece_enum] == piece_names["rook"] and ! ele[chess_enum.has_moved] and ele[chess_enum.pos][1] == y: #rint(ele) var rook_x = ele[chess_enum.pos][0] # king side if rook_x > king_x: var blocked = false var diff = rook_x - king_x for i in range(1, diff): if board[king_x + i][y]: blocked = true # cannot castle through or to a tile that is attacked if curr_team == team1: if team2_capture[king_x + i][y] == 1: blocked = true else: # team2 if team1_capture[king_x + i][y] == 1: blocked = true #rint("There is something at (%s,%s) %s" % [king_x + i,y, board[king_x + i][y].get_piece() ]) if ! blocked: var test = make_tiles(coords, [2,0], 1, false, curr_team, {"castling_rook": ele}, create_tiles, text_board) if test: test[0].push_back(movement_condition.king_side_castling) can_move.append_array(test) else: var blocked = false var diff = king_x - rook_x for i in range(1, diff): #rint(board[rook_x + i][y]) if board[rook_x + i][y]: blocked = true if i != 1: # on queenside, that first square doesn't really matter if it is attacked if curr_team == team1: if team2_capture[rook_x + i][y] == 1: blocked = true else: # team2 if team1_capture[rook_x + i][y] == 1: blocked = true #rint("There is something at (%s,%s) %s" % [rook_x + i, y, board[rook_x + i][y].get_piece()]) if ! blocked: var test = make_tiles(coords, [-2,0], 1, false, curr_team, {"castling_rook": ele}, create_tiles, text_board) if test: test[0].push_back(movement_condition.queen_side_castling) can_move.append_array(test) move_ne_inf: can_move.append_array(make_tiles(coords, [1,-1], 8, false, curr_team, {}, create_tiles, text_board)) move_nw_inf: can_move.append_array(make_tiles(coords, [-1,-1], 8, false, curr_team, {}, create_tiles, text_board)) move_sw_inf: can_move.append_array(make_tiles(coords, [-1,1], 8, false, curr_team, {}, create_tiles, text_board)) move_se_inf: can_move.append_array(make_tiles(coords, [1,1], 8, false, curr_team, {}, create_tiles, text_board)) knight: can_move.append_array(make_tiles(coords, [1,2], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [1,-2], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [-1,-2], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [-1,2], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [2,1], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [2,-1], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [-2,-1], 1, false, curr_team, {}, create_tiles, text_board)) can_move.append_array(make_tiles(coords, [-2,1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_down: can_move.append_array(make_tiles(coords, [0,1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_up: can_move.append_array(make_tiles(coords, [0,-1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_right: can_move.append_array(make_tiles(coords, [1,0], 1, false, curr_team, {}, create_tiles, text_board)) move_1_left: can_move.append_array(make_tiles(coords, [-1,0], 1, false, curr_team, {}, create_tiles, text_board)) move_1_ne: can_move.append_array(make_tiles(coords, [1,-1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_nw: can_move.append_array(make_tiles(coords, [-1,-1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_se: can_move.append_array(make_tiles(coords, [1,1], 1, false, curr_team, {}, create_tiles, text_board)) move_1_sw: can_move.append_array(make_tiles(coords, [-1,1], 1, false, curr_team, {}, create_tiles, text_board)) return can_move func position_to_board_cell(vect2): var x = floor(vect2.x / board_cell) var y = floor(vect2.y / board_cell) return [x,y] func movetile_clicked(move_tile): #rint("Yep, I was clicked") var location = click_spot() var check = board[location[0]][location[1]] var curr_piece = board[movement_layer_piece[0]][movement_layer_piece[1]] if ! check: pass else: check.kill() board[location[0]][location[1]] = curr_piece if move_tile.en_passant_tile: #rint("toggling en passant able...") en_passant_pawn = curr_piece en_passant_wait = 2 # gets -1 in this script later if move_tile.castling_rook: # move_tile.castling_rook actually an array (created by get_pieces() rather than an object) var rook_location = move_tile.castling_rook[chess_enum["pos"]] # need to take that pos and figure out which rook object refers to var pos = position_to_board_cell(Vector2(rook_location[0] * board_cell, rook_location[1] * board_cell)) var rook = board[pos[0]][pos[1]] # king side if 7 == rook_location[0]: rook.position = in_square(Vector2(5 * board_cell, rook_location[1] * board_cell)) board[5][rook_location[1]] = board[7][rook_location[1]] board[7][rook_location[1]] = 0 # queen side else: rook.position = in_square(Vector2(3 * board_cell, rook_location[1] * board_cell)) board[3][rook_location[1]] = board[0][rook_location[1]] board[0][rook_location[1]] = 0 curr_piece.position = in_square(Vector2(location[0] * board_cell, location[1] * board_cell)) board[movement_layer_piece[0]][movement_layer_piece[1]] = 0 remove_movement_layer() safely_handle_movement = true curr_piece.has_moved = true if move_tile.en_passant_kill_tile: kill_en_passant_pawn(location) if en_passant_wait >= 1: en_passant_wait -= 1 if en_passant_wait == 0: en_passant_pawn = null new_turn() func kill_en_passant_pawn(location): if board[location[0]+1][location[1]] is Object and board[location[0]+1][location[1]] == en_passant_pawn: board[location[0]+1][location[1]] = 0 if board[location[0]-1][location[1]] is Object and board[location[0]-1][location[1]] == en_passant_pawn: board[location[0]-1][location[1]] = 0 if board[location[0]][location[1]+1] is Object and board[location[0]][location[1]+1] == en_passant_pawn: board[location[0]][location[1]+1] = 0 if board[location[0]][location[1]-1] is Object and board[location[0]][location[1]-1] == en_passant_pawn: board[location[0]][location[1]-1] = 0 en_passant_pawn.kill() func spawn_move_tile(coords, en_passant_tile=false, en_passant_kill_tile=null, castling_rook=null): var move_tile = movetile_scene.instance() add_child(move_tile) move_tile.connect("move_clicked", self, "movetile_clicked", [move_tile]) move_tile.position = in_square(Vector2(coords[0] * board_cell, coords[1] * board_cell)) if en_passant_tile: move_tile.en_passant_tile = true if en_passant_kill_tile: move_tile.en_passant_kill_tile = true if castling_rook: move_tile.castling_rook = castling_rook #rint(move_tile.position) func make_tiles(coords, pattern, go_range, cant_attack, curr_team, dict = { "must_attack": false, 'tile_is_en_passant': false, 'en_passant_pawn': null, 'castling_rook': null }, create_tiles = tile_setting.show_tiles, text_board=[]): var x = coords[0] var y = coords[1] var pattern0 = pattern[0] var pattern1 = pattern[1] var a = 0 var b = 0 var made_tile = [] for _i in range(1,go_range+1): a += pattern0 b += pattern1 # dont go out of bounds: not bigger than board size but not smaller than 0 if (x + a) <= BOARD_WIDTH and (y + b) <= BOARD_HEIGHT and (x + a) >= 0 and (y + b) >= 0 : var check = text_board[x + a][y + b] if ! check and ! dict.get("must_attack"): if create_tiles == tile_setting.show_tiles: spawn_move_tile([x + a, y + b], dict.get("tile_is_en_passant"), dict.get("en_passant_pawn"), dict.get("castling_rook")) made_tile.push_back([x + a, y + b]) elif dict.get("must_attack"): # pawn setting if check and check[chess_enum.team] != curr_team: if create_tiles == tile_setting.show_tiles: spawn_move_tile([x + a, y + b]) made_tile.push_back([x + a, y + b]) elif create_tiles == 0: made_tile.push_back([x + a, y + b]) elif ! cant_attack and check[chess_enum.team] != curr_team: if create_tiles == tile_setting.show_tiles: spawn_move_tile([x + a, y + b], dict.get("tile_is_en_passant"), dict.get("en_passant_pawn")) made_tile.push_back([x + a, y + b]) break # rules of chess say pieces cant go past another elif create_tiles == tile_setting.hide_tiles_and_cover_allies and ! cant_attack and check[chess_enum.team] == curr_team : # ^ in otherwords: we won't mark it on map but will 'mark' it for non-maps (like capture board) made_tile.push_back([x + a, y + b]) break # but still can't go past teammate else: break return made_tile # option (used when we KNOW it is an array) # "object" -> sprite object # "tile" -> return info about the tile func array_piece(coords, option=null): var element = board[coords[0]][coords[1]] #rint(element) if element is Array: if option == "object": return element[0] elif option == "tile": return element[1] return element