From 3e2ca654e09ab42580e57bc12b915b6c2ea5092b Mon Sep 17 00:00:00 2001 From: GearsDatapacks Date: Tue, 9 Sep 2025 17:43:47 +0100 Subject: [PATCH] Keep track of previous positions to prevent 3-fold repetition draws --- src/starfish_testing.gleam | 61 ++++++++++++++--- starfish_original/gleam.toml | 1 + starfish_original/manifest.toml | 3 +- starfish_original/src/starfish_original.gleam | 66 ++++++++++++++++-- starfish_updated/gleam.toml | 1 + starfish_updated/manifest.toml | 1 + starfish_updated/src/starfish_updated.gleam | 68 ++++++++++++++++--- 7 files changed, 173 insertions(+), 28 deletions(-) diff --git a/src/starfish_testing.gleam b/src/starfish_testing.gleam index 450b426..8efc3d3 100644 --- a/src/starfish_testing.gleam +++ b/src/starfish_testing.gleam @@ -62,7 +62,9 @@ fn run_game(fen: String, i: Int) -> List(Outcome) { let assert Ok(game) = starfish.try_from_fen(fen) as "Failed to parse fen string" - io.println("Running match " <> int.to_string(i) <> ", position " <> fen) + io.println("Running match " <> int.to_string(i + 1) <> ", position " <> fen) + + update_fen(fen) let first_outcome = run_game_loop(game, UpdatedPlaysWhite) @@ -70,6 +72,8 @@ fn run_game(fen: String, i: Int) -> List(Outcome) { io.println("Running again with reversed colours...") + update_fen(fen) + let second_outcome = run_game_loop(game, UpdatedPlaysBlack) io.println("Finished second game of match, " <> print_outcome(second_outcome)) @@ -108,21 +112,56 @@ fn run_game_loop(game: starfish.Game, configuration: Configuration) -> Outcome { } } +fn update_fen(fen: String) -> Nil { + let assert Ok(original_req) = request.to(original_url <> "/fen") + + let assert Ok(response) = + httpc.send( + original_req |> request.set_body(fen) |> request.set_method(http.Post), + ) + assert response.status == 200 + + let assert Ok(updated_req) = request.to(updated_url <> "/fen") + + let assert Ok(response) = + httpc.send( + updated_req |> request.set_body(fen) |> request.set_method(http.Post), + ) + assert response.status == 200 + + Nil +} + +const updated_url = "http://0.0.0.0:8000" + +const original_url = "http://0.0.0.0:8001" + fn get_best_move(game: starfish.Game, configuration: Configuration) -> Move { - let url = case game.to_move, configuration { - board.White, UpdatedPlaysWhite | board.Black, UpdatedPlaysBlack -> - "http://0.0.0.0:8000/move" - board.Black, UpdatedPlaysWhite | board.White, UpdatedPlaysBlack -> - "http://0.0.0.0:8001/move" + let #(url, opposing_url) = case game.to_move, configuration { + board.White, UpdatedPlaysWhite | board.Black, UpdatedPlaysBlack -> #( + updated_url, + original_url, + ) + board.Black, UpdatedPlaysWhite | board.White, UpdatedPlaysBlack -> #( + original_url, + updated_url, + ) } - let assert Ok(request) = request.to(url) - let request = - request - |> request.set_body(starfish.to_fen(game)) - |> request.set_method(http.Post) + let assert Ok(request) = request.to(url <> "/get_move") let assert Ok(response) = httpc.send(request) + assert response.status == 200 let assert Ok(move) = starfish.parse_move(response.body, game) + + let assert Ok(request) = request.to(opposing_url <> "/move") + let assert Ok(response) = + httpc.send( + request + |> request.set_body(response.body) + |> request.set_method(http.Post), + ) + assert response.status == 200 + move } diff --git a/starfish_original/gleam.toml b/starfish_original/gleam.toml index da08a07..4838b2b 100644 --- a/starfish_original/gleam.toml +++ b/starfish_original/gleam.toml @@ -18,6 +18,7 @@ wisp = ">= 2.0.0 and < 3.0.0" mist = ">= 5.0.3 and < 6.0.0" gleam_erlang = ">= 1.3.0 and < 2.0.0" starfish = { git = "https://github.com/GearsDatapacks/starfish", ref = "main" } +gleam_otp = ">= 1.1.0 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/starfish_original/manifest.toml b/starfish_original/manifest.toml index 54022ed..b338644 100644 --- a/starfish_original/manifest.toml +++ b/starfish_original/manifest.toml @@ -27,13 +27,14 @@ packages = [ { name = "platform", version = "1.0.0", build_tools = ["gleam"], requirements = [], otp_app = "platform", source = "hex", outer_checksum = "8339420A95AD89AAC0F82F4C3DB8DD401041742D6C3F46132A8739F6AEB75391" }, { name = "ranger", version = "1.4.0", build_tools = ["gleam"], requirements = ["gleam_stdlib", "gleam_yielder"], otp_app = "ranger", source = "hex", outer_checksum = "C8988E8F8CDBD3E7F4D8F2E663EF76490390899C2B2885A6432E942495B3E854" }, { name = "simplifile", version = "2.3.0", build_tools = ["gleam"], requirements = ["filepath", "gleam_stdlib"], otp_app = "simplifile", source = "hex", outer_checksum = "0A868DAC6063D9E983477981839810DC2E553285AB4588B87E3E9C96A7FB4CB4" }, - { name = "starfish", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_stdlib", "iv"], source = "git", repo = "https://github.com/GearsDatapacks/starfish", commit = "2fe02ea19edac4d5b968369acf97252b35151095" }, + { name = "starfish", version = "1.0.0", build_tools = ["gleam"], requirements = ["birl", "gleam_stdlib", "iv"], source = "git", repo = "https://github.com/GearsDatapacks/starfish", commit = "90ae6d7feab65ee578c22adaa19f1c3151011db4" }, { name = "telemetry", version = "1.3.0", build_tools = ["rebar3"], requirements = [], otp_app = "telemetry", source = "hex", outer_checksum = "7015FC8919DBE63764F4B4B87A95B7C0996BD539E0D499BE6EC9D7F3875B79E6" }, { name = "wisp", version = "2.0.0", build_tools = ["gleam"], requirements = ["directories", "exception", "filepath", "gleam_crypto", "gleam_erlang", "gleam_http", "gleam_json", "gleam_stdlib", "houdini", "logging", "marceau", "mist", "simplifile"], otp_app = "wisp", source = "hex", outer_checksum = "E9E4CEE4A5ACB41E3D9CFEF7AB07BF7DF670AB32E1CB434A61C6DA6859C66168" }, ] [requirements] gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } +gleam_otp = { version = ">= 1.1.0 and < 2.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } mist = { version = ">= 5.0.3 and < 6.0.0" } diff --git a/starfish_original/src/starfish_original.gleam b/starfish_original/src/starfish_original.gleam index 8b5f9f6..adf4c3b 100644 --- a/starfish_original/src/starfish_original.gleam +++ b/starfish_original/src/starfish_original.gleam @@ -1,14 +1,18 @@ import gleam/erlang/process +import gleam/otp/actor import mist import starfish import wisp.{type Request, type Response} import wisp/wisp_mist pub fn main() { + let assert Ok(actor) = + actor.new(starfish.new()) |> actor.on_message(handle_message) |> actor.start + wisp.configure_logger() let secret_key_base = wisp.random_string(64) let assert Ok(_) = - handle_request + handle_request(_, actor.data) |> wisp_mist.handler(secret_key_base) |> mist.new |> mist.bind("0.0.0.0") @@ -17,25 +21,73 @@ pub fn main() { process.sleep_forever() } -fn handle_request(request: Request) -> Response { +type Message { + RecordMove(move: String) + Inspect(respond_with: process.Subject(starfish.Game)) + SetFen(fen: String) + SetGame(game: starfish.Game) +} + +fn handle_message( + game: starfish.Game, + message: Message, +) -> actor.Next(starfish.Game, Message) { + case message { + RecordMove(move:) -> { + let assert Ok(legal) = starfish.parse_move(move, game) + let game = starfish.apply_move(game, legal) + actor.continue(game) + } + SetFen(fen:) -> { + let assert Ok(game) = starfish.try_from_fen(fen) + actor.continue(game) + } + SetGame(game:) -> actor.continue(game) + Inspect(respond_with:) -> { + process.send(respond_with, game) + actor.continue(game) + } + } +} + +fn handle_request(request: Request, actor: process.Subject(Message)) -> Response { case wisp.path_segments(request) { - ["move"] -> handle_move(request) + ["move"] -> handle_move(request, actor) + ["get_move"] -> handle_get_move(request, actor) + ["fen"] -> handle_fen(request, actor) _ -> wisp.ok() } } -fn handle_move(request: Request) -> Response { - use fen <- wisp.require_string_body(request) - let game = starfish.from_fen(fen) +fn handle_move(request: Request, actor: process.Subject(Message)) -> Response { + use move <- wisp.require_string_body(request) + process.send(actor, RecordMove(move:)) + wisp.ok() +} + +fn handle_get_move( + _request: Request, + actor: process.Subject(Message), +) -> Response { + let game = actor.call(actor, 100, Inspect) let move_result = starfish.search(game, until: starfish.Time(milliseconds: 1000)) case move_result { - Ok(move) -> + Ok(move) -> { + let game = starfish.apply_move(game, move) + process.send(actor, SetGame(game:)) wisp.ok() |> wisp.string_body(starfish.to_long_algebraic_notation(move)) |> wisp.set_header("Access-Control-Allow-Origin", "*") + } Error(Nil) -> wisp.internal_server_error() |> wisp.string_body("No moves found") } } + +fn handle_fen(request: Request, actor: process.Subject(Message)) -> Response { + use fen <- wisp.require_string_body(request) + process.send(actor, SetFen(fen:)) + wisp.ok() +} diff --git a/starfish_updated/gleam.toml b/starfish_updated/gleam.toml index 04c81c5..08729c5 100644 --- a/starfish_updated/gleam.toml +++ b/starfish_updated/gleam.toml @@ -18,6 +18,7 @@ starfish = { path = "../../starfish" } wisp = ">= 2.0.0 and < 3.0.0" gleam_erlang = ">= 1.3.0 and < 2.0.0" mist = ">= 5.0.3 and < 6.0.0" +gleam_otp = ">= 1.1.0 and < 2.0.0" [dev-dependencies] gleeunit = ">= 1.0.0 and < 2.0.0" diff --git a/starfish_updated/manifest.toml b/starfish_updated/manifest.toml index d1f4bba..15c1e45 100644 --- a/starfish_updated/manifest.toml +++ b/starfish_updated/manifest.toml @@ -34,6 +34,7 @@ packages = [ [requirements] gleam_erlang = { version = ">= 1.3.0 and < 2.0.0" } +gleam_otp = { version = ">= 1.1.0 and < 2.0.0" } gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" } gleeunit = { version = ">= 1.0.0 and < 2.0.0" } mist = { version = ">= 5.0.3 and < 6.0.0" } diff --git a/starfish_updated/src/starfish_updated.gleam b/starfish_updated/src/starfish_updated.gleam index e3828f4..33379d6 100644 --- a/starfish_updated/src/starfish_updated.gleam +++ b/starfish_updated/src/starfish_updated.gleam @@ -1,43 +1,93 @@ import gleam/erlang/process +import gleam/otp/actor import mist import starfish import wisp.{type Request, type Response} import wisp/wisp_mist pub fn main() { + let assert Ok(actor) = + actor.new(starfish.new()) |> actor.on_message(handle_message) |> actor.start + wisp.configure_logger() let secret_key_base = wisp.random_string(64) - let assert Ok(_) = - handle_request + handle_request(_, actor.data) |> wisp_mist.handler(secret_key_base) |> mist.new |> mist.bind("0.0.0.0") |> mist.port(8000) |> mist.start - process.sleep_forever() } -fn handle_request(request: Request) -> Response { +type Message { + RecordMove(move: String) + Inspect(respond_with: process.Subject(starfish.Game)) + SetFen(fen: String) + SetGame(game: starfish.Game) +} + +fn handle_message( + game: starfish.Game, + message: Message, +) -> actor.Next(starfish.Game, Message) { + case message { + RecordMove(move:) -> { + let assert Ok(legal) = starfish.parse_move(move, game) + let game = starfish.apply_move(game, legal) + actor.continue(game) + } + SetFen(fen:) -> { + let assert Ok(game) = starfish.try_from_fen(fen) + actor.continue(game) + } + SetGame(game:) -> actor.continue(game) + Inspect(respond_with:) -> { + process.send(respond_with, game) + actor.continue(game) + } + } +} + +fn handle_request(request: Request, actor: process.Subject(Message)) -> Response { case wisp.path_segments(request) { - ["move"] -> handle_move(request) + ["move"] -> handle_move(request, actor) + ["get_move"] -> handle_get_move(request, actor) + ["fen"] -> handle_fen(request, actor) _ -> wisp.ok() } } -fn handle_move(request: Request) -> Response { - use fen <- wisp.require_string_body(request) - let game = starfish.from_fen(fen) +fn handle_move(request: Request, actor: process.Subject(Message)) -> Response { + use move <- wisp.require_string_body(request) + process.send(actor, RecordMove(move:)) + wisp.ok() +} + +fn handle_get_move( + _request: Request, + actor: process.Subject(Message), +) -> Response { + let game = actor.call(actor, 100, Inspect) let move_result = starfish.search(game, until: starfish.Time(milliseconds: 1000)) case move_result { - Ok(move) -> + Ok(move) -> { + let game = starfish.apply_move(game, move) + process.send(actor, SetGame(game:)) wisp.ok() |> wisp.string_body(starfish.to_long_algebraic_notation(move)) |> wisp.set_header("Access-Control-Allow-Origin", "*") + } Error(Nil) -> wisp.internal_server_error() |> wisp.string_body("No moves found") } } + +fn handle_fen(request: Request, actor: process.Subject(Message)) -> Response { + use fen <- wisp.require_string_body(request) + process.send(actor, SetFen(fen:)) + wisp.ok() +} -- 2.51.2