online multiplayer chess game (note server currently down)
mostly
| -rw-r--r-- | Grid.gd | 30 | ||||
| -rw-r--r-- | SanParse/Move.gd | 60 | ||||
| -rw-r--r-- | SanParse/test.gd | 2 | ||||
| -rw-r--r-- | Utils.gd | 6 | ||||
| -rw-r--r-- | networking/Network.gd | 6 | ||||
| -rw-r--r-- | networking/PacketHandler.gd | 102 | ||||
| -rw-r--r-- | pieces/King.gd | 2 | ||||
| -rw-r--r-- | pieces/Pawn.gd | 50 | ||||
| -rw-r--r-- | pieces/Piece.gd | 36 | ||||
| -rw-r--r-- | test.gd | 1 |
10 files changed, 177 insertions, 118 deletions
@@ -319,9 +319,8 @@ func handle_take(position: Vector2) -> void: if Utils.is_pawn(last_clicked): # if its a pawn if check_promote(last_clicked, position, "take"): return - Globals.network.relay_signal( - PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move, "positions" - ) # piece taking piece + var mov = Move.new(SanParse.from_str(last_clicked.shortname), [last_clicked.real_position, position], true) + Globals.network.send_mov(mov) # piece taking piece func handle_move(position: Vector2) -> void: @@ -330,17 +329,8 @@ func handle_move(position: Vector2) -> void: var castle_data = last_clicked.can_castle[i] if castle_data[0] == position: # send some packet - Globals.network.relay_signal( - { - "king": last_clicked.real_position, - "rook": castle_data[1].real_position, - "rookdestination": castle_data[2], - "kingdestination": castle_data[0] - }, - Network.MOVEHEADERS.castle, - "positions" - ) - + var mov = Move.new(SanParser.KING, Move.castle_type(castle_data[3])) + Globals.network.send_mov(mov) return if Utils.is_pawn(last_clicked): var pawn: Pawn = last_clicked @@ -349,17 +339,13 @@ func handle_move(position: Vector2) -> void: var en_passant_data = pawn.enpassant[i] if en_passant_data[0] == position: # send some packet - Globals.network.relay_signal( - PoolVector2Array([pawn.real_position, position, en_passant_data[1].real_position]), - Network.MOVEHEADERS.passant, - "positions" - ) + var mov = Move.new(SanParser.PAWN, [pawn.real_position, position]) + Globals.network.send_mov(mov) return elif check_promote(pawn, position): return - Globals.network.relay_signal( - PoolVector2Array([last_clicked.real_position, position]), Network.MOVEHEADERS.move, "positions" - ) # piece moving + var mov = Move.new(SanParse.from_str(last_clicked.shortname), [last_clicked.real_position, position]) + Globals.network.send_mov(mov) func check_promote(pawn, position, calltype: String = "move") -> bool: diff --git a/SanParse/Move.gd b/SanParse/Move.gd index 8abfca1..82076ea 100644 --- a/SanParse/Move.gd +++ b/SanParse/Move.gd @@ -4,9 +4,9 @@ extends Resource enum CASTLETYPES { NONE, QUEEN_SIDE, KING_SIDE } enum CHECKTYPES { NONE, CHECK, CHECKMATE } var generated_from := "" -var piece := 0 +var piece := -1 var move_kind: MoveKind -var promotion := 0 +var promotion := -1 # var annotation := "" # later var check_type := 0 var is_capture := false @@ -40,19 +40,67 @@ func compile() -> String: # compiles the structure to a san MoveKind.NORMAL: res += Utils.to_str(piece) res += Utils.to_algebraic(move_kind.data[0]) - res = res + "x" if is_capture else res + res += "x" if is_capture else "" res += Utils.to_algebraic(move_kind.data[1]) - res = res + "=" + Utils.to_str(promotion) if promotion != -1 else res + res += "=" + Utils.to_str(promotion) if promotion != -1 else "" match check_type: CHECKTYPES.CHECK: res += "+" CHECKTYPES.CHECKMATE: res += "#" - _: - pass return res +## tests +# print(Utils.to_algebraic(make_long(SanParse.parse("e4").move_kind.data, false, SanParser.PAWN)[0]) == "e2") +# print(Utils.to_algebraic(make_long(SanParse.parse("Nbc3").move_kind.data, false, SanParser.KNIGHT)[0]) == "b1") +# print(Utils.to_algebraic(make_long(SanParse.parse("N1c3").move_kind.data, false, SanParser.KNIGHT)[0]) == "b1") + + +# print(Utils.to_algebraic(make_long(SanParse.parse("exe4").move_kind.data, false, SanParser.PAWN)[0]) == "e2") +# print(Utils.to_algebraic(make_long(SanParse.parse("Nbxc3").move_kind.data, false, SanParser.KNIGHT)[0]) == "b1") +# print(Utils.to_algebraic(make_long(SanParse.parse("N1xc3").move_kind.data, false, SanParser.KNIGHT)[0]) == "b1") +### fix short san +func make_long(): + var newvecs: PoolVector2Array = [] + + var vectors = move_kind.data + + if Piece.is_on_board(vectors[0]): # [0] is the only one with -1(s) possible + return vectors + + if is_capture: + newvecs.append(long_helper(vectors[0], true, false, vectors[1])) + else: + newvecs.append(long_helper(vectors[0], false, true, vectors[1])) + + if newvecs.empty(): + Log.error("cruddlesticks") + return + newvecs.append(vectors[1]) + + move_kind.data = newvecs + + +func long_helper(vec: Vector2, attack: bool, move: bool, touch: Vector2): + if vec.y == -1 and vec.x != -1: + for y in range(8): + var spot = Piece.at_pos(Vector2(vec.x, y)) + if Utils.spotispiece(piece, spot) and spot.can_touch(touch, attack, move): + return Vector2(vec.x, y) + elif vec.x == -1 and vec.y != -1: + for x in range(8): + var spot = Piece.at_pos(Vector2(x, vec.y)) + if Utils.spotispiece(piece, spot) and spot.can_touch(touch, attack, move): + return Vector2(x, vec.y) + elif vec == Vector2(-1, -1): + for x in range(8): + for y in range(8): + var spot = Piece.at_pos(Vector2(x, y)) + if Utils.spotispiece(piece, spot) and spot.can_touch(touch, attack, move): + return Vector2(x, y) + + class MoveKind: extends Resource enum { NONE, NORMAL, CASTLE } diff --git a/SanParse/test.gd b/SanParse/test.gd index 4c5bd5d..137d7b9 100644 --- a/SanParse/test.gd +++ b/SanParse/test.gd @@ -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) @@ -18,6 +18,10 @@ func _on_turn_over() -> void: emit_signal("newfen", fen) +func spotispiece(piece_type: int, spot: Piece) -> bool: + return SanParse.from_str(spot.shortname.to_upper()) == piece_type if spot else false + + func get_fen() -> String: var pieces := "" for rank in range(8): @@ -118,7 +122,7 @@ func reset_vars() -> void: static func get_node_name(node: Node) -> Array: if is_pawn(node): - return ["♙", "p"] if node.white else ["♟", "p"] + return ["♙", "P"] if node.white else ["♟", "P"] elif node is King: return ["♔", "K"] if node.white else ["♚", "K"] elif node is Queen: diff --git a/networking/Network.gd b/networking/Network.gd index 4633ef6..10a21e8 100644 --- a/networking/Network.gd +++ b/networking/Network.gd @@ -104,6 +104,10 @@ func relay_signal(body, header: String, keyname := "body") -> Dictionary: # its return signal(body, header, keyname, HEADERS.relay) +func send_mov(mov: Move): + relay_signal(mov.compile(), MOVEHEADERS.move, "move") + + func stopgame(reason: String) -> void: var packet := {"reason": reason, "gamecode": game_code} send_packet(packet, HEADERS.stopgame) @@ -119,7 +123,7 @@ func _data_recieved() -> void: HEADERS.relay: var relay: Dictionary = text if relay.type in MOVEHEADERS.values(): - emit_signal("move_data", text) + emit_signal("move_data", text.move) else: match relay.type: RELAYHEADERS.startgame: diff --git a/networking/PacketHandler.gd b/networking/PacketHandler.gd index 9cb6bbd..eb96f08 100644 --- a/networking/PacketHandler.gd +++ b/networking/PacketHandler.gd @@ -95,44 +95,68 @@ func _start_game() -> void: lobby.set_buttons(false) -func _on_data(data: Dictionary) -> void: +func _on_data(data: String) -> void: Globals.add_turn() Log.debug([data, " recieved"]) - 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.castle: - var king := Piece.at_pos(dict2vec(data["positions"]["king"])) - var rook := Piece.at_pos(dict2vec(data["positions"]["rook"])) - rook.moveto(dict2vec(data["positions"]["rookdestination"]), true, false, true) - Utils.add_move(king.castle(dict2vec(data["positions"]["kingdestination"]))) - Network.MOVEHEADERS.promote: - var dict_data: Dictionary = data["positions"] # positions is a dict for readability sometimes - var pawn: Pawn = Piece.at_pos(dict2vec(dict_data["start_position"])) - var dest := dict2vec(dict_data["destination"]) - if Piece.at_pos(dest) != null: - Piece.at_pos(dest).took() # move the pawn to the new place, killing if necessary - pawn.clear_clicked() - Globals.grid.make_piece(dest, Pawn.piece(dict_data["become"]), dict_data["white"]) # create the promotion - pawn.took() # kill the pawn - Utils.add_move(dict_data["notation"]) # add a move - Globals.grid.print_matrix_pretty(Globals.grid.matrix) - _: - Log.err("Wtf") - - -static func dict2vec(dict: Dictionary) -> Vector2: - return Vector2(dict["x"], dict["y"]) + Utils.add_move(data) + var mov = SanParse.parse(data) + match mov.move_kind.type: + Move.MoveKind.CASTLE: + var side = 7 if Globals.turn else 0 + 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: + rook = Piece.at_pos(Vector2(7, side)) + rook_goto = Vector2(5, side) + king_goto = Vector2(6, side) + Move.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. + mov.make_long() + var positions = mov.move_kind.data + if mov.promotion != -1: + var promote_to = SanParse.from_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]) + 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") diff --git a/pieces/King.gd b/pieces/King.gd index 7360054..5411676 100644 --- a/pieces/King.gd +++ b/pieces/King.gd @@ -85,7 +85,7 @@ func castle(position: Vector2) -> String: return_string = i[3] break can_castle.clear() - moveto(position, true, false, true) + moveto(position, true) return return_string diff --git a/pieces/Pawn.gd b/pieces/Pawn.gd index a4078ec..93efb31 100644 --- a/pieces/Pawn.gd +++ b/pieces/Pawn.gd @@ -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.connect("clicked", self, "handle_sprite_input_event", [newsprite]) + 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 newsprite.hide() add_child(newsprite) @@ -36,7 +38,7 @@ func _exit_tree() -> void: Globals.pawns.remove(find) -func moveto(position: Vector2, real := true, take := false, override_moveto := false) -> void: +func moveto(position: Vector2, real := true) -> void: # check if 2 step if real: if !twostepfirstmove and !has_moved: @@ -46,7 +48,7 @@ func moveto(position: Vector2, real := true, take := false, override_moveto := f if !white and position.y - real_position.y == 2: twostepfirstmove = true just_set = true - .moveto(position, real, take, override_moveto) + .moveto(position, real) if real: Globals.reset_halfmove() @@ -74,6 +76,12 @@ 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() enpassant.resize(0) moveto(position) @@ -124,34 +132,22 @@ func promote(position: Vector2, type: String) -> void: promoteposition = position darken.show() for i in range(len(promotables)): - sprites[i].sprite.texture = load( - "%s%s%s.png" % [Globals.grid.ASSETS_PATH, team.to_lower(), promotables[i]] - ) - sprites[i].name = promotables[i] sprites[i].show() -func handle_sprite_input_event(node: Node2D) -> void: +func promote_to(promote_to: String, is_capture: bool, position: Vector2): + if is_capture and at_pos(position): + at_pos(position).took() + clear_clicked() + Globals.grid.make_piece(position, piece(promote_to), white) + took() + + +func handle_sprite_input_event(promote_to: String) -> void: darken.hide() - var promote_to := node.name - var first := ( - algebraic_move_notation(promoteposition) - if !promotetake - else algebraic_take_notation(promoteposition, real_position) - ) - Log.debug(promote_to) - var notation := "%s=%s" % [first, promote_to] - Globals.network.relay_signal( - { - "start_position": real_position, - "destination": promoteposition, - "become": promote_to, - "notation": notation, - "white": white - }, - Network.MOVEHEADERS.promote, - "positions" - ) + var mov = Move.new(SanParser.PAWN, [real_position, promoteposition]) + mov.promotion = SanParse.from_str(promote_to) + Globals.network.send_mov(mov) static func piece(string: String) -> String: diff --git a/pieces/Piece.gd b/pieces/Piece.gd index 299d3a9..0c52252 100644 --- a/pieces/Piece.gd +++ b/pieces/Piece.gd @@ -67,27 +67,12 @@ func move(newpos: Vector2) -> void: # dont use directly; use moveto tween.start() -func moveto(position: Vector2, real := true, take := false, override_moveto := false) -> void: +func moveto(pos: Vector2, real := true) -> void: Globals.grid.matrix[real_position.y][real_position.x] = null - Globals.grid.matrix[position.y][position.x] = self + Globals.grid.matrix[pos.y][pos.x] = self if real: - if !override_moveto: - if !take: - Utils.add_move(algebraic_move_notation(position)) - else: - Utils.add_move(algebraic_take_notation(position)) - real_position = position + real_position = pos move(real_position) - Log.debug( - ( - "%s moving from %s to %s" - % [ - shortname + " white" if white else " black", - Utils.to_algebraic((global_position / Globals.grid.piece_size).snapped(Vector2(1, 1))), - Utils.to_algebraic(real_position) - ] - ) - ) SoundFx.play("Move") has_moved = true @@ -161,13 +146,24 @@ func get_attacks(check_spots_check := true) -> PoolVector2Array: # @Override return final -func can_attack_piece(piece: Piece) -> bool:##i cant use pos in get_attacks for some bizarre reasons +func can_attack_piece(piece: Piece) -> bool: ##i cant use pos in get_attacks for some bizarre reasons for pos in get_attacks(false): if at_pos(pos) == piece: return true return false +func can_touch(pos: Vector2, attack := true, move := true) -> bool: + if attack and move: + return pos in get_attacks() or pos in get_moves() + elif attack: + return pos in get_attacks() + elif move: + return pos in get_moves() + else: + return false + + static func create_move_circles(pos: Vector2) -> void: Globals.grid.background_matrix[pos.x][pos.y].set_circle(true) # make the move circle @@ -205,7 +201,7 @@ static func is_on_board(vector: Vector2) -> bool: # limit the vector to the boa func take(piece: Piece) -> void: clear_clicked() piece.took() - moveto(piece.real_position, true, true) + moveto(piece.real_position, true) Globals.reset_halfmove() @@ -84,6 +84,7 @@ class TestSan: s.is_capture = true var result = s.compile() assert(result == "exd8=Q+") + assert(Move.parse("e4").compile() == "e4") func _init(): test_algebraic_conversion() |