From 5163f85f12078b6573ddc28f546581343f5c65fe Mon Sep 17 00:00:00 2001 From: jake Date: Sun, 19 Feb 2023 21:06:13 -0500 Subject: added checkmating. also touched every function to support this, and added a few more too --- Main.gd | 358 ++++++++++++++++++++++++++++++++++++++++++++-------------- project.godot | 5 + 2 files changed, 281 insertions(+), 82 deletions(-) diff --git a/Main.gd b/Main.gd index a6c3201..37f7052 100644 --- a/Main.gd +++ b/Main.gd @@ -8,9 +8,13 @@ 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 @@ -34,66 +38,117 @@ func _ready(): #spawn_piece('pawn', 'teal', 1, 6, team1) #spawn_piece('pawn', 'orange', 2, 4, team2) - #team2_king = spawn_piece('king', 'red', 4, 0, team2) - #spawn_piece('rook', 'teal', 5, 1, team1) - #spawn_piece('rook', 'red', 7, 0, team2) - #spawn_piece('rook', 'red', 0, 0, team2) + #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) + #spawn_piece('rook', 'orange', 0, 0, team2) + #spawn_piece('rook', 'orange', 7, 0, team2) #team1_king = spawn_piece('rook', 'teal', 5, 3, team1) #spawn_piece('pawn', 'blue', 6, 0, team1) - update_capture_tables() + 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)) - OS.set_window_always_on_top(true) + #OS.set_window_always_on_top(true) # horrifying discovery: this occurs after the signal capturing functions 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(team2_every_legal_move(board_to_text_board(board))) + print("whoops") + if click_spot() == Vector2(2,0): + print(board_to_text_board(board)) func new_turn(): - update_capture_tables() - is_king_checked() + 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) check_for_promotion() turn += 1 print("Turn: %s" % turn) + save_turn() -func update_capture_tables(): - team1_capture = new_board() - team2_capture = new_board() - var pieces = get_tree().get_nodes_in_group("piece") +func save_turn(): + var text_board = board_to_text_board(board) + history.append(text_board) + +enum piece_names { + pawn, + rook, + knight, + bishop, + king, + queen +} + +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 + +func update_capture_tables(text_board): + var t1_capture = new_board() + var t2_capture = new_board() + var pieces = get_pieces(text_board) for e in pieces: - if ! e.killed: - var coords = position_to_board_cell(e.position) - if e.get_team() == team1: - team1_capture[coords[0]][coords[1]] = 2 - else: # team2 - team2_capture[coords[0]][coords[1]] = 2 + 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: - if ! e.killed: - var coords = position_to_board_cell(e.position) - var pattern = get_move_pattern(e, coords) - var captured = can_chess_move(pattern, coords, false) - if e.get_team() == team1: - #rint(captured) - for c in captured: - if c.size() == 3: - if c[2] == "not attacking": - continue - team1_capture[c[0]][c[1]] = 1 - else: # team2 - for c in captured: - if c.size() == 3: - if c[2] == "not attacking": - continue - team2_capture[c[0]][c[1]] = 1 + var coords = e[chess_enum.pos] + var pattern = get_move_pattern(e, coords) + var captured = can_chess_move(pattern, coords, text_board, tile_setting.hide_tiles_and_cover_allies) + if e[chess_enum.team] == team1: + #rint(captured) + for c in captured: + if c.size() == 3: + if c[2] == "not attacking": + continue + t1_capture[c[0]][c[1]] = 1 + else: # team2 + for c in captured: + if c.size() == 3: + if c[2] == "not attacking": + continue + t2_capture[c[0]][c[1]] = 1 #print(team1_capture) #print(team2_capture) - #for i in 8: # for k in 8: - # if team2_capture[i][k] == 1: + # if t1_capture[i][k] == 1: # var move_tile = movetile_scene.instance() # add_child(move_tile) # move_tile.set_color("red") # move_tile.position = in_square(Vector2(i * board_cell, k * board_cell)) + return [t1_capture, t2_capture] func check_for_promotion(): var pieces = get_tree().get_nodes_in_group("piece") @@ -105,21 +160,117 @@ func check_for_promotion(): # TODO: player option e.set_piece("queen", e.get_piece_color_by_region()) -func is_king_checked(): +func is_king_team2_checked(text_board, enumerate=true, capture_table=[]): if team2_king: - var coords_team2 = position_to_board_cell(team2_king.position) - if team1_capture[coords_team2[0]][coords_team2[1]] >= 1: - print("Aye, team2 in check.") - team2_king.in_check = true - else: - team2_king.in_check = false + 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: - var coords_team1 = position_to_board_cell(team1_king.position) - if team2_capture[coords_team1[0]][coords_team1[1]] >= 1: - print("Aye, team1 in check.") - team1_king.in_check = true - else: - team1_king.in_check = false + 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]: + #rint("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) + if which_king == 1: + if is_king_team1_checked(fake_board, false, fake_captures[1]): + pass + #rint("King in check on this fake board!!") + else: + #rint("King ***NOT*** in check! Not a ckeckmate!") + checkmate = false + else: # team2 + if is_king_team2_checked(fake_board, false, fake_captures[0]): + pass + #rint("King in check on this fake board!!") + else: + #rint("King ***NOT*** in check! Not a ckeckmate!") + 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, team2], coords) + every_legal_move.append([[i,k], 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 @@ -140,7 +291,7 @@ func piece_clicked(piece): var location = click_spot() #rint("Spot: %s " % location) var pattern = get_move_pattern(piece, location) - if can_chess_move(pattern, location): + if can_chess_move(pattern, location, board_to_text_board(board)): movement_layer = true movement_layer_piece = location @@ -257,10 +408,20 @@ enum { } func get_move_pattern(piece, coords): - var piece_name = piece.get_piece() + 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 piece.get_team() == team1: + 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: @@ -283,10 +444,26 @@ func get_move_pattern(piece, coords): _: return [] -func can_chess_move(pattern, coords, create_tiles=true): +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 = [] - var curr_piece = board[coords[0]][coords[1]] - var curr_team = curr_piece.get_team() + #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: @@ -304,17 +481,23 @@ func can_chess_move(pattern, coords, create_tiles=true): test2[0].push_back("not attacking") can_move.append_array(test2) attack_1_sw: - can_move.append_array(make_tiles(coords, [-1,1], 1, false, curr_team, {"must_attack": true}, create_tiles)) + var test = make_tiles(coords, [-1,1], 1, false, curr_team, {"must_attack": true}, create_tiles) + if test: + test[0].push_back("must attack") + can_move.append_array(test) attack_1_se: - can_move.append_array(make_tiles(coords, [1,1], 1, false, curr_team, {"must_attack": true}, create_tiles)) + var test = make_tiles(coords, [1,1], 1, false, curr_team, {"must_attack": true}, create_tiles) + if test: + test[0].push_back("must attack") + can_move.append_array(test) en_passant_sw: - var pawn_maybe = board[coords[0]-1][coords[1]] - if pawn_maybe and pawn_maybe.get_piece() == "pawn" and pawn_maybe == en_passant_pawn and pawn_maybe.get_team() != curr_team: + 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: can_move.append_array(make_tiles(coords, [-1,1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles)) en_passant_se: if ! coords[0] + 1 > BOARD_WIDTH: - var pawn_maybe = board[coords[0]+1][coords[1]] - if pawn_maybe and pawn_maybe.get_piece() == "pawn" and pawn_maybe == en_passant_pawn and pawn_maybe.get_team() != curr_team: + 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: can_move.append_array(make_tiles(coords, [1,1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles)) move_1_up_pawn: @@ -332,17 +515,23 @@ func can_chess_move(pattern, coords, create_tiles=true): test2[0].push_back("not attacking") can_move.append_array(test2) attack_1_nw: - can_move.append_array(make_tiles(coords, [-1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles)) + var test = make_tiles(coords, [-1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles) + if test: + test[0].push_back("must attack") + can_move.append_array(test) attack_1_ne: - can_move.append_array(make_tiles(coords, [1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles)) + var test = make_tiles(coords, [1,-1], 1, false, curr_team, {"must_attack": true}, create_tiles) + if test: + test[0].push_back("must attack") + can_move.append_array(test) en_passant_nw: - var pawn_maybe = board[coords[0]-1][coords[1]] - if pawn_maybe and pawn_maybe.get_piece() == "pawn" and pawn_maybe == en_passant_pawn and pawn_maybe.get_team() != curr_team: + 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: can_move.append_array(make_tiles(coords, [-1,-1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles)) en_passant_ne: if ! coords[0] + 1 > BOARD_WIDTH: - var pawn_maybe = board[coords[0]+1][coords[1]] - if pawn_maybe and pawn_maybe.get_piece() == "pawn" and pawn_maybe == en_passant_pawn and pawn_maybe.get_team() != curr_team: + 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: can_move.append_array(make_tiles(coords, [1,-1], 1, true, curr_team, {"en_passant_pawn": pawn_maybe}, create_tiles)) move_up_inf: @@ -354,14 +543,15 @@ func can_chess_move(pattern, coords, create_tiles=true): move_right_inf: can_move.append_array(make_tiles(coords, [1,0], BOARD_WIDTH, false, curr_team, {}, create_tiles)) castling: - if ! curr_piece.has_moved and ! curr_piece.in_check: + 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_tree().get_nodes_in_group("piece") + var pieces = get_pieces(text_board) for ele in pieces: - if ele.get_team() == curr_team and ele.get_piece() == "rook" and ! ele.has_moved and position_to_board_cell(ele.position)[1] == y: + 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 = position_to_board_cell(ele.position)[0] + var rook_x = ele[chess_enum.pos][0] # king side if rook_x > king_x: var blocked = false @@ -456,15 +646,19 @@ func movetile_clicked(move_tile): en_passant_pawn = curr_piece en_passant_wait = 2 # gets -1 in this script later if move_tile.castling_rook: - var rook_location = position_to_board_cell(move_tile.castling_rook.position) - # king + # 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]: - move_tile.castling_rook.position = in_square(Vector2(5 * board_cell, rook_location[1] * board_cell)) + 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 + # queen side else: - move_tile.castling_rook.position = in_square(Vector2(3 * board_cell, rook_location[1] * board_cell)) + 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 @@ -512,7 +706,7 @@ func make_tiles(coords, pattern, go_range, cant_attack, curr_team, 'tile_is_en_passant': false, 'en_passant_pawn': null, 'castling_rook': null - }, create_tiles = true): + }, create_tiles = 1): var x = coords[0] var y = coords[1] var pattern0 = pattern[0] @@ -529,18 +723,18 @@ func make_tiles(coords, pattern, go_range, cant_attack, curr_team, if (x + a) <= BOARD_WIDTH and (y + b) <= BOARD_HEIGHT and (x + a) >= 0 and (y + b) >= 0 : var check = board[x + a][y + b] if ! check and ! dict.get("must_attack"): - if create_tiles: + if create_tiles == 1: 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.get_team() != curr_team: - if create_tiles: + if create_tiles == 1: spawn_move_tile([x + a, y + b]) made_tile.push_back([x + a, y + b]) - elif ! create_tiles: + elif create_tiles == 0: made_tile.push_back([x + a, y + b]) elif ! cant_attack and check.get_team() != curr_team: - if create_tiles: + if create_tiles == 1: 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 diff --git a/project.godot b/project.godot index f7d93c8..91e12b7 100644 --- a/project.godot +++ b/project.godot @@ -41,6 +41,11 @@ mouse1={ "events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":1,"pressed":false,"doubleclick":false,"script":null) ] } +mouse2={ +"deadzone": 0.5, +"events": [ Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"button_mask":0,"position":Vector2( 0, 0 ),"global_position":Vector2( 0, 0 ),"factor":1.0,"button_index":2,"pressed":false,"doubleclick":false,"script":null) + ] +} [physics] -- cgit v1.2.3