online multiplayer chess game (note server currently down)
working movements
| -rw-r--r-- | Debug.gd | 2 | ||||
| -rw-r--r-- | Grid.gd | 4 | ||||
| -rw-r--r-- | SanParse/Move.gd | 6 | ||||
| -rw-r--r-- | SanParse/SanParse.gd | 9 | ||||
| -rw-r--r-- | SanParse/test.gd | 109 | ||||
| -rw-r--r-- | Utils.gd | 2 | ||||
| -rw-r--r-- | networking/PacketHandler.gd | 54 | ||||
| -rw-r--r-- | pieces/Pawn.gd | 35 | ||||
| -rw-r--r-- | pieces/Piece.gd | 2 | ||||
| -rw-r--r-- | test.gd | 11 | ||||
| -rw-r--r-- | ui/StartMenu.tscn | 2 |
11 files changed, 59 insertions, 177 deletions
@@ -15,7 +15,7 @@ static func is_debug() -> bool: var args := Utils.get_args() if "debug" in args: return bool(args.debug) - return false or OS.is_debug_build() + return OS.is_debug_build() func _ready() -> void: @@ -77,7 +77,7 @@ static func print_matrix_pretty(mat: Array) -> void: # print the matrix print(topper_header) # print the top border else: print(middle_header) # print the middle border - var row := "%s%s %s " % [ender, 8 - j, ender] # init the string + var row := "%s %s%s" % [ender.strip_edges(), 8 - j, ender] # init the string for i in range(8): # for each column var c: Piece = r[i] # get the column row += "%s%s" % [c.mininame, ender] if c else " " + ender # add the piece @@ -339,7 +339,7 @@ func handle_move(position: Vector2) -> void: var en_passant_data = pawn.enpassant[i] if en_passant_data[0] == position: # send some packet - var mov = Move.new(SanParser.PAWN, [pawn.real_position, position]) + var mov = Move.new(SanParser.PAWN, [pawn.real_position, position], true) Globals.network.send_mov(mov) return elif check_promote(pawn, position): diff --git a/SanParse/Move.gd b/SanParse/Move.gd index 82076ea..5bb35b1 100644 --- a/SanParse/Move.gd +++ b/SanParse/Move.gd @@ -1,7 +1,6 @@ class_name Move extends Resource -enum CASTLETYPES { NONE, QUEEN_SIDE, KING_SIDE } enum CHECKTYPES { NONE, CHECK, CHECKMATE } var generated_from := "" var piece := -1 @@ -19,7 +18,7 @@ func _init(newpiece: int, newmove, capture := false) -> void: static func castle_type(type: String) -> int: - return CASTLETYPES.QUEEN_SIDE if type == "O-O-O" else CASTLETYPES.KING_SIDE + return MoveKind.CASTLETYPES.QUEEN_SIDE if type == "O-O-O" else MoveKind.CASTLETYPES.KING_SIDE func set_check_type(type: String) -> void: @@ -103,6 +102,7 @@ func long_helper(vec: Vector2, attack: bool, move: bool, touch: Vector2): class MoveKind: extends Resource + enum CASTLETYPES { NONE, QUEEN_SIDE, KING_SIDE } enum { NONE, NORMAL, CASTLE } var type := 0 var data # string OR array @@ -118,4 +118,4 @@ class MoveKind: assert(false) func to_str() -> String: - return "O-O-O" if data == CASTLETYPES.QUEENSIDE else "O-O" + return "O-O-O" if data == CASTLETYPES.QUEEN_SIDE else "O-O" diff --git a/SanParse/SanParse.gd b/SanParse/SanParse.gd index 3669672..9a1f130 100644 --- a/SanParse/SanParse.gd +++ b/SanParse/SanParse.gd @@ -17,6 +17,7 @@ var regexs := { "specific_row_piece_capture": compile("^([KQBNR])([0-9])x([a-h])([1-8])"), "long_piece_capture": compile("^([KQBNR])([a-h])([0-9])x([a-h])([1-8])"), "pawn_promotion": compile("^([a-h])([1-8])=?([KQBNR])"), + "long_pawn_promotion": compile("^([a-h])([1-8])([a-h])([1-8])=?([KQBNR])"), "castling": compile("^(O-O-O|O-O)"), } @@ -144,6 +145,14 @@ func regexmatch(san: String) -> Move: mov.set_check_type(cap[4]) return mov + re = regexs.long_pawn_promotion.search(san) + if re: + var cap = re.strings + var mov = Move.new(PAWN, [pos(cap[1], cap[2]), pos(cap[3], cap[4])], true) + mov.promotion = from_str(cap[5]) + mov.set_check_type(cap[6]) + return mov + re = regexs.castling.search(san) if re: var cap = re.strings diff --git a/SanParse/test.gd b/SanParse/test.gd deleted file mode 100644 index 137d7b9..0000000 --- a/SanParse/test.gd +++ /dev/null @@ -1,109 +0,0 @@ -extends Node - - -class TestSan: - extends SanParser - - func assert_castle(string: String, s): - var m = parse(string) - assert(m.move_kind.type == Move.MoveKind.CASTLE) - assert(m.move_kind.data == s) - assert(m.piece == KING) - assert(m.promotion == -1) - assert(m.check_type == Move.CHECKTYPES.NONE) - assert(m.is_capture == false) - - func assert_move(mv: String, start: Vector2, dest: Vector2, piece: int) -> void: - assert_all(parse(mv), PoolVector2Array([start, dest]), piece, false) - - func assert_capture(mv: String, start: Vector2, dest: Vector2, piece: int) -> void: - assert_all(parse(mv), PoolVector2Array([start, dest]), piece, true) - - func assert_all(mv: Move, vectors: PoolVector2Array, piece: int, capture: bool, promote = -1) -> void: - assert(mv.move_kind.type == Move.MoveKind.NORMAL) - assert([mv.move_kind.data == vectors, mv.piece == piece, mv.is_capture == capture].min()) - if promote != -1: - assert(mv.promotion == promote) - - func test_algebraic_conversion(): - assert(Utils.from_algebraic(Utils.to_algebraic(Vector2.ZERO)) == Vector2.ZERO) - assert(Utils.from_algebraic(Utils.to_algebraic(Vector2.ONE)) == Vector2.ONE) - assert(pos("a", "9") == Utils.from_algebraic("a9")) - assert(Utils.col_pos("h") == 7) - assert(Utils.row_pos("1") == 7) - - func test_castle_short(): - assert_castle("O-O", Move.CASTLETYPES.KING_SIDE) - - func test_castle_long(): - assert_castle("O-O-O", Move.CASTLETYPES.QUEEN_SIDE) - - func test_pawn(): - assert_move("e4", UNKNOWN_POS, Vector2(4, 4), PAWN) - - func test_pawn_long(): - assert_move("e2e4", Vector2(4, 6), Vector2(4, 4), PAWN) - - func test_piece(): - assert_move("Qe4", UNKNOWN_POS, Vector2(4, 4), QUEEN) - - func test_piece_file(): - assert_move("Qbe4", Vector2(1, -1), Vector2(4, 4), QUEEN) - - func test_piece_rank(): - assert_move("Q1e4", Vector2(-1, 7), Vector2(4, 4), QUEEN) - - func test_piece_long(): - assert_move("Qb1e4", Vector2(1, 7), Vector2(4, 4), QUEEN) - - func test_pawn_capture(): - assert_capture("exd4", Vector2(4, -1), Vector2(3, 4), PAWN) - - func test_pawn_capture_promotion(): - assert_all(parse("exd8=Q"), PoolVector2Array([Vector2(4, -1), Vector2(3, 0)]), PAWN, true, QUEEN) - - func test_pawn_capture_long(): - assert_capture("e3xd4", Vector2(4, 5), Vector2(3, 4), PAWN) - - func test_piece_capture(): - assert_capture("R1xh3", Vector2(-1, 7), Vector2(7, 5), ROOK) - - func test_piece_capture_file(): - assert_capture("Rexh3", Vector2(4, -1), Vector2(7, 5), ROOK) - - func test_piece_capture_long(): - assert_capture("Re3xh3", Vector2(4, 5), Vector2(7, 5), ROOK) - - func test_pawn_promotion(): - assert_all(parse("d8=Q"), PoolVector2Array([UNKNOWN_POS, Vector2(3, 0)]), PAWN, QUEEN) - - func test_compile(): - var s = Move.new(PAWN, [Vector2(4, -1), Vector2(3, 0)]) - s.promotion = QUEEN - s.check_type = Move.CHECKTYPES.CHECK - s.is_capture = true - var result = s.compile() - assert(result == "exd8=Q+") - - func _init(): - test_algebraic_conversion() - test_castle_short() - test_castle_long() - test_pawn() - test_pawn_long() - test_piece() - test_piece_file() - test_piece_rank() - test_piece_long() - test_pawn_capture() - test_pawn_capture_promotion() - test_pawn_capture_long() - test_piece_capture() - test_piece_capture_file() - test_piece_capture_long() - test_pawn_promotion() - test_compile() - - -func _ready(): - TestSan.new() @@ -50,7 +50,7 @@ func get_fen() -> String: var enpassants := "" for pawn in Globals.pawns: - if pawn.twostepfirstmove and pawn.just_set: + if pawn.just_double_stepped and pawn.just_set: enpassants += Utils.to_algebraic(pawn.real_position + (Vector2.DOWN * pawn.whiteint)) return ( "%s %s %s %s %s %s" diff --git a/networking/PacketHandler.gd b/networking/PacketHandler.gd index eb96f08..28ee0e8 100644 --- a/networking/PacketHandler.gd +++ b/networking/PacketHandler.gd @@ -98,65 +98,43 @@ func _start_game() -> void: func _on_data(data: String) -> void: Globals.add_turn() Log.debug([data, " recieved"]) - Utils.add_move(data) + var san_to_add := data var mov = SanParse.parse(data) match mov.move_kind.type: Move.MoveKind.CASTLE: - var side = 7 if Globals.turn else 0 + var side = 0 if Globals.turn else 7 var rook: Rook var rook_goto: Vector2 var kingpos = Vector2(4, side) var king: King = Piece.at_pos(kingpos) var king_goto: Vector2 match mov.move_kind.data: - Move.CASTLETYPES.KING_SIDE: + Move.MoveKind.CASTLETYPES.KING_SIDE: rook = Piece.at_pos(Vector2(7, side)) rook_goto = Vector2(5, side) king_goto = Vector2(6, side) - Move.CASTLETYPES.QUEEN_SIDE: + Move.MoveKind.CASTLETYPES.QUEEN_SIDE: rook = Piece.at_pos(Vector2(0, side)) rook_goto = Vector2(3, side) king_goto = Vector2(2, side) - _: - Log.error("Invalid castle type") - return rook.moveto(rook_goto) king.castle(king_goto) Move.MoveKind.NORMAL: - # this needs to handle enpassant, taking, and promotion. + # this handles promotion, taking, enpassant, and moves. mov.make_long() var positions = mov.move_kind.data - if mov.promotion != -1: - var promote_to = SanParse.from_str(mov.promotion) + if mov.promotion != -1: # promotion part + Globals.grid.print_matrix_pretty(Globals.grid.matrix) + var promote_to = Utils.to_str(mov.promotion) Piece.at_pos(positions[0]).promote_to(promote_to, mov.is_capture, positions[1]) - elif mov.is_capture: - Piece.at_pos(positions[0]).take(Piece.at_pos(positions[1])) - - elif not Piece.at_pos(positions[1]) and mov.piece == SanParser.PAWN: # if not positions[1] and piece is pawn: enpassant! - var pawn: Pawn = Piece.at_pos(positions[0]) - pawn.passant(positions[1]) + elif mov.is_capture: # taking part + if Piece.at_pos(positions[1]): + Piece.at_pos(positions[0]).take(Piece.at_pos(positions[1])) + elif mov.piece == SanParser.PAWN: # enpassant part + var pawn: Pawn = Piece.at_pos(positions[0]) + pawn.passant(positions[1]) + san_to_add += " e.p." else: # a very normal move Piece.at_pos(positions[0]).moveto(positions[1]) - - # Events.emit_signal("data_recieved") - # match data["type"]: - # Network.MOVEHEADERS.passant: - # # en passant - # var end_pos := dict2vec(data["positions"][1]) - # var start_piece := Piece.at_pos(dict2vec(data["positions"][0])) - # Piece.at_pos(dict2vec(data["positions"][2])).took() # kill the unfortunate - # start_piece.passant(end_pos) - # Network.MOVEHEADERS.move: - # var start_piece := Piece.at_pos(dict2vec(data["positions"][0])) - # var end_pos := dict2vec(data["positions"][1]) - # var end_piece := Piece.at_pos(end_pos) - # if end_piece != null: - # start_piece.take(end_piece) - # else: - # start_piece.moveto(end_pos) - - # Network.MOVEHEADERS.promote: - # var dict_data: Dictionary = data["positions"] # positions is a dict for readability sometimes - # _: - # Log.err("Wtf") + Utils.add_move(san_to_add) diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd index 93efb31..f17bca3 100644 --- a/pieces/Pawn.gd +++ b/pieces/Pawn.gd @@ -3,7 +3,7 @@ class_name Pawn, "res://assets/pieces/california/wP.png" const promotables := "QNRB" -var twostepfirstmove := false +var just_double_stepped := false var just_set := false var enpassant: Array = [] @@ -23,7 +23,9 @@ func _ready() -> void: for i in range(0, 4): # add 3 sprites var newsprite: Node2D = load("res://ui/ClickableSprite.tscn").instance() newsprite.position = (sprite.position + Vector2(0, (i * Globals.grid.piece_size.y) * whiteint)) - newsprite.get_node("Sprite").texture = load("%s%s%s.png" % [Globals.grid.ASSETS_PATH, team.to_lower(), promotables[i]]) + newsprite.get_node("Sprite").texture = load( + "%s%s%s.png" % [Globals.grid.ASSETS_PATH, team.to_lower(), promotables[i]] + ) newsprite.name = promotables[i] newsprite.connect("clicked", self, "handle_sprite_input_event", [newsprite.name]) newsprite.z_index = 5 # its not a texturebutton so i can use this @@ -41,12 +43,12 @@ func _exit_tree() -> void: func moveto(position: Vector2, real := true) -> void: # check if 2 step if real: - if !twostepfirstmove and !has_moved: + if !just_double_stepped and !has_moved: if white and real_position.y - position.y == 2: - twostepfirstmove = true + just_double_stepped = true just_set = true if !white and position.y - real_position.y == 2: - twostepfirstmove = true + just_double_stepped = true just_set = true .moveto(position, real) if real: @@ -76,16 +78,16 @@ static func can_promote(position: Vector2) -> bool: func passant(position: Vector2) -> void: - var to_take = position + Vector2(-1, -1) * whiteint - if !at_pos(to_take): - if at_pos(to_take + Vector2(2, 0)): - to_take += Vector2(2, 0) - if at_pos(position): - at_pos(position).took() + var to_take = position + Vector2(0, whiteint) + at_pos(to_take).took() enpassant.resize(0) moveto(position) +func valid_to_passant_take(piece) -> bool: + return !piece or !Utils.is_pawn(piece) or piece.white != white or !piece.just_double_stepped + + func get_attacks(check_spots_check := true) -> PoolVector2Array: var points := [Vector2.UP + Vector2.RIGHT, Vector2.UP + Vector2.LEFT] var moves: PoolVector2Array = [] @@ -99,7 +101,7 @@ func get_attacks(check_spots_check := true) -> PoolVector2Array: continue if at_pos(point) != null and at_pos(point).white != white: moves.append(point) - en_passant() + en_passant() # for the fen return moves @@ -114,7 +116,7 @@ func en_passant(turncheck := true, check_spots_check := true) -> Array: # in pa continue if turncheck and white != Globals.turn: continue - if !spot.twostepfirstmove: + if !spot.just_double_stepped: continue if check_spots_check and checkcheck(i): continue @@ -145,7 +147,8 @@ func promote_to(promote_to: String, is_capture: bool, position: Vector2): func handle_sprite_input_event(promote_to: String) -> void: darken.hide() - var mov = Move.new(SanParser.PAWN, [real_position, promoteposition]) + var is_cap = at_pos(promoteposition) != null + var mov = Move.new(SanParser.PAWN, [real_position, promoteposition], is_cap) mov.promotion = SanParse.from_str(promote_to) Globals.network.send_mov(mov) @@ -168,8 +171,8 @@ func _on_turn_over() -> void: if just_set: just_set = false return - if twostepfirstmove: - twostepfirstmove = false + if just_double_stepped: + just_double_stepped = false func _just_before_turn_over() -> void: diff --git a/pieces/Piece.gd b/pieces/Piece.gd index 0c52252..07b4b4a 100644 --- a/pieces/Piece.gd +++ b/pieces/Piece.gd @@ -119,7 +119,7 @@ func traverse(arr: PoolVector2Array = [], no_enemys := false, check_spots_check static func at_pos(vector: Vector2) -> Piece: - if is_instance_valid(Globals.grid): + if is_on_board(vector): return Globals.grid.matrix[vector.y][vector.x] return null @@ -9,7 +9,7 @@ class TestSan: assert(m.move_kind.type == Move.MoveKind.CASTLE) assert(m.move_kind.data == s) assert(m.piece == KING) - assert(m.promotion == 0) + assert(m.promotion == -1) assert(m.check_type == Move.CHECKTYPES.NONE) assert(m.is_capture == false) @@ -33,10 +33,10 @@ class TestSan: assert(Utils.row_pos("1") == 7) func test_castle_short(): - assert_castle("O-O", Move.CASTLETYPES.KING_SIDE) + assert_castle("O-O", Move.MoveKind.CASTLETYPES.KING_SIDE) func test_castle_long(): - assert_castle("O-O-O", Move.CASTLETYPES.QUEEN_SIDE) + assert_castle("O-O-O", Move.MoveKind.CASTLETYPES.QUEEN_SIDE) func test_pawn(): assert_move("e4", UNKNOWN_POS, Vector2(4, 4), PAWN) @@ -84,7 +84,7 @@ class TestSan: s.is_capture = true var result = s.compile() assert(result == "exd8=Q+") - assert(Move.parse("e4").compile() == "e4") + assert((SanParse.parse("e4").compile()) == "e4") func _init(): test_algebraic_conversion() @@ -107,4 +107,5 @@ class TestSan: func _ready(): - TestSan.new() + if Debug.is_debug(): + TestSan.new() diff --git a/ui/StartMenu.tscn b/ui/StartMenu.tscn index 2d8a117..80304ee 100644 --- a/ui/StartMenu.tscn +++ b/ui/StartMenu.tscn @@ -6,7 +6,7 @@ [ext_resource path="res://ui/Lobby.tscn" type="PackedScene" id=4] [ext_resource path="res://assets/ui/verdana-bold.ttf" type="DynamicFontData" id=5] [ext_resource path="res://ui/account/Account.tscn" type="PackedScene" id=6] -[ext_resource path="res://SanParse/test.gd" type="Script" id=7] +[ext_resource path="res://test.gd" type="Script" id=7] [sub_resource type="DynamicFont" id=1] size = 400 |