diff --git a/.gitignore b/.gitignore index fa83e0e..f06eefd 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,4 @@ devenv.local.nix # generated by samply rust profiler profile.json - bot/models -client_web/dist -var diff --git a/Cargo.lock b/Cargo.lock index 94e366c..fa260cd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -148,17 +148,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "any_spawner" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41058deaa38c9d9dd933d6d238d825227cffa668e2839b52879f6619c63eee3b" -dependencies = [ - "futures", - "thiserror 2.0.18", - "wasm-bindgen-futures", -] - [[package]] name = "anyhow" version = "1.0.101" @@ -245,37 +234,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-lock" -version = "3.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" -dependencies = [ - "event-listener", - "event-listener-strategy", - "pin-project-lite", -] - -[[package]] -name = "async-trait" -version = "0.1.89" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "atomic-polyfill" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4" -dependencies = [ - "critical-section", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -288,36 +246,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a" -[[package]] -name = "attribute-derive" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05832cdddc8f2650cc2cc187cc2e952b8c133a48eb055f35211f61ee81502d77" -dependencies = [ - "attribute-derive-macro", - "derive-where", - "manyhow", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "attribute-derive-macro" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a7cdbbd4bd005c5d3e2e9c885e6fa575db4f4a3572335b974d8db853b6beb61" -dependencies = [ - "collection_literals", - "interpolator", - "manyhow", - "proc-macro-utils", - "proc-macro2", - "quote", - "quote-use", - "syn 2.0.114", -] - [[package]] name = "autocfg" version = "1.5.0" @@ -422,21 +350,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "backbone-lib" -version = "0.1.0" -dependencies = [ - "bytes", - "ewebsock", - "futures", - "gloo-timers", - "postcard", - "protocol", - "serde", - "wasm-bindgen-futures", - "web-time", -] - [[package]] name = "backtrace" version = "0.3.76" @@ -599,7 +512,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" dependencies = [ "memchr", - "regex-automata 0.4.14", + "regex-automata", "serde", ] @@ -653,7 +566,7 @@ dependencies = [ "num-traits", "parking_lot", "portable-atomic", - "spin 0.10.0", + "spin", "tracing", ] @@ -756,7 +669,7 @@ dependencies = [ "rmp-serde", "serde", "serde_json", - "spin 0.10.0", + "spin", "uuid", ] @@ -869,7 +782,7 @@ dependencies = [ "hashbrown 0.16.1", "log", "serde", - "spin 0.10.0", + "spin", "tracing", ] @@ -997,7 +910,7 @@ dependencies = [ "burn-std", "hashbrown 0.16.1", "log", - "spin 0.10.0", + "spin", ] [[package]] @@ -1171,22 +1084,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdd7a427adc0135366d99db65b36dae9237130997e560ed61118041fb72be6e8" -[[package]] -name = "calendrical_calculations" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97f73e95d668625c9b28a3072e6326773785a0cf807de9f3d632778438f3d38" -dependencies = [ - "core_maths", - "displaydoc", -] - -[[package]] -name = "camino" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" - [[package]] name = "candle-core" version = "0.9.2" @@ -1206,7 +1103,7 @@ dependencies = [ "rayon", "safetensors 0.7.0", "thiserror 2.0.18", - "yoke 0.8.1", + "yoke", "zip 7.4.0", ] @@ -1390,23 +1287,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" -[[package]] -name = "client_web" -version = "0.1.0" -dependencies = [ - "backbone-lib", - "futures", - "getrandom 0.3.4", - "gloo-storage", - "leptos", - "leptos_i18n", - "rand 0.9.2", - "serde", - "serde_json", - "trictrac-store", - "wasm-bindgen-futures", -] - [[package]] name = "cmake" version = "0.1.57" @@ -1416,26 +1296,6 @@ dependencies = [ "cc", ] -[[package]] -name = "cobs" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" -dependencies = [ - "thiserror 2.0.18", -] - -[[package]] -name = "codee" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dbbdc4b4d349732bc6690de10a9de952bd39ba6a065c586e26600b6b0b91f5" -dependencies = [ - "serde", - "serde_json", - "thiserror 2.0.18", -] - [[package]] name = "codespan-reporting" version = "0.12.0" @@ -1458,12 +1318,6 @@ dependencies = [ "unicode-width 0.2.0", ] -[[package]] -name = "collection_literals" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2550f75b8cfac212855f6b1885455df8eaee8fe8e246b647d69146142e016084" - [[package]] name = "color_quant" version = "1.1.0" @@ -1522,19 +1376,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "config" -version = "0.15.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b30fa8254caad766fc03cb0ccae691e14bf3bd72bfff27f72802ce729551b3d6" -dependencies = [ - "convert_case 0.6.0", - "pathdiff", - "serde_core", - "toml 0.9.11+spec-1.1.0", - "winnow", -] - [[package]] name = "confy" version = "1.0.0" @@ -1567,32 +1408,6 @@ dependencies = [ "tiny-keccak", ] -[[package]] -name = "const_format" -version = "0.2.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" -dependencies = [ - "const_format_proc_macros", -] - -[[package]] -name = "const_format_proc_macros" -version = "0.2.34" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "const_str_slice_concat" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67855af358fcb20fac58f9d714c94e2b228fe5694c1c9b4ead4a366343eda1b" - [[package]] name = "constant_time_eq" version = "0.1.5" @@ -1605,24 +1420,6 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "136d3e02915a2cea4d74caa8681e2d44b1c3254bdbf17d11d41d587ff858832c" -[[package]] -name = "convert_case" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "convert_case" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "convert_case" version = "0.8.0" @@ -1641,17 +1438,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -1688,15 +1474,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "core_maths" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30" -dependencies = [ - "libm", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -1902,7 +1679,7 @@ dependencies = [ "serde", "serde_bytes", "serde_json", - "spin 0.10.0", + "spin", "tracing", "wasm-bindgen-futures", "web-time", @@ -2114,7 +1891,7 @@ dependencies = [ "md5", "serde", "serde_json", - "spin 0.10.0", + "spin", "thiserror 2.0.18", "toml 0.9.11+spec-1.1.0", "tracing", @@ -2137,7 +1914,7 @@ dependencies = [ "num-traits", "paste", "serde", - "spin 0.10.0", + "spin", "variadics_please", ] @@ -2473,18 +2250,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "default-struct-builder" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0df63c21a4383f94bd5388564829423f35c316aed85dc4f8427aded372c7c0d" -dependencies = [ - "darling 0.20.11", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "deranged" version = "0.5.5" @@ -2516,17 +2281,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "derive-where" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "derive_more" version = "2.1.1" @@ -2623,18 +2377,6 @@ dependencies = [ "litrs", ] -[[package]] -name = "drain_filter_polyfill" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "669a445ee724c5c69b1b06fe0b63e70a1c84bc9bb7d9696cd4f4e3ec45050408" - -[[package]] -name = "dyn-clone" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" - [[package]] name = "dyn-stack" version = "0.13.2" @@ -2657,16 +2399,6 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" -[[package]] -name = "either_of" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14f7f86eef3a7e4b9c2107583dbbbe3d9535c4b800796faf1774b82ba22033da" -dependencies = [ - "paste", - "pin-project-lite", -] - [[package]] name = "embassy-futures" version = "0.1.2" @@ -2723,18 +2455,6 @@ dependencies = [ "embedded-hal 1.0.0", ] -[[package]] -name = "embedded-io" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" - -[[package]] -name = "embedded-io" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" - [[package]] name = "entities" version = "1.0.1" @@ -2868,21 +2588,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "ewebsock" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "679247b4a005c82218a5f13b713239b0b6d484ec25347a719f5b7066152a748a" -dependencies = [ - "document-features", - "js-sys", - "log", - "tungstenite 0.24.0", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "exr" version = "1.74.0" @@ -2984,18 +2689,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" -[[package]] -name = "fixed_decimal" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0febbeb1118a9ecdee6e4520ead6b54882e843dd0592ad233247dbee84c53db8" -dependencies = [ - "displaydoc", - "ryu", - "smallvec", - "writeable 0.5.5", -] - [[package]] name = "fixedbitset" version = "0.4.2" @@ -3139,7 +2832,6 @@ dependencies = [ "futures-core", "futures-task", "futures-util", - "num_cpus", ] [[package]] @@ -3475,67 +3167,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "gloo-net" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06f627b1a58ca3d42b45d6104bf1e1a03799df472df00988b6ba21accc10580" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "http", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror 1.0.69", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "gloo-storage" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a" -dependencies = [ - "gloo-utils", - "js-sys", - "serde", - "serde_json", - "thiserror 1.0.69", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "gloo-timers" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "gloo-utils" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" -dependencies = [ - "js-sys", - "serde", - "serde_json", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "glow" version = "0.16.0" @@ -3608,12 +3239,6 @@ dependencies = [ "bitflags 2.10.0", ] -[[package]] -name = "guardian" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17e2ac29387b1aa07a1e448f7bb4f35b500787971e965b02842b900afa5c8f6f" - [[package]] name = "gym-rs" version = "0.3.1" @@ -3666,15 +3291,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "hash32" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" -dependencies = [ - "byteorder", -] - [[package]] name = "hashbrown" version = "0.13.2" @@ -3724,20 +3340,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "heapless" -version = "0.7.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f" -dependencies = [ - "atomic-polyfill", - "hash32", - "rustc_version", - "serde", - "spin 0.9.8", - "stable_deref_trait", -] - [[package]] name = "heck" version = "0.5.0" @@ -3765,15 +3367,6 @@ dependencies = [ "digest", ] -[[package]] -name = "html-escape" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" -dependencies = [ - "utf8-width", -] - [[package]] name = "http" version = "1.4.0" @@ -3825,20 +3418,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" -[[package]] -name = "hydration_context" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d35485b3dcbf7e044b8f28c73f04f13e7b509c2466fd10cb2a8a447e38f8a93a" -dependencies = [ - "futures", - "once_cell", - "or_poisoned", - "pin-project-lite", - "serde", - "throw_error", -] - [[package]] name = "hyper" version = "1.8.1" @@ -3902,41 +3481,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "icu_calendar" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7265b2137f9a36f7634a308d91f984574bbdba8cfd95ceffe1c345552275a8ff" -dependencies = [ - "calendrical_calculations", - "displaydoc", - "icu_calendar_data", - "icu_locid", - "icu_locid_transform", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_calendar_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "820499e77e852162190608b4f444e7b4552619150eafc39a9e39333d9efae9e1" - -[[package]] -name = "icu_collections" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" -dependencies = [ - "displaydoc", - "yoke 0.7.5", - "zerofrom", - "zerovec 0.10.4", -] - [[package]] name = "icu_collections" version = "2.1.1" @@ -3945,116 +3489,11 @@ checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "yoke 0.8.1", + "yoke", "zerofrom", - "zerovec 0.11.5", + "zerovec", ] -[[package]] -name = "icu_datetime" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d115efb85e08df3fd77e77f52e7e087545a783fffba8be80bfa2102f306b1780" -dependencies = [ - "displaydoc", - "either", - "fixed_decimal", - "icu_calendar", - "icu_datetime_data", - "icu_decimal", - "icu_locid", - "icu_locid_transform", - "icu_plurals", - "icu_provider 1.5.0", - "icu_timezone", - "smallvec", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_datetime_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef5f04076123cab1b7a926a7083db27fe0d7a0e575adb984854aae3f3a6507d" - -[[package]] -name = "icu_decimal" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb8fd98f86ec0448d85e1edf8884e4e318bb2e121bd733ec929a05c0a5e8b0eb" -dependencies = [ - "displaydoc", - "fixed_decimal", - "icu_decimal_data", - "icu_locid_transform", - "icu_provider 1.5.0", - "writeable 0.5.5", -] - -[[package]] -name = "icu_decimal_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c95dd97f5ccf6d837a9c115496ec7d36646fa86ca18e7f1412115b4c820ae2" - -[[package]] -name = "icu_experimental" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "844ad7b682a165c758065d694bc4d74ac67f176da1c499a04d85d492c0f193b7" -dependencies = [ - "displaydoc", - "fixed_decimal", - "icu_collections 1.5.0", - "icu_decimal", - "icu_experimental_data", - "icu_locid", - "icu_locid_transform", - "icu_normalizer 1.5.0", - "icu_pattern", - "icu_plurals", - "icu_properties 1.5.1", - "icu_provider 1.5.0", - "litemap 0.7.5", - "num-bigint", - "num-rational", - "num-traits", - "smallvec", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerofrom", - "zerotrie 0.1.3", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_experimental_data" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121df92eafb8f5286d4e8ff401c1e7db8384377f806db3f8db77b91e5b7bd4dd" - -[[package]] -name = "icu_list" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbfeda1d7775b6548edd4e8b7562304a559a91ed56ab56e18961a053f367c365" -dependencies = [ - "displaydoc", - "icu_list_data", - "icu_locid_transform", - "icu_provider 1.5.0", - "regex-automata 0.2.0", - "writeable 0.5.5", -] - -[[package]] -name = "icu_list_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52b1a7fbdbf3958f1be8354cb59ac73f165b7b7082d447ff2090355c9a069120" - [[package]] name = "icu_locale_core" version = "2.1.1" @@ -4062,61 +3501,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", - "litemap 0.8.1", - "tinystr 0.8.2", - "writeable 0.6.2", - "zerovec 0.11.5", -] - -[[package]] -name = "icu_locid" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" -dependencies = [ - "displaydoc", - "litemap 0.7.5", - "tinystr 0.7.6", - "writeable 0.5.5", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_locid_transform" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_locid_transform_data", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_locid_transform_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" - -[[package]] -name = "icu_normalizer" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" -dependencies = [ - "displaydoc", - "icu_collections 1.5.0", - "icu_normalizer_data 1.5.1", - "icu_properties 1.5.1", - "icu_provider 1.5.0", - "smallvec", - "utf16_iter", - "utf8_iter", - "write16", - "zerovec 0.10.4", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] @@ -4125,117 +3513,40 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "icu_collections 2.1.1", - "icu_normalizer_data 2.1.1", - "icu_properties 2.1.2", - "icu_provider 2.1.1", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", "smallvec", - "zerovec 0.11.5", + "zerovec", ] -[[package]] -name = "icu_normalizer_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" - [[package]] name = "icu_normalizer_data" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" -[[package]] -name = "icu_pattern" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7f36aafd098d6717de34e668a8120822275c1fba22b936e757b7de8a2fd7e4" -dependencies = [ - "displaydoc", - "either", - "writeable 0.5.5", - "yoke 0.7.5", - "zerofrom", -] - -[[package]] -name = "icu_plurals" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a70e7c025dbd5c501b0a5c188cd11666a424f0dadcd4f0a95b7dafde3b114" -dependencies = [ - "displaydoc", - "fixed_decimal", - "icu_locid_transform", - "icu_plurals_data", - "icu_provider 1.5.0", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_plurals_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a483403238cb7d6a876a77a5f8191780336d80fe7b8b00bfdeb20be6abbfd112" - -[[package]] -name = "icu_properties" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" -dependencies = [ - "displaydoc", - "icu_collections 1.5.0", - "icu_locid_transform", - "icu_properties_data 1.5.1", - "icu_provider 1.5.0", - "tinystr 0.7.6", - "zerovec 0.10.4", -] - [[package]] name = "icu_properties" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "icu_collections 2.1.1", + "icu_collections", "icu_locale_core", - "icu_properties_data 2.1.2", - "icu_provider 2.1.1", - "zerotrie 0.2.3", - "zerovec 0.11.5", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] -[[package]] -name = "icu_properties_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" - [[package]] name = "icu_properties_data" version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" -[[package]] -name = "icu_provider" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" -dependencies = [ - "displaydoc", - "icu_locid", - "icu_provider_macros", - "stable_deref_trait", - "tinystr 0.7.6", - "writeable 0.5.5", - "yoke 0.7.5", - "zerofrom", - "zerovec 0.10.4", -] - [[package]] name = "icu_provider" version = "2.1.1" @@ -4244,45 +3555,13 @@ checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "writeable 0.6.2", - "yoke 0.8.1", + "writeable", + "yoke", "zerofrom", - "zerotrie 0.2.3", - "zerovec 0.11.5", + "zerotrie", + "zerovec", ] -[[package]] -name = "icu_provider_macros" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "icu_timezone" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa91ba6a585939a020c787235daa8aee856d9bceebd6355e283c0c310bc6de96" -dependencies = [ - "displaydoc", - "icu_calendar", - "icu_provider 1.5.0", - "icu_timezone_data", - "tinystr 0.7.6", - "zerotrie 0.1.3", - "zerovec 0.10.4", -] - -[[package]] -name = "icu_timezone_data" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adcf7b613a268af025bc2a2532b4b9ee294e6051c5c0832d8bff20ac0232e68" - [[package]] name = "ident_case" version = "1.0.1" @@ -4306,8 +3585,8 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ - "icu_normalizer 2.1.1", - "icu_properties 2.1.2", + "icu_normalizer", + "icu_properties", ] [[package]] @@ -4408,12 +3687,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "interpolator" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71dd52191aae121e8611f1e8dc3e324dd0dd1dee1e6dd91d10ee07a3cfb4d9d8" - [[package]] name = "ipnet" version = "2.11.0" @@ -4530,17 +3803,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "json5" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" -dependencies = [ - "pest", - "pest_derive", - "serde", -] - [[package]] name = "khronos-egl" version = "6.0.0" @@ -4570,230 +3832,6 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a79a3332a6609480d7d0c9eab957bca6b455b91bb84e66d19f5ff66294b85b8" -[[package]] -name = "leptos" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b8731cb00f3f0894058155410b95c8955b17273181d2bc72600ab84edd24f1" -dependencies = [ - "any_spawner", - "cfg-if", - "either_of", - "futures", - "hydration_context", - "leptos_config", - "leptos_dom", - "leptos_hot_reload", - "leptos_macro", - "leptos_server", - "oco_ref", - "or_poisoned", - "paste", - "reactive_graph", - "rustc-hash 2.1.1", - "send_wrapper", - "serde", - "serde_qs", - "server_fn", - "slotmap", - "tachys", - "thiserror 2.0.18", - "throw_error", - "typed-builder", - "typed-builder-macro", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "leptos-use" -version = "0.15.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2457c1abaa00dd4601695a989ed796bb19bc44e47ecffe2ad1336cc4c9e4f505" -dependencies = [ - "cfg-if", - "codee", - "cookie", - "default-struct-builder", - "js-sys", - "lazy_static", - "leptos", - "paste", - "send_wrapper", - "thiserror 2.0.18", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "leptos_config" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bae3e0ead5a7a814c8340eef7cb8b6cba364125bd8174b15dc9fe1b3cab7e03" -dependencies = [ - "config", - "regex", - "serde", - "thiserror 2.0.18", - "typed-builder", -] - -[[package]] -name = "leptos_dom" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f89d4eb263bd5a9e7c49f780f17063f15aca56fd638c90b9dfd5f4739152e87d" -dependencies = [ - "js-sys", - "or_poisoned", - "reactive_graph", - "send_wrapper", - "tachys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "leptos_hot_reload" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e80219388501d99b246f43b6e7d08a28f327cdd34ba630a35654d917f3e1788e" -dependencies = [ - "anyhow", - "camino", - "indexmap", - "parking_lot", - "proc-macro2", - "quote", - "rstml", - "serde", - "syn 2.0.114", - "walkdir", -] - -[[package]] -name = "leptos_i18n" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d368a184611a7f6bd1d23568887da4cea80e457b7932ff7c8c00b39032f4dd66" -dependencies = [ - "codee", - "default-struct-builder", - "icu_calendar", - "icu_datetime", - "icu_decimal", - "icu_experimental", - "icu_list", - "icu_locid", - "icu_plurals", - "leptos", - "leptos-use", - "leptos_i18n_macro", - "leptos_meta", - "serde", - "typed-builder", - "wasm-bindgen", - "writeable 0.5.5", -] - -[[package]] -name = "leptos_i18n_macro" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f56a479ebc4416dae57732d3524a0a67f6e84af8f51501f5e2df7c26392d601" -dependencies = [ - "fixed_decimal", - "icu_locid", - "icu_locid_transform", - "leptos_i18n_parser", - "proc-macro2", - "quote", - "serde", - "serde_json", - "syn 2.0.114", - "tinystr 0.7.6", - "toml 0.8.23", -] - -[[package]] -name = "leptos_i18n_parser" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c389bd7767d52dc3e3676d8a71584ee490e801ac0eb7e02c04beeb611a7c4f" -dependencies = [ - "fixed_decimal", - "icu_locid", - "icu_plurals", - "json5", - "proc-macro2", - "quote", - "serde", - "serde_json", - "serde_yaml", - "syn 2.0.114", - "tinystr 0.7.6", - "toml 0.8.23", -] - -[[package]] -name = "leptos_macro" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e621f8f5342b9bdc93bb263b839cee7405027a74560425a2dabea9de7952b1fd" -dependencies = [ - "attribute-derive", - "cfg-if", - "convert_case 0.7.1", - "html-escape", - "itertools 0.14.0", - "leptos_hot_reload", - "prettyplease", - "proc-macro-error2", - "proc-macro2", - "quote", - "rstml", - "server_fn_macro", - "syn 2.0.114", - "uuid", -] - -[[package]] -name = "leptos_meta" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "448a6387e9e2cccbb756f474a54e36a39557127a3b8e46744b6ef6372b50f575" -dependencies = [ - "futures", - "indexmap", - "leptos", - "once_cell", - "or_poisoned", - "send_wrapper", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "leptos_server" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66985242812ec95e224fb48effe651ba02728beca92c461a9464c811a71aab11" -dependencies = [ - "any_spawner", - "base64 0.22.1", - "codee", - "futures", - "hydration_context", - "or_poisoned", - "reactive_graph", - "send_wrapper", - "serde", - "serde_json", - "server_fn", - "tachys", -] - [[package]] name = "libc" version = "0.2.180" @@ -4869,12 +3907,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linear-map" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" - [[package]] name = "link-cplusplus" version = "1.0.12" @@ -4896,12 +3928,6 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" -[[package]] -name = "litemap" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" - [[package]] name = "litemap" version = "0.8.1" @@ -4990,36 +4016,13 @@ dependencies = [ "libc", ] -[[package]] -name = "manyhow" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b33efb3ca6d3b07393750d4030418d594ab1139cee518f0dc88db70fec873587" -dependencies = [ - "manyhow-macros", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "manyhow-macros" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fce34d199b78b6e6073abf984c9cf5fd3e9330145a93ee0738a7443e371495" -dependencies = [ - "proc-macro-utils", - "proc-macro2", - "quote", -] - [[package]] name = "matchers" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" dependencies = [ - "regex-automata 0.4.14", + "regex-automata", ] [[package]] @@ -5283,12 +4286,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" -[[package]] -name = "next_tuple" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60993920e071b0c9b66f14e2b32740a4e27ffc82854dcd72035887f336a09a28" - [[package]] name = "no-std-compat" version = "0.2.0" @@ -5521,16 +4518,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "oco_ref" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0423ff9973dea4d6bd075934fdda86ebb8c05bdf9d6b0507067d4a1226371d" -dependencies = [ - "serde", - "thiserror 2.0.18", -] - [[package]] name = "octets" version = "0.2.0" @@ -5567,12 +4554,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "or_poisoned" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c04f5d74368e4d0dfe06c45c8627c81bd7c317d52762d118fb9b3076f6420fd" - [[package]] name = "ordered-float" version = "4.6.0" @@ -5645,12 +4626,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec" -[[package]] -name = "pathdiff" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" - [[package]] name = "pbkdf2" version = "0.11.0" @@ -5669,49 +4644,6 @@ version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" -[[package]] -name = "pest" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" -dependencies = [ - "memchr", - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "pest_meta" -version = "2.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" -dependencies = [ - "pest", - "sha2", -] - [[package]] name = "petgraph" version = "0.6.5" @@ -5728,26 +4660,6 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" -[[package]] -name = "pin-project" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "pin-project-lite" version = "0.2.16" @@ -5836,26 +4748,13 @@ dependencies = [ "portable-atomic", ] -[[package]] -name = "postcard" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" -dependencies = [ - "cobs", - "embedded-io 0.4.0", - "embedded-io 0.6.1", - "heapless", - "serde", -] - [[package]] name = "potential_utf" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ - "zerovec 0.11.5", + "zerovec", ] [[package]] @@ -5932,39 +4831,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "proc-macro-error-attr2" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "proc-macro-error2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" -dependencies = [ - "proc-macro-error-attr2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - -[[package]] -name = "proc-macro-utils" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeaf08a13de400bc215877b5bdc088f241b12eb42f0a548d3390dc1c56bb7071" -dependencies = [ - "proc-macro2", - "quote", - "smallvec", -] - [[package]] name = "proc-macro2" version = "1.0.106" @@ -5974,19 +4840,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "version_check", - "yansi", -] - [[package]] name = "profiling" version = "1.0.17" @@ -6006,13 +4859,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "protocol" -version = "0.1.0" -dependencies = [ - "serde", -] - [[package]] name = "pulp" version = "0.22.2" @@ -6187,28 +5033,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "quote-use" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9619db1197b497a36178cfc736dc96b271fe918875fbf1344c436a7e93d0321e" -dependencies = [ - "quote", - "quote-use-macros", -] - -[[package]] -name = "quote-use-macros" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82ebfb7faafadc06a7ab141a6f67bcfb24cb8beb158c6fe933f2f035afa99f35" -dependencies = [ - "proc-macro-utils", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "r-efi" version = "5.3.0" @@ -6491,55 +5315,6 @@ dependencies = [ "crossbeam-utils", ] -[[package]] -name = "reactive_graph" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76a0ccddbc11a648bd09761801dac9e3f246ef7641130987d6120fced22515e6" -dependencies = [ - "any_spawner", - "async-lock", - "futures", - "guardian", - "hydration_context", - "or_poisoned", - "pin-project-lite", - "rustc-hash 2.1.1", - "send_wrapper", - "serde", - "slotmap", - "thiserror 2.0.18", - "web-sys", -] - -[[package]] -name = "reactive_stores" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aadc7c19e3a360bf19cd595d2dc8b58ce67b9240b95a103fbc1317a8ff194237" -dependencies = [ - "guardian", - "itertools 0.14.0", - "or_poisoned", - "paste", - "reactive_graph", - "reactive_stores_macro", - "rustc-hash 2.1.1", -] - -[[package]] -name = "reactive_stores_macro" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "221095cb028dc51fbc2833743ea8b1a585da1a2af19b440b3528027495bf1f2d" -dependencies = [ - "convert_case 0.7.1", - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "reborrow" version = "0.5.5" @@ -6583,19 +5358,10 @@ checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.14", + "regex-automata", "regex-syntax", ] -[[package]] -name = "regex-automata" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9368763f5a9b804326f3af749e16f9abf378d227bcdee7634b13d8f17793782" -dependencies = [ - "memchr", -] - [[package]] name = "regex-automata" version = "0.4.14" @@ -6762,21 +5528,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "rstml" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61cf4616de7499fc5164570d40ca4e1b24d231c6833a88bff0fe00725080fd56" -dependencies = [ - "derive-where", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.114", - "syn_derive", - "thiserror 2.0.18", -] - [[package]] name = "rusqlite" version = "0.37.0" @@ -6992,15 +5743,6 @@ version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" -dependencies = [ - "futures-core", -] - [[package]] name = "seq-macro" version = "0.3.6" @@ -7071,17 +5813,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_qs" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd34f36fe4c5ba9654417139a9b3a20d2e1de6012ee678ad14d240c22c78d8d6" -dependencies = [ - "percent-encoding", - "serde", - "thiserror 1.0.69", -] - [[package]] name = "serde_rusqlite" version = "0.40.1" @@ -7122,73 +5853,6 @@ dependencies = [ "serde", ] -[[package]] -name = "serde_yaml" -version = "0.9.34+deprecated" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" -dependencies = [ - "indexmap", - "itoa", - "ryu", - "serde", - "unsafe-libyaml", -] - -[[package]] -name = "server_fn" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d05a9e3fd8d7404985418db38c6617cc793a1a27f398d4fbc9dfe8e41b804e6" -dependencies = [ - "bytes", - "const_format", - "dashmap", - "futures", - "gloo-net", - "http", - "js-sys", - "once_cell", - "pin-project-lite", - "send_wrapper", - "serde", - "serde_json", - "serde_qs", - "server_fn_macro_default", - "thiserror 2.0.18", - "throw_error", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-streams", - "web-sys", - "xxhash-rust", -] - -[[package]] -name = "server_fn_macro" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504b35e883267b3206317b46d02952ed7b8bf0e11b2e209e2eb453b609a5e052" -dependencies = [ - "const_format", - "convert_case 0.6.0", - "proc-macro2", - "quote", - "syn 2.0.114", - "xxhash-rust", -] - -[[package]] -name = "server_fn_macro_default" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb8b274f568c94226a8045668554aace8142a59b8bca5414ac5a79627c825568" -dependencies = [ - "server_fn_macro", - "syn 2.0.114", -] - [[package]] name = "sha1" version = "0.10.6" @@ -7349,15 +6013,6 @@ dependencies = [ "trictrac-store", ] -[[package]] -name = "spin" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -dependencies = [ - "lock_api", -] - [[package]] name = "spin" version = "0.10.0" @@ -7481,18 +6136,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb066a04799e45f5d582e8fc6ec8e6d6896040d00898eb4e6a835196815b219" -dependencies = [ - "proc-macro-error2", - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -7581,40 +6224,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tachys" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66c3b70c32844a6f1e2943c72a33ebb777ad6acbeb20d1329d62e3a7806d6ec" -dependencies = [ - "any_spawner", - "async-trait", - "const_str_slice_concat", - "drain_filter_polyfill", - "dyn-clone", - "either_of", - "futures", - "html-escape", - "indexmap", - "itertools 0.14.0", - "js-sys", - "linear-map", - "next_tuple", - "oco_ref", - "once_cell", - "or_poisoned", - "parking_lot", - "paste", - "reactive_graph", - "reactive_stores", - "rustc-hash 2.1.1", - "send_wrapper", - "slotmap", - "throw_error", - "wasm-bindgen", - "web-sys", -] - [[package]] name = "tar" version = "0.4.44" @@ -7746,15 +6355,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "throw_error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ef8bf264c6ae02a065a4a16553283f0656bd6266fc1fcb09fd2e6b5e91427b" -dependencies = [ - "pin-project-lite", -] - [[package]] name = "tiff" version = "0.10.3" @@ -7811,16 +6411,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "tinystr" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" -dependencies = [ - "displaydoc", - "zerovec 0.10.4", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -7828,7 +6418,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", - "zerovec 0.11.5", + "zerovec", ] [[package]] @@ -7903,7 +6493,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite", ] [[package]] @@ -8216,7 +6806,7 @@ dependencies = [ "matchers", "nu-ansi-term", "once_cell", - "regex-automata 0.4.14", + "regex-automata", "sharded-slab", "smallvec", "thread_local", @@ -8292,24 +6882,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http", - "httparse", - "log", - "rand 0.8.5", - "sha1", - "thiserror 1.0.69", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.28.0" @@ -8342,26 +6914,6 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" -[[package]] -name = "typed-builder" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7" -dependencies = [ - "typed-builder-macro", -] - -[[package]] -name = "typed-builder-macro" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", -] - [[package]] name = "typed-path" version = "0.12.2" @@ -8374,12 +6926,6 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" -[[package]] -name = "ucd-trie" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" - [[package]] name = "unicode-ident" version = "1.0.22" @@ -8452,12 +6998,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "unsafe-libyaml" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" - [[package]] name = "untrusted" version = "0.9.0" @@ -8506,18 +7046,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "utf16_iter" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" - -[[package]] -name = "utf8-width" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1292c0d970b54115d14f2492fe0170adf21d68a1de108eebc51c1df4f346a091" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -8687,19 +7215,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-streams" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" -dependencies = [ - "futures-util", - "js-sys", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "web-sys" version = "0.3.85" @@ -9307,21 +7822,6 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "write16" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" - -[[package]] -name = "writeable" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" -dependencies = [ - "either", -] - [[package]] name = "writeable" version = "0.6.2" @@ -9344,12 +7844,6 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" -[[package]] -name = "xxhash-rust" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd20c5420375476fbd4394763288da7eb0cc0b8c11deed431a91562af7335d3" - [[package]] name = "y4m" version = "0.8.0" @@ -9362,18 +7856,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" -[[package]] -name = "yoke" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" -dependencies = [ - "serde", - "stable_deref_trait", - "yoke-derive 0.7.5", - "zerofrom", -] - [[package]] name = "yoke" version = "0.8.1" @@ -9381,22 +7863,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", - "yoke-derive 0.8.1", + "yoke-derive", "zerofrom", ] -[[package]] -name = "yoke-derive" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", - "synstructure 0.13.2", -] - [[package]] name = "yoke-derive" version = "0.8.1" @@ -9456,17 +7926,6 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" -[[package]] -name = "zerotrie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb594dd55d87335c5f60177cee24f19457a5ec10a065e0a3014722ad252d0a1f" -dependencies = [ - "displaydoc", - "yoke 0.7.5", - "zerofrom", -] - [[package]] name = "zerotrie" version = "0.2.3" @@ -9474,41 +7933,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", - "yoke 0.8.1", + "yoke", "zerofrom", ] -[[package]] -name = "zerovec" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" -dependencies = [ - "yoke 0.7.5", - "zerofrom", - "zerovec-derive 0.10.3", -] - [[package]] name = "zerovec" version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ - "yoke 0.8.1", + "yoke", "zerofrom", - "zerovec-derive 0.11.2", -] - -[[package]] -name = "zerovec-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.114", + "zerovec-derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 72e3f08..4c2eb15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,4 @@ [workspace] resolver = "2" -members = ["client_cli", "bot", "store", "spiel_bot", "client_web"] +members = ["client_cli", "bot", "store", "spiel_bot"] diff --git a/README.md b/README.md index e74fb69..e5a0f39 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Training of AI bots is the work in progress. - game rules and game state are implemented in the _store/_ folder. - the command-line application is implemented in _client_cli/_; it allows you to play against a bot, or to have two bots play against each other -- the bots algorithms and the training of their models are implemented in the _bot/_ and _spiel_bot_ folders. +- the bots algorithms and the training of their models are implemented in the _bot/_ folder ### _store_ package diff --git a/bot/Cargo.toml b/bot/Cargo.toml index d24adcc..de957df 100644 --- a/bot/Cargo.toml +++ b/bot/Cargo.toml @@ -13,7 +13,7 @@ path = "src/burnrl/main.rs" pretty_assertions = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -trictrac-store = { path = "../store", features = ["python"] } +trictrac-store = { path = "../store" } rand = "0.9" env_logger = "0.10" burn = { version = "0.20", features = ["ndarray", "autodiff"] } diff --git a/client_cli/Cargo.toml b/client_cli/Cargo.toml index d85dd8b..52318cb 100644 --- a/client_cli/Cargo.toml +++ b/client_cli/Cargo.toml @@ -13,7 +13,7 @@ bincode = "1.3.3" pico-args = "0.5.0" pretty_assertions = "1.4.0" renet = "0.0.13" -trictrac-store = { path = "../store", features = ["python"] } +trictrac-store = { path = "../store" } trictrac-bot = { path = "../bot" } spiel_bot = { path = "../spiel_bot" } itertools = "0.13.0" diff --git a/client_web/Cargo.toml b/client_web/Cargo.toml deleted file mode 100644 index 3e648ea..0000000 --- a/client_web/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "client_web" -version = "0.1.0" -edition = "2021" - -[package.metadata.leptos-i18n] -default = "en" -locales = ["en", "fr"] - -[dependencies] -leptos_i18n = { version = "0.5", features = ["csr", "interpolate_display"] } -trictrac-store = { path = "../store" } -backbone-lib = { path = "../../forks/multiplayer/backbone-lib" } -leptos = { version = "0.7", features = ["csr"] } -serde = { version = "1.0", features = ["derive"] } -serde_json = "1" -futures = "0.3" -rand = "0.9" -gloo-storage = "0.3" - -[target.'cfg(target_arch = "wasm32")'.dependencies] -wasm-bindgen-futures = "0.4" -# getrandom 0.3 requires an explicit WASM backend; "wasm_js" uses window.crypto.getRandomValues. -# Must be a direct dependency (not just transitive) for the feature to take effect. -getrandom = { version = "0.3", features = ["wasm_js"] } diff --git a/client_web/Trunk.toml b/client_web/Trunk.toml deleted file mode 100644 index 57a2aaa..0000000 --- a/client_web/Trunk.toml +++ /dev/null @@ -1,2 +0,0 @@ -[serve] -port = 9092 diff --git a/client_web/assets/style.css b/client_web/assets/style.css deleted file mode 100644 index f6816c2..0000000 --- a/client_web/assets/style.css +++ /dev/null @@ -1,357 +0,0 @@ -/* ── Reset & base ──────────────────────────────────────────────────── */ -*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } - -body { - font-family: sans-serif; - background: #c8b084; - display: flex; - justify-content: center; - padding: 1.5rem; - min-height: 100vh; -} - -/* ── Login / Connecting screens ────────────────────────────────────── */ -.login-container { - display: flex; - flex-direction: column; - gap: 0.75rem; - max-width: 320px; - margin-top: 4rem; -} - -.login-container h1 { font-size: 2rem; text-align: center; margin-bottom: 0.5rem; } - -input[type="text"] { - padding: 0.5rem 0.75rem; - font-size: 1rem; - border: 1px solid #aaa; - border-radius: 4px; -} - -.error-msg { color: #c00; font-size: 0.9rem; } - -.connecting { font-size: 1.2rem; margin-top: 4rem; text-align: center; } - -/* ── Buttons ────────────────────────────────────────────────────────── */ -.btn { - padding: 0.5rem 1.25rem; - font-size: 1rem; - border: none; - border-radius: 4px; - cursor: pointer; - transition: opacity 0.15s; -} -.btn:disabled { opacity: 0.4; cursor: default; } -.btn-primary { background: #3a6b3a; color: #fff; } -.btn-secondary { background: #5a4a2a; color: #fff; } -.btn:not(:disabled):hover { opacity: 0.85; } - -/* ── Game container ─────────────────────────────────────────────────── */ -.game-container { - display: flex; - flex-direction: column; - align-items: center; - gap: 0.75rem; - width: 100%; - max-width: 900px; -} - -/* ── Language switcher ──────────────────────────────────────────────── */ -.lang-switcher { - display: flex; - gap: 0.25rem; -} - -.lang-switcher button { - font-size: 0.75rem; - padding: 0.15rem 0.4rem; - border: 1px solid rgba(0,0,0,0.3); - border-radius: 3px; - background: transparent; - cursor: pointer; - color: inherit; - opacity: 0.6; -} - -.lang-switcher button.lang-active { - opacity: 1; - font-weight: bold; - background: rgba(0,0,0,0.12); -} - -.login-container .lang-switcher { - justify-content: flex-end; - margin-bottom: 1rem; -} - -/* ── Top bar ─────────────────────────────────────────────────────────── */ -.top-bar { - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; -} - -.quit-link { - font-size: 0.85rem; - color: #5a4a2a; - text-decoration: underline; - cursor: pointer; -} - -/* ── Player score panel ─────────────────────────────────────────────── */ -.player-score-panel { - background: #f5edd8; - border-radius: 6px; - padding: 0.5rem 1rem; - font-size: 0.9rem; - box-shadow: 0 1px 4px rgba(0,0,0,0.2); - width: 100%; - max-width: 900px; -} - -.player-score-header { - margin-bottom: 0.3rem; -} - -.player-name { - font-weight: bold; - font-size: 1rem; -} - -.score-bars { - display: flex; - flex-direction: column; - gap: 4px; -} - -.score-bar-row { - display: flex; - align-items: center; - gap: 0.5rem; -} - -.score-bar-label { - font-size: 0.8rem; - color: #555; - width: 3.5rem; - text-align: right; - flex-shrink: 0; -} - -.score-bar { - width: 140px; - height: 10px; - background: rgba(0,0,0,0.12); - border-radius: 5px; - overflow: hidden; - flex-shrink: 0; -} - -.score-bar-fill { - height: 100%; - border-radius: 5px; - transition: width 0.3s; -} - -.score-bar-points { background: #4a7a3a; } -.score-bar-holes { background: #7a4a2a; } - -.score-bar-value { - font-size: 0.8rem; - color: #444; - min-width: 2.5rem; -} - -.bredouille-badge { - font-size: 0.7rem; - font-weight: bold; - color: #fff; - background: #c07800; - border-radius: 3px; - padding: 0.05em 0.35em; - cursor: default; -} - -.player-jans { - margin-top: 0.35rem; - border-top: 1px solid rgba(0,0,0,0.1); - padding-top: 0.25rem; -} - -/* ── Status bar ─────────────────────────────────────────────────────── */ -.status-bar { - display: flex; - gap: 1rem; - align-items: center; - font-size: 1.05rem; - font-weight: 500; -} - -/* ── Dice bars ──────────────────────────────────────────────────────── */ -.dice-bar { - display: flex; - align-items: center; - gap: 0.75rem; -} - -/* ── Die face (SVG) ─────────────────────────────────────────────────── */ -.die-face rect { - fill: #fffff0; - stroke: #2a1a00; - stroke-width: 2; -} -.die-face circle { - fill: #1a0a00; -} -.die-face.die-used rect { - fill: #d8d4c8; - stroke: #8a7a60; -} -.die-face.die-used circle { - fill: #8a7a60; -} - -/* ── Jan panel ──────────────────────────────────────────────────────── */ -.jan-panel { - display: flex; - flex-direction: column; - gap: 2px; - background: #f5edd8; - border-radius: 6px; - padding: 0.4rem 1rem; - font-size: 0.9rem; - box-shadow: 0 1px 4px rgba(0,0,0,0.15); - min-width: 260px; -} - -.jan-row { - display: flex; - align-items: center; - gap: 0.5rem; - padding: 2px 4px; - border-radius: 3px; -} -.jan-expandable { cursor: pointer; } -.jan-expandable:hover { background: rgba(0,0,0,0.06); } - -.jan-positive { color: #1a5c1a; } -.jan-negative { color: #8b1a1a; } - -.jan-label { flex: 1; } -.jan-tag { - font-size: 0.75rem; - padding: 0.1em 0.4em; - border-radius: 3px; - background: rgba(0,0,0,0.08); - color: #555; - white-space: nowrap; -} -.jan-pts { font-weight: bold; text-align: right; min-width: 3rem; } - -.jan-moves { padding: 1px 4px 4px 1rem; display: flex; flex-direction: column; gap: 2px; } -.jan-moves.hidden { display: none; } -.jan-move-line { font-family: monospace; font-size: 0.8rem; color: #444; } - -/* ── Board ──────────────────────────────────────────────────────────── */ -.board { - background: #2e6b2e; - border: 4px solid #1a3d1a; - border-radius: 8px; - padding: 4px; - display: flex; - flex-direction: column; - gap: 4px; - user-select: none; - box-shadow: 0 4px 12px rgba(0,0,0,0.4); -} - -.board-row { - display: flex; - gap: 4px; -} - -.board-quarter { - display: flex; - gap: 2px; -} - -.board-bar { - width: 20px; - background: #1a3d1a; - border-radius: 3px; -} - -.board-center-bar { - height: 12px; - background: #1a3d1a; - border-radius: 3px; -} - -/* ── Fields ─────────────────────────────────────────────────────────── */ -.field { - width: 60px; - height: 180px; - background: #d4a843; - border-radius: 4px; - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-end; - padding: 4px 2px; - position: relative; - transition: background 0.1s; -} - -/* Alternating field colours */ -.board-quarter .field:nth-child(odd) { background: #c49030; } -.board-quarter .field:nth-child(even) { background: #d4a843; } - -.top-row .field { justify-content: flex-start; } - -.field.clickable { cursor: pointer; } -.field.clickable:hover { background: #e8c060 !important; } -.field.selected { background: #88bb44 !important; outline: 2px solid #446622; } -.field.dest { background: #aad060 !important; } - -.field-num { - font-size: 0.65rem; - color: rgba(0,0,0,0.45); - position: absolute; - bottom: 2px; -} - -.top-row .field-num { bottom: auto; top: 2px; } - -/* ── Checkers ───────────────────────────────────────────────────────── */ -.checker-stack { - display: flex; - flex-direction: column; - align-items: center; -} - -.checker { - width: 40px; - height: 40px; - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - font-size: 0.8rem; - font-weight: bold; - border: 2px solid rgba(0,0,0,0.3); - box-shadow: inset 0 2px 4px rgba(255,255,255,0.3), 0 1px 3px rgba(0,0,0,0.3); - flex-shrink: 0; -} - -.checker + .checker { margin-top: 2px; } - -.checker.white { - background: radial-gradient(circle at 35% 35%, #ffffff, #cccccc); - color: #333; -} - -.checker.black { - background: radial-gradient(circle at 35% 35%, #555555, #111111); - color: #eee; -} diff --git a/client_web/index.html b/client_web/index.html deleted file mode 100644 index b661d76..0000000 --- a/client_web/index.html +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - Trictrac - - - - - diff --git a/client_web/locales/en.json b/client_web/locales/en.json deleted file mode 100644 index 0898aee..0000000 --- a/client_web/locales/en.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "room_name_placeholder": "Room name", - "create_room": "Create Room", - "join_room": "Join Room", - "connecting": "Connecting…", - "game_over": "Game over", - "waiting_for_opponent": "Waiting for opponent…", - "your_turn_roll": "Your turn — roll the dice", - "hold_or_go": "Hold or Go?", - "select_move": "Select move {{ n }} of 2", - "your_turn": "Your turn", - "opponent_turn": "Opponent's turn", - "room_label": "Room: {{ id }}", - "quit": "Quit", - "roll_dice": "Roll dice", - "go": "Go", - "empty_move": "Empty move", - "you_suffix": " (you)", - "points_label": "Points", - "holes_label": "Holes", - "bredouille_title": "Can bredouille", - "jan_double": "double", - "jan_simple": "simple", - "jan_filled_quarter": "Quarter filled", - "jan_true_hit_small": "True hit (small jan)", - "jan_true_hit_big": "True hit (big jan)", - "jan_true_hit_corner": "True hit (opp. corner)", - "jan_first_exit": "First to exit", - "jan_six_tables": "Six tables", - "jan_two_tables": "Two tables", - "jan_mezeas": "Mezeas", - "jan_false_hit_small": "False hit (small jan)", - "jan_false_hit_big": "False hit (big jan)", - "jan_contre_two": "Contre two tables", - "jan_contre_mezeas": "Contre mezeas", - "jan_helpless_man": "Helpless man", - "play_vs_bot": "Play vs Bot", - "vs_bot_label": "vs Bot" -} diff --git a/client_web/locales/fr.json b/client_web/locales/fr.json deleted file mode 100644 index b41b8ed..0000000 --- a/client_web/locales/fr.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "room_name_placeholder": "Nom de la salle", - "create_room": "Créer une salle", - "join_room": "Rejoindre", - "connecting": "Connexion en cours…", - "game_over": "Partie terminée", - "waiting_for_opponent": "En attente de l'adversaire…", - "your_turn_roll": "Votre tour — lancez les dés", - "hold_or_go": "Tenir ou aller ?", - "select_move": "Sélectionner le coup {{ n }} sur 2", - "your_turn": "Votre tour", - "opponent_turn": "Tour de l'adversaire", - "room_label": "Salle : {{ id }}", - "quit": "Quitter", - "roll_dice": "Lancer les dés", - "go": "Aller", - "empty_move": "Coup vide", - "you_suffix": " (vous)", - "points_label": "Points", - "holes_label": "Trous", - "bredouille_title": "Peut faire bredouille", - "jan_double": "double", - "jan_simple": "simple", - "jan_filled_quarter": "Remplissage", - "jan_true_hit_small": "Battage à vrai (petit jan)", - "jan_true_hit_big": "Battage à vrai (grand jan)", - "jan_true_hit_corner": "Battage coin adverse", - "jan_first_exit": "Premier sorti", - "jan_six_tables": "Six tables", - "jan_two_tables": "Deux tables", - "jan_mezeas": "Mezeas", - "jan_false_hit_small": "Battage à faux (petit jan)", - "jan_false_hit_big": "Battage à faux (grand jan)", - "jan_contre_two": "Contre deux tables", - "jan_contre_mezeas": "Contre mezeas", - "jan_helpless_man": "Dame impuissante", - "play_vs_bot": "Jouer contre le bot", - "vs_bot_label": "contre le bot" -} diff --git a/client_web/src/app.rs b/client_web/src/app.rs deleted file mode 100644 index 7e605cb..0000000 --- a/client_web/src/app.rs +++ /dev/null @@ -1,326 +0,0 @@ -use futures::channel::mpsc; -use futures::{FutureExt, StreamExt}; -use gloo_storage::{LocalStorage, Storage}; -use leptos::prelude::*; -use leptos::task::spawn_local; -use serde::{Deserialize, Serialize}; - -use backbone_lib::session::{ConnectError, GameSession, RoomConfig, RoomRole, SessionEvent}; -use backbone_lib::traits::{BackEndArchitecture, BackendCommand, ViewStateUpdate}; - -use crate::components::{ConnectingScreen, GameScreen, LoginScreen}; -use crate::i18n::I18nContextProvider; -use crate::trictrac::backend::TrictracBackend; -use crate::trictrac::bot_local::bot_decide; -use crate::trictrac::types::{GameDelta, PlayerAction, ViewState}; - -const RELAY_URL: &str = "ws://127.0.0.1:8080/ws"; -const GAME_ID: &str = "trictrac"; -const STORAGE_KEY: &str = "trictrac_session"; - -/// The state the UI needs to render the game screen. -#[derive(Clone, PartialEq)] -pub struct GameUiState { - pub view_state: ViewState, - /// 0 = host, 1 = guest - pub player_id: u16, - pub room_id: String, - pub is_bot_game: bool, -} - -/// Which screen is currently shown. -#[derive(Clone, PartialEq)] -pub enum Screen { - Login { error: Option }, - Connecting, - Playing(GameUiState), -} - -/// Commands sent from UI event handlers into the network task. -pub enum NetCommand { - CreateRoom { - room: String, - }, - JoinRoom { - room: String, - }, - Reconnect { - relay_url: String, - game_id: String, - room_id: String, - token: u64, - host_state: Option>, - }, - PlayVsBot, - Action(PlayerAction), - Disconnect, -} - -/// Stored in localStorage to reconnect after a page refresh. -#[derive(Serialize, Deserialize)] -struct StoredSession { - relay_url: String, - game_id: String, - room_id: String, - token: u64, - #[serde(default)] - is_host: bool, - #[serde(default)] - view_state: Option, -} - -fn save_session(session: &StoredSession) { - LocalStorage::set(STORAGE_KEY, session).ok(); -} - -fn load_session() -> Option { - LocalStorage::get::(STORAGE_KEY).ok() -} - -fn clear_session() { - LocalStorage::delete(STORAGE_KEY); -} - -#[component] -pub fn App() -> impl IntoView { - let stored = load_session(); - let initial_screen = if stored.is_some() { - Screen::Connecting - } else { - Screen::Login { error: None } - }; - let screen = RwSignal::new(initial_screen); - - let (cmd_tx, mut cmd_rx) = mpsc::unbounded::(); - provide_context(cmd_tx.clone()); - - if let Some(s) = stored { - let host_state = s - .view_state - .as_ref() - .and_then(|vs| serde_json::to_vec(vs).ok()); - cmd_tx - .unbounded_send(NetCommand::Reconnect { - relay_url: s.relay_url, - game_id: s.game_id, - room_id: s.room_id, - token: s.token, - host_state, - }) - .ok(); - } - - spawn_local(async move { - loop { - // Wait for a connect/reconnect command (or PlayVsBot). - // None means "play vs bot"; Some((config, is_reconnect)) means "connect to relay". - let remote_config: Option<(RoomConfig, bool)> = loop { - match cmd_rx.next().await { - Some(NetCommand::PlayVsBot) => break None, - Some(NetCommand::CreateRoom { room }) => { - break Some(( - RoomConfig { - relay_url: RELAY_URL.to_string(), - game_id: GAME_ID.to_string(), - room_id: room, - rule_variation: 0, - role: RoomRole::Create, - reconnect_token: None, - host_state: None, - }, - false, - )); - } - Some(NetCommand::JoinRoom { room }) => { - break Some(( - RoomConfig { - relay_url: RELAY_URL.to_string(), - game_id: GAME_ID.to_string(), - room_id: room, - rule_variation: 0, - role: RoomRole::Join, - reconnect_token: None, - host_state: None, - }, - false, - )); - } - Some(NetCommand::Reconnect { - relay_url, - game_id, - room_id, - token, - host_state, - }) => { - break Some(( - RoomConfig { - relay_url, - game_id, - room_id, - rule_variation: 0, - role: RoomRole::Join, - reconnect_token: Some(token), - host_state, - }, - true, - )); - } - _ => {} // Ignore game commands while disconnected. - } - }; - - if remote_config.is_none() { - run_local_bot_game(screen, &mut cmd_rx).await; - screen.set(Screen::Login { error: None }); - continue; - } - let (config, is_reconnect) = remote_config.unwrap(); - - screen.set(Screen::Connecting); - - let room_id_for_storage = config.room_id.clone(); - let mut session: GameSession = - match GameSession::connect::(config).await { - Ok(s) => s, - Err(ConnectError::WebSocket(e) | ConnectError::Handshake(e)) => { - if is_reconnect { - clear_session(); - } - screen.set(Screen::Login { error: Some(e) }); - continue; - } - }; - - if !session.is_host { - save_session(&StoredSession { - relay_url: RELAY_URL.to_string(), - game_id: GAME_ID.to_string(), - room_id: room_id_for_storage.clone(), - token: session.reconnect_token, - is_host: false, - view_state: None, - }); - } - - let is_host = session.is_host; - let player_id = session.player_id; - let reconnect_token = session.reconnect_token; - let mut vs = ViewState::default_with_names("Host", "Guest"); - - loop { - futures::select! { - cmd = cmd_rx.next().fuse() => match cmd { - Some(NetCommand::Action(action)) => { - session.send_action(action); - } - _ => { - clear_session(); - session.disconnect(); - screen.set(Screen::Login { error: None }); - break; - } - }, - event = session.next_event().fuse() => match event { - Some(SessionEvent::Update(u)) => { - match u { - ViewStateUpdate::Full(state) => vs = state, - ViewStateUpdate::Incremental(delta) => vs.apply_delta(&delta), - } - if is_host { - save_session(&StoredSession { - relay_url: RELAY_URL.to_string(), - game_id: GAME_ID.to_string(), - room_id: room_id_for_storage.clone(), - token: reconnect_token, - is_host: true, - view_state: Some(vs.clone()), - }); - } - screen.set(Screen::Playing(GameUiState { - view_state: vs.clone(), - player_id, - room_id: room_id_for_storage.clone(), - is_bot_game: false, - })); - } - Some(SessionEvent::Disconnected(reason)) => { - screen.set(Screen::Login { error: reason }); - break; - } - None => { - screen.set(Screen::Login { error: None }); - break; - } - } - } - } - } - }); - - view! { - - {move || match screen.get() { - Screen::Login { error } => view! { }.into_any(), - Screen::Connecting => view! { }.into_any(), - Screen::Playing(state) => view! { }.into_any(), - }} - - } -} - -async fn run_local_bot_game( - screen: RwSignal, - cmd_rx: &mut futures::channel::mpsc::UnboundedReceiver, -) { - let mut backend = TrictracBackend::new(0); - backend.player_arrival(0); - backend.player_arrival(1); - - let mut vs = ViewState::default_with_names("You", "Bot"); - drain_and_update(&mut backend, &mut vs, screen); - - loop { - match cmd_rx.next().await { - Some(NetCommand::Action(action)) => { - backend.inform_rpc(0, action); - } - _ => break, - } - - drain_and_update(&mut backend, &mut vs, screen); - - loop { - match bot_decide(backend.get_game()) { - None => break, - Some(action) => { - backend.inform_rpc(1, action); - drain_and_update(&mut backend, &mut vs, screen); - } - } - } - } -} - -fn drain_and_update( - backend: &mut TrictracBackend, - vs: &mut ViewState, - screen: RwSignal, -) { - for cmd in backend.drain_commands() { - match cmd { - BackendCommand::ResetViewState => { - *vs = backend.get_view_state().clone(); - } - BackendCommand::Delta(delta) => { - vs.apply_delta(&delta); - } - _ => {} - } - } - screen.set(Screen::Playing(GameUiState { - view_state: vs.clone(), - player_id: 0, - room_id: String::new(), - is_bot_game: true, - })); -} diff --git a/client_web/src/components/board.rs b/client_web/src/components/board.rs deleted file mode 100644 index 0ec3040..0000000 --- a/client_web/src/components/board.rs +++ /dev/null @@ -1,149 +0,0 @@ -use leptos::prelude::*; - -use crate::trictrac::types::{SerTurnStage, ViewState}; - -/// Field numbers in visual display order (left-to-right for each quarter), white's perspective. -const TOP_LEFT_W: [u8; 6] = [13, 14, 15, 16, 17, 18]; -const TOP_RIGHT_W: [u8; 6] = [19, 20, 21, 22, 23, 24]; -const BOT_LEFT_W: [u8; 6] = [12, 11, 10, 9, 8, 7]; -const BOT_RIGHT_W: [u8; 6] = [6, 5, 4, 3, 2, 1]; - -/// 180° rotation of white's layout: black's pieces (field 24) appear at the bottom. -const TOP_LEFT_B: [u8; 6] = [1, 2, 3, 4, 5, 6]; -const TOP_RIGHT_B: [u8; 6] = [7, 8, 9, 10, 11, 12]; -const BOT_LEFT_B: [u8; 6] = [24, 23, 22, 21, 20, 19]; -const BOT_RIGHT_B: [u8; 6] = [18, 17, 16, 15, 14, 13]; - -/// Returns the displayed board value for `field_num` after applying `staged_moves`. -/// Field numbers are always in white's coordinate system (1–24). -fn displayed_value( - base_board: [i8; 24], - staged_moves: &[(u8, u8)], - is_white: bool, - field_num: u8, -) -> i8 { - let mut val = base_board[(field_num - 1) as usize]; - let delta: i8 = if is_white { 1 } else { -1 }; - for &(from, to) in staged_moves { - if from == field_num { - val -= delta; - } - if to == field_num { - val += delta; - } - } - val -} - -#[component] -pub fn Board( - view_state: ViewState, - player_id: u16, - /// Pending origin selection (first click of a move pair). - selected_origin: RwSignal>, - /// Moves staged so far this turn (max 2). Each entry is (from, to), 0 = empty move. - staged_moves: RwSignal>, -) -> impl IntoView { - let board = view_state.board; - let is_move_stage = view_state.active_mp_player == Some(player_id) - && matches!( - view_state.turn_stage, - SerTurnStage::Move | SerTurnStage::HoldOrGoChoice - ); - let is_white = player_id == 0; - - let fields_from = |nums: &[u8], is_top_row: bool| -> Vec { - nums.iter() - .map(|&field_num| { - view! { -
0 } else { val < 0 }; - let can_stage = is_move_stage && moves.len() < 2; - let sel = selected_origin.get(); - - let mut cls = "field".to_string(); - if can_stage && (sel.is_some() || is_mine) { - cls.push_str(" clickable"); - } - if sel == Some(field_num) { cls.push_str(" selected"); } - if can_stage && sel.is_some() && sel != Some(field_num) { - cls.push_str(" dest"); - } - cls - } - on:click=move |_| { - if !is_move_stage { return; } - if staged_moves.get_untracked().len() >= 2 { return; } - - let moves = staged_moves.get_untracked(); - let val = displayed_value(board, &moves, is_white, field_num); - let is_mine = if is_white { val > 0 } else { val < 0 }; - - match selected_origin.get_untracked() { - Some(origin) if origin == field_num => { - selected_origin.set(None); - } - Some(origin) => { - staged_moves.update(|v| v.push((origin, field_num))); - selected_origin.set(None); - } - None if is_mine => selected_origin.set(Some(field_num)), - None => {} - } - } - > - {field_num} - {move || { - let moves = staged_moves.get(); - let val = displayed_value(board, &moves, is_white, field_num); - let count = val.unsigned_abs(); - (count > 0).then(|| { - let color = if val > 0 { "white" } else { "black" }; - let display_n = (count as usize).min(4); - // outermost index: last for top rows, first for bottom rows. - let outer_idx = if is_top_row { display_n - 1 } else { 0 }; - let chips: Vec = (0..display_n).map(|i| { - let label = if i == outer_idx && count >= 5 { - count.to_string() - } else { - String::new() - }; - view! { -
{label}
- }.into_any() - }).collect(); - view! {
{chips}
} - }) - }} -
- } - .into_any() - }) - .collect() - }; - - let (tl, tr, bl, br) = if is_white { - (&TOP_LEFT_W, &TOP_RIGHT_W, &BOT_LEFT_W, &BOT_RIGHT_W) - } else { - (&TOP_LEFT_B, &TOP_RIGHT_B, &BOT_LEFT_B, &BOT_RIGHT_B) - }; - - view! { -
-
-
{fields_from(tl, true)}
-
-
{fields_from(tr, true)}
-
-
-
-
{fields_from(bl, false)}
-
-
{fields_from(br, false)}
-
-
- } -} diff --git a/client_web/src/components/connecting_screen.rs b/client_web/src/components/connecting_screen.rs deleted file mode 100644 index 6f40da5..0000000 --- a/client_web/src/components/connecting_screen.rs +++ /dev/null @@ -1,9 +0,0 @@ -use leptos::prelude::*; - -use crate::i18n::*; - -#[component] -pub fn ConnectingScreen() -> impl IntoView { - let i18n = use_i18n(); - view! {

{t!(i18n, connecting)}

} -} diff --git a/client_web/src/components/die.rs b/client_web/src/components/die.rs deleted file mode 100644 index 1f83ea9..0000000 --- a/client_web/src/components/die.rs +++ /dev/null @@ -1,32 +0,0 @@ -use leptos::prelude::*; - -/// (cx, cy) positions for dots on a 48×48 die face. -fn dot_positions(value: u8) -> &'static [(&'static str, &'static str)] { - match value { - 1 => &[("24", "24")], - 2 => &[("35", "13"), ("13", "35")], - 3 => &[("35", "13"), ("24", "24"), ("13", "35")], - 4 => &[("13", "13"), ("35", "13"), ("13", "35"), ("35", "35")], - 5 => &[("13", "13"), ("35", "13"), ("24", "24"), ("13", "35"), ("35", "35")], - 6 => &[("13", "13"), ("35", "13"), ("13", "24"), ("35", "24"), ("13", "35"), ("35", "35")], - _ => &[], - } -} - -/// A single die face rendered as SVG. -/// `value` 1–6 shows dots; 0 shows an empty face (not-yet-rolled). -/// `used` dims the die. -#[component] -pub fn Die(value: u8, used: bool) -> impl IntoView { - let cls = if used { "die-face die-used" } else { "die-face" }; - let dots: Vec = dot_positions(value) - .iter() - .map(|&(cx, cy)| view! { }.into_any()) - .collect(); - view! { - - - {dots} - - } -} diff --git a/client_web/src/components/game_screen.rs b/client_web/src/components/game_screen.rs deleted file mode 100644 index 51747a8..0000000 --- a/client_web/src/components/game_screen.rs +++ /dev/null @@ -1,224 +0,0 @@ -use futures::channel::mpsc::UnboundedSender; -use leptos::prelude::*; -use trictrac_store::CheckerMove; - -use crate::app::{GameUiState, NetCommand}; -use crate::i18n::*; -use crate::trictrac::types::{JanEntry, PlayerAction, SerStage, SerTurnStage}; - -use super::board::Board; -use super::die::Die; -use super::score_panel::PlayerScorePanel; - -#[allow(dead_code)] -/// Returns (d0_used, d1_used) by matching each staged move's distance to a die. -fn matched_dice_used(staged: &[(u8, u8)], dice: (u8, u8)) -> (bool, bool) { - let mut d0 = false; - let mut d1 = false; - for &(from, to) in staged { - let dist = if from < to { - to.saturating_sub(from) - } else { - from.saturating_sub(to) - }; - if !d0 && dist == dice.0 { - d0 = true; - } else if !d1 && dist == dice.1 { - d1 = true; - } else if !d0 { - d0 = true; - } else { - d1 = true; - } - } - (d0, d1) -} - -/// Split `dice_jans` into (viewer_jans, opponent_jans). -fn split_jans( - dice_jans: &[JanEntry], - viewer_is_active: bool, -) -> (Vec, Vec) { - let mut mine = Vec::new(); - let mut theirs = Vec::new(); - for e in dice_jans { - if viewer_is_active { - if e.total >= 0 { - mine.push(e.clone()); - } else { - theirs.push(JanEntry { total: -e.total, points_per: -e.points_per, ..e.clone() }); - } - } else if e.total >= 0 { - theirs.push(e.clone()); - } else { - mine.push(JanEntry { total: -e.total, points_per: -e.points_per, ..e.clone() }); - } - } - (mine, theirs) -} - -#[component] -pub fn GameScreen(state: GameUiState) -> impl IntoView { - let i18n = use_i18n(); - - let vs = state.view_state.clone(); - let player_id = state.player_id; - let is_my_turn = vs.active_mp_player == Some(player_id); - let is_move_stage = is_my_turn - && matches!( - vs.turn_stage, - SerTurnStage::Move | SerTurnStage::HoldOrGoChoice - ); - - // ── Staged move state ────────────────────────────────────────────────────── - let selected_origin: RwSignal> = RwSignal::new(None); - let staged_moves: RwSignal> = RwSignal::new(Vec::new()); - - let cmd_tx = use_context::>() - .expect("UnboundedSender not found in context"); - let cmd_tx_effect = cmd_tx.clone(); - Effect::new(move |_| { - let moves = staged_moves.get(); - if moves.len() == 2 { - let to_cm = |&(from, to): &(u8, u8)| { - CheckerMove::new(from as usize, to as usize).unwrap_or_default() - }; - cmd_tx_effect - .unbounded_send(NetCommand::Action(PlayerAction::Move( - to_cm(&moves[0]), - to_cm(&moves[1]), - ))) - .ok(); - staged_moves.set(vec![]); - selected_origin.set(None); - } - }); - - let dice = vs.dice; - let show_dice = dice != (0, 0); - - // ── Button senders ───────────────────────────────────────────────────────── - let cmd_tx_roll = cmd_tx.clone(); - let cmd_tx_go = cmd_tx.clone(); - let cmd_tx_quit = cmd_tx.clone(); - let show_roll = is_my_turn && vs.turn_stage == SerTurnStage::RollDice; - let show_hold_go = is_my_turn && vs.turn_stage == SerTurnStage::HoldOrGoChoice; - - // ── Jan split: viewer_jans / opponent_jans ───────────────────────────────── - let (my_jans, opp_jans) = split_jans(&vs.dice_jans, is_my_turn); - - // ── Scores ───────────────────────────────────────────────────────────────── - let my_score = vs.scores[player_id as usize].clone(); - let opp_score = vs.scores[1 - player_id as usize].clone(); - - // ── Capture for closures ─────────────────────────────────────────────────── - let stage = vs.stage.clone(); - let turn_stage = vs.turn_stage.clone(); - let room_id = state.room_id.clone(); - let is_bot_game = state.is_bot_game; - - view! { -
- // ── Top bar ────────────────────────────────────────────────────── -
- {move || if is_bot_game { - t_string!(i18n, vs_bot_label).to_owned() - } else { - t_string!(i18n, room_label, id = room_id.as_str()) - }} -
- - -
- {t!(i18n, quit)} -
- - // ── Opponent score (above board) ───────────────────────────────── - - - // ── Status ─────────────────────────────────────────────────────── -
- {move || { - let n = staged_moves.get().len(); - if is_move_stage { - t_string!(i18n, select_move, n = n + 1) - } else { - String::from(match (&stage, is_my_turn, &turn_stage) { - (SerStage::Ended, _, _) => t_string!(i18n, game_over), - (SerStage::PreGame, _, _) => t_string!(i18n, waiting_for_opponent), - (SerStage::InGame, true, SerTurnStage::RollDice) => t_string!(i18n, your_turn_roll), - (SerStage::InGame, true, SerTurnStage::HoldOrGoChoice) => t_string!(i18n, hold_or_go), - (SerStage::InGame, true, _) => t_string!(i18n, your_turn), - (SerStage::InGame, false, _) => t_string!(i18n, opponent_turn), - }) - } - }} -
- - // ── Opponent dice (top) ────────────────────────────────────────── - {(!is_my_turn && show_dice).then(|| view! { -
- - -
- })} - - // ── Board ──────────────────────────────────────────────────────── - - - // ── Player action bar (bottom) ─────────────────────────────────── - {is_my_turn.then(|| view! { -
- {move || { - let (d0, d1) = if is_move_stage { - matched_dice_used(&staged_moves.get(), dice) - } else { - (false, false) - }; - view! { - - - } - }} - {show_roll.then(|| view! { - - })} - {show_hold_go.then(|| view! { - - })} - {is_move_stage.then(|| view! { - - })} -
- })} - - // ── Player score (below board) ──────────────────────────────────── - -
- } -} diff --git a/client_web/src/components/login_screen.rs b/client_web/src/components/login_screen.rs deleted file mode 100644 index 91e6d1b..0000000 --- a/client_web/src/components/login_screen.rs +++ /dev/null @@ -1,77 +0,0 @@ -use futures::channel::mpsc::UnboundedSender; -use leptos::prelude::*; - -use crate::app::NetCommand; -use crate::i18n::*; - -#[component] -pub fn LoginScreen(error: Option) -> impl IntoView { - let i18n = use_i18n(); - let (room_name, set_room_name) = signal(String::new()); - - let cmd_tx = use_context::>() - .expect("UnboundedSender not found in context"); - - let cmd_tx_create = cmd_tx.clone(); - let cmd_tx_join = cmd_tx.clone(); - let cmd_tx_bot = cmd_tx; - - view! { - - } -} diff --git a/client_web/src/components/mod.rs b/client_web/src/components/mod.rs deleted file mode 100644 index cd5fc33..0000000 --- a/client_web/src/components/mod.rs +++ /dev/null @@ -1,10 +0,0 @@ -mod board; -mod connecting_screen; -mod die; -mod game_screen; -mod login_screen; -mod score_panel; - -pub use connecting_screen::ConnectingScreen; -pub use game_screen::GameScreen; -pub use login_screen::LoginScreen; diff --git a/client_web/src/components/score_panel.rs b/client_web/src/components/score_panel.rs deleted file mode 100644 index bb57bce..0000000 --- a/client_web/src/components/score_panel.rs +++ /dev/null @@ -1,143 +0,0 @@ -use leptos::prelude::*; -use trictrac_store::{CheckerMove, Jan}; - -use crate::i18n::*; -use crate::trictrac::types::{JanEntry, PlayerScore}; - -fn jan_label(jan: &Jan) -> String { - let i18n = use_i18n(); - match jan { - Jan::FilledQuarter => t_string!(i18n, jan_filled_quarter).to_owned(), - Jan::TrueHitSmallJan => t_string!(i18n, jan_true_hit_small).to_owned(), - Jan::TrueHitBigJan => t_string!(i18n, jan_true_hit_big).to_owned(), - Jan::TrueHitOpponentCorner => t_string!(i18n, jan_true_hit_corner).to_owned(), - Jan::FirstPlayerToExit => t_string!(i18n, jan_first_exit).to_owned(), - Jan::SixTables => t_string!(i18n, jan_six_tables).to_owned(), - Jan::TwoTables => t_string!(i18n, jan_two_tables).to_owned(), - Jan::Mezeas => t_string!(i18n, jan_mezeas).to_owned(), - Jan::FalseHitSmallJan => t_string!(i18n, jan_false_hit_small).to_owned(), - Jan::FalseHitBigJan => t_string!(i18n, jan_false_hit_big).to_owned(), - Jan::ContreTwoTables => t_string!(i18n, jan_contre_two).to_owned(), - Jan::ContreMezeas => t_string!(i18n, jan_contre_mezeas).to_owned(), - Jan::HelplessMan => t_string!(i18n, jan_helpless_man).to_owned(), - } -} - -fn format_move_pair(m1: CheckerMove, m2: CheckerMove) -> String { - let fmt = |m: CheckerMove| -> String { - let (f, t) = (m.get_from(), m.get_to()); - if f == 0 && t == 0 { - "—".to_string() - } else if t == 0 { - format!("{f}↑") - } else { - format!("{f}→{t}") - } - }; - format!("{} & {}", fmt(m1), fmt(m2)) -} - -fn jan_row(idx: usize, entry: JanEntry, expanded: RwSignal>) -> impl IntoView { - let i18n = use_i18n(); - let row_class = if entry.total >= 0 { - "jan-row jan-expandable jan-positive" - } else { - "jan-row jan-expandable jan-negative" - }; - let label = jan_label(&entry.jan); - let double_tag = if entry.is_double { - t_string!(i18n, jan_double).to_owned() - } else { - t_string!(i18n, jan_simple).to_owned() - }; - let ways_tag = format!("×{}", entry.ways); - let pts_str = if entry.total >= 0 { - format!("+{}", entry.total) - } else { - format!("{}", entry.total) - }; - - let moves = entry.moves.clone(); - - view! { -
-
- {label} - {double_tag} - {ways_tag} - {pts_str} -
- { - let move_lines: Vec<_> = moves.iter() - .map(|&(m1, m2)| { - let text = format_move_pair(m1, m2); - view! {
{text}
} - }) - .collect(); - view! { -
- {move_lines} -
- } - } -
- } -} - -#[component] -pub fn PlayerScorePanel(score: PlayerScore, jans: Vec, is_you: bool) -> impl IntoView { - let i18n = use_i18n(); - - let points_pct = format!("{}%", (score.points as u32 * 100 / 12).min(100)); - let holes_pct = format!("{}%", (score.holes as u32 * 100 / 12).min(100)); - let points_val = format!("{}/12", score.points); - let holes_val = format!("{}/12", score.holes); - let can_bredouille = score.can_bredouille; - - let expanded: RwSignal> = RwSignal::new(None); - let jan_rows: Vec<_> = jans - .into_iter() - .enumerate() - .map(|(i, entry)| jan_row(i, entry, expanded)) - .collect(); - - view! { -
-
- - {score.name} - {is_you.then(|| t!(i18n, you_suffix))} - -
-
-
- {t!(i18n, points_label)} -
-
-
- {points_val} - {can_bredouille.then(|| view! { - "B" - })} -
-
- {t!(i18n, holes_label)} -
-
-
- {holes_val} -
-
- {(!jan_rows.is_empty()).then(|| view! { -
{jan_rows}
- })} -
- } -} diff --git a/client_web/src/main.rs b/client_web/src/main.rs deleted file mode 100644 index 209ae60..0000000 --- a/client_web/src/main.rs +++ /dev/null @@ -1,12 +0,0 @@ -leptos_i18n::load_locales!(); - -mod app; -mod components; -mod trictrac; - -use app::App; -use leptos::prelude::*; - -fn main() { - mount_to_body(|| view! { }) -} diff --git a/client_web/src/trictrac/backend.rs b/client_web/src/trictrac/backend.rs deleted file mode 100644 index 3e57935..0000000 --- a/client_web/src/trictrac/backend.rs +++ /dev/null @@ -1,326 +0,0 @@ -use backbone_lib::traits::{BackEndArchitecture, BackendCommand}; -use trictrac_store::{DiceRoller, GameEvent, GameState, TurnStage}; - -use crate::trictrac::types::{GameDelta, PlayerAction, ViewState}; - -// Store PlayerId (u64) values used for the two players. -const HOST_PLAYER_ID: u64 = 1; -const GUEST_PLAYER_ID: u64 = 2; - -pub struct TrictracBackend { - game: GameState, - dice_roller: DiceRoller, - commands: Vec>, - view_state: ViewState, - /// Arrival flags: have host (index 0) and guest (index 1) joined? - arrived: [bool; 2], -} - -impl TrictracBackend { - fn sync_view_state(&mut self) { - self.view_state = ViewState::from_game_state(&self.game, HOST_PLAYER_ID, GUEST_PLAYER_ID); - } - - fn broadcast_state(&mut self) { - self.sync_view_state(); - let delta = GameDelta { - state: self.view_state.clone(), - }; - self.commands.push(BackendCommand::Delta(delta)); - } - - /// Roll dice using the store's DiceRoller and fire Roll + RollResult events. - fn do_roll(&mut self) { - let dice = self.dice_roller.roll(); - let player_id = self.game.active_player_id; - let _ = self.game.consume(&GameEvent::Roll { player_id }); - let _ = self - .game - .consume(&GameEvent::RollResult { player_id, dice }); - - // Drive automatic stages that require no player input. - self.drive_automatic_stages(); - } - - /// Advance through stages that can be resolved without player input - /// (MarkPoints, MarkAdvPoints). - fn drive_automatic_stages(&mut self) { - loop { - let player_id = self.game.active_player_id; - match self.game.turn_stage { - TurnStage::MarkPoints | TurnStage::MarkAdvPoints => { - let _ = self.game.consume(&GameEvent::Mark { - player_id, - points: self.game.dice_points.0.max(self.game.dice_points.1), - }); - } - _ => break, - } - } - } -} - -impl TrictracBackend { - pub fn get_game(&self) -> &GameState { - &self.game - } -} - -impl BackEndArchitecture for TrictracBackend { - fn new(_rule_variation: u16) -> Self { - let mut game = GameState::new(false); - game.init_player("Host"); - game.init_player("Guest"); - - let view_state = ViewState::from_game_state(&game, HOST_PLAYER_ID, GUEST_PLAYER_ID); - - TrictracBackend { - game, - dice_roller: DiceRoller::default(), - commands: Vec::new(), - view_state, - arrived: [false; 2], - } - } - - fn from_bytes(_rule_variation: u16, bytes: &[u8]) -> Option { - let view_state: ViewState = serde_json::from_slice(bytes).ok()?; - // Reconstruct a fresh game; full state restore is not yet implemented. - let mut backend = Self::new(_rule_variation); - backend.view_state = view_state; - Some(backend) - } - - fn player_arrival(&mut self, mp_player: u16) { - if mp_player > 1 { - self.commands - .push(BackendCommand::KickPlayer { player: mp_player }); - return; - } - self.arrived[mp_player as usize] = true; - - // Cancel any reconnect timer for this player. - self.commands.push(BackendCommand::CancelTimer { - timer_id: mp_player, - }); - - // Start the game once both players have arrived. - if self.arrived[0] && self.arrived[1] && self.game.stage == trictrac_store::Stage::PreGame { - let _ = self.game.consume(&GameEvent::BeginGame { - goes_first: HOST_PLAYER_ID, - }); - self.sync_view_state(); - self.commands.push(BackendCommand::ResetViewState); - } else { - self.broadcast_state(); - } - } - - fn player_departure(&mut self, mp_player: u16) { - if mp_player > 1 { - return; - } - self.arrived[mp_player as usize] = false; - // Give 60 seconds to reconnect before terminating the room. - self.commands.push(BackendCommand::SetTimer { - timer_id: mp_player, - duration: 60.0, - }); - } - - fn inform_rpc(&mut self, mp_player: u16, action: PlayerAction) { - if self.game.stage == trictrac_store::Stage::Ended { - return; - } - - let store_id = if mp_player == 0 { - HOST_PLAYER_ID - } else { - GUEST_PLAYER_ID - }; - - // Only the active player may act (except during Chance-like waiting stages). - if self.game.active_player_id != store_id { - return; - } - - match action { - PlayerAction::Roll => { - if self.game.turn_stage == TurnStage::RollDice { - self.do_roll(); - } - } - PlayerAction::Move(m1, m2) => { - if self.game.turn_stage != TurnStage::Move - && self.game.turn_stage != TurnStage::HoldOrGoChoice - { - return; - } - let event = GameEvent::Move { - player_id: store_id, - moves: (m1, m2), - }; - if self.game.validate(&event) { - let _ = self.game.consume(&event); - self.drive_automatic_stages(); - } - } - PlayerAction::Go => { - if self.game.turn_stage == TurnStage::HoldOrGoChoice { - let _ = self.game.consume(&GameEvent::Go { - player_id: store_id, - }); - } - } - PlayerAction::Mark => { - if matches!( - self.game.turn_stage, - TurnStage::MarkPoints | TurnStage::MarkAdvPoints - ) { - self.drive_automatic_stages(); - } - } - } - - self.broadcast_state(); - } - - fn timer_triggered(&mut self, timer_id: u16) { - match timer_id { - 0 | 1 => { - // Reconnect grace period expired for host (0) or guest (1). - self.commands.push(BackendCommand::TerminateRoom); - } - _ => {} - } - } - - fn get_view_state(&self) -> &ViewState { - &self.view_state - } - - fn drain_commands(&mut self) -> Vec> { - std::mem::take(&mut self.commands) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use backbone_lib::traits::BackEndArchitecture; - - fn make_backend() -> TrictracBackend { - TrictracBackend::new(0) - } - - /// Helper: drain and return only Delta commands, extracting their ViewStates. - fn drain_deltas(b: &mut TrictracBackend) -> Vec { - b.drain_commands() - .into_iter() - .filter_map(|cmd| match cmd { - BackendCommand::Delta(d) => Some(d.state), - BackendCommand::ResetViewState => Some(b.view_state.clone()), - _ => None, - }) - .collect() - } - - #[test] - fn both_players_arrive_starts_game() { - let mut b = make_backend(); - b.player_arrival(0); // host - b.drain_commands(); - b.player_arrival(1); // guest - let cmds = b.drain_commands(); - - // ResetViewState should have been issued after BeginGame. - let has_reset = cmds - .iter() - .any(|c| matches!(c, BackendCommand::ResetViewState)); - assert!( - has_reset, - "expected ResetViewState after both players arrive" - ); - - // Game should now be InGame. - use crate::trictrac::types::SerStage; - assert_eq!(b.get_view_state().stage, SerStage::InGame); - } - - #[test] - fn unknown_player_kicked() { - let mut b = make_backend(); - b.player_arrival(99); - let cmds = b.drain_commands(); - assert!(cmds - .iter() - .any(|c| matches!(c, BackendCommand::KickPlayer { player: 99 }))); - } - - #[test] - fn roll_advances_to_move_or_hold() { - let mut b = make_backend(); - b.player_arrival(0); - b.player_arrival(1); - b.drain_commands(); - - // Host rolls (player_id 0, whose store id == HOST_PLAYER_ID == active after BeginGame). - b.inform_rpc(0, PlayerAction::Roll); - let states = drain_deltas(&mut b); - assert!(!states.is_empty(), "expected a state broadcast after roll"); - - use crate::trictrac::types::SerTurnStage; - let last = states.last().unwrap(); - assert!( - matches!( - last.turn_stage, - SerTurnStage::Move | SerTurnStage::HoldOrGoChoice - ), - "expected Move or HoldOrGoChoice after roll, got {:?}", - last.turn_stage - ); - assert_eq!(last.dice, b.get_view_state().dice); - assert!(last.dice.0 >= 1 && last.dice.0 <= 6); - assert!(last.dice.1 >= 1 && last.dice.1 <= 6); - } - - #[test] - fn wrong_player_roll_ignored() { - let mut b = make_backend(); - b.player_arrival(0); - b.player_arrival(1); - b.drain_commands(); - - // Guest tries to roll when it's the host's turn. - b.inform_rpc(1, PlayerAction::Roll); - let cmds = b.drain_commands(); - assert!( - cmds.is_empty(), - "guest roll should be ignored when it's host's turn" - ); - } - - #[test] - fn departure_sets_reconnect_timer() { - let mut b = make_backend(); - b.player_arrival(0); - b.drain_commands(); - b.player_departure(0); - let cmds = b.drain_commands(); - assert!( - cmds.iter() - .any(|c| matches!(c, BackendCommand::SetTimer { timer_id: 0, .. })), - "expected reconnect timer after host departure" - ); - } - - #[test] - fn timer_triggers_terminate_room() { - let mut b = make_backend(); - b.timer_triggered(0); - let cmds = b.drain_commands(); - assert!(cmds - .iter() - .any(|c| matches!(c, BackendCommand::TerminateRoom))); - } -} diff --git a/client_web/src/trictrac/bot_local.rs b/client_web/src/trictrac/bot_local.rs deleted file mode 100644 index 537ffcb..0000000 --- a/client_web/src/trictrac/bot_local.rs +++ /dev/null @@ -1,30 +0,0 @@ -use rand::prelude::IndexedRandom; -use trictrac_store::{CheckerMove, Color, GameState, MoveRules, TurnStage}; - -use crate::trictrac::types::PlayerAction; - -const GUEST_PLAYER_ID: u64 = 2; - -/// Returns the next action for the bot (mp_player 1 / guest), or None if it is not the bot's turn. -pub fn bot_decide(game: &GameState) -> Option { - if game.active_player_id != GUEST_PLAYER_ID { - return None; - } - match game.turn_stage { - TurnStage::RollDice => Some(PlayerAction::Roll), - TurnStage::HoldOrGoChoice => Some(PlayerAction::Go), - TurnStage::Move => { - let rules = MoveRules::new(&Color::Black, &game.board, game.dice); - let sequences = rules.get_possible_moves_sequences(true, vec![]); - let mut rng = rand::rng(); - let (m1, m2) = sequences - .choose(&mut rng) - .cloned() - .unwrap_or((CheckerMove::default(), CheckerMove::default())); - // MoveRules with Color::Black mirrors the board internally, so - // returned move coordinates are in mirrored (White) space — mirror back. - Some(PlayerAction::Move(m1.mirror(), m2.mirror())) - } - _ => None, - } -} diff --git a/client_web/src/trictrac/mod.rs b/client_web/src/trictrac/mod.rs deleted file mode 100644 index 38d05bb..0000000 --- a/client_web/src/trictrac/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod backend; -pub mod bot_local; -pub mod types; diff --git a/client_web/src/trictrac/types.rs b/client_web/src/trictrac/types.rs deleted file mode 100644 index 02e2675..0000000 --- a/client_web/src/trictrac/types.rs +++ /dev/null @@ -1,200 +0,0 @@ -use serde::{Deserialize, Serialize}; -use trictrac_store::{CheckerMove, GameState, Jan, Stage, TurnStage}; - -// ── Actions sent by a player to the host backend ───────────────────────────── - -#[derive(Clone, Serialize, Deserialize)] -pub enum PlayerAction { - /// Active player requests a dice roll. - Roll, - /// Both checker moves for this turn. Use `EMPTY_MOVE` (from=0, to=0) when a die - /// has no valid move. - Move(CheckerMove, CheckerMove), - /// Choose to "go" (advance) during HoldOrGoChoice. - Go, - /// Acknowledge point marking (hold / advance points). - Mark, -} - -// ── Incremental state update broadcast to all clients ──────────────────────── - -/// Carries a full state snapshot; `apply_delta` replaces the local state. -/// Simple and correct; can be refined to true diffs later. -#[derive(Clone, Serialize, Deserialize)] -pub struct GameDelta { - pub state: ViewState, -} - -// ── Full game snapshot ──────────────────────────────────────────────────────── - -#[derive(Clone, PartialEq, Serialize, Deserialize)] -pub struct ViewState { - /// Board positions: index i = field i+1. Positive = white, negative = black. - pub board: [i8; 24], - pub stage: SerStage, - pub turn_stage: SerTurnStage, - /// Which multiplayer player_id (0 = host, 1 = guest) is the active player. - pub active_mp_player: Option, - /// Scores indexed by multiplayer player_id (0 = host, 1 = guest). - pub scores: [PlayerScore; 2], - /// Last rolled dice values. - pub dice: (u8, u8), - /// Jans (scoring events) triggered by the last dice roll. - pub dice_jans: Vec, -} - -/// One scoring event from a dice roll. -#[derive(Clone, PartialEq, Serialize, Deserialize, Debug)] -pub struct JanEntry { - pub jan: Jan, - /// True when the dice are doubles (both same value) — changes the point value. - /// Special case for HelplessMan: true when *both* dice are unplayable. - pub is_double: bool, - /// Number of distinct move pairs that produce this jan. - pub ways: usize, - /// Points per way (negative = scored against the active player). - pub points_per: i8, - /// Total = points_per × ways. - pub total: i8, - /// The move pairs that produce this jan (for move display). - pub moves: Vec<(CheckerMove, CheckerMove)>, -} - -impl ViewState { - pub fn default_with_names(host_name: &str, guest_name: &str) -> Self { - ViewState { - board: [0i8; 24], - stage: SerStage::PreGame, - turn_stage: SerTurnStage::RollDice, - active_mp_player: None, - scores: [ - PlayerScore { name: host_name.to_string(), points: 0, holes: 0, can_bredouille: false }, - PlayerScore { name: guest_name.to_string(), points: 0, holes: 0, can_bredouille: false }, - ], - dice: (0, 0), - dice_jans: Vec::new(), - } - } - - pub fn apply_delta(&mut self, delta: &GameDelta) { - *self = delta.state.clone(); - } - - /// Convert a store `GameState` to a `ViewState`. - /// `host_store_id` and `guest_store_id` are the trictrac `PlayerId`s assigned - /// to the host (mp player 0) and guest (mp player 1) respectively. - pub fn from_game_state( - gs: &GameState, - host_store_id: u64, - guest_store_id: u64, - ) -> Self { - let board_vec = gs.board.to_vec(); - let board: [i8; 24] = board_vec.try_into().expect("board is always 24 fields"); - - let stage = match gs.stage { - Stage::PreGame => SerStage::PreGame, - Stage::InGame => SerStage::InGame, - Stage::Ended => SerStage::Ended, - }; - let turn_stage = match gs.turn_stage { - TurnStage::RollDice => SerTurnStage::RollDice, - TurnStage::RollWaiting => SerTurnStage::RollWaiting, - TurnStage::MarkPoints => SerTurnStage::MarkPoints, - TurnStage::HoldOrGoChoice => SerTurnStage::HoldOrGoChoice, - TurnStage::Move => SerTurnStage::Move, - TurnStage::MarkAdvPoints => SerTurnStage::MarkAdvPoints, - }; - - let active_mp_player = if gs.active_player_id == host_store_id { - Some(0) - } else if gs.active_player_id == guest_store_id { - Some(1) - } else { - None - }; - - let score_for = |store_id: u64| -> PlayerScore { - gs.players - .get(&store_id) - .map(|p| PlayerScore { - name: p.name.clone(), - points: p.points, - holes: p.holes, - can_bredouille: p.can_bredouille, - }) - .unwrap_or_else(|| PlayerScore { name: String::new(), points: 0, holes: 0, can_bredouille: false }) - }; - - // is_double for scoring: dice show the same value (both dice identical). - // Exception: HelplessMan uses a special rule (see below). - let dice_are_double = gs.dice.values.0 == gs.dice.values.1; - - // Build JanEntry list from the PossibleJans map. - let empty_move = CheckerMove::new(0, 0).unwrap_or_default(); - let mut dice_jans: Vec = gs.dice_jans - .iter() - .map(|(jan, moves)| { - // HelplessMan: is_double = true only when *both* dice are unplayable - // (the moves list contains a single (empty, empty) sentinel). - let is_double = if *jan == Jan::HelplessMan { - moves.first().map(|&(m1, m2)| m1 == empty_move && m2 == empty_move) - .unwrap_or(false) - } else { - dice_are_double - }; - let points_per = jan.get_points(is_double); - let ways = moves.len(); - let total = points_per.saturating_mul(ways as i8); - JanEntry { - jan: jan.clone(), - is_double, - ways, - points_per, - total, - moves: moves.clone(), - } - }) - .collect(); - // Sort: highest total first, most-negative last. - dice_jans.sort_by_key(|e| std::cmp::Reverse(e.total)); - - ViewState { - board, - stage, - turn_stage, - active_mp_player, - scores: [score_for(host_store_id), score_for(guest_store_id)], - dice: (gs.dice.values.0, gs.dice.values.1), - dice_jans, - } - } -} - -// ── Score snapshot ──────────────────────────────────────────────────────────── - -#[derive(Clone, PartialEq, Serialize, Deserialize)] -pub struct PlayerScore { - pub name: String, - pub points: u8, - pub holes: u8, - pub can_bredouille: bool, -} - -// ── Serialisable mirrors of store enums ────────────────────────────────────── - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum SerStage { - PreGame, - InGame, - Ended, -} - -#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] -pub enum SerTurnStage { - RollDice, - RollWaiting, - MarkPoints, - HoldOrGoChoice, - Move, - MarkAdvPoints, -} diff --git a/devenv.nix b/devenv.nix index c8cc20c..f7a8daa 100644 --- a/devenv.nix +++ b/devenv.nix @@ -5,9 +5,6 @@ let in { packages = [ - # for Leptos - pkgs.trunk - # pkgs.wasm-bindgen-cli_0_2_114 # pour burn-rs pkgs.SDL2_gfx diff --git a/doc/backlog.md b/doc/backlog.md index 339c552..dd52d54 100644 --- a/doc/backlog.md +++ b/doc/backlog.md @@ -31,6 +31,21 @@ ulimit -s unlimited # Pour revenir à la normale Cheatsheet : arbre des situations et priorité des règles +### Epic : jeu simple + +- déplacements autorisés par les règles (pourront être validés physiquement si jeu avec écoles) +- calcul des points automatique (pas d'écoles) + +Server + +- + +Client + +- client tui (ratatui) +- client desktop (bevy) +- client web + ### Epic : jeu avec écoles - déplacement de fiches points : validation physique diff --git a/justfile b/justfile index 1c650fc..2bfc052 100644 --- a/justfile +++ b/justfile @@ -8,19 +8,6 @@ shell: devenv shell runcli: RUST_LOG=info cargo run --bin=client_cli - -[working-directory: 'client_web/'] -dev-leptos: - trunk serve - -[working-directory: 'client_web'] -build-leptos: - trunk build --release - cp dist/index.html /home/henri/travaux/programmes/forks/multiplayer/deploy/trictrac.html - cp dist/*.wasm /home/henri/travaux/programmes/forks/multiplayer/deploy/ - cp dist/*.js /home/henri/travaux/programmes/forks/multiplayer/deploy/ - cp dist/*.css /home/henri/travaux/programmes/forks/multiplayer/deploy/ - runclibots: cargo run --bin=client_cli -- --bot random,dqnburn:./bot/models/burnrl_dqn_40.mpk #cargo run --bin=client_cli -- --bot dqn:./bot/models/dqn_model_final.json,dummy diff --git a/spiel_bot/Cargo.toml b/spiel_bot/Cargo.toml index 1458d66..b541adc 100644 --- a/spiel_bot/Cargo.toml +++ b/spiel_bot/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -trictrac-store = { path = "../store", features = ["python"] } +trictrac-store = { path = "../store" } trictrac-bot = { path = "../bot" } anyhow = "1" rand = "0.9" diff --git a/store/Cargo.toml b/store/Cargo.toml index 58e9e32..935a2a0 100644 --- a/store/Cargo.toml +++ b/store/Cargo.toml @@ -12,21 +12,15 @@ name = "trictrac_store" # "staticlib" → used by the C++ OpenSpiel game (cxxengine) crate-type = ["cdylib", "rlib", "staticlib"] -[features] -# Enable Python bindings (required for maturin / AI training). Not available on wasm32. -python = ["pyo3"] -# Enable C++ bridge for OpenSpiel integration. Not available on wasm32. -cpp = ["dep:cxx"] - [dependencies] anyhow = "1.0" base64 = "0.21.7" -cxx = { version = "1.0", optional = true } +cxx = "1.0" # provides macros for creating log messages to be used by a logger (for example env_logger) log = "0.4.20" merge = "0.1.0" # generate python lib (with maturin) to be used in AI training -pyo3 = { version = "0.23", features = ["extension-module", "abi3-py38"], optional = true } +pyo3 = { version = "0.23", features = ["extension-module", "abi3-py38"] } rand = "0.9" serde = { version = "1.0", features = ["derive"] } transpose = "0.2.2" diff --git a/store/build.rs b/store/build.rs index 88d743f..852bcf6 100644 --- a/store/build.rs +++ b/store/build.rs @@ -1,9 +1,7 @@ fn main() { - if std::env::var("CARGO_FEATURE_CPP").is_ok() { - cxx_build::bridge("src/cxxengine.rs") - .std("c++17") - .compile("trictrac-cxx"); + cxx_build::bridge("src/cxxengine.rs") + .std("c++17") + .compile("trictrac-cxx"); - println!("cargo:rerun-if-changed=src/cxxengine.rs"); - } + println!("cargo:rerun-if-changed=src/cxxengine.rs"); } diff --git a/store/src/game.rs b/store/src/game.rs index 57f69dd..e4e938c 100644 --- a/store/src/game.rs +++ b/store/src/game.rs @@ -987,12 +987,7 @@ impl GameState { player.color, self.board, dice, player.dice_roll_count ); let points_rules = PointsRules::new(&player.color, &self.board, *dice); - let (jans, points) = points_rules.get_result_jans(player.dice_roll_count); - Ok(if player.color == Color::White { - (jans, points) - } else { - (jans.mirror(), points) - }) + Ok(points_rules.get_result_jans(player.dice_roll_count)) } /// Determines if someone has won the game diff --git a/store/src/game_rules_moves.rs b/store/src/game_rules_moves.rs index d695d84..396bcaf 100644 --- a/store/src/game_rules_moves.rs +++ b/store/src/game_rules_moves.rs @@ -297,11 +297,7 @@ impl MoveRules { } // the last 2 checkers of a corner must leave at the same time - if (from0 == corner_field || from1 == corner_field) - && (from0 != from1) - && corner_count == 2 - && to0 != corner_field - && to1 != corner_field + if (from0 == corner_field || from1 == corner_field) && (from0 != from1) && corner_count == 2 { return Err(MoveError::CornerNeedsTwoCheckers); } @@ -343,7 +339,8 @@ impl MoveRules { let seqs = match exit_seqs { Some(s) => s, None => { - owned = self.get_possible_moves_sequences(false, vec![TricTracRule::Exit]); + owned = self + .get_possible_moves_sequences(false, vec![TricTracRule::Exit]); &owned } }; @@ -623,9 +620,8 @@ impl MoveRules { || self .check_exit_rules(&(first_move, second_move), exit_seqs.as_deref()) .is_ok()) - && filling_seqs.map_or(true, |seqs| { - seqs.is_empty() || seqs.contains(&(first_move, second_move)) - }) + && filling_seqs + .map_or(true, |seqs| seqs.is_empty() || seqs.contains(&(first_move, second_move))) { if second_move.get_to() == 0 && first_move.get_to() == 0 @@ -648,12 +644,9 @@ impl MoveRules { && !(self.is_move_by_puissance(&(first_move, EMPTY_MOVE)) && self.can_take_corner_by_effect()) && (ignored_rules.contains(&TricTracRule::Exit) - || self - .check_exit_rules(&(first_move, EMPTY_MOVE), exit_seqs.as_deref()) - .is_ok()) - && filling_seqs.map_or(true, |seqs| { - seqs.is_empty() || seqs.contains(&(first_move, EMPTY_MOVE)) - }) + || self.check_exit_rules(&(first_move, EMPTY_MOVE), exit_seqs.as_deref()).is_ok()) + && filling_seqs + .map_or(true, |seqs| seqs.is_empty() || seqs.contains(&(first_move, EMPTY_MOVE))) { // empty move moves_seqs.push((first_move, EMPTY_MOVE)); @@ -1647,21 +1640,4 @@ mod tests { ); assert!(state.check_must_fill_quarter_rule(&moves).is_ok()); } - - #[test] - fn check_rest_on_rest_corner() { - let mut state = MoveRules::default(); - state.dice.values = (4, 1); - state.board.set_positions( - &crate::Color::White, - [ - 0, 0, -1, -4, -2, -1, 0, -2, -2, 4, 3, 2, 0, -1, -2, 0, 0, 1, 0, 1, 1, 1, 0, 2, - ], - ); - let moves = ( - CheckerMove::new(11, 12).unwrap(), - CheckerMove::new(12, 16).unwrap(), - ); - state.moves_allowed(&moves).expect("moves_allowed failed"); - } } diff --git a/store/src/lib.rs b/store/src/lib.rs index 0bc4128..4fc8dff 100644 --- a/store/src/lib.rs +++ b/store/src/lib.rs @@ -3,7 +3,7 @@ mod game_rules_moves; pub use game_rules_moves::MoveRules; mod game_rules_points; pub use game::{EndGameReason, GameEvent, GameState, Stage, TurnStage}; -pub use game_rules_points::{Jan, PointsRules}; +pub use game_rules_points::PointsRules; mod player; pub use player::{Color, Player, PlayerId}; @@ -20,9 +20,7 @@ pub use dice::{Dice, DiceRoller}; pub mod training_common; // python interface "trictrac_engine" (for AI training..) -#[cfg(feature = "python")] mod pyengine; // C++ interface via cxx.rs (for OpenSpiel C++ integration) -#[cfg(feature = "cpp")] pub mod cxxengine; diff --git a/store/src/player.rs b/store/src/player.rs index cca02b5..1e48593 100644 --- a/store/src/player.rs +++ b/store/src/player.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "python")] use pyo3::prelude::*; use serde::{Deserialize, Serialize}; use std::fmt; @@ -6,7 +5,7 @@ use std::fmt; // This just makes it easier to dissern between a player id and any ol' u64 pub type PlayerId = u64; -#[cfg_attr(feature = "python", pyclass(eq, eq_int))] +#[pyclass(eq, eq_int)] #[derive(Copy, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum Color { White,