online multiplayer chess game (note server currently down)
| -rw-r--r-- | Board.gd | 11 | ||||
| -rw-r--r-- | Log.gd | 2 | ||||
| -rw-r--r-- | Utils.gd | 5 | ||||
| -rw-r--r-- | board/chess.gd | 28 | ||||
| -rw-r--r-- | project.godot | 6 | ||||
| -rw-r--r-- | ui/menus/sidebarright/OpeningLabel.gd | 42 | ||||
| -rw-r--r-- | ui/menus/sidebarright/SidebarRight.tscn | 30 | ||||
| -rw-r--r-- | ui/menus/sidebarright/sandisplay/SanDisplay.gd | 6 | ||||
| -rw-r--r-- | ui/menus/tests/engine_test.gd | 30 |
9 files changed, 115 insertions, 45 deletions
@@ -7,6 +7,7 @@ const Square := preload("res://Square.tscn") ### for the sandisplay signal add_to_pgn(move) signal clear_pgn +signal load_pgn(moves) signal remove_last const piece_size := Vector2(80, 80) @@ -159,7 +160,8 @@ func square_clicked(clicked_square: String) -> void: if !is_instance_valid(last_clicked): return for m in last_clicked_moves: - if m.to == clicked_square: + if m.to == clicked_square && m.from == last_clicked.position: + print(m) move(m.san, false) break clear_circles() @@ -182,7 +184,9 @@ func square_clicked(clicked_square: String) -> void: func move(san: String, is_recieved_move := true) -> void: if is_valid_move(san): var sound_handled = false + print(san) var move_0x88 = chess.__move_from_san(san, true) + print(chess.__move_to_san(move_0x88)) chess.__make_move(move_0x88) if move_0x88.flags & Chess.BITS.CAPTURE: board[move_0x88.to].took() @@ -279,9 +283,8 @@ func load_pgn(pgn: String) -> void: clear_pieces() create_pieces() emit_signal("clear_pgn") - var movs = Pgn.parse(pgn).moves - for mov in movs: - emit_signal("add_to_pgn", mov) + var movs: PoolStringArray = Pgn.parse(pgn).moves + emit_signal("load_pgn", movs) func undo(two: bool = false) -> void: @@ -13,7 +13,7 @@ static func debug(information) -> void: # logs the input string on debug builds static func err(information) -> void: # logs the input string to stderr - printerr("(%s) [E] %s" % [now(), to_str(information)]) + push_error("(%s) [E] %s" % [now(), to_str(information)]) static func to_str(args) -> String: @@ -54,7 +54,10 @@ func cli() -> void: if "host" in args && args.host: print("hosting game: %s" % args.host) if PacketHandler.lobby.validate_text(args.host): - PacketHandler.host_game(args.host) + var move_list = Pgn.parse(OS.get_environment("MOVES"), false).moves + if move_list: + print("with moves: %s" % move_list) + PacketHandler.host_game(args.host, true, move_list) return elif "join" in args && args.join: print("joining game: %s" % args.join) diff --git a/board/chess.gd b/board/chess.gd index 77a74bd..e895a3f 100644 --- a/board/chess.gd +++ b/board/chess.gd @@ -130,21 +130,21 @@ func get_disambiguator(move: Dictionary, moves: Array) -> String: var ambig_piece: String var ambig_to: int var ambig_from: int - for i in range(moves.size()): - ambig_from = moves[i].from - ambig_to = moves[i].to - ambig_piece = moves[i].piece + for m in moves: + ambig_from = m.from + ambig_to = m.to + ambig_piece = m.piece - # if a move of the same piece type ends on the same to square, we'll - # need to add a disambiguator to the algebraic notation - if piece == ambig_piece && from != ambig_from && to == ambig_to: - ambiguities += 1 + # if a move of the same piece type ends on the same to square, we'll + # need to add a disambiguator to the algebraic notation + if piece == ambig_piece && from != ambig_from && to == ambig_to: + ambiguities += 1 - if rank(from) == rank(ambig_from): - same_rank += 1 + if rank(from) == rank(ambig_from): + same_rank += 1 - if file(from) == file(ambig_from): - same_file += 1 + if file(from) == file(ambig_from): + same_file += 1 if ambiguities > 0: # if there exists a similar moving piece on the same rank and file as @@ -282,7 +282,7 @@ func fen() -> String: var empty := 0 var pieces := "" var i := 0 - while i < SQUARE_MAP.h1: + while i < SQUARE_MAP.h1 + 1: if board[i] == null: empty += 1 else: @@ -395,7 +395,7 @@ func __generate_moves(options := {}) -> Array: var them := __swap_color(us) var second_rank := {b = RANK_7, w = RANK_2} - var first_sq: int = SQUARE_MAP.a8 + var first_sq: int = SQUARE_MAP.a8 - 1 var last_sq: int = SQUARE_MAP.h1 var single_square := false diff --git a/project.godot b/project.godot index 124edab..aa87fa8 100644 --- a/project.godot +++ b/project.godot @@ -139,6 +139,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://ui/colorpicker/OldColorView.gd" }, { +"base": "Label", +"class": "OpeningLabel", +"language": "GDScript", +"path": "res://ui/menus/sidebarright/OpeningLabel.gd" +}, { "base": "Node", "class": "PGN", "language": "GDScript", @@ -236,6 +241,7 @@ _global_script_class_icons={ "MessageList": "", "Network": "", "OldColorView": "", +"OpeningLabel": "", "PGN": "", "Piece": "", "Preview": "", diff --git a/ui/menus/sidebarright/OpeningLabel.gd b/ui/menus/sidebarright/OpeningLabel.gd new file mode 100644 index 0000000..47ba3c6 --- /dev/null +++ b/ui/menus/sidebarright/OpeningLabel.gd @@ -0,0 +1,42 @@ +extends Label +class_name OpeningLabel + +var http_request := HTTPRequest.new() + +var url := "https://explorer.lichess.ovh/masters?topGames=0&moves=2&fen=%s" +var current_req := "" + + +func _ready(): + add_child(http_request) + Events.connect("turn_over", self, "update_opening") + Globals.grid.connect("load_pgn", self, "update_opening") + Globals.grid.connect("clear_pgn", self, "update_opening") + Globals.grid.connect("remove_last", self, "update_opening") + http_request.connect("request_completed", self, "_request_completed") + + +func update_opening(_var := null) -> void: + if Utils.internet: + var fen := Globals.grid.chess.fen() + if fen != Globals.grid.chess.DEFAULT_POSITION && fen != current_req: + if current_req: + http_request.cancel_request() + text = "" + current_req = fen + var u = url % fen.replace(" ", "_").http_escape() + Log.net(["REQUEST: get opening with url:", u]) + http_request.request(u) + + +func _request_completed(result, _response_code, _headers, byte_body): + text = "" + current_req = "" + if result != OK: # technically REQUEST_SUCCESS but i cant find it + return + var body = byte_body.get_string_from_utf8() + Log.net("RECIEVED:" + body) + var response = parse_json(body) + + if response.opening != null and "name" in response.opening: + text = " %s" % response.opening.name diff --git a/ui/menus/sidebarright/SidebarRight.tscn b/ui/menus/sidebarright/SidebarRight.tscn index b1850b6..d36b303 100644 --- a/ui/menus/sidebarright/SidebarRight.tscn +++ b/ui/menus/sidebarright/SidebarRight.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=20 format=2] +[gd_scene load_steps=21 format=2] [ext_resource path="res://ui/menus/sidebarright/drawbutton.gd" type="Script" id=1] [ext_resource path="res://ui/menus/sidebarright/resignbutton.gd" type="Script" id=2] @@ -9,6 +9,7 @@ [ext_resource path="res://ui/barbutton/default.tres" type="StyleBox" id=7] [ext_resource path="res://ui/ubuntu-bold-small.tres" type="DynamicFont" id=8] [ext_resource path="res://ui/ubuntu-bold.tres" type="DynamicFont" id=9] +[ext_resource path="res://ui/menus/sidebarright/OpeningLabel.gd" type="Script" id=10] [ext_resource path="res://ui/menus/sidebarright/SidebarRight.gd" type="Script" id=13] [ext_resource path="res://ui/theme/main.theme" type="Theme" id=14] [ext_resource path="res://ui/menus/sidebarright/undobutton.gd" type="Script" id=18] @@ -68,17 +69,24 @@ margin_bottom = 800.0 custom_constants/separation = 0 alignment = 1 +[node name="OpeningLabel" type="Label" parent="V"] +margin_top = 200.0 +margin_right = 1422.0 +margin_bottom = 223.0 +custom_fonts/font = ExtResource( 8 ) +script = ExtResource( 10 ) + [node name="BlackPanel" parent="V" instance=ExtResource( 22 )] anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 212.0 +margin_top = 223.0 margin_right = 1422.0 -margin_bottom = 252.0 +margin_bottom = 263.0 [node name="buttonbarholder" type="PanelContainer" parent="V"] -margin_top = 252.0 +margin_top = 263.0 margin_right = 1422.0 -margin_bottom = 302.0 +margin_bottom = 313.0 rect_min_size = Vector2( 50, 50 ) __meta__ = { "_edit_group_": true, @@ -147,22 +155,22 @@ status = NodePath("../../../Status") [node name="SanDisplay" parent="V" instance=ExtResource( 21 )] anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 302.0 +margin_top = 313.0 margin_right = 1422.0 -margin_bottom = 502.0 +margin_bottom = 513.0 rect_min_size = Vector2( 482, 200 ) [node name="WhitePanel" parent="V" instance=ExtResource( 22 )] anchor_right = 0.0 anchor_bottom = 0.0 -margin_top = 502.0 +margin_top = 513.0 margin_right = 1422.0 -margin_bottom = 542.0 +margin_bottom = 553.0 [node name="Status" type="Label" parent="V"] -margin_top = 542.0 +margin_top = 553.0 margin_right = 1422.0 -margin_bottom = 588.0 +margin_bottom = 599.0 align = 1 autowrap = true script = ExtResource( 3 ) diff --git a/ui/menus/sidebarright/sandisplay/SanDisplay.gd b/ui/menus/sidebarright/sandisplay/SanDisplay.gd index 502d321..fdb64ef 100644 --- a/ui/menus/sidebarright/sandisplay/SanDisplay.gd +++ b/ui/menus/sidebarright/sandisplay/SanDisplay.gd @@ -18,6 +18,7 @@ func _ready() -> void: add_child(tween) if Globals.grid: Globals.grid.connect("add_to_pgn", self, "add_move") + Globals.grid.connect("load_pgn", self, "add_moves") Globals.grid.connect("clear_pgn", self, "clear") Globals.grid.connect("remove_last", self, "pop") else: @@ -42,6 +43,11 @@ func add_move(move: String) -> void: scroll_down() +func add_moves(moves: PoolStringArray) -> void: + for move in moves: + add_move(move) + + func scroll_down(): tween.interpolate_property(scroll_bar, "value", scroll_bar.value, scroll_bar.max_value, 0.5, 9) # bouncy tween.start() diff --git a/ui/menus/tests/engine_test.gd b/ui/menus/tests/engine_test.gd index 97173c0..a95b069 100644 --- a/ui/menus/tests/engine_test.gd +++ b/ui/menus/tests/engine_test.gd @@ -39,43 +39,36 @@ class TestChess: { fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", square = "e2", - verbose = false, moves = ["e3", "e4"], }, { fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1", square = "e9", - verbose = false, moves = [], }, #invalid square { fen = "rnbqk1nr/pppp1ppp/4p3/8/1b1P4/2N5/PPP1PPPP/R1BQKBNR w KQkq - 2 3", square = "c3", - verbose = false, moves = [], }, # pinned piece { fen = "8/k7/8/8/8/8/7p/K7 b - - 0 1", square = "h2", - verbose = false, moves = ["h1=Q+", "h1=R+", "h1=B", "h1=N"], }, # promotion { fen = "r1bq1rk1/1pp2ppp/p1np1n2/2b1p3/2B1P3/2NP1N2/PPPBQPPP/R3K2R w KQ - 0 8", square = "e1", - verbose = false, moves = ["Kf1", "Kd1", "O-O", "O-O-O"], }, # castling { fen = "r1bq1rk1/1pp2ppp/p1np1n2/2b1p3/2B1P3/2NP1N2/PPPBQPPP/R3K2R w - - 0 8", square = "e1", - verbose = false, moves = ["Kf1", "Kd1"], }, # no castling { fen = "8/7K/8/8/1R6/k7/1R1p4/8 b - - 0 1", square = "a3", - verbose = false, moves = [], }, # trapped king { @@ -126,16 +119,21 @@ class TestChess: square = "f1", verbose = true, moves = [], - }, # issue #30 + }, + { + fen = "rnbqkbnr/ppp2ppp/3pp3/8/4P3/2N5/PPPP1PPP/R1BQKBNR w KQkq - 0 3", + square = "g1", + moves = ["Nge2", "Nf3", "Nh3"] + } # disambiguation ] for position in positions: var chess = Chess.new(position.fen) var cfg = { square = position.square, - verbose = position.verbose, + verbose = position.verbose if "verbose" in position else false, } var moves = chess.moves(cfg) - if position.verbose: + if "verbose" in position && position.verbose: for i in range(len(moves)): assert( moves[i].hash() == position.moves[i].hash(), @@ -224,6 +222,10 @@ class TestChess: func test_move_generation(): var positions = [ { + fen = "r6k/8/8/8/8/8/8/7K b - - 0 1", + moves = """Ra7 Ra6 Ra5 Ra4 Ra3 Ra2 Ra1 Rb8 Rc8 Rd8 Re8 Rf8 Rg8 Kh7 Kg8 Kg7""" + }, + { fen = "7k/3R4/3p2Q1/6Q1/2N1N3/8/8/3R3K w - - 0 1", moves = """Rd8# Re7 Rf7 Rg7 Rh7# R7xd6 Rc7 Rb7 Ra7 Qf7 Qe8# Qg7# Qg8# Qh7# Q6h6# Q6h5# Q6f5 Q6f6# Qe6 Qxd6 Q5f6# Qe7 Qd8# Q5h6# Q5h5# Qh4# Qg4 Qg3 Qg2 Qg1 Qf4 Qe3 Qd2 Qc1 Q5f5 Qe5+ Qd5 Qc5 Qb5 Qa5 Na5 Nb6 Ncxd6 Ne5 Ne3 Ncd2 Nb2 Na3 Nc5 Nexd6 Nf6 Ng3 Nf2 Ned2 Nc3 Rd2 Rd3 Rd4 Rd5 R1xd6 Re1 Rf1 Rg1 Rc1 Rb1 Ra1 Kg2 Kh2 Kg1""", }, @@ -266,8 +268,8 @@ class TestChess: SaveLoad.save_string("user://tests.log", "") #overwrite last logs Log.file(LOG_FILE, "starting algebraic conversion tests") test_algebraic_conversion() - Log.file(LOG_FILE, "starting perft tests") - test_perft() + # Log.file(LOG_FILE, "starting perft tests") + # test_perft() Log.file(LOG_FILE, "starting move generation tests") test_single_square_move_generation() Log.file(LOG_FILE, "starting checkmate tests") @@ -281,8 +283,8 @@ class TestChess: Log.file(LOG_FILE, "starting move generation tests") test_move_generation() Log.file(LOG_FILE, "starting random moves tests") - test_random_moves() # crash testing - Log.file(LOG_FILE, "all tests passed") + # test_random_moves() # crash testing + # Log.file(LOG_FILE, "all tests passed") func _pressed(): |