diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index 1fd942a..0000000 --- a/.gitattributes +++ /dev/null @@ -1 +0,0 @@ -/frontend.js linguist-generated=true diff --git a/.gitignore b/.gitignore index 8075013..be0b715 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ -/dist-newstyle +/target +gamestate.yml +/release diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..d0f553c --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4916 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "ab_glyph" +version = "0.2.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79faae4620f45232f599d9bc7b290f88247a0834162c4495ab2f02d60004adfb" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c71b1793ee61086797f5c80b6efa2b8ffa6d5dd703f118545808a7f2e27f7046" + +[[package]] +name = "accesskit" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cf780eb737f2d4a49ffbd512324d53ad089070f813f7be7f99dbd5123a7f448" + +[[package]] +name = "accesskit_consumer" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdfa1638ddd6eb9c752def95568df8b3ad832df252e9156d2eb783b201ca8a9" +dependencies = [ + "accesskit", + "immutable-chunkmap", +] + +[[package]] +name = "accesskit_macos" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c236a84ff1111defc280cee755eaa953d0b24398786851b9d28322c6d3bb1ebd" +dependencies = [ + "accesskit", + "accesskit_consumer", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", +] + +[[package]] +name = "accesskit_windows" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7f43d24b16b3e76bef248124fbfd2493c3a9860edb5aae1010c890e826de5e" +dependencies = [ + "accesskit", + "accesskit_consumer", + "paste", + "static_assertions", + "windows 0.54.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.20.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755535e6bf711a42dac28b888b884b10fc00ff4010d9d3bd871c5f5beae5aa78" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_windows", + "raw-window-handle", + "winit", +] + +[[package]] +name = "addr2line" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "alsa" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37fe60779335388a88c01ac6c3be40304d1e349de3ada3b15f7808bb90fa9dce" +dependencies = [ + "alsa-sys", + "bitflags 2.6.0", + "libc", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.6.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk 0.9.0", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.37.3+1.3.251" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" +dependencies = [ + "libloading 0.7.4", +] + +[[package]] +name = "async-broadcast" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c48ccdbf6ca6b121e0f586cbc0e73ae440e56c67c30fa0873b4e110d9c26d2b" +dependencies = [ + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener 2.5.3", + "futures-core", +] + +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-compat" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bab94bde396a3f7b4962e396fdad640e241ed797d4d8d77fc8c237d14c58fc0" +dependencies = [ + "futures-core", + "futures-io", + "once_cell", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-executor" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand 2.1.0", + "futures-lite 2.3.0", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", +] + +[[package]] +name = "async-global-executor" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b1b633a2115cd122d73b955eadd9916c18c8f510ec9cd1686404c60ad1c29c" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "async-io 2.3.3", + "async-lock 3.4.0", + "blocking", + "futures-lite 2.3.0", + "once_cell", +] + +[[package]] +name = "async-io" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc5b45d93ef0529756f812ca52e44c221b35341892d3dcc34132ac02f3dd2af" +dependencies = [ + "async-lock 2.8.0", + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-lite 1.13.0", + "log", + "parking", + "polling 2.8.0", + "rustix 0.37.27", + "slab", + "socket2", + "waker-fn", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock 3.4.0", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite 2.3.0", + "parking", + "polling 3.7.2", + "rustix 0.38.34", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "287272293e9d8c41773cec55e365490fe034813a2f172f502d6ddcf75b2f582b" +dependencies = [ + "event-listener 2.5.3", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener 5.3.1", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-std" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d" +dependencies = [ + "async-channel 1.9.0", + "async-global-executor", + "async-io 1.13.0", + "async-lock 2.8.0", + "crossbeam-utils", + "futures-channel", + "futures-core", + "futures-io", + "futures-lite 1.13.0", + "gloo-timers", + "kv-log-macro", + "log", + "memchr", + "once_cell", + "pin-project-lite", + "pin-utils", + "slab", + "wasm-bindgen-futures", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "bevy" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e938630e9f472b1899c78ef84aa907081b23bad8333140e2295c620485b6ee7" +dependencies = [ + "bevy_internal", +] + +[[package]] +name = "bevy_a11y" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e613f0e7d5a92637e59744f7185e374c9a59654ecc6d7575adcec9581db1363" +dependencies = [ + "accesskit", + "bevy_app", + "bevy_derive", + "bevy_ecs", +] + +[[package]] +name = "bevy_animation" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23aa4141df149b743e69c90244261c6372bafb70d9f115885de48a75fc28fd9b" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_log", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_time", + "bevy_transform", + "bevy_utils", + "blake3", + "fixedbitset 0.5.7", + "petgraph", + "ron", + "serde", + "thiserror", + "thread_local", + "uuid", +] + +[[package]] +name = "bevy_app" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f548e9dab7d10c5f99e3b504c758c4bf87aa67df9bcb9cc8b317a0271770e72" +dependencies = [ + "bevy_derive", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "console_error_panic_hook", + "downcast-rs", + "thiserror", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "bevy_asset" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d198e4c3419215de2ad981d4e734bbfab46469b7575e3b7150c912b9ec5175" +dependencies = [ + "async-broadcast", + "async-fs", + "async-lock 3.4.0", + "bevy_app", + "bevy_asset_macros", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bevy_winit", + "blake3", + "crossbeam-channel", + "downcast-rs", + "futures-io", + "futures-lite 2.3.0", + "js-sys", + "parking_lot", + "ron", + "serde", + "thiserror", + "uuid", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "bevy_asset_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11b2cbeba287a4b44e116c33dbaf37dce80a9d84477b2bb35ff459999d6c9e1b" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_async_task" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3570cf1389d868d4c0f154fd161d9f338f1bc837f2add3d458552cf895171256" +dependencies = [ + "async-compat", + "async-std", + "bevy", + "tokio", +] + +[[package]] +name = "bevy_audio" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e41ecf15d0aae31bdb6d2b5cc590f966451e9736ddfee634c8f1ca5af1ac4342" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_math", + "bevy_reflect", + "bevy_transform", + "bevy_utils", + "cpal", + "rodio", +] + +[[package]] +name = "bevy_color" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a933306f5c7dc9568209180f482b28b5f40d2f8d5b361bc1b270c0a588752c0" +dependencies = [ + "bevy_math", + "bevy_reflect", + "bytemuck", + "encase", + "serde", + "thiserror", + "wgpu-types", +] + +[[package]] +name = "bevy_core" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ddeed5ebf2fa75a4d4f32e2da9c60f11037e36252695059a151c6685cd3d72b" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "uuid", +] + +[[package]] +name = "bevy_core_pipeline" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b978220b5edc98f2c5cbbd14c118c74b3ec7216e5416d3c187c1097279b009b" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_derive", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bitflags 2.6.0", + "nonmax", + "radsort", + "serde", + "smallvec", + "thiserror", +] + +[[package]] +name = "bevy_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8a8173bad3ed53fa158806b1beda147263337d6ef71a093780dd141b74386b1" +dependencies = [ + "bevy_macro_utils", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_diagnostic" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7f82011fd70048be282526a99756d54bf00e874edafa9664ba0dc247678f03" +dependencies = [ + "bevy_app", + "bevy_core", + "bevy_ecs", + "bevy_tasks", + "bevy_time", + "bevy_utils", + "const-fnv1a-hash", + "sysinfo", +] + +[[package]] +name = "bevy_ecs" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c77fdc3a7230eff2fcebe4bd17c155bd238c660a0089d0f98c39ba0d461b923" +dependencies = [ + "arrayvec", + "bevy_ecs_macros", + "bevy_ptr", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bitflags 2.6.0", + "concurrent-queue", + "fixedbitset 0.5.7", + "nonmax", + "petgraph", + "serde", + "thiserror", +] + +[[package]] +name = "bevy_ecs_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9272b511958525306cd141726d3ca59740f79fc0707c439b55a007bcc3497308" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_encase_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0452d8254c8bfae4bff6caca2a8be3b0c1b2e1a72b93e9b9f6a21c8dff807e0" +dependencies = [ + "bevy_macro_utils", + "encase_derive_impl", +] + +[[package]] +name = "bevy_gilrs" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbad8e59470c3d5cf25aa8c48462c4cf6f0c6314538c68ab2f5cf393146f0fc2" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_input", + "bevy_time", + "bevy_utils", + "gilrs", + "thiserror", +] + +[[package]] +name = "bevy_gizmos" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdbb0556f0c6e45f4a17aef9c708c06ebf15ae1bed4533d7eddb493409f9f025" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_gizmos_macros", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bytemuck", +] + +[[package]] +name = "bevy_gizmos_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ef351a4b6498c197d1317c62f46ba84b69fbde3dbeb57beb2e744bbe5b7c3e0" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_gltf" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfd7abeaf3f28afd1f8999c2169aa17b40a37ad11253cf7dd05017024b65adc6" +dependencies = [ + "base64 0.22.1", + "bevy_animation", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_core_pipeline", + "bevy_ecs", + "bevy_hierarchy", + "bevy_math", + "bevy_pbr", + "bevy_reflect", + "bevy_render", + "bevy_scene", + "bevy_tasks", + "bevy_transform", + "bevy_utils", + "gltf", + "percent-encoding", + "serde", + "serde_json", + "smallvec", + "thiserror", +] + +[[package]] +name = "bevy_hierarchy" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "802eca6f341d19ade790ccfaba7044be4d823b708087eb5ac4c1f74e4ea0916a" +dependencies = [ + "bevy_app", + "bevy_core", + "bevy_ecs", + "bevy_reflect", + "bevy_utils", + "smallvec", +] + +[[package]] +name = "bevy_input" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d050f1433f48ca23f1ea078734ebff119a3f76eb7d221725ab0f1fd9f81230b" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_utils", + "smol_str", + "thiserror", +] + +[[package]] +name = "bevy_internal" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ddd2b23e44d3a1f8ae547cbee5b6661f8135cc456c5de206e8648789944e7a1" +dependencies = [ + "bevy_a11y", + "bevy_animation", + "bevy_app", + "bevy_asset", + "bevy_audio", + "bevy_color", + "bevy_core", + "bevy_core_pipeline", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_gilrs", + "bevy_gizmos", + "bevy_gltf", + "bevy_hierarchy", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_pbr", + "bevy_ptr", + "bevy_reflect", + "bevy_render", + "bevy_scene", + "bevy_sprite", + "bevy_state", + "bevy_tasks", + "bevy_text", + "bevy_time", + "bevy_transform", + "bevy_ui", + "bevy_utils", + "bevy_window", + "bevy_winit", +] + +[[package]] +name = "bevy_log" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab641fd0de254915ab746165a07677465b2d89b72f5b49367d73b9197548a35" +dependencies = [ + "android_log-sys", + "bevy_app", + "bevy_ecs", + "bevy_utils", + "tracing-log", + "tracing-subscriber", + "tracing-wasm", +] + +[[package]] +name = "bevy_macro_utils" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ad860d35d74b35d4d6ae7f656d163b6f475aa2e64fc293ee86ac901977ddb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", + "toml_edit 0.22.14", +] + +[[package]] +name = "bevy_math" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51bd6ce2174d3237d30e0ab5b2508480cc7593ca4d96ffb3a3095f9fc6bbc34c" +dependencies = [ + "bevy_reflect", + "glam", + "rand", + "smallvec", + "thiserror", +] + +[[package]] +name = "bevy_mikktspace" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ce4266293629a2d10459cc112dffe3b3e9229a4f2b8a4d20061b8dd53316d0" +dependencies = [ + "glam", +] + +[[package]] +name = "bevy_pbr" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3effe8ff28899f14d250d0649ca9868dbe68b389d0f2b7af086759b8e16c6e3d" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.6.0", + "bytemuck", + "fixedbitset 0.5.7", + "nonmax", + "radsort", + "smallvec", + "static_assertions", +] + +[[package]] +name = "bevy_ptr" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c115c97a5c8a263bd0aa7001b999772c744ac5ba797d07c86f25734ce381ea69" + +[[package]] +name = "bevy_reflect" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "406ea0fce267169c2320c7302d97d09f605105686346762562c5f65960b5ca2f" +dependencies = [ + "bevy_ptr", + "bevy_reflect_derive", + "bevy_utils", + "downcast-rs", + "erased-serde", + "glam", + "petgraph", + "serde", + "smallvec", + "smol_str", + "thiserror", + "uuid", +] + +[[package]] +name = "bevy_reflect_derive" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0427fdb4425fc72cc96d45e550df83ace6347f0503840de116c76a40843ba751" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", + "uuid", +] + +[[package]] +name = "bevy_render" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c48acf1ff4267c231def4cbf573248d42ac60c9952108822d505019460bf36d" +dependencies = [ + "async-channel 2.3.1", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core", + "bevy_derive", + "bevy_diagnostic", + "bevy_ecs", + "bevy_encase_derive", + "bevy_hierarchy", + "bevy_math", + "bevy_mikktspace", + "bevy_reflect", + "bevy_render_macros", + "bevy_tasks", + "bevy_time", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bitflags 2.6.0", + "bytemuck", + "codespan-reporting", + "downcast-rs", + "encase", + "futures-lite 2.3.0", + "hexasphere", + "image", + "js-sys", + "ktx2", + "naga", + "naga_oil", + "nonmax", + "ruzstd", + "send_wrapper", + "serde", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu", +] + +[[package]] +name = "bevy_render_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ddf4a96d71519c8eca3d74dabcb89a9c0d50ab5d9230638cb004145f46e9ed" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_scene" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7a9f0388612a116f02ab6187aeab66e52c9e91abbc21f919b8b50230c4d83e7" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "serde", + "thiserror", + "uuid", +] + +[[package]] +name = "bevy_sprite" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d837e33ed27b9f2e5212eca4bdd5655a9ee64c52914112e6189c043cb25dd1ec" +dependencies = [ + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_transform", + "bevy_utils", + "bitflags 2.6.0", + "bytemuck", + "fixedbitset 0.5.7", + "guillotiere", + "radsort", + "rectangle-pack", + "thiserror", +] + +[[package]] +name = "bevy_state" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0959984092d56885fd3b320ea84fb816821bad6bfa3040b9d4ee850d3273233d" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_hierarchy", + "bevy_reflect", + "bevy_state_macros", + "bevy_utils", +] + +[[package]] +name = "bevy_state_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887a98bfa268258377cd073f5bb839518d3a1cd6b96ed81418145485b69378e6" +dependencies = [ + "bevy_macro_utils", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_tasks" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a8bfb8d484bdb1e9bec3789c75202adc5e608c4244347152e50fb31668a54f9" +dependencies = [ + "async-channel 2.3.1", + "async-executor", + "concurrent-queue", + "futures-lite 2.3.0", + "wasm-bindgen-futures", +] + +[[package]] +name = "bevy_text" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "454fd29b7828244356b2e0ce782e6d0a6f26b47f521456accde3a7191b121727" +dependencies = [ + "ab_glyph", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_transform", + "bevy_utils", + "bevy_window", + "glyph_brush_layout", + "serde", + "thiserror", +] + +[[package]] +name = "bevy_time" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6c3d3d14ee8b0dbe4819fd516cc75509b61946134d78e0ee89ad3d1835ffe6c" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_reflect", + "bevy_utils", + "crossbeam-channel", + "thiserror", +] + +[[package]] +name = "bevy_transform" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97e8aa6b16be573277c6ceda30aebf1d78af7c6ede19b448dcb052fb8601d815" +dependencies = [ + "bevy_app", + "bevy_ecs", + "bevy_hierarchy", + "bevy_math", + "bevy_reflect", + "thiserror", +] + +[[package]] +name = "bevy_tweening" +version = "0.10.0" +source = "git+https://github.com/BraymatterOrg/bevy_tweening_0_14?branch=0.14#1e46e67938ef21cfd3b80a9bd7f9e3de1edd425c" +dependencies = [ + "bevy", + "interpolation", +] + +[[package]] +name = "bevy_ui" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d9f864c646f3742ff77f67bcd89a13a7ab024b68ca2f1bfbab8245bcb1c06c" +dependencies = [ + "bevy_a11y", + "bevy_app", + "bevy_asset", + "bevy_color", + "bevy_core_pipeline", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_input", + "bevy_math", + "bevy_reflect", + "bevy_render", + "bevy_sprite", + "bevy_text", + "bevy_transform", + "bevy_utils", + "bevy_window", + "bytemuck", + "nonmax", + "smallvec", + "taffy", + "thiserror", +] + +[[package]] +name = "bevy_utils" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fab364910e8f5839578aba9cfda00a8388e9ebe352ceb8491a742ce6af9ec6e" +dependencies = [ + "ahash", + "bevy_utils_proc_macros", + "getrandom", + "hashbrown", + "thread_local", + "tracing", + "web-time", +] + +[[package]] +name = "bevy_utils_proc_macros" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad9db261ab33a046e1f54b35f885a44f21fcc80aa2bc9050319466b88fe58fe3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "bevy_window" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9ea5777f933bf7ecaeb3af1a30845720ec730e007972ca7d4aba2d3512abe24" +dependencies = [ + "bevy_a11y", + "bevy_app", + "bevy_ecs", + "bevy_math", + "bevy_reflect", + "bevy_utils", + "raw-window-handle", + "smol_str", +] + +[[package]] +name = "bevy_winit" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c2213bbf14debe819ec8ad4913f233c596002d087bc6f1f20d533e2ebaf8c6" +dependencies = [ + "accesskit_winit", + "approx", + "bevy_a11y", + "bevy_app", + "bevy_derive", + "bevy_ecs", + "bevy_hierarchy", + "bevy_input", + "bevy_log", + "bevy_math", + "bevy_reflect", + "bevy_tasks", + "bevy_utils", + "bevy_window", + "cfg-if", + "crossbeam-channel", + "raw-window-handle", + "wasm-bindgen", + "web-sys", + "winit", +] + +[[package]] +name = "bindgen" +version = "0.69.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a00dc851838a2120612785d195287475a3ac45514741da670b735818822129a0" +dependencies = [ + "bitflags 2.6.0", + "cexpr", + "clang-sys", + "itertools 0.12.1", + "lazy_static", + "lazycell", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.69", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "blake3" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel 2.3.1", + "async-task", + "futures-io", + "futures-lite 2.3.0", + "piper", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "bytemuck" +version = "1.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" + +[[package]] +name = "calloop" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba7adb4dd5aa98e5553510223000e7148f621165ec5f9acd7113f6ca4995298" +dependencies = [ + "bitflags 2.6.0", + "log", + "polling 3.7.2", + "rustix 0.38.34", + "slab", + "thiserror", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.105" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5208975e568d83b6b05cc0a063c8e7e9acc2b43bee6da15616a5b73e109d7437" +dependencies = [ + "jobserver", + "libc", + "once_cell", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading 0.8.4", +] + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "com" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e17887fd17353b65b1b2ef1c526c83e26cd72e74f598a8dc1bee13a48f3d9f6" +dependencies = [ + "com_macros", +] + +[[package]] +name = "com_macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d375883580a668c7481ea6631fc1a8863e33cc335bf56bfad8d7e6d4b04b13a5" +dependencies = [ + "com_macros_support", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "com_macros_support" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad899a1087a9296d5644792d7cb72b8e34c1bec8e7d4fbc002230169a6e8710c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "const-fnv1a-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b13ea120a812beba79e34316b3942a857c86ec1593cb34f27bb28272ce2cca" + +[[package]] +name = "const_panic" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" + +[[package]] +name = "const_soft_float" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ca1caa64ef4ed453e68bb3db612e51cf1b2f5b871337f0fcab1c8f87cc3dff" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "constgebra" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1aaf9b65849a68662ac6c0810c8893a765c960b907dd7cfab9c4a50bf764fbc" +dependencies = [ + "const_soft_float", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "libc", +] + +[[package]] +name = "coreaudio-rs" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "321077172d79c662f64f5071a03120748d5bb652f5231570141be24cfcd2bace" +dependencies = [ + "bitflags 1.3.2", + "core-foundation-sys", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f01585027057ff5f0a5bf276174ae4c1594a2c5bde93d5f46a016d76270f5a9" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "873dab07c8f743075e57f524c583985fbaf745602acbe916a01539364369a779" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "dasp_sample", + "jni", + "js-sys", + "libc", + "mach2", + "ndk 0.8.0", + "ndk-context", + "oboe", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "windows 0.54.0", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap", + "criterion-plot", + "csv", + "itertools 0.10.5", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "csv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac574ff4d437a7b5ad237ef331c17ccca63c46479e5b5453eb8e10bb99a759fe" +dependencies = [ + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "cursor-icon" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96a6ac251f4a2aca6b3f91340350eab87ae57c3f127ffeb585e92bd336717991" + +[[package]] +name = "d3d12" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b28bfe653d79bd16c77f659305b195b82bb5ce0c0eb2a4846b82ddbd77586813" +dependencies = [ + "bitflags 2.6.0", + "libloading 0.8.4", + "winapi", +] + +[[package]] +name = "dasp_sample" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f" + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading 0.8.4", +] + +[[package]] +name = "document-features" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "encase" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9299a95fa5671ddf29ecc22b00e121843a65cb9ff24911e394b4ae556baf36" +dependencies = [ + "const_panic", + "encase_derive", + "glam", + "thiserror", +] + +[[package]] +name = "encase_derive" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07e09decb3beb1fe2db6940f598957b2e1f7df6206a804d438ff6cb2a9cddc10" +dependencies = [ + "encase_derive_impl", +] + +[[package]] +name = "encase_derive_impl" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd31dbbd9743684d339f907a87fe212cb7b51d75b9e8e74181fe363199ee9b47" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "euclid" +version = "0.22.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f0eb73b934648cd7a4a61f1b15391cd95dab0b4da6e2e66c2a072c144b4a20" +dependencies = [ + "num-traits", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener 5.3.1", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "fdeflate" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f9bfee30e4dedf0ab8b422f03af778d9612b63f502710fc500a334ebe2de645" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fixedbitset" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" + +[[package]] +name = "fixedbitset" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" + +[[package]] +name = "flate2" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce" +dependencies = [ + "fastrand 1.9.0", + "futures-core", + "futures-io", + "memchr", + "parking", + "pin-project-lite", + "waker-fn", +] + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand 2.1.0", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "gethostname" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" +dependencies = [ + "libc", + "windows-targets 0.48.5", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gilrs" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f226b8f4d9bc7da93de8efd8747c6b1086409ca3f4b6d51e9a7f5461a9183fe" +dependencies = [ + "fnv", + "gilrs-core", + "log", + "uuid", + "vec_map", +] + +[[package]] +name = "gilrs-core" +version = "0.5.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b922f294d9f062af517ea0bd0a036ddcf11c2842211c2f9c71a3ceee859e10b6" +dependencies = [ + "core-foundation", + "inotify", + "io-kit-sys", + "js-sys", + "libc", + "libudev-sys", + "log", + "nix", + "uuid", + "vec_map", + "wasm-bindgen", + "web-sys", + "windows 0.57.0", +] + +[[package]] +name = "gimli" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glam" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e05e7e6723e3455f4818c7b26e855439f7546cf617ef669d1adedb8669e5cb9" +dependencies = [ + "bytemuck", + "rand", + "serde", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "glow" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348e04c43b32574f2de31c8bb397d96c9fcfa1371bd4ca6d8bdc464ab121b1" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "gltf" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ce1918195723ce6ac74e80542c5a96a40c2b26162c1957a5cd70799b8cacf7" +dependencies = [ + "byteorder", + "gltf-json", + "lazy_static", + "serde_json", +] + +[[package]] +name = "gltf-derive" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14070e711538afba5d6c807edb74bcb84e5dbb9211a3bf5dea0dfab5b24f4c51" +dependencies = [ + "inflections", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "gltf-json" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14" +dependencies = [ + "gltf-derive", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8098adac955faa2d31079b65dc48841251f69efd3ac25477903fc424362ead" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "glyph_brush_layout" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1e288bfd2f6c0313f78bf5aa538356ad481a3bb97e9b7f93220ab0066c5992" +dependencies = [ + "ab_glyph", + "approx", + "xi-unicode", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.6.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "gpu-allocator" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f56f6318968d03c18e1bcf4857ff88c61157e9da8e47c5f29055d60e1228884" +dependencies = [ + "log", + "presser", + "thiserror", + "winapi", + "windows 0.52.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c08c1f623a8d0b722b8b99f821eb0ba672a1618f0d3b16ddbee1cedd2dd8557" +dependencies = [ + "bitflags 2.6.0", + "gpu-descriptor-types", + "hashbrown", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "grid" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be136d9dacc2a13cc70bb6c8f902b414fb2641f8db1314637c6b7933411a8f82" + +[[package]] +name = "guillotiere" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62d5865c036cb1393e23c50693df631d3f5d7bcca4c04fe4cc0fd592e74a782" +dependencies = [ + "euclid", + "svg_fmt", +] + +[[package]] +name = "half" +version = "1.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403" + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash", + "allocator-api2", + "serde", +] + +[[package]] +name = "hassle-rs" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af2a7e73e1f34c48da31fb668a907f250794837e08faa144fd24f0b8b741e890" +dependencies = [ + "bitflags 2.6.0", + "com", + "libc", + "libloading 0.8.4", + "thiserror", + "widestring", + "winapi", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hexasphere" +version = "12.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd6b038160f086b0a7496edae34169ae22f328793cbe2b627a5a3d8373748ec" +dependencies = [ + "constgebra", + "glam", +] + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "image" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd54d660e773627692c524beaad361aca785a4f9f5730ce91f42aabe5bce3d11" +dependencies = [ + "bytemuck", + "byteorder", + "num-traits", + "png", +] + +[[package]] +name = "immutable-chunkmap" +version = "2.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4419f022e55cc63d5bbd6b44b71e1d226b9c9480a47824c706e9d54e5c40c5eb" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "inotify" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "instant" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "interpolation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c13ae9d91148fcb4aab6654c4c2a7d02a15395ea9e23f65170f175f8b269ce" + +[[package]] +name = "io-kit-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617ee6cf8e3f66f3b4ea67a4058564628cde41901316e19f559e14c7c72c5e7b" +dependencies = [ + "core-foundation-sys", + "mach2", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading 0.8.4", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "ktx2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87d65e08a9ec02e409d27a0139eaa6b9756b4d81fe7cde71f6941a83730ce838" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "kv-log-macro" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +dependencies = [ + "log", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e310b3a6b5907f99202fcdb4960ff45b93735d7c7d96b760fcff8db2dc0e103d" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libredox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3af92c55d7d839293953fcd0fda5ecfe93297cfde6ffbdec13b41d99c0ba6607" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall 0.4.1", +] + +[[package]] +name = "libudev-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litrs" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] + +[[package]] +name = "mach2" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b955cdeb2a02b9117f121ce63aa52d08ade45de53e48fe6a38b39c10f6f709" +dependencies = [ + "libc", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "matchers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" +dependencies = [ + "regex-automata 0.1.10", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "metal" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5637e166ea14be6063a3f8ba5ccb9a4159df7d8f6d61c02fc3d480b1f90dcfcb" +dependencies = [ + "bitflags 2.6.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minimax" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14cab3f6cf6238d693c59cd9403c5d565741c049c02be086c3589a846cda78f0" +dependencies = [ + "getrandom", + "instant", + "num_cpus", + "rand", + "rayon", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", + "simd-adler32", +] + +[[package]] +name = "naga" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e536ae46fcab0876853bd4a632ede5df4b1c2527a58f6c5a4150fe86be858231" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.6.0", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "num-traits", + "pp-rs", + "rustc-hash", + "spirv", + "termcolor", + "thiserror", + "unicode-xid", +] + +[[package]] +name = "naga_oil" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "275d9720a7338eedac966141089232514c84d76a246a58ef501af88c5edf402f" +dependencies = [ + "bit-set", + "codespan-reporting", + "data-encoding", + "indexmap", + "naga", + "once_cell", + "regex", + "regex-syntax 0.8.4", + "rustc-hash", + "thiserror", + "tracing", + "unicode-ident", +] + +[[package]] +name = "ndk" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.5.0+25.2.9519653", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases 0.2.1", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.9", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "dispatch", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081b846d1d56ddfc18fdf1a922e4f6e07a11768ea1b92dec44e42b72712ccfce" +dependencies = [ + "memchr", +] + +[[package]] +name = "oboe" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8b61bebd49e5d43f5f8cc7ee2891c16e0f41ec7954d36bcb6c14c5e0de867fb" +dependencies = [ + "jni", + "ndk 0.8.0", + "ndk-context", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8bb09a4a2b1d668170cfe0a7d5bc103f8999fb316c98099b6a9939c9f2e79d" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "oorandom" +version = "11.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" + +[[package]] +name = "orbclient" +version = "0.3.47" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52f0d54bde9774d3a51dcf281a5def240c71996bc6ca05d2c847ec8b2b216166" +dependencies = [ + "libredox", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "owned_ttf_parser" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490d3a563d3122bf7c911a59b0add9389e5ec0f5f0c3ac6b91ff235a0e6a7f90" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.2", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "petgraph" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" +dependencies = [ + "fixedbitset 0.4.2", + "indexmap", + "serde", + "serde_derive", +] + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand 2.1.0", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "plotters" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15b6eccb8484002195a3e44fe65a4ce8e93a625797a063735536fd59cb01cf3" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "414cec62c6634ae900ea1c56128dfe87cf63e7caece0852ec76aba307cebadb7" + +[[package]] +name = "plotters-svg" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81b30686a7d9c3e010b84284bdd26a29f2138574f52f5eb6f794fc0ad924e705" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "png" +version = "0.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06e4b0d3d1312775e782c86c91a111aa1f910cbb65e1337f9975b5f9a554b5e1" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b2d323e8ca7996b3e23126511a523f7e62924d93ecd5ae73b333815b0eb3dce" +dependencies = [ + "autocfg", + "bitflags 1.3.2", + "cfg-if", + "concurrent-queue", + "libc", + "log", + "pin-project-lite", + "windows-sys 0.48.0", +] + +[[package]] +name = "polling" +version = "3.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi 0.4.0", + "pin-project-lite", + "rustix 0.38.34", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "pp-rs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb458bb7f6e250e6eb79d5026badc10a3ebb8f9a15d1fff0f13d17c71f4d6dee" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "presser" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radsort" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17fd96390ed3feda12e1dfe2645ed587e0bea749e319333f104a33ff62f77a0b" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "range-alloc" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8a99fddc9f0ba0a85884b8d14e3592853e787d581ca1816c91349b10e4eeab" + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rectangle-pack" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0d463f2884048e7153449a55166f91028d5b0ea53c79377099ce4e8cf0cf9bb" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata 0.4.7", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" +dependencies = [ + "regex-syntax 0.6.29", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.4", +] + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rodio" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1fceb9d127d515af1586d8d0cc601e1245bdb0af38e75c865a156290184f5b3" +dependencies = [ + "cpal", + "lewton", + "thiserror", +] + +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.6.0", + "serde", + "serde_derive", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "ruzstd" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5022b253619b1ba797f243056276bed8ed1a73b0f5a7ce7225d524067644bf8f" +dependencies = [ + "byteorder", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "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 = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "svg_fmt" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20e16a0f46cf5fd675563ef54f26e83e20f2366bcf027bcb3cc3ed2b98aaf2ca" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201fcda3845c23e8212cd466bfebf0bd20694490fc0356ae8e428e0824a915a6" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sysinfo" +version = "0.30.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "windows 0.52.0", +] + +[[package]] +name = "taffy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cb893bff0f80ae17d3a57e030622a967b8dbc90e38284d9b4b1442e23873c94" +dependencies = [ + "arrayvec", + "grid", + "num-traits", + "serde", + "slotmap", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "thread_local" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6b6a2fb3a985e99cebfaefa9faa3024743da73304ca1c683a36429613d3d22" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.38.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" +dependencies = [ + "backtrace", + "pin-project-lite", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.6.13", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "tracing-wasm" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4575c663a174420fa2d78f4108ff68f65bf2fbb7dd89f33749b6e826b3626e07" +dependencies = [ + "tracing", + "tracing-subscriber", + "wasm-bindgen", +] + +[[package]] +name = "ttf-parser" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8686b91785aff82828ed725225925b33b4fde44c4bb15876e5f7c832724c420a" + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typeid" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059d83cc991e7a42fc37bd50941885db0888e34209f8cfd9aab07ddec03bc9cf" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" + +[[package]] +name = "unicode-width" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "uuid" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de17fd2f7da591098415cff336e12965a28061ddace43b59cb3c430179c9439" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "waker-fn" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317211a0dc0ceedd78fb2ca9a44aed3d7b9b26f81870d485c07122b4350673b7" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.69", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "web-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wgpu" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e37c7b9921b75dfd26dd973fdcbce36f13dfa6e2dc82aece584e0ed48c355c" +dependencies = [ + "arrayvec", + "cfg-if", + "cfg_aliases 0.1.1", + "document-features", + "js-sys", + "log", + "naga", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50819ab545b867d8a454d1d756b90cd5f15da1f2943334ca314af10583c9d39" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.6.0", + "cfg_aliases 0.1.1", + "codespan-reporting", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash", + "smallvec", + "thiserror", + "web-sys", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "172e490a87295564f3fcc0f165798d87386f6231b04d4548bca458cbbfd63222" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bit-set", + "bitflags 2.6.0", + "block", + "cfg_aliases 0.1.1", + "core-graphics-types", + "d3d12", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-allocator", + "gpu-descriptor", + "hassle-rs", + "js-sys", + "khronos-egl", + "libc", + "libloading 0.8.4", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "parking_lot", + "profiling", + "range-alloc", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash", + "smallvec", + "thiserror", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "winapi", +] + +[[package]] +name = "wgpu-types" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1353d9a46bff7f955a680577f34c69122628cc2076e1d6f3a9be6ef00ae793ef" +dependencies = [ + "bitflags 2.6.0", + "js-sys", + "web-sys", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9252e5725dbed82865af151df558e754e4a3c2c30818359eb17465f1346a1b49" +dependencies = [ + "windows-core 0.54.0", + "windows-implement 0.53.0", + "windows-interface 0.53.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143" +dependencies = [ + "windows-core 0.57.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12661b9c89351d684a50a8a643ce5f608e20243b9fb84687800163429f161d65" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d" +dependencies = [ + "windows-implement 0.57.0", + "windows-interface 0.57.0", + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942ac266be9249c84ca862f0a164a39533dc2f6f33dc98ec89c8da99b82ea0bd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "windows-implement" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "windows-interface" +version = "0.53.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da33557140a288fae4e1d5f8873aaf9eb6613a9cf82c3e070223ff177f598b60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "windows-interface" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] + +[[package]] +name = "windows-result" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winit" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f45a7b7e2de6af35448d7718dab6d95acec466eb3bb7a56f4d31d1af754004" +dependencies = [ + "android-activity", + "atomic-waker", + "bitflags 2.6.0", + "block2", + "bytemuck", + "calloop", + "cfg_aliases 0.2.1", + "concurrent-queue", + "core-foundation", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "ndk 0.9.0", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.34", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1" +dependencies = [ + "memchr", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d91ffca73ee7f68ce055750bf9f6eca0780b8c85eff9bc046a3b0da41755e12" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading 0.8.4", + "once_cell", + "rustix 0.38.34", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec107c4503ea0b4a98ef47356329af139c0a4f7750e621cf2973cd3385ebcb3d" + +[[package]] +name = "xi-unicode" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a" + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.6.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" + +[[package]] +name = "yinsh" +version = "0.1.0" +dependencies = [ + "bevy", + "bevy_async_task", + "bevy_tweening", + "criterion", + "itertools 0.13.0", + "minimax", + "rand", + "rayon", + "serde", + "serde_yaml", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.69", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..1c6dcb0 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,48 @@ +[package] +name = "yinsh" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bevy = { version = "0.14.0" } +bevy_tweening = { git = "https://github.com/BraymatterOrg/bevy_tweening_0_14", branch = "0.14" } +bevy_async_task = "0.2.0" + +minimax = "0.5.3" + +itertools = "0.13.0" +serde = "1.0.204" +serde_yaml = "0.9.34" + +# separate lib and app: +[[bin]] +name = "yinsh" +path = "src/main.rs" + + +[profile.dev] +opt-level = 1 + +[profile.dev.package."*"] +opt-level = 3 + +[profile.release] +codegen-units = 1 +lto = "thin" +strip = "debuginfo" + +[profile.wasm-release] +inherits = "release" +opt-level = "z" +strip = "debuginfo" + +[dev-dependencies] +criterion = "0.3" +rayon = "1.10.0" +rand = "0.8.5" + +[[bench]] +name = "board" +harness = false diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 182a1f9..0000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) David Peter - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/README.md b/README.md index 4bc47f7..5b1e48d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Yinsh ===== -An HTML5 version of the board game [Yinsh](http://en.wikipedia.org/wiki/Yinsh) written in [Haskell](http://haskell.org/) / [Haste](https://github.com/valderman/haste-compiler). +An implemenation of the board game [Yinsh](http://en.wikipedia.org/wiki/Yinsh) with a strong AI player. [**Play in your browser**](http://david-peter.de/yinsh) (See [Yinsh rules](http://en.wikipedia.org/wiki/Yinsh#Rules)) diff --git a/backend/Main.hs b/backend/Main.hs deleted file mode 100644 index 26d79f9..0000000 --- a/backend/Main.hs +++ /dev/null @@ -1,40 +0,0 @@ -import Happstack.Server.SimpleHTTPS -import Happstack.Server -import Data.Maybe (listToMaybe, fromJust) - -import Yinsh -import AI -import Floyd - -backendAI :: AIFunction -backendAI = aiFloyd 3 mhNumber rhControlledMarkers - --- | Get new game state after AI turn. This also resolves @WaitRemoveRun@ and --- @WaitAddMarker@ turns for the *human* player. -aiTurn' :: AIFunction -aiTurn' gs = let gs' = backendAI gs in - case turnMode gs' of - (WaitRemoveRun _) -> backendAI $ fromJust $ newGameState gs' (0, 0) - WaitAddMarker -> backendAI $ fromJust $ newGameState gs' (0, 0) - _ -> gs' - -maybeRead :: Read a => String -> Maybe a -maybeRead = fmap fst . listToMaybe . reads - -handler :: ServerPart Response -handler = do gsString <- look "gamestate" - let mgs = maybeRead gsString :: Maybe GameState - case mgs of - Nothing -> badRequest $ toResponse "malformed gamestate" - (Just gs) -> ok $ xssHeader $ toResponse $ show (aiTurn' gs) - where xssHeader = setHeader "Access-Control-Allow-Origin" "*" - -main :: IO () -main = do - putStrLn "Yinsh backend: waiting for incoming requests..." - let conf = nullTLSConf { - tlsCert = "/etc/letsencrypt/live/andrea-peter.de/fullchain.pem", - tlsKey = "/etc/letsencrypt/live/andrea-peter.de/privkey.pem", - tlsPort = 8000 - } - simpleHTTPS conf handler diff --git a/benches/board.rs b/benches/board.rs new file mode 100644 index 0000000..1b6023b --- /dev/null +++ b/benches/board.rs @@ -0,0 +1,12 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use yinsh::GameState; + +pub fn criterion_benchmark(c: &mut Criterion) { + let game_state = GameState::load_from("tests/midgame_1.yml"); + let board = game_state.board.clone(); + + c.bench_function("Board::check_run", |b| b.iter(|| board.check_run())); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/build_web_version.sh b/build_web_version.sh new file mode 100644 index 0000000..a6ddaee --- /dev/null +++ b/build_web_version.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -euo pipefail + +cargo build --release --target wasm32-unknown-unknown + +wasm-bindgen --no-typescript --target web \ + --out-dir ./web \ + --out-name "yinsh" \ + ./target/wasm32-unknown-unknown/release/yinsh.wasm + +rsync --archive --stats --progress --human-readable web/* shark.fish:david-peter.de/yinsh/preview/ diff --git a/deployment/Dockerfile b/deployment/Dockerfile deleted file mode 100644 index 3f9d1c3..0000000 --- a/deployment/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM ubuntu:23.04 -RUN mkdir /app -COPY ./yinsh-backend /app/yinsh-backend -RUN apt-get update && apt-get install -y openssl -CMD ["/app/yinsh-backend"] diff --git a/deployment/create-image.sh b/deployment/create-image.sh deleted file mode 100644 index d0141ae..0000000 --- a/deployment/create-image.sh +++ /dev/null @@ -1 +0,0 @@ -docker image build -t yinsh-backend . diff --git a/deployment/run.sh b/deployment/run.sh deleted file mode 100644 index 8354870..0000000 --- a/deployment/run.sh +++ /dev/null @@ -1 +0,0 @@ -docker run --detach -p 8000:8000 -v /etc/letsencrypt/:/etc/letsencrypt:ro yinsh-backend:latest diff --git a/doc/states_and_events.svg b/doc/states_and_events.svg new file mode 100644 index 0000000..1dc0255 --- /dev/null +++ b/doc/states_and_events.svg @@ -0,0 +1,557 @@ + + + + + + + + + + + + + PlayerActionEvent + + AiComputationEvent + + Event + + Resource + + GameState + + InteractionState + + System + + update state + + history (undo, load) + + perform AI actions + + + mouse interaction + + + start/cancel AI comp. + + + + + grid cursorupdate boardmove board elementscolorize board elements + + BoardUpdateEvent + + + + + + System ordering + + + + + + + (next cycle) + + AI task + + + + + + + + PlayerActionEvent + + + (previous cycle) + + ForcedUpdateEvent + + + (discard player action events, if this happens) + + diff --git a/examples/ai_game.rs b/examples/ai_game.rs new file mode 100644 index 0000000..fe79110 --- /dev/null +++ b/examples/ai_game.rs @@ -0,0 +1,122 @@ +use rand::seq::SliceRandom; +use rayon::prelude::*; + +use yinsh::{possible_moves, GameState, Move, Player, SimpleHeuristic, YinshAi, YinshAiPlayer}; + +enum Outcome { + Draw, + Winner(Player), +} + +impl Outcome { + fn invert(&self) -> Self { + match self { + Outcome::Draw => Outcome::Draw, + Outcome::Winner(Player::A) => Outcome::Winner(Player::B), + Outcome::Winner(Player::B) => Outcome::Winner(Player::A), + } + } +} + +fn play_match(a: &impl YinshAiPlayer, b: &impl YinshAiPlayer) -> Outcome { + let mut game_state = GameState::initial(); + + // Make two random ring moves for both players to improve the statistics. + for _ in 0..4 { + let mut free_coords: Vec<_> = game_state.board.free_coords().collect(); + free_coords.shuffle(&mut rand::thread_rng()); + game_state.perform_move(&Move::PlaceRing(free_coords[0])); + } + + while game_state.winner().is_none() { + if possible_moves(&game_state).count() == 0 { + return Outcome::Draw; + } + + let player_move = if game_state.active_player == Player::A { + a.choose_move(&game_state) + } else { + b.choose_move(&game_state) + }; + game_state.perform_move(&player_move); + } + + Outcome::Winner(game_state.winner().unwrap()) +} + +fn play_matches(a: &impl YinshAiPlayer, b: &impl YinshAiPlayer, num_games: usize) -> f64 { + println!("Playing {num_games} games between:"); + println!( + " Player A (depth = {:>2}): {}", + a.search_depth(), + a.identifier() + ); + println!( + " Player B (depth = {:>2}): {}", + b.search_depth(), + b.identifier() + ); + + let mut wins_a = 0; + let mut wins_b = 0; + let mut draws = 0; + + let outcomes: Vec<_> = (0..num_games) + .into_par_iter() + .flat_map(|_| { + let outcome1 = play_match(a, b); + let outcome2 = play_match(b, a).invert(); + + [outcome1, outcome2] + }) + .collect(); + + for outcome in outcomes { + match outcome { + Outcome::Draw => draws += 1, + Outcome::Winner(Player::A) => wins_a += 1, + Outcome::Winner(Player::B) => wins_b += 1, + } + } + + let percentage_a = wins_a as f64 / (2 * num_games) as f64 * 100.0; + let percentage_b = wins_b as f64 / (2 * num_games) as f64 * 100.0; + let percentage_draws = draws as f64 / (2 * num_games) as f64 * 100.0; + + println!("Wins A: {wins_a:>3} ({percentage_a:.0}%)"); + println!("Wins B: {wins_b:>3} ({percentage_b:.0}%)"); + println!("Draws: {draws:>3} ({percentage_draws:.0}%)"); + println!(); + + percentage_a +} + +fn main() { + let num_games = 12; + + let search_depth_a = 8; + let player_a = YinshAi::new( + SimpleHeuristic { + f_points: 10_000, + f_markers: 100, + f_controlled_markers_own: 5, + f_controlled_markers_opponent: 10, + f_accessible_fields: 0, + }, + search_depth_a, + ); + + let search_depth_b = 10; + let player_b = YinshAi::new( + SimpleHeuristic { + f_points: 10_000, + f_markers: 100, + f_controlled_markers_own: 0, + f_controlled_markers_opponent: 0, + f_accessible_fields: 0, + }, + search_depth_b, + ); + + play_matches(&player_a, &player_b, num_games); +} diff --git a/frontend.js b/frontend.js deleted file mode 100644 index fc4e5b4..0000000 --- a/frontend.js +++ /dev/null @@ -1,2185 +0,0 @@ -// This object will hold all exports. -var Haste = {}; - -/* Thunk - Creates a thunk representing the given closure. - Since we want automatic memoization of as many expressions as possible, we - use a JS object as a sort of tagged pointer, where the member x denotes the - object actually pointed to. If a "pointer" points to a thunk, it has a - member 't' which is set to true; if it points to a value, be it a function, - a value of an algebraic type of a primitive value, it has no member 't'. -*/ - -function T(f) { - this.f = f; -} - -function F(f) { - this.f = f; -} - -// Special object used for blackholing. -var __blackhole = {}; - -/* Apply - Applies the function f to the arguments args. If the application is under- - saturated, a closure is returned, awaiting further arguments. If it is over- - saturated, the function is fully applied, and the result (assumed to be a - function) is then applied to the remaining arguments. -*/ -function A(f, args) { - if(f instanceof T) { - f = E(f); - } - // Closure does some funny stuff with functions that occasionally - // results in non-functions getting applied, so we have to deal with - // it. - if(!(f instanceof Function)) { - f = B(f); - if(!(f instanceof Function)) { - return f; - } - } - - if(f.arity === undefined) { - f.arity = f.length; - } - if(args.length === f.arity) { - switch(f.arity) { - case 0: return f(); - case 1: return f(args[0]); - default: return f.apply(null, args); - } - } else if(args.length > f.arity) { - switch(f.arity) { - case 0: return f(); - case 1: return A(f(args.shift()), args); - default: return A(f.apply(null, args.splice(0, f.arity)), args); - } - } else { - var g = function() { - return A(f, args.concat(Array.prototype.slice.call(arguments))); - }; - g.arity = f.arity - args.length; - return g; - } -} - -/* Eval - Evaluate the given thunk t into head normal form. - If the "thunk" we get isn't actually a thunk, just return it. -*/ -function E(t) { - if(t instanceof T) { - if(t.f != __blackhole) { - var f = t.f; - t.f = __blackhole; - t.x = f(); - } - return t.x; - } else { - return t; - } -} - -/* Bounce - Bounce on a trampoline for as long as we get a function back. -*/ -function B(f) { - while(f instanceof F) { - var fun = f.f; - f = __blackhole; - f = fun(); - } - return f; -} - -// Export Haste, A, B and E. Haste because we need to preserve exports, A, B -// and E because they're handy for Haste.Foreign. -if(!window) { - var window = {}; -} -window['Haste'] = Haste; -window['A'] = A; -window['E'] = E; -window['B'] = B; - - -/* Throw an error. - We need to be able to use throw as an exception so we wrap it in a function. -*/ -function die(err) { - throw err; -} - -function quot(a, b) { - return (a-a%b)/b; -} - -function quotRemI(a, b) { - return [0, (a-a%b)/b, a%b]; -} - -// 32 bit integer multiplication, with correct overflow behavior -// note that |0 or >>>0 needs to be applied to the result, for int and word -// respectively. -if(Math.imul) { - var imul = Math.imul; -} else { - var imul = function(a, b) { - // ignore high a * high a as the result will always be truncated - var lows = (a & 0xffff) * (b & 0xffff); // low a * low b - var aB = (a & 0xffff) * (b & 0xffff0000); // low a * high b - var bA = (a & 0xffff0000) * (b & 0xffff); // low b * high a - return lows + aB + bA; // sum will not exceed 52 bits, so it's safe - } -} - -function addC(a, b) { - var x = a+b; - return [0, x & 0xffffffff, x > 0x7fffffff]; -} - -function subC(a, b) { - var x = a-b; - return [0, x & 0xffffffff, x < -2147483648]; -} - -function sinh (arg) { - return (Math.exp(arg) - Math.exp(-arg)) / 2; -} - -function tanh (arg) { - return (Math.exp(arg) - Math.exp(-arg)) / (Math.exp(arg) + Math.exp(-arg)); -} - -function cosh (arg) { - return (Math.exp(arg) + Math.exp(-arg)) / 2; -} - -// Scratch space for byte arrays. -var rts_scratchBuf = new ArrayBuffer(8); -var rts_scratchW32 = new Uint32Array(rts_scratchBuf); -var rts_scratchFloat = new Float32Array(rts_scratchBuf); -var rts_scratchDouble = new Float64Array(rts_scratchBuf); - -function decodeFloat(x) { - rts_scratchFloat[0] = x; - var sign = x < 0 ? -1 : 1; - var exp = ((rts_scratchW32[0] >> 23) & 0xff) - 150; - var man = rts_scratchW32[0] & 0x7fffff; - if(exp === 0) { - ++exp; - } else { - man |= (1 << 23); - } - return [0, sign*man, exp]; -} - -function decodeDouble(x) { - rts_scratchDouble[0] = x; - var sign = x < 0 ? -1 : 1; - var manHigh = rts_scratchW32[1] & 0xfffff; - var manLow = rts_scratchW32[0]; - var exp = ((rts_scratchW32[1] >> 20) & 0x7ff) - 1075; - if(exp === 0) { - ++exp; - } else { - manHigh |= (1 << 20); - } - return [0, sign, manHigh, manLow, exp]; -} - -function isFloatFinite(x) { - return isFinite(x); -} - -function isDoubleFinite(x) { - return isFinite(x); -} - -function err(str) { - die(toJSStr(str)); -} - -/* unpackCString# - NOTE: update constructor tags if the code generator starts munging them. -*/ -function unCStr(str) {return unAppCStr(str, [0]);} - -function unFoldrCStr(str, f, z) { - var acc = z; - for(var i = str.length-1; i >= 0; --i) { - acc = B(A(f, [[0, str.charCodeAt(i)], acc])); - } - return acc; -} - -function unAppCStr(str, chrs) { - var i = arguments[2] ? arguments[2] : 0; - if(i >= str.length) { - return E(chrs); - } else { - return [1,[0,str.charCodeAt(i)],new T(function() { - return unAppCStr(str,chrs,i+1); - })]; - } -} - -function charCodeAt(str, i) {return str.charCodeAt(i);} - -function fromJSStr(str) { - return unCStr(E(str)); -} - -function toJSStr(hsstr) { - var s = ''; - for(var str = E(hsstr); str[0] == 1; str = E(str[2])) { - s += String.fromCharCode(E(str[1])[1]); - } - return s; -} - -// newMutVar -function nMV(val) { - return ({x: val}); -} - -// readMutVar -function rMV(mv) { - return mv.x; -} - -// writeMutVar -function wMV(mv, val) { - mv.x = val; -} - -// atomicModifyMutVar -function mMV(mv, f) { - var x = B(A(f, [mv.x])); - mv.x = x[1]; - return x[2]; -} - -function localeEncoding() { - var le = newByteArr(5); - le['v']['i8'][0] = 'U'.charCodeAt(0); - le['v']['i8'][1] = 'T'.charCodeAt(0); - le['v']['i8'][2] = 'F'.charCodeAt(0); - le['v']['i8'][3] = '-'.charCodeAt(0); - le['v']['i8'][4] = '8'.charCodeAt(0); - return le; -} - -var isDoubleNaN = isNaN; -var isFloatNaN = isNaN; - -function isDoubleInfinite(d) { - return (d === Infinity); -} -var isFloatInfinite = isDoubleInfinite; - -function isDoubleNegativeZero(x) { - return (x===0 && (1/x)===-Infinity); -} -var isFloatNegativeZero = isDoubleNegativeZero; - -function strEq(a, b) { - return a == b; -} - -function strOrd(a, b) { - if(a < b) { - return [0]; - } else if(a == b) { - return [1]; - } - return [2]; -} - -function jsCatch(act, handler) { - try { - return B(A(act,[0])); - } catch(e) { - return B(A(handler,[e, 0])); - } -} - -/* Haste represents constructors internally using 1 for the first constructor, - 2 for the second, etc. - However, dataToTag should use 0, 1, 2, etc. Also, booleans might be unboxed. - */ -function dataToTag(x) { - if(x instanceof Array) { - return x[0]; - } else { - return x; - } -} - -function __word_encodeDouble(d, e) { - return d * Math.pow(2,e); -} - -var __word_encodeFloat = __word_encodeDouble; -var jsRound = Math.round; // Stupid GHC doesn't like periods in FFI IDs... -var realWorld = undefined; -if(typeof _ == 'undefined') { - var _ = undefined; -} - -function popCnt(i) { - i = i - ((i >> 1) & 0x55555555); - i = (i & 0x33333333) + ((i >> 2) & 0x33333333); - return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; -} - -function jsAlert(val) { - if(typeof alert != 'undefined') { - alert(val); - } else { - print(val); - } -} - -function jsLog(val) { - console.log(val); -} - -function jsPrompt(str) { - var val; - if(typeof prompt != 'undefined') { - val = prompt(str); - } else { - print(str); - val = readline(); - } - return val == undefined ? '' : val.toString(); -} - -function jsEval(str) { - var x = eval(str); - return x == undefined ? '' : x.toString(); -} - -function isNull(obj) { - return obj === null; -} - -function jsRead(str) { - return Number(str); -} - -function jsShowI(val) {return val.toString();} -function jsShow(val) { - var ret = val.toString(); - return val == Math.round(val) ? ret + '.0' : ret; -} - -function jsGetMouseCoords(e) { - var posx = 0; - var posy = 0; - if (!e) var e = window.event; - if (e.pageX || e.pageY) { - posx = e.pageX; - posy = e.pageY; - } - else if (e.clientX || e.clientY) { - posx = e.clientX + document.body.scrollLeft - + document.documentElement.scrollLeft; - posy = e.clientY + document.body.scrollTop - + document.documentElement.scrollTop; - } - return [posx - (e.currentTarget.offsetLeft || 0), - posy - (e.currentTarget.offsetTop || 0)]; -} - -function jsSetCB(elem, evt, cb) { - // Count return press in single line text box as a change event. - if(evt == 'change' && elem.type.toLowerCase() == 'text') { - setCB(elem, 'keyup', function(k) { - if(k == '\n'.charCodeAt(0)) { - B(A(cb,[[0,k.keyCode],0])); - } - }); - } - - var fun; - switch(evt) { - case 'click': - case 'dblclick': - case 'mouseup': - case 'mousedown': - fun = function(x) { - var mpos = jsGetMouseCoords(x); - var mx = [0,mpos[0]]; - var my = [0,mpos[1]]; - B(A(cb,[[0,x.button],[0,mx,my],0])); - }; - break; - case 'mousemove': - case 'mouseover': - fun = function(x) { - var mpos = jsGetMouseCoords(x); - var mx = [0,mpos[0]]; - var my = [0,mpos[1]]; - B(A(cb,[[0,mx,my],0])); - }; - break; - case 'keypress': - case 'keyup': - case 'keydown': - fun = function(x) {B(A(cb,[[0,x.keyCode],0]));}; - break; - default: - fun = function() {B(A(cb,[0]));}; - break; - } - return setCB(elem, evt, fun); -} - -function setCB(elem, evt, cb) { - if(elem.addEventListener) { - elem.addEventListener(evt, cb, false); - return true; - } else if(elem.attachEvent) { - elem.attachEvent('on'+evt, cb); - return true; - } - return false; -} - -function jsSetTimeout(msecs, cb) { - window.setTimeout(function() {B(A(cb,[0]));}, msecs); -} - -function jsGet(elem, prop) { - return elem[prop].toString(); -} - -function jsSet(elem, prop, val) { - elem[prop] = val; -} - -function jsGetAttr(elem, prop) { - if(elem.hasAttribute(prop)) { - return elem.getAttribute(prop).toString(); - } else { - return ""; - } -} - -function jsSetAttr(elem, prop, val) { - elem.setAttribute(prop, val); -} - -function jsGetStyle(elem, prop) { - return elem.style[prop].toString(); -} - -function jsSetStyle(elem, prop, val) { - elem.style[prop] = val; -} - -function jsKillChild(child, parent) { - parent.removeChild(child); -} - -function jsClearChildren(elem) { - while(elem.hasChildNodes()){ - elem.removeChild(elem.lastChild); - } -} - -function jsFind(elem) { - var e = document.getElementById(elem) - if(e) { - return [1,[0,e]]; - } - return [0]; -} - -function jsQuerySelectorAll(elem, query) { - var els = [0], - len, nl, i; - - if (!elem || typeof elem.querySelectorAll !== 'function') { - return els; - } - - nl = elem.querySelectorAll(query); - len = nl.length; - - for (i=len-1; i >= 0; --i) { - els = [1, [0, nl[i]], els]; - } - - return els; -} - -function jsCreateElem(tag) { - return document.createElement(tag); -} - -function jsCreateTextNode(str) { - return document.createTextNode(str); -} - -function jsGetChildBefore(elem) { - elem = elem.previousSibling; - while(elem) { - if(typeof elem.tagName != 'undefined') { - return [1,[0,elem]]; - } - elem = elem.previousSibling; - } - return [0]; -} - -function jsGetLastChild(elem) { - var len = elem.childNodes.length; - for(var i = len-1; i >= 0; --i) { - if(typeof elem.childNodes[i].tagName != 'undefined') { - return [1,[0,elem.childNodes[i]]]; - } - } - return [0]; -} - - -function jsGetFirstChild(elem) { - var len = elem.childNodes.length; - for(var i = 0; i < len; i++) { - if(typeof elem.childNodes[i].tagName != 'undefined') { - return [1,[0,elem.childNodes[i]]]; - } - } - return [0]; -} - - -function jsGetChildren(elem) { - var children = [0]; - var len = elem.childNodes.length; - for(var i = len-1; i >= 0; --i) { - if(typeof elem.childNodes[i].tagName != 'undefined') { - children = [1, [0,elem.childNodes[i]], children]; - } - } - return children; -} - -function jsSetChildren(elem, children) { - children = E(children); - jsClearChildren(elem, 0); - while(children[0] === 1) { - elem.appendChild(E(E(children[1])[1])); - children = E(children[2]); - } -} - -function jsAppendChild(child, container) { - container.appendChild(child); -} - -function jsAddChildBefore(child, container, after) { - container.insertBefore(child, after); -} - -var jsRand = Math.random; - -// Concatenate a Haskell list of JS strings -function jsCat(strs, sep) { - var arr = []; - strs = E(strs); - while(strs[0]) { - strs = E(strs); - arr.push(E(strs[1])[1]); - strs = E(strs[2]); - } - return arr.join(sep); -} - -var jsJSONParse = JSON.parse; - -// JSON stringify a string -function jsStringify(str) { - return JSON.stringify(str); -} - -// Parse a JSON message into a Haste.JSON.JSON value. -// As this pokes around inside Haskell values, it'll need to be updated if: -// * Haste.JSON.JSON changes; -// * E() starts to choke on non-thunks; -// * data constructor code generation changes; or -// * Just and Nothing change tags. -function jsParseJSON(str) { - try { - var js = JSON.parse(str); - var hs = toHS(js); - } catch(_) { - return [0]; - } - return [1,hs]; -} - -function toHS(obj) { - switch(typeof obj) { - case 'number': - return [0, [0, jsRead(obj)]]; - case 'string': - return [1, [0, obj]]; - break; - case 'boolean': - return [2, obj]; // Booleans are special wrt constructor tags! - break; - case 'object': - if(obj instanceof Array) { - return [3, arr2lst_json(obj, 0)]; - } else if (obj == null) { - return [5]; - } else { - // Object type but not array - it's a dictionary. - // The RFC doesn't say anything about the ordering of keys, but - // considering that lots of people rely on keys being "in order" as - // defined by "the same way someone put them in at the other end," - // it's probably a good idea to put some cycles into meeting their - // misguided expectations. - var ks = []; - for(var k in obj) { - ks.unshift(k); - } - var xs = [0]; - for(var i = 0; i < ks.length; i++) { - xs = [1, [0, [0,ks[i]], toHS(obj[ks[i]])], xs]; - } - return [4, xs]; - } - } -} - -function arr2lst_json(arr, elem) { - if(elem >= arr.length) { - return [0]; - } - return [1, toHS(arr[elem]), new T(function() {return arr2lst_json(arr,elem+1);})] -} - -function arr2lst(arr, elem) { - if(elem >= arr.length) { - return [0]; - } - return [1, arr[elem], new T(function() {return arr2lst(arr,elem+1);})] -} - -function lst2arr(xs) { - var arr = []; - for(; xs[0]; xs = E(xs[2])) { - arr.push(E(xs[1])); - } - return arr; -} - -function ajaxReq(method, url, async, postdata, cb) { - var xhr = new XMLHttpRequest(); - xhr.open(method, url, async); - - if(method == "POST") { - xhr.setRequestHeader("Content-type", - "application/x-www-form-urlencoded"); - } - xhr.onreadystatechange = function() { - if(xhr.readyState == 4) { - if(xhr.status == 200) { - B(A(cb,[[1,[0,xhr.responseText]],0])); - } else { - B(A(cb,[[0],0])); // Nothing - } - } - } - xhr.send(postdata); -} - -// Create a little endian ArrayBuffer representation of something. -function toABHost(v, n, x) { - var a = new ArrayBuffer(n); - new window[v](a)[0] = x; - return a; -} - -function toABSwap(v, n, x) { - var a = new ArrayBuffer(n); - new window[v](a)[0] = x; - var bs = new Uint8Array(a); - for(var i = 0, j = n-1; i < j; ++i, --j) { - var tmp = bs[i]; - bs[i] = bs[j]; - bs[j] = tmp; - } - return a; -} - -window['toABle'] = toABHost; -window['toABbe'] = toABSwap; - -// Swap byte order if host is not little endian. -var buffer = new ArrayBuffer(2); -new DataView(buffer).setInt16(0, 256, true); -if(new Int16Array(buffer)[0] !== 256) { - window['toABle'] = toABSwap; - window['toABbe'] = toABHost; -} - -// MVar implementation. -// Since Haste isn't concurrent, takeMVar and putMVar don't block on empty -// and full MVars respectively, but terminate the program since they would -// otherwise be blocking forever. - -function newMVar() { - return ({empty: true}); -} - -function tryTakeMVar(mv) { - if(mv.empty) { - return [0, 0, undefined]; - } else { - var val = mv.x; - mv.empty = true; - mv.x = null; - return [0, 1, val]; - } -} - -function takeMVar(mv) { - if(mv.empty) { - // TODO: real BlockedOnDeadMVar exception, perhaps? - err("Attempted to take empty MVar!"); - } - var val = mv.x; - mv.empty = true; - mv.x = null; - return val; -} - -function putMVar(mv, val) { - if(!mv.empty) { - // TODO: real BlockedOnDeadMVar exception, perhaps? - err("Attempted to put full MVar!"); - } - mv.empty = false; - mv.x = val; -} - -function tryPutMVar(mv, val) { - if(!mv.empty) { - return 0; - } else { - mv.empty = false; - mv.x = val; - return 1; - } -} - -function sameMVar(a, b) { - return (a == b); -} - -function isEmptyMVar(mv) { - return mv.empty ? 1 : 0; -} - -// Implementation of stable names. -// Unlike native GHC, the garbage collector isn't going to move data around -// in a way that we can detect, so each object could serve as its own stable -// name if it weren't for the fact we can't turn a JS reference into an -// integer. -// So instead, each object has a unique integer attached to it, which serves -// as its stable name. - -var __next_stable_name = 1; - -function makeStableName(x) { - if(!x.stableName) { - x.stableName = __next_stable_name; - __next_stable_name += 1; - } - return x.stableName; -} - -function eqStableName(x, y) { - return (x == y) ? 1 : 0; -} - -var Integer = function(bits, sign) { - this.bits_ = []; - this.sign_ = sign; - - var top = true; - for (var i = bits.length - 1; i >= 0; i--) { - var val = bits[i] | 0; - if (!top || val != sign) { - this.bits_[i] = val; - top = false; - } - } -}; - -Integer.IntCache_ = {}; - -var I_fromInt = function(value) { - if (-128 <= value && value < 128) { - var cachedObj = Integer.IntCache_[value]; - if (cachedObj) { - return cachedObj; - } - } - - var obj = new Integer([value | 0], value < 0 ? -1 : 0); - if (-128 <= value && value < 128) { - Integer.IntCache_[value] = obj; - } - return obj; -}; - -var I_fromNumber = function(value) { - if (isNaN(value) || !isFinite(value)) { - return Integer.ZERO; - } else if (value < 0) { - return I_negate(I_fromNumber(-value)); - } else { - var bits = []; - var pow = 1; - for (var i = 0; value >= pow; i++) { - bits[i] = (value / pow) | 0; - pow *= Integer.TWO_PWR_32_DBL_; - } - return new Integer(bits, 0); - } -}; - -var I_fromBits = function(bits) { - var high = bits[bits.length - 1]; - return new Integer(bits, high & (1 << 31) ? -1 : 0); -}; - -var I_fromString = function(str, opt_radix) { - if (str.length == 0) { - throw Error('number format error: empty string'); - } - - var radix = opt_radix || 10; - if (radix < 2 || 36 < radix) { - throw Error('radix out of range: ' + radix); - } - - if (str.charAt(0) == '-') { - return I_negate(I_fromString(str.substring(1), radix)); - } else if (str.indexOf('-') >= 0) { - throw Error('number format error: interior "-" character'); - } - - var radixToPower = I_fromNumber(Math.pow(radix, 8)); - - var result = Integer.ZERO; - for (var i = 0; i < str.length; i += 8) { - var size = Math.min(8, str.length - i); - var value = parseInt(str.substring(i, i + size), radix); - if (size < 8) { - var power = I_fromNumber(Math.pow(radix, size)); - result = I_add(I_mul(result, power), I_fromNumber(value)); - } else { - result = I_mul(result, radixToPower); - result = I_add(result, I_fromNumber(value)); - } - } - return result; -}; - - -Integer.TWO_PWR_32_DBL_ = (1 << 16) * (1 << 16); -Integer.ZERO = I_fromInt(0); -Integer.ONE = I_fromInt(1); -Integer.TWO_PWR_24_ = I_fromInt(1 << 24); - -var I_toInt = function(self) { - return self.bits_.length > 0 ? self.bits_[0] : self.sign_; -}; - -var I_toWord = function(self) { - return I_toInt(self) >>> 0; -}; - -var I_toNumber = function(self) { - if (isNegative(self)) { - return -I_toNumber(I_negate(self)); - } else { - var val = 0; - var pow = 1; - for (var i = 0; i < self.bits_.length; i++) { - val += I_getBitsUnsigned(self, i) * pow; - pow *= Integer.TWO_PWR_32_DBL_; - } - return val; - } -}; - -var I_getBits = function(self, index) { - if (index < 0) { - return 0; - } else if (index < self.bits_.length) { - return self.bits_[index]; - } else { - return self.sign_; - } -}; - -var I_getBitsUnsigned = function(self, index) { - var val = I_getBits(self, index); - return val >= 0 ? val : Integer.TWO_PWR_32_DBL_ + val; -}; - -var getSign = function(self) { - return self.sign_; -}; - -var isZero = function(self) { - if (self.sign_ != 0) { - return false; - } - for (var i = 0; i < self.bits_.length; i++) { - if (self.bits_[i] != 0) { - return false; - } - } - return true; -}; - -var isNegative = function(self) { - return self.sign_ == -1; -}; - -var isOdd = function(self) { - return (self.bits_.length == 0) && (self.sign_ == -1) || - (self.bits_.length > 0) && ((self.bits_[0] & 1) != 0); -}; - -var I_equals = function(self, other) { - if (self.sign_ != other.sign_) { - return false; - } - var len = Math.max(self.bits_.length, other.bits_.length); - for (var i = 0; i < len; i++) { - if (I_getBits(self, i) != I_getBits(other, i)) { - return false; - } - } - return true; -}; - -var I_notEquals = function(self, other) { - return !I_equals(self, other); -}; - -var I_greaterThan = function(self, other) { - return I_compare(self, other) > 0; -}; - -var I_greaterThanOrEqual = function(self, other) { - return I_compare(self, other) >= 0; -}; - -var I_lessThan = function(self, other) { - return I_compare(self, other) < 0; -}; - -var I_lessThanOrEqual = function(self, other) { - return I_compare(self, other) <= 0; -}; - -var I_compare = function(self, other) { - var diff = I_sub(self, other); - if (isNegative(diff)) { - return -1; - } else if (isZero(diff)) { - return 0; - } else { - return +1; - } -}; - -var I_compareInt = function(self, other) { - return I_compare(self, I_fromInt(other)); -} - -var shorten = function(self, numBits) { - var arr_index = (numBits - 1) >> 5; - var bit_index = (numBits - 1) % 32; - var bits = []; - for (var i = 0; i < arr_index; i++) { - bits[i] = I_getBits(self, i); - } - var sigBits = bit_index == 31 ? 0xFFFFFFFF : (1 << (bit_index + 1)) - 1; - var val = I_getBits(self, arr_index) & sigBits; - if (val & (1 << bit_index)) { - val |= 0xFFFFFFFF - sigBits; - bits[arr_index] = val; - return new Integer(bits, -1); - } else { - bits[arr_index] = val; - return new Integer(bits, 0); - } -}; - -var I_negate = function(self) { - return I_add(not(self), Integer.ONE); -}; - -var I_add = function(self, other) { - var len = Math.max(self.bits_.length, other.bits_.length); - var arr = []; - var carry = 0; - - for (var i = 0; i <= len; i++) { - var a1 = I_getBits(self, i) >>> 16; - var a0 = I_getBits(self, i) & 0xFFFF; - - var b1 = I_getBits(other, i) >>> 16; - var b0 = I_getBits(other, i) & 0xFFFF; - - var c0 = carry + a0 + b0; - var c1 = (c0 >>> 16) + a1 + b1; - carry = c1 >>> 16; - c0 &= 0xFFFF; - c1 &= 0xFFFF; - arr[i] = (c1 << 16) | c0; - } - return I_fromBits(arr); -}; - -var I_sub = function(self, other) { - return I_add(self, I_negate(other)); -}; - -var I_mul = function(self, other) { - if (isZero(self)) { - return Integer.ZERO; - } else if (isZero(other)) { - return Integer.ZERO; - } - - if (isNegative(self)) { - if (isNegative(other)) { - return I_mul(I_negate(self), I_negate(other)); - } else { - return I_negate(I_mul(I_negate(self), other)); - } - } else if (isNegative(other)) { - return I_negate(I_mul(self, I_negate(other))); - } - - if (I_lessThan(self, Integer.TWO_PWR_24_) && - I_lessThan(other, Integer.TWO_PWR_24_)) { - return I_fromNumber(I_toNumber(self) * I_toNumber(other)); - } - - var len = self.bits_.length + other.bits_.length; - var arr = []; - for (var i = 0; i < 2 * len; i++) { - arr[i] = 0; - } - for (var i = 0; i < self.bits_.length; i++) { - for (var j = 0; j < other.bits_.length; j++) { - var a1 = I_getBits(self, i) >>> 16; - var a0 = I_getBits(self, i) & 0xFFFF; - - var b1 = I_getBits(other, j) >>> 16; - var b0 = I_getBits(other, j) & 0xFFFF; - - arr[2 * i + 2 * j] += a0 * b0; - Integer.carry16_(arr, 2 * i + 2 * j); - arr[2 * i + 2 * j + 1] += a1 * b0; - Integer.carry16_(arr, 2 * i + 2 * j + 1); - arr[2 * i + 2 * j + 1] += a0 * b1; - Integer.carry16_(arr, 2 * i + 2 * j + 1); - arr[2 * i + 2 * j + 2] += a1 * b1; - Integer.carry16_(arr, 2 * i + 2 * j + 2); - } - } - - for (var i = 0; i < len; i++) { - arr[i] = (arr[2 * i + 1] << 16) | arr[2 * i]; - } - for (var i = len; i < 2 * len; i++) { - arr[i] = 0; - } - return new Integer(arr, 0); -}; - -Integer.carry16_ = function(bits, index) { - while ((bits[index] & 0xFFFF) != bits[index]) { - bits[index + 1] += bits[index] >>> 16; - bits[index] &= 0xFFFF; - } -}; - -var I_mod = function(self, other) { - return I_rem(I_add(other, I_rem(self, other)), other); -} - -var I_div = function(self, other) { - if(I_greaterThan(self, Integer.ZERO) != I_greaterThan(other, Integer.ZERO)) { - if(I_rem(self, other) != Integer.ZERO) { - return I_sub(I_quot(self, other), Integer.ONE); - } - } - return I_quot(self, other); -} - -var I_quotRem = function(self, other) { - return [0, I_quot(self, other), I_rem(self, other)]; -} - -var I_divMod = function(self, other) { - return [0, I_div(self, other), I_mod(self, other)]; -} - -var I_quot = function(self, other) { - if (isZero(other)) { - throw Error('division by zero'); - } else if (isZero(self)) { - return Integer.ZERO; - } - - if (isNegative(self)) { - if (isNegative(other)) { - return I_quot(I_negate(self), I_negate(other)); - } else { - return I_negate(I_quot(I_negate(self), other)); - } - } else if (isNegative(other)) { - return I_negate(I_quot(self, I_negate(other))); - } - - var res = Integer.ZERO; - var rem = self; - while (I_greaterThanOrEqual(rem, other)) { - var approx = Math.max(1, Math.floor(I_toNumber(rem) / I_toNumber(other))); - var log2 = Math.ceil(Math.log(approx) / Math.LN2); - var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); - var approxRes = I_fromNumber(approx); - var approxRem = I_mul(approxRes, other); - while (isNegative(approxRem) || I_greaterThan(approxRem, rem)) { - approx -= delta; - approxRes = I_fromNumber(approx); - approxRem = I_mul(approxRes, other); - } - - if (isZero(approxRes)) { - approxRes = Integer.ONE; - } - - res = I_add(res, approxRes); - rem = I_sub(rem, approxRem); - } - return res; -}; - -var I_rem = function(self, other) { - return I_sub(self, I_mul(I_quot(self, other), other)); -}; - -var not = function(self) { - var len = self.bits_.length; - var arr = []; - for (var i = 0; i < len; i++) { - arr[i] = ~self.bits_[i]; - } - return new Integer(arr, ~self.sign_); -}; - -var I_and = function(self, other) { - var len = Math.max(self.bits_.length, other.bits_.length); - var arr = []; - for (var i = 0; i < len; i++) { - arr[i] = I_getBits(self, i) & I_getBits(other, i); - } - return new Integer(arr, self.sign_ & other.sign_); -}; - -var I_or = function(self, other) { - var len = Math.max(self.bits_.length, other.bits_.length); - var arr = []; - for (var i = 0; i < len; i++) { - arr[i] = I_getBits(self, i) | I_getBits(other, i); - } - return new Integer(arr, self.sign_ | other.sign_); -}; - -var I_xor = function(self, other) { - var len = Math.max(self.bits_.length, other.bits_.length); - var arr = []; - for (var i = 0; i < len; i++) { - arr[i] = I_getBits(self, i) ^ I_getBits(other, i); - } - return new Integer(arr, self.sign_ ^ other.sign_); -}; - -var I_shiftLeft = function(self, numBits) { - var arr_delta = numBits >> 5; - var bit_delta = numBits % 32; - var len = self.bits_.length + arr_delta + (bit_delta > 0 ? 1 : 0); - var arr = []; - for (var i = 0; i < len; i++) { - if (bit_delta > 0) { - arr[i] = (I_getBits(self, i - arr_delta) << bit_delta) | - (I_getBits(self, i - arr_delta - 1) >>> (32 - bit_delta)); - } else { - arr[i] = I_getBits(self, i - arr_delta); - } - } - return new Integer(arr, self.sign_); -}; - -var I_shiftRight = function(self, numBits) { - var arr_delta = numBits >> 5; - var bit_delta = numBits % 32; - var len = self.bits_.length - arr_delta; - var arr = []; - for (var i = 0; i < len; i++) { - if (bit_delta > 0) { - arr[i] = (I_getBits(self, i + arr_delta) >>> bit_delta) | - (I_getBits(self, i + arr_delta + 1) << (32 - bit_delta)); - } else { - arr[i] = I_getBits(self, i + arr_delta); - } - } - return new Integer(arr, self.sign_); -}; - -var I_signum = function(self) { - var cmp = I_compare(self, Integer.ZERO); - if(cmp > 0) { - return Integer.ONE - } - if(cmp < 0) { - return I_sub(Integer.ZERO, Integer.ONE); - } - return Integer.ZERO; -}; - -var I_abs = function(self) { - if(I_compare(self, Integer.ZERO) < 0) { - return I_sub(Integer.ZERO, self); - } - return self; -}; - -var I_decodeDouble = function(x) { - var dec = decodeDouble(x); - var mantissa = I_fromBits([dec[3], dec[2]]); - if(dec[1] < 0) { - mantissa = I_negate(mantissa); - } - return [0, dec[4], mantissa]; -} - -var I_toString = function(self) { - var radix = 10; - - if (isZero(self)) { - return '0'; - } else if (isNegative(self)) { - return '-' + I_toString(I_negate(self)); - } - - var radixToPower = I_fromNumber(Math.pow(radix, 6)); - - var rem = self; - var result = ''; - while (true) { - var remDiv = I_div(rem, radixToPower); - var intval = I_toInt(I_sub(rem, I_mul(remDiv, radixToPower))); - var digits = intval.toString(); - - rem = remDiv; - if (isZero(rem)) { - return digits + result; - } else { - while (digits.length < 6) { - digits = '0' + digits; - } - result = '' + digits + result; - } - } -}; - -var I_fromRat = function(a, b) { - return I_toNumber(a) / I_toNumber(b); -} - -function I_fromInt64(x) { - return I_fromBits([x.getLowBits(), x.getHighBits()]); -} - -function I_toInt64(x) { - return Long.fromBits(I_getBits(x, 0), I_getBits(x, 1)); -} - -function I_fromWord64(x) { - return x; -} - -function I_toWord64(x) { - return I_rem(I_add(__w64_max, x), __w64_max); -} - -// Copyright 2009 The Closure Library Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS-IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -var Long = function(low, high) { - this.low_ = low | 0; - this.high_ = high | 0; -}; - -Long.IntCache_ = {}; - -Long.fromInt = function(value) { - if (-128 <= value && value < 128) { - var cachedObj = Long.IntCache_[value]; - if (cachedObj) { - return cachedObj; - } - } - - var obj = new Long(value | 0, value < 0 ? -1 : 0); - if (-128 <= value && value < 128) { - Long.IntCache_[value] = obj; - } - return obj; -}; - -Long.fromNumber = function(value) { - if (isNaN(value) || !isFinite(value)) { - return Long.ZERO; - } else if (value <= -Long.TWO_PWR_63_DBL_) { - return Long.MIN_VALUE; - } else if (value + 1 >= Long.TWO_PWR_63_DBL_) { - return Long.MAX_VALUE; - } else if (value < 0) { - return Long.fromNumber(-value).negate(); - } else { - return new Long( - (value % Long.TWO_PWR_32_DBL_) | 0, - (value / Long.TWO_PWR_32_DBL_) | 0); - } -}; - -Long.fromBits = function(lowBits, highBits) { - return new Long(lowBits, highBits); -}; - -Long.TWO_PWR_16_DBL_ = 1 << 16; -Long.TWO_PWR_24_DBL_ = 1 << 24; -Long.TWO_PWR_32_DBL_ = - Long.TWO_PWR_16_DBL_ * Long.TWO_PWR_16_DBL_; -Long.TWO_PWR_31_DBL_ = - Long.TWO_PWR_32_DBL_ / 2; -Long.TWO_PWR_48_DBL_ = - Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_16_DBL_; -Long.TWO_PWR_64_DBL_ = - Long.TWO_PWR_32_DBL_ * Long.TWO_PWR_32_DBL_; -Long.TWO_PWR_63_DBL_ = - Long.TWO_PWR_64_DBL_ / 2; -Long.ZERO = Long.fromInt(0); -Long.ONE = Long.fromInt(1); -Long.NEG_ONE = Long.fromInt(-1); -Long.MAX_VALUE = - Long.fromBits(0xFFFFFFFF | 0, 0x7FFFFFFF | 0); -Long.MIN_VALUE = Long.fromBits(0, 0x80000000 | 0); -Long.TWO_PWR_24_ = Long.fromInt(1 << 24); - -Long.prototype.toInt = function() { - return this.low_; -}; - -Long.prototype.toNumber = function() { - return this.high_ * Long.TWO_PWR_32_DBL_ + - this.getLowBitsUnsigned(); -}; - -Long.prototype.getHighBits = function() { - return this.high_; -}; - -Long.prototype.getLowBits = function() { - return this.low_; -}; - -Long.prototype.getLowBitsUnsigned = function() { - return (this.low_ >= 0) ? - this.low_ : Long.TWO_PWR_32_DBL_ + this.low_; -}; - -Long.prototype.isZero = function() { - return this.high_ == 0 && this.low_ == 0; -}; - -Long.prototype.isNegative = function() { - return this.high_ < 0; -}; - -Long.prototype.isOdd = function() { - return (this.low_ & 1) == 1; -}; - -Long.prototype.equals = function(other) { - return (this.high_ == other.high_) && (this.low_ == other.low_); -}; - -Long.prototype.notEquals = function(other) { - return (this.high_ != other.high_) || (this.low_ != other.low_); -}; - -Long.prototype.lessThan = function(other) { - return this.compare(other) < 0; -}; - -Long.prototype.lessThanOrEqual = function(other) { - return this.compare(other) <= 0; -}; - -Long.prototype.greaterThan = function(other) { - return this.compare(other) > 0; -}; - -Long.prototype.greaterThanOrEqual = function(other) { - return this.compare(other) >= 0; -}; - -Long.prototype.compare = function(other) { - if (this.equals(other)) { - return 0; - } - - var thisNeg = this.isNegative(); - var otherNeg = other.isNegative(); - if (thisNeg && !otherNeg) { - return -1; - } - if (!thisNeg && otherNeg) { - return 1; - } - - if (this.subtract(other).isNegative()) { - return -1; - } else { - return 1; - } -}; - -Long.prototype.negate = function() { - if (this.equals(Long.MIN_VALUE)) { - return Long.MIN_VALUE; - } else { - return this.not().add(Long.ONE); - } -}; - -Long.prototype.add = function(other) { - var a48 = this.high_ >>> 16; - var a32 = this.high_ & 0xFFFF; - var a16 = this.low_ >>> 16; - var a00 = this.low_ & 0xFFFF; - - var b48 = other.high_ >>> 16; - var b32 = other.high_ & 0xFFFF; - var b16 = other.low_ >>> 16; - var b00 = other.low_ & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 + b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 + b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 + b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 + b48; - c48 &= 0xFFFF; - return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); -}; - -Long.prototype.subtract = function(other) { - return this.add(other.negate()); -}; - -Long.prototype.multiply = function(other) { - if (this.isZero()) { - return Long.ZERO; - } else if (other.isZero()) { - return Long.ZERO; - } - - if (this.equals(Long.MIN_VALUE)) { - return other.isOdd() ? Long.MIN_VALUE : Long.ZERO; - } else if (other.equals(Long.MIN_VALUE)) { - return this.isOdd() ? Long.MIN_VALUE : Long.ZERO; - } - - if (this.isNegative()) { - if (other.isNegative()) { - return this.negate().multiply(other.negate()); - } else { - return this.negate().multiply(other).negate(); - } - } else if (other.isNegative()) { - return this.multiply(other.negate()).negate(); - } - - if (this.lessThan(Long.TWO_PWR_24_) && - other.lessThan(Long.TWO_PWR_24_)) { - return Long.fromNumber(this.toNumber() * other.toNumber()); - } - - var a48 = this.high_ >>> 16; - var a32 = this.high_ & 0xFFFF; - var a16 = this.low_ >>> 16; - var a00 = this.low_ & 0xFFFF; - - var b48 = other.high_ >>> 16; - var b32 = other.high_ & 0xFFFF; - var b16 = other.low_ >>> 16; - var b00 = other.low_ & 0xFFFF; - - var c48 = 0, c32 = 0, c16 = 0, c00 = 0; - c00 += a00 * b00; - c16 += c00 >>> 16; - c00 &= 0xFFFF; - c16 += a16 * b00; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c16 += a00 * b16; - c32 += c16 >>> 16; - c16 &= 0xFFFF; - c32 += a32 * b00; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a16 * b16; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c32 += a00 * b32; - c48 += c32 >>> 16; - c32 &= 0xFFFF; - c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48; - c48 &= 0xFFFF; - return Long.fromBits((c16 << 16) | c00, (c48 << 16) | c32); -}; - -Long.prototype.div = function(other) { - if (other.isZero()) { - throw Error('division by zero'); - } else if (this.isZero()) { - return Long.ZERO; - } - - if (this.equals(Long.MIN_VALUE)) { - if (other.equals(Long.ONE) || - other.equals(Long.NEG_ONE)) { - return Long.MIN_VALUE; - } else if (other.equals(Long.MIN_VALUE)) { - return Long.ONE; - } else { - var halfThis = this.shiftRight(1); - var approx = halfThis.div(other).shiftLeft(1); - if (approx.equals(Long.ZERO)) { - return other.isNegative() ? Long.ONE : Long.NEG_ONE; - } else { - var rem = this.subtract(other.multiply(approx)); - var result = approx.add(rem.div(other)); - return result; - } - } - } else if (other.equals(Long.MIN_VALUE)) { - return Long.ZERO; - } - - if (this.isNegative()) { - if (other.isNegative()) { - return this.negate().div(other.negate()); - } else { - return this.negate().div(other).negate(); - } - } else if (other.isNegative()) { - return this.div(other.negate()).negate(); - } - - var res = Long.ZERO; - var rem = this; - while (rem.greaterThanOrEqual(other)) { - var approx = Math.max(1, Math.floor(rem.toNumber() / other.toNumber())); - - var log2 = Math.ceil(Math.log(approx) / Math.LN2); - var delta = (log2 <= 48) ? 1 : Math.pow(2, log2 - 48); - - var approxRes = Long.fromNumber(approx); - var approxRem = approxRes.multiply(other); - while (approxRem.isNegative() || approxRem.greaterThan(rem)) { - approx -= delta; - approxRes = Long.fromNumber(approx); - approxRem = approxRes.multiply(other); - } - - if (approxRes.isZero()) { - approxRes = Long.ONE; - } - - res = res.add(approxRes); - rem = rem.subtract(approxRem); - } - return res; -}; - -Long.prototype.modulo = function(other) { - return this.subtract(this.div(other).multiply(other)); -}; - -Long.prototype.not = function() { - return Long.fromBits(~this.low_, ~this.high_); -}; - -Long.prototype.and = function(other) { - return Long.fromBits(this.low_ & other.low_, - this.high_ & other.high_); -}; - -Long.prototype.or = function(other) { - return Long.fromBits(this.low_ | other.low_, - this.high_ | other.high_); -}; - -Long.prototype.xor = function(other) { - return Long.fromBits(this.low_ ^ other.low_, - this.high_ ^ other.high_); -}; - -Long.prototype.shiftLeft = function(numBits) { - numBits &= 63; - if (numBits == 0) { - return this; - } else { - var low = this.low_; - if (numBits < 32) { - var high = this.high_; - return Long.fromBits( - low << numBits, - (high << numBits) | (low >>> (32 - numBits))); - } else { - return Long.fromBits(0, low << (numBits - 32)); - } - } -}; - -Long.prototype.shiftRight = function(numBits) { - numBits &= 63; - if (numBits == 0) { - return this; - } else { - var high = this.high_; - if (numBits < 32) { - var low = this.low_; - return Long.fromBits( - (low >>> numBits) | (high << (32 - numBits)), - high >> numBits); - } else { - return Long.fromBits( - high >> (numBits - 32), - high >= 0 ? 0 : -1); - } - } -}; - -Long.prototype.shiftRightUnsigned = function(numBits) { - numBits &= 63; - if (numBits == 0) { - return this; - } else { - var high = this.high_; - if (numBits < 32) { - var low = this.low_; - return Long.fromBits( - (low >>> numBits) | (high << (32 - numBits)), - high >>> numBits); - } else if (numBits == 32) { - return Long.fromBits(high, 0); - } else { - return Long.fromBits(high >>> (numBits - 32), 0); - } - } -}; - - - -// Int64 -function hs_eqInt64(x, y) {return x.equals(y);} -function hs_neInt64(x, y) {return !x.equals(y);} -function hs_ltInt64(x, y) {return x.compare(y) < 0;} -function hs_leInt64(x, y) {return x.compare(y) <= 0;} -function hs_gtInt64(x, y) {return x.compare(y) > 0;} -function hs_geInt64(x, y) {return x.compare(y) >= 0;} -function hs_quotInt64(x, y) {return x.div(y);} -function hs_remInt64(x, y) {return x.modulo(y);} -function hs_plusInt64(x, y) {return x.add(y);} -function hs_minusInt64(x, y) {return x.subtract(y);} -function hs_timesInt64(x, y) {return x.multiply(y);} -function hs_negateInt64(x) {return x.negate();} -function hs_uncheckedIShiftL64(x, bits) {return x.shiftLeft(bits);} -function hs_uncheckedIShiftRA64(x, bits) {return x.shiftRight(bits);} -function hs_uncheckedIShiftRL64(x, bits) {return x.shiftRightUnsigned(bits);} -function hs_intToInt64(x) {return new Long(x, 0);} -function hs_int64ToInt(x) {return x.toInt();} - - - -// Word64 -function hs_wordToWord64(x) { - return I_fromInt(x); -} -function hs_word64ToWord(x) { - return I_toInt(x); -} -function hs_mkWord64(low, high) { - return I_fromBits([low, high]); -} - -var hs_and64 = I_and; -var hs_or64 = I_or; -var hs_xor64 = I_xor; -var __i64_all_ones = I_fromBits([0xffffffff, 0xffffffff]); -function hs_not64(x) { - return I_xor(x, __i64_all_ones); -} -var hs_eqWord64 = I_equals; -var hs_neWord64 = I_notEquals; -var hs_ltWord64 = I_lessThan; -var hs_leWord64 = I_lessThanOrEqual; -var hs_gtWord64 = I_greaterThan; -var hs_geWord64 = I_greaterThanOrEqual; -var hs_quotWord64 = I_quot; -var hs_remWord64 = I_rem; -var __w64_max = I_fromBits([0,0,1]); -function hs_uncheckedShiftL64(x, bits) { - return I_rem(I_shiftLeft(x, bits), __w64_max); -} -var hs_uncheckedShiftRL64 = I_shiftRight; -function hs_int64ToWord64(x) { - var tmp = I_add(__w64_max, I_fromBits([x.getLowBits(), x.getHighBits()])); - return I_rem(tmp, __w64_max); -} -function hs_word64ToInt64(x) { - return Long.fromBits(I_getBits(x, 0), I_getBits(x, 1)); -} - -// Joseph Myers' MD5 implementation; used under the BSD license. - -function md5cycle(x, k) { -var a = x[0], b = x[1], c = x[2], d = x[3]; - -a = ff(a, b, c, d, k[0], 7, -680876936); -d = ff(d, a, b, c, k[1], 12, -389564586); -c = ff(c, d, a, b, k[2], 17, 606105819); -b = ff(b, c, d, a, k[3], 22, -1044525330); -a = ff(a, b, c, d, k[4], 7, -176418897); -d = ff(d, a, b, c, k[5], 12, 1200080426); -c = ff(c, d, a, b, k[6], 17, -1473231341); -b = ff(b, c, d, a, k[7], 22, -45705983); -a = ff(a, b, c, d, k[8], 7, 1770035416); -d = ff(d, a, b, c, k[9], 12, -1958414417); -c = ff(c, d, a, b, k[10], 17, -42063); -b = ff(b, c, d, a, k[11], 22, -1990404162); -a = ff(a, b, c, d, k[12], 7, 1804603682); -d = ff(d, a, b, c, k[13], 12, -40341101); -c = ff(c, d, a, b, k[14], 17, -1502002290); -b = ff(b, c, d, a, k[15], 22, 1236535329); - -a = gg(a, b, c, d, k[1], 5, -165796510); -d = gg(d, a, b, c, k[6], 9, -1069501632); -c = gg(c, d, a, b, k[11], 14, 643717713); -b = gg(b, c, d, a, k[0], 20, -373897302); -a = gg(a, b, c, d, k[5], 5, -701558691); -d = gg(d, a, b, c, k[10], 9, 38016083); -c = gg(c, d, a, b, k[15], 14, -660478335); -b = gg(b, c, d, a, k[4], 20, -405537848); -a = gg(a, b, c, d, k[9], 5, 568446438); -d = gg(d, a, b, c, k[14], 9, -1019803690); -c = gg(c, d, a, b, k[3], 14, -187363961); -b = gg(b, c, d, a, k[8], 20, 1163531501); -a = gg(a, b, c, d, k[13], 5, -1444681467); -d = gg(d, a, b, c, k[2], 9, -51403784); -c = gg(c, d, a, b, k[7], 14, 1735328473); -b = gg(b, c, d, a, k[12], 20, -1926607734); - -a = hh(a, b, c, d, k[5], 4, -378558); -d = hh(d, a, b, c, k[8], 11, -2022574463); -c = hh(c, d, a, b, k[11], 16, 1839030562); -b = hh(b, c, d, a, k[14], 23, -35309556); -a = hh(a, b, c, d, k[1], 4, -1530992060); -d = hh(d, a, b, c, k[4], 11, 1272893353); -c = hh(c, d, a, b, k[7], 16, -155497632); -b = hh(b, c, d, a, k[10], 23, -1094730640); -a = hh(a, b, c, d, k[13], 4, 681279174); -d = hh(d, a, b, c, k[0], 11, -358537222); -c = hh(c, d, a, b, k[3], 16, -722521979); -b = hh(b, c, d, a, k[6], 23, 76029189); -a = hh(a, b, c, d, k[9], 4, -640364487); -d = hh(d, a, b, c, k[12], 11, -421815835); -c = hh(c, d, a, b, k[15], 16, 530742520); -b = hh(b, c, d, a, k[2], 23, -995338651); - -a = ii(a, b, c, d, k[0], 6, -198630844); -d = ii(d, a, b, c, k[7], 10, 1126891415); -c = ii(c, d, a, b, k[14], 15, -1416354905); -b = ii(b, c, d, a, k[5], 21, -57434055); -a = ii(a, b, c, d, k[12], 6, 1700485571); -d = ii(d, a, b, c, k[3], 10, -1894986606); -c = ii(c, d, a, b, k[10], 15, -1051523); -b = ii(b, c, d, a, k[1], 21, -2054922799); -a = ii(a, b, c, d, k[8], 6, 1873313359); -d = ii(d, a, b, c, k[15], 10, -30611744); -c = ii(c, d, a, b, k[6], 15, -1560198380); -b = ii(b, c, d, a, k[13], 21, 1309151649); -a = ii(a, b, c, d, k[4], 6, -145523070); -d = ii(d, a, b, c, k[11], 10, -1120210379); -c = ii(c, d, a, b, k[2], 15, 718787259); -b = ii(b, c, d, a, k[9], 21, -343485551); - -x[0] = add32(a, x[0]); -x[1] = add32(b, x[1]); -x[2] = add32(c, x[2]); -x[3] = add32(d, x[3]); - -} - -function cmn(q, a, b, x, s, t) { -a = add32(add32(a, q), add32(x, t)); -return add32((a << s) | (a >>> (32 - s)), b); -} - -function ff(a, b, c, d, x, s, t) { -return cmn((b & c) | ((~b) & d), a, b, x, s, t); -} - -function gg(a, b, c, d, x, s, t) { -return cmn((b & d) | (c & (~d)), a, b, x, s, t); -} - -function hh(a, b, c, d, x, s, t) { -return cmn(b ^ c ^ d, a, b, x, s, t); -} - -function ii(a, b, c, d, x, s, t) { -return cmn(c ^ (b | (~d)), a, b, x, s, t); -} - -function md51(s) { -var n = s.length, -state = [1732584193, -271733879, -1732584194, 271733878], i; -for (i=64; i<=s.length; i+=64) { -md5cycle(state, md5blk(s.substring(i-64, i))); -} -s = s.substring(i-64); -var tail = [0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0]; -for (i=0; i>2] |= s.charCodeAt(i) << ((i%4) << 3); -tail[i>>2] |= 0x80 << ((i%4) << 3); -if (i > 55) { -md5cycle(state, tail); -for (i=0; i<16; i++) tail[i] = 0; -} -tail[14] = n*8; -md5cycle(state, tail); -return state; -} - -function md5blk(s) { -var md5blks = [], i; -for (i=0; i<64; i+=4) { -md5blks[i>>2] = s.charCodeAt(i) -+ (s.charCodeAt(i+1) << 8) -+ (s.charCodeAt(i+2) << 16) -+ (s.charCodeAt(i+3) << 24); -} -return md5blks; -} - -var hex_chr = '0123456789abcdef'.split(''); - -function rhex(n) -{ -var s='', j=0; -for(; j<4; j++) -s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] -+ hex_chr[(n >> (j * 8)) & 0x0F]; -return s; -} - -function hex(x) { -for (var i=0; i= 0; --n) { - arr.push(x); - } - return arr; -} - -// Create all views at once; perhaps it's wasteful, but it's better than having -// to check for the right view at each read or write. -function newByteArr(n) { - // Pad the thing to multiples of 8. - var padding = 8 - n % 8; - if(padding < 8) { - n += padding; - } - var arr = {}; - var buffer = new ArrayBuffer(n); - var views = {}; - views['i8'] = new Int8Array(buffer); - views['i16'] = new Int16Array(buffer); - views['i32'] = new Int32Array(buffer); - views['w8'] = new Uint8Array(buffer); - views['w16'] = new Uint16Array(buffer); - views['w32'] = new Uint32Array(buffer); - views['f32'] = new Float32Array(buffer); - views['f64'] = new Float64Array(buffer); - arr['b'] = buffer; - arr['v'] = views; - // ByteArray and Addr are the same thing, so keep an offset if we get - // casted. - arr['off'] = 0; - return arr; -} - -// An attempt at emulating pointers enough for ByteString and Text to be -// usable without patching the hell out of them. -// The general idea is that Addr# is a byte array with an associated offset. - -function plusAddr(addr, off) { - var newaddr = {}; - newaddr['off'] = addr['off'] + off; - newaddr['b'] = addr['b']; - newaddr['v'] = addr['v']; - return newaddr; -} - -function writeOffAddr(type, elemsize, addr, off, x) { - addr['v'][type][addr.off/elemsize + off] = x; -} - -function readOffAddr(type, elemsize, addr, off) { - return addr['v'][type][addr.off/elemsize + off]; -} - -// Two addresses are equal if they point to the same buffer and have the same -// offset. For other comparisons, just use the offsets - nobody in their right -// mind would check if one pointer is less than another, completely unrelated, -// pointer and then act on that information anyway. -function addrEq(a, b) { - if(a == b) { - return true; - } - return a && b && a['b'] == b['b'] && a['off'] == b['off']; -} - -function addrLT(a, b) { - if(a) { - return b && a['off'] < b['off']; - } else { - return (b != 0); - } -} - -function addrGT(a, b) { - if(b) { - return a && a['off'] > b['off']; - } else { - return (a != 0); - } -} - -function withChar(f, charCode) { - return f(String.fromCharCode(charCode)).charCodeAt(0); -} - -function u_towlower(charCode) { - return withChar(function(c) {return c.toLowerCase()}, charCode); -} - -function u_towupper(charCode) { - return withChar(function(c) {return c.toUpperCase()}, charCode); -} - -var u_towtitle = u_towupper; - -function u_iswupper(charCode) { - var c = String.fromCharCode(charCode); - return c == c.toUpperCase() && c != c.toLowerCase(); -} - -function u_iswlower(charCode) { - var c = String.fromCharCode(charCode); - return c == c.toLowerCase() && c != c.toUpperCase(); -} - -function u_iswdigit(charCode) { - return charCode >= 48 && charCode <= 57; -} - -function u_iswcntrl(charCode) { - return charCode <= 0x1f || charCode == 0x7f; -} - -function u_iswspace(charCode) { - var c = String.fromCharCode(charCode); - return c.replace(/\s/g,'') != c; -} - -function u_iswalpha(charCode) { - var c = String.fromCharCode(charCode); - return c.replace(__hs_alphare, '') != c; -} - -function u_iswalnum(charCode) { - return u_iswdigit(charCode) || u_iswalpha(charCode); -} - -function u_iswprint(charCode) { - return !u_iswcntrl(charCode); -} - -function u_gencat(c) { - throw 'u_gencat is only supported with --full-unicode.'; -} - -// Regex that matches any alphabetic character in any language. Horrible thing. -var __hs_alphare = /[\u0041-\u005A\u0061-\u007A\u00AA\u00B5\u00BA\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u0527\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0828\u0840-\u0858\u08A0\u08A2-\u08AC\u0904-\u0939\u093D\u0950\u0958-\u0961\u0971-\u0977\u0979-\u097F\u0985-\u098C\u098F\u0990\u0993-\u09A8\u09AA-\u09B0\u09B2\u09B6-\u09B9\u09BD\u09CE\u09DC\u09DD\u09DF-\u09E1\u09F0\u09F1\u0A05-\u0A0A\u0A0F\u0A10\u0A13-\u0A28\u0A2A-\u0A30\u0A32\u0A33\u0A35\u0A36\u0A38\u0A39\u0A59-\u0A5C\u0A5E\u0A72-\u0A74\u0A85-\u0A8D\u0A8F-\u0A91\u0A93-\u0AA8\u0AAA-\u0AB0\u0AB2\u0AB3\u0AB5-\u0AB9\u0ABD\u0AD0\u0AE0\u0AE1\u0B05-\u0B0C\u0B0F\u0B10\u0B13-\u0B28\u0B2A-\u0B30\u0B32\u0B33\u0B35-\u0B39\u0B3D\u0B5C\u0B5D\u0B5F-\u0B61\u0B71\u0B83\u0B85-\u0B8A\u0B8E-\u0B90\u0B92-\u0B95\u0B99\u0B9A\u0B9C\u0B9E\u0B9F\u0BA3\u0BA4\u0BA8-\u0BAA\u0BAE-\u0BB9\u0BD0\u0C05-\u0C0C\u0C0E-\u0C10\u0C12-\u0C28\u0C2A-\u0C33\u0C35-\u0C39\u0C3D\u0C58\u0C59\u0C60\u0C61\u0C85-\u0C8C\u0C8E-\u0C90\u0C92-\u0CA8\u0CAA-\u0CB3\u0CB5-\u0CB9\u0CBD\u0CDE\u0CE0\u0CE1\u0CF1\u0CF2\u0D05-\u0D0C\u0D0E-\u0D10\u0D12-\u0D3A\u0D3D\u0D4E\u0D60\u0D61\u0D7A-\u0D7F\u0D85-\u0D96\u0D9A-\u0DB1\u0DB3-\u0DBB\u0DBD\u0DC0-\u0DC6\u0E01-\u0E30\u0E32\u0E33\u0E40-\u0E46\u0E81\u0E82\u0E84\u0E87\u0E88\u0E8A\u0E8D\u0E94-\u0E97\u0E99-\u0E9F\u0EA1-\u0EA3\u0EA5\u0EA7\u0EAA\u0EAB\u0EAD-\u0EB0\u0EB2\u0EB3\u0EBD\u0EC0-\u0EC4\u0EC6\u0EDC-\u0EDF\u0F00\u0F40-\u0F47\u0F49-\u0F6C\u0F88-\u0F8C\u1000-\u102A\u103F\u1050-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081\u108E\u10A0-\u10C5\u10C7\u10CD\u10D0-\u10FA\u10FC-\u1248\u124A-\u124D\u1250-\u1256\u1258\u125A-\u125D\u1260-\u1288\u128A-\u128D\u1290-\u12B0\u12B2-\u12B5\u12B8-\u12BE\u12C0\u12C2-\u12C5\u12C8-\u12D6\u12D8-\u1310\u1312-\u1315\u1318-\u135A\u1380-\u138F\u13A0-\u13F4\u1401-\u166C\u166F-\u167F\u1681-\u169A\u16A0-\u16EA\u1700-\u170C\u170E-\u1711\u1720-\u1731\u1740-\u1751\u1760-\u176C\u176E-\u1770\u1780-\u17B3\u17D7\u17DC\u1820-\u1877\u1880-\u18A8\u18AA\u18B0-\u18F5\u1900-\u191C\u1950-\u196D\u1970-\u1974\u1980-\u19AB\u19C1-\u19C7\u1A00-\u1A16\u1A20-\u1A54\u1AA7\u1B05-\u1B33\u1B45-\u1B4B\u1B83-\u1BA0\u1BAE\u1BAF\u1BBA-\u1BE5\u1C00-\u1C23\u1C4D-\u1C4F\u1C5A-\u1C7D\u1CE9-\u1CEC\u1CEE-\u1CF1\u1CF5\u1CF6\u1D00-\u1DBF\u1E00-\u1F15\u1F18-\u1F1D\u1F20-\u1F45\u1F48-\u1F4D\u1F50-\u1F57\u1F59\u1F5B\u1F5D\u1F5F-\u1F7D\u1F80-\u1FB4\u1FB6-\u1FBC\u1FBE\u1FC2-\u1FC4\u1FC6-\u1FCC\u1FD0-\u1FD3\u1FD6-\u1FDB\u1FE0-\u1FEC\u1FF2-\u1FF4\u1FF6-\u1FFC\u2071\u207F\u2090-\u209C\u2102\u2107\u210A-\u2113\u2115\u2119-\u211D\u2124\u2126\u2128\u212A-\u212D\u212F-\u2139\u213C-\u213F\u2145-\u2149\u214E\u2183\u2184\u2C00-\u2C2E\u2C30-\u2C5E\u2C60-\u2CE4\u2CEB-\u2CEE\u2CF2\u2CF3\u2D00-\u2D25\u2D27\u2D2D\u2D30-\u2D67\u2D6F\u2D80-\u2D96\u2DA0-\u2DA6\u2DA8-\u2DAE\u2DB0-\u2DB6\u2DB8-\u2DBE\u2DC0-\u2DC6\u2DC8-\u2DCE\u2DD0-\u2DD6\u2DD8-\u2DDE\u2E2F\u3005\u3006\u3031-\u3035\u303B\u303C\u3041-\u3096\u309D-\u309F\u30A1-\u30FA\u30FC-\u30FF\u3105-\u312D\u3131-\u318E\u31A0-\u31BA\u31F0-\u31FF\u3400-\u4DB5\u4E00-\u9FCC\uA000-\uA48C\uA4D0-\uA4FD\uA500-\uA60C\uA610-\uA61F\uA62A\uA62B\uA640-\uA66E\uA67F-\uA697\uA6A0-\uA6E5\uA717-\uA71F\uA722-\uA788\uA78B-\uA78E\uA790-\uA793\uA7A0-\uA7AA\uA7F8-\uA801\uA803-\uA805\uA807-\uA80A\uA80C-\uA822\uA840-\uA873\uA882-\uA8B3\uA8F2-\uA8F7\uA8FB\uA90A-\uA925\uA930-\uA946\uA960-\uA97C\uA984-\uA9B2\uA9CF\uAA00-\uAA28\uAA40-\uAA42\uAA44-\uAA4B\uAA60-\uAA76\uAA7A\uAA80-\uAAAF\uAAB1\uAAB5\uAAB6\uAAB9-\uAABD\uAAC0\uAAC2\uAADB-\uAADD\uAAE0-\uAAEA\uAAF2-\uAAF4\uAB01-\uAB06\uAB09-\uAB0E\uAB11-\uAB16\uAB20-\uAB26\uAB28-\uAB2E\uABC0-\uABE2\uAC00-\uD7A3\uD7B0-\uD7C6\uD7CB-\uD7FB\uF900-\uFA6D\uFA70-\uFAD9\uFB00-\uFB06\uFB13-\uFB17\uFB1D\uFB1F-\uFB28\uFB2A-\uFB36\uFB38-\uFB3C\uFB3E\uFB40\uFB41\uFB43\uFB44\uFB46-\uFBB1\uFBD3-\uFD3D\uFD50-\uFD8F\uFD92-\uFDC7\uFDF0-\uFDFB\uFE70-\uFE74\uFE76-\uFEFC\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFBE\uFFC2-\uFFC7\uFFCA-\uFFCF\uFFD2-\uFFD7\uFFDA-\uFFDC]/g; - -// 2D Canvas drawing primitives. -function jsHasCtx2D(elem) {return !!elem.getContext;} -function jsGetCtx2D(elem) {return elem.getContext('2d');} -function jsBeginPath(ctx) {ctx.beginPath();} -function jsMoveTo(ctx, x, y) {ctx.moveTo(x, y);} -function jsLineTo(ctx, x, y) {ctx.lineTo(x, y);} -function jsStroke(ctx) {ctx.stroke();} -function jsFill(ctx) {ctx.fill();} -function jsRotate(ctx, radians) {ctx.rotate(radians);} -function jsTranslate(ctx, x, y) {ctx.translate(x, y);} -function jsScale(ctx, x, y) {ctx.scale(x, y);} -function jsPushState(ctx) {ctx.save();} -function jsPopState(ctx) {ctx.restore();} -function jsResetCanvas(el) {el.width = el.width;} -function jsDrawImage(ctx, img, x, y) {ctx.drawImage(img, x, y);} -function jsDrawImageClipped(ctx, img, x, y, cx, cy, cw, ch) { - ctx.drawImage(img, cx, cy, cw, ch, x, y, cw, ch); -} -function jsDrawText(ctx, str, x, y) {ctx.fillText(str, x, y);} -function jsClip(ctx) {ctx.clip();} -function jsArc(ctx, x, y, radius, fromAngle, toAngle) { - ctx.arc(x, y, radius, fromAngle, toAngle); -} -function jsCanvasToDataURL(el) {return el.toDataURL('image/png');} - -// Simulate handles. -// When implementing new handles, remember that passed strings may be thunks, -// and so need to be evaluated before use. - -function jsNewHandle(init, read, write, flush, close, seek, tell) { - var h = { - read: read || function() {}, - write: write || function() {}, - seek: seek || function() {}, - tell: tell || function() {}, - close: close || function() {}, - flush: flush || function() {} - }; - init.call(h); - return h; -} - -function jsReadHandle(h, len) {return h.read(len);} -function jsWriteHandle(h, str) {return h.write(str);} -function jsFlushHandle(h) {return h.flush();} -function jsCloseHandle(h) {return h.close();} - -function jsMkConWriter(op) { - return function(str) { - str = E(str); - var lines = (this.buf + str).split('\n'); - for(var i = 0; i < lines.length-1; ++i) { - op.call(console, lines[i]); - } - this.buf = lines[lines.length-1]; - } -} - -function jsMkStdout() { - return jsNewHandle( - function() {this.buf = '';}, - function(_) {return '';}, - jsMkConWriter(console.log), - function() {console.log(this.buf); this.buf = '';} - ); -} - -function jsMkStderr() { - return jsNewHandle( - function() {this.buf = '';}, - function(_) {return '';}, - jsMkConWriter(console.warn), - function() {console.warn(this.buf); this.buf = '';} - ); -} - -function jsMkStdin() { - return jsNewHandle( - function() {this.buf = '';}, - function(len) { - while(this.buf.length < len) { - this.buf += prompt('[stdin]') + '\n'; - } - var ret = this.buf.substr(0, len); - this.buf = this.buf.substr(len); - return ret; - } - ); -} - -var _0=[0],_1=new T(function(){return B(unCStr("Prelude.(!!): negative index\n"));}),_2=new T(function(){return B(err(_1));}),_3=new T(function(){return B(unCStr("Prelude.(!!): index too large\n"));}),_4=new T(function(){return B(err(_3));}),_5=function(_6,_7){while(1){var _8=E(_6);if(!_8[0]){return E(_4);}else{var _9=E(_7);if(!_9){return E(_8[1]);}else{_6=_8[2];_7=_9-1|0;continue;}}}},_a=new T(function(){return B(unCStr("GHC.IO.Exception"));}),_b=new T(function(){return B(unCStr("base"));}),_c=new T(function(){return B(unCStr("IOException"));}),_d=[0],_e=new T(function(){var _f=hs_wordToWord64(4053623282),_g=_f,_h=hs_wordToWord64(3693590983),_i=_h;return [0,_g,_i,[0,_g,_i,_b,_a,_c],_d];}),_j=function(_k){return E(_e);},_l=function(_m){return E(E(_m)[1]);},_n=function(_o,_p,_q){var _r=B(A(_o,[_])),_s=B(A(_p,[_])),_t=hs_eqWord64(_r[1],_s[1]),_u=_t;if(!E(_u)){return [0];}else{var _v=hs_eqWord64(_r[2],_s[2]),_w=_v;return E(_w)==0?[0]:[1,_q];}},_x=function(_y){var _z=E(_y);return new F(function(){return _n(B(_l(_z[1])),_j,_z[2]);});},_A=new T(function(){return B(unCStr(": "));}),_B=[0,41],_C=new T(function(){return B(unCStr(" ("));}),_D=function(_E,_F){var _G=E(_E);return _G[0]==0?E(_F):[1,_G[1],new T(function(){return B(_D(_G[2],_F));})];},_H=new T(function(){return B(unCStr("already exists"));}),_I=new T(function(){return B(unCStr("does not exist"));}),_J=new T(function(){return B(unCStr("protocol error"));}),_K=new T(function(){return B(unCStr("failed"));}),_L=new T(function(){return B(unCStr("invalid argument"));}),_M=new T(function(){return B(unCStr("inappropriate type"));}),_N=new T(function(){return B(unCStr("hardware fault"));}),_O=new T(function(){return B(unCStr("unsupported operation"));}),_P=new T(function(){return B(unCStr("timeout"));}),_Q=new T(function(){return B(unCStr("resource vanished"));}),_R=new T(function(){return B(unCStr("interrupted"));}),_S=new T(function(){return B(unCStr("resource busy"));}),_T=new T(function(){return B(unCStr("resource exhausted"));}),_U=new T(function(){return B(unCStr("end of file"));}),_V=new T(function(){return B(unCStr("illegal operation"));}),_W=new T(function(){return B(unCStr("permission denied"));}),_X=new T(function(){return B(unCStr("user error"));}),_Y=new T(function(){return B(unCStr("unsatisified constraints"));}),_Z=new T(function(){return B(unCStr("system error"));}),_10=function(_11,_12){switch(E(_11)){case 0:return new F(function(){return _D(_H,_12);});break;case 1:return new F(function(){return _D(_I,_12);});break;case 2:return new F(function(){return _D(_S,_12);});break;case 3:return new F(function(){return _D(_T,_12);});break;case 4:return new F(function(){return _D(_U,_12);});break;case 5:return new F(function(){return _D(_V,_12);});break;case 6:return new F(function(){return _D(_W,_12);});break;case 7:return new F(function(){return _D(_X,_12);});break;case 8:return new F(function(){return _D(_Y,_12);});break;case 9:return new F(function(){return _D(_Z,_12);});break;case 10:return new F(function(){return _D(_J,_12);});break;case 11:return new F(function(){return _D(_K,_12);});break;case 12:return new F(function(){return _D(_L,_12);});break;case 13:return new F(function(){return _D(_M,_12);});break;case 14:return new F(function(){return _D(_N,_12);});break;case 15:return new F(function(){return _D(_O,_12);});break;case 16:return new F(function(){return _D(_P,_12);});break;case 17:return new F(function(){return _D(_Q,_12);});break;default:return new F(function(){return _D(_R,_12);});}},_13=[0,125],_14=new T(function(){return B(unCStr("{handle: "));}),_15=function(_16,_17,_18,_19,_1a,_1b){var _1c=new T(function(){var _1d=new T(function(){return B(_10(_17,new T(function(){var _1e=E(_19);return _1e[0]==0?E(_1b):B(_D(_C,new T(function(){return B(_D(_1e,[1,_B,_1b]));})));})));}),_1f=E(_18);return _1f[0]==0?E(_1d):B(_D(_1f,new T(function(){return B(_D(_A,_1d));})));}),_1g=E(_1a);if(!_1g[0]){var _1h=E(_16);if(!_1h[0]){return E(_1c);}else{var _1i=E(_1h[1]);return _1i[0]==0?B(_D(_14,new T(function(){return B(_D(_1i[1],[1,_13,new T(function(){return B(_D(_A,_1c));})]));}))):B(_D(_14,new T(function(){return B(_D(_1i[1],[1,_13,new T(function(){return B(_D(_A,_1c));})]));})));}}else{return new F(function(){return _D(_1g[1],new T(function(){return B(_D(_A,_1c));}));});}},_1j=function(_1k){var _1l=E(_1k);return new F(function(){return _15(_1l[1],_1l[2],_1l[3],_1l[4],_1l[6],_d);});},_1m=function(_1n,_1o){var _1p=E(_1n);return new F(function(){return _15(_1p[1],_1p[2],_1p[3],_1p[4],_1p[6],_1o);});},_1q=[0,44],_1r=[0,93],_1s=[0,91],_1t=function(_1u,_1v,_1w){var _1x=E(_1v);return _1x[0]==0?B(unAppCStr("[]",_1w)):[1,_1s,new T(function(){return B(A(_1u,[_1x[1],new T(function(){var _1y=function(_1z){var _1A=E(_1z);return _1A[0]==0?E([1,_1r,_1w]):[1,_1q,new T(function(){return B(A(_1u,[_1A[1],new T(function(){return B(_1y(_1A[2]));})]));})];};return B(_1y(_1x[2]));})]));})];},_1B=function(_1C,_1D){return new F(function(){return _1t(_1m,_1C,_1D);});},_1E=function(_1F,_1G,_1H){var _1I=E(_1G);return new F(function(){return _15(_1I[1],_1I[2],_1I[3],_1I[4],_1I[6],_1H);});},_1J=[0,_1E,_1j,_1B],_1K=new T(function(){return [0,_j,_1J,_1L,_x];}),_1L=function(_1M){return [0,_1K,_1M];},_1N=7,_1O=function(_1P){return [0,_0,_1N,_d,_1P,_0,_0];},_1Q=function(_1R,_){return new F(function(){return die(new T(function(){return B(_1L(new T(function(){return B(_1O(_1R));})));}));});},_1S=function(_1T,_){return new F(function(){return _1Q(_1T,_);});},_1U=function(_1V,_){return new F(function(){return _1S(_1V,_);});},_1W=function(_1X,_){return new F(function(){return _1U(_1X,_);});},_1Y=[0,87],_1Z=[0,66],_20=[0,125],_21=new T(function(){return B(unCStr(", "));}),_22=new T(function(){return B(unCStr("pointsW = "));}),_23=new T(function(){return B(unCStr("pointsB = "));}),_24=new T(function(){return B(unCStr("board = "));}),_25=new T(function(){return B(unCStr("turnMode = "));}),_26=new T(function(){return B(unCStr("activePlayer = "));}),_27=new T(function(){return B(unCStr("GameState {"));}),_28=[0,0],_29=function(_2a,_2b,_2c){return new F(function(){return A(_2a,[[1,_1q,new T(function(){return B(A(_2b,[_2c]));})]]);});},_2d=new T(function(){return B(unCStr("WaitRemoveRun "));}),_2e=new T(function(){return B(unCStr("RemoveRing "));}),_2f=new T(function(){return B(unCStr("RemoveRun "));}),_2g=new T(function(){return B(unCStr("MoveRing "));}),_2h=new T(function(){return B(unCStr("AddMarker"));}),_2i=function(_2j){return new F(function(){return _D(_2h,_2j);});},_2k=new T(function(){return B(unCStr("AddRing"));}),_2l=function(_2j){return new F(function(){return _D(_2k,_2j);});},_2m=new T(function(){return B(unCStr("WaitAddMarker"));}),_2n=function(_2j){return new F(function(){return _D(_2m,_2j);});},_2o=function(_2p,_2q){var _2r=jsShowI(_2p),_2s=_2r;return new F(function(){return _D(fromJSStr(_2s),_2q);});},_2t=[0,41],_2u=[0,40],_2v=function(_2w,_2x,_2y){if(_2x>=0){return new F(function(){return _2o(_2x,_2y);});}else{return _2w<=6?B(_2o(_2x,_2y)):[1,_2u,new T(function(){var _2z=jsShowI(_2x),_2A=_2z;return B(_D(fromJSStr(_2A),[1,_2t,_2y]));})];}},_2B=new T(function(){return B(unCStr(": empty list"));}),_2C=new T(function(){return B(unCStr("Prelude."));}),_2D=function(_2E){return new F(function(){return err(B(_D(_2C,new T(function(){return B(_D(_2E,_2B));}))));});},_2F=new T(function(){return B(unCStr("foldr1"));}),_2G=new T(function(){return B(_2D(_2F));}),_2H=function(_2I,_2J){var _2K=E(_2J);if(!_2K[0]){return E(_2G);}else{var _2L=_2K[1],_2M=E(_2K[2]);if(!_2M[0]){return E(_2L);}else{return new F(function(){return A(_2I,[_2L,new T(function(){return B(_2H(_2I,_2M));})]);});}}},_2N=function(_2O,_2P){var _2Q=E(_2P);switch(_2Q[0]){case 0:return E(_2l);case 1:return E(_2i);case 2:var _2R=function(_2S){return new F(function(){return _D(_2g,new T(function(){var _2T=E(_2Q[1]);return [1,_2u,new T(function(){return B(A(_2H,[_29,[1,function(_2U){return new F(function(){return _2v(0,E(_2T[1])[1],_2U);});},[1,function(_2V){return new F(function(){return _2v(0,E(_2T[2])[1],_2V);});},_d]],[1,_2t,_2S]]));})];}));});};return E(_2O)[1]<11?E(_2R):function(_2W){return [1,_2u,new T(function(){return B(_2R([1,_2t,_2W]));})];};case 3:var _2X=_2Q[1];return E(_2O)[1]<11?function(_2Y){return new F(function(){return _D(_2f,new T(function(){return E(_2X)==0?[1,_1Z,_2Y]:[1,_1Y,_2Y];}));});}:function(_2Z){return [1,_2u,new T(function(){return B(_D(_2f,new T(function(){return E(_2X)==0?[1,_1Z,[1,_2t,_2Z]]:[1,_1Y,[1,_2t,_2Z]];})));})];};case 4:var _30=_2Q[1];return E(_2O)[1]<11?function(_31){return new F(function(){return _D(_2e,new T(function(){return E(_30)==0?[1,_1Z,_31]:[1,_1Y,_31];}));});}:function(_32){return [1,_2u,new T(function(){return B(_D(_2e,new T(function(){return E(_30)==0?[1,_1Z,[1,_2t,_32]]:[1,_1Y,[1,_2t,_32]];})));})];};case 5:var _33=_2Q[1];return E(_2O)[1]<11?function(_34){return new F(function(){return _D(_2d,new T(function(){return E(_33)==0?[1,_1Z,_34]:[1,_1Y,_34];}));});}:function(_35){return [1,_2u,new T(function(){return B(_D(_2d,new T(function(){return E(_33)==0?[1,_1Z,[1,_2t,_35]]:[1,_1Y,[1,_2t,_35]];})));})];};default:return E(_2n);}},_36=[0,0],_37=function(_38){return E(E(_38)[1]);},_39=function(_3a,_3b,_3c,_3d){return new F(function(){return _1t(function(_3e,_3f){var _3g=E(_3e);return [1,_2u,new T(function(){return B(A(_2H,[_29,[1,new T(function(){return B(A(new T(function(){return B(_37(_3a));}),[_36,_3g[1]]));}),[1,new T(function(){return B(A(new T(function(){return B(_37(_3b));}),[_36,_3g[2]]));}),_d]],[1,_2t,_3f]]));})];},_3c,_3d);});},_3h=[1,_2t,_d],_3i=function(_3j,_3k,_3l){var _3m=E(_3l);return [1,_2u,new T(function(){return B(A(_2H,[_29,[1,new T(function(){return B(A(_37,[_3j,_36,_3m[1]]));}),[1,new T(function(){return B(A(_37,[_3k,_36,_3m[2]]));}),_d]],_3h]));})];},_3n=function(_3o,_3p,_3q,_3r,_3s){var _3t=E(_3r);return [1,_2u,new T(function(){return B(A(_2H,[_29,[1,new T(function(){return B(A(_37,[_3o,_36,_3t[1]]));}),[1,new T(function(){return B(A(_37,[_3p,_36,_3t[2]]));}),_d]],[1,_2t,_3s]]));})];},_3u=function(_3v,_3w){return [0,function(_3x,_3y,_3z){return new F(function(){return _3n(_3v,_3w,_3x,_3y,_3z);});},function(_3z){return new F(function(){return _3i(_3v,_3w,_3z);});},function(_3y,_3z){return new F(function(){return _39(_3v,_3w,_3y,_3z);});}];},_3A=function(_3B){return new F(function(){return _2v(0,E(_3B)[1],_d);});},_3C=function(_3D,_3E){return new F(function(){return _2v(0,E(_3D)[1],_3E);});},_3F=function(_3G,_3H){return new F(function(){return _1t(_3C,_3G,_3H);});},_3I=function(_3J,_3K,_3L){return new F(function(){return _2v(E(_3J)[1],E(_3K)[1],_3L);});},_3M=[0,_3I,_3A,_3F],_3N=new T(function(){return B(_3u(_3M,_3M));}),_3O=new T(function(){return B(unCStr("markersW = "));}),_3P=new T(function(){return B(unCStr("markersB = "));}),_3Q=new T(function(){return B(unCStr("ringsW = "));}),_3R=new T(function(){return B(unCStr("ringsB = "));}),_3S=new T(function(){return B(unCStr("bmap = "));}),_3T=new T(function(){return B(unCStr("Board {"));}),_3U=new T(function(){return B(unCStr("Marker "));}),_3V=new T(function(){return B(unCStr("Ring "));}),_3W=function(_3X,_3Y,_3Z){var _40=E(_3Y);if(!_40[0]){var _41=_40[1];return _3X<11?B(_D(_3V,new T(function(){return E(_41)==0?[1,_1Z,_3Z]:[1,_1Y,_3Z];}))):[1,_2u,new T(function(){return B(_D(_3V,new T(function(){return E(_41)==0?[1,_1Z,[1,_2t,_3Z]]:[1,_1Y,[1,_2t,_3Z]];})));})];}else{var _42=_40[1];return _3X<11?B(_D(_3U,new T(function(){return E(_42)==0?[1,_1Z,_3Z]:[1,_1Y,_3Z];}))):[1,_2u,new T(function(){return B(_D(_3U,new T(function(){return E(_42)==0?[1,_1Z,[1,_2t,_3Z]]:[1,_1Y,[1,_2t,_3Z]];})));})];}},_43=function(_44){return new F(function(){return _3W(0,_44,_d);});},_45=function(_46,_47){return new F(function(){return _3W(0,_46,_47);});},_48=function(_49,_2j){return new F(function(){return _1t(_45,_49,_2j);});},_4a=function(_4b,_4c,_4d){return new F(function(){return _3W(E(_4b)[1],_4c,_4d);});},_4e=[0,_4a,_43,_48],_4f=new T(function(){return B(unCStr("fromList "));}),_4g=function(_4h,_4i){while(1){var _4j=(function(_4k,_4l){var _4m=E(_4l);if(!_4m[0]){_4h=[1,[0,_4m[2],_4m[3]],new T(function(){return B(_4g(_4k,_4m[5]));})];_4i=_4m[4];return null;}else{return E(_4k);}})(_4h,_4i);if(_4j!=null){return _4j;}}},_4n=function(_4o,_4p,_4q,_4r){var _4s=new T(function(){return B(_4g(_d,_4r));});return _4q<=10?function(_4t){return new F(function(){return _D(_4f,new T(function(){return B(_39(_4o,_4p,_4s,_4t));}));});}:function(_4u){return [1,_2u,new T(function(){return B(_D(_4f,new T(function(){return B(_39(_4o,_4p,_4s,[1,_2t,_4u]));})));})];};},_4v=function(_4w,_4x,_4y,_4z,_4A,_4B){var _4C=function(_4D){return new F(function(){return _D(_3T,new T(function(){return B(_D(_3S,new T(function(){return B(A(new T(function(){return B(_4n(_3N,_4e,0,_4x));}),[new T(function(){return B(_D(_21,new T(function(){return B(_D(_3R,new T(function(){return B(_39(_3M,_3M,_4y,new T(function(){return B(_D(_21,new T(function(){return B(_D(_3Q,new T(function(){return B(_39(_3M,_3M,_4z,new T(function(){return B(_D(_21,new T(function(){return B(_D(_3P,new T(function(){return B(_39(_3M,_3M,_4A,new T(function(){return B(_D(_21,new T(function(){return B(_D(_3O,new T(function(){return B(_39(_3M,_3M,_4B,[1,_20,_4D]));})));})));})));})));})));})));})));})));})));})));})));})]));})));}));});};return _4w<11?E(_4C):function(_4E){return [1,_2u,new T(function(){return B(_4C([1,_2t,_4E]));})];};},_4F=function(_4G,_4H,_4I,_4J,_4K,_4L){var _4M=function(_4N){return new F(function(){return _D(_27,new T(function(){return B(_D(_26,new T(function(){var _4O=new T(function(){return B(_D(_21,new T(function(){return B(_D(_25,new T(function(){return B(A(new T(function(){return B(_2N(_28,_4I));}),[new T(function(){return B(_D(_21,new T(function(){return B(_D(_24,new T(function(){return B(A(new T(function(){var _4P=E(_4J);return B(_4v(0,_4P[1],_4P[2],_4P[3],_4P[4],_4P[5]));}),[new T(function(){return B(_D(_21,new T(function(){return B(_D(_23,new T(function(){return B(_2v(0,E(_4K)[1],new T(function(){return B(_D(_21,new T(function(){return B(_D(_22,new T(function(){return B(_2v(0,E(_4L)[1],[1,_20,_4N]));})));})));})));})));})));})]));})));})));})]));})));})));});return E(_4H)==0?[1,_1Z,_4O]:[1,_1Y,_4O];})));}));});};return _4G<11?E(_4M):function(_4Q){return [1,_2u,new T(function(){return B(_4M([1,_2t,_4Q]));})];};},_4R=function(_4S,_4T){if(_4S<=_4T){var _4U=function(_4V){return [1,[0,_4V],new T(function(){if(_4V!=_4T){var _4W=B(_4U(_4V+1|0));}else{var _4W=[0];}var _4X=_4W;return _4X;})];};return new F(function(){return _4U(_4S);});}else{return [0];}},_4Y=new T(function(){return B(_4R(0,2147483647));}),_4Z=function(_50,_51,_52){while(1){var _53=E(_52);if(!_53[0]){return [0,[0,_50],_51];}else{var _54=_53[2],_55=E(_53[1]),_56=E(_55[1])[1];if(_50>=_56){if(_50!=_56){_50=_56;_51=_55[2];_52=_54;continue;}else{_52=_54;continue;}}else{_52=_54;continue;}}}},_57=new T(function(){return B(_4R(-5,5));}),_58=function(_59){var _5a=_59,_5b=function(_5c){while(1){var _5d=(function(_5e){var _5f=E(_5e);if(!_5f[0]){return E(new T(function(){var _5g=E(_59);if(_5g==5){var _5h=[0];}else{var _5h=B(_58(_5g+1|0));}return _5h;}));}else{var _5i=_5f[2],_5j=E(_5f[1]);if(Math.pow(0.5*Math.sqrt(3)*_5a,2)+Math.pow(0.5*_5a-_5j[1],2)>Math.pow(4.6,2)){_5c=_5i;return null;}else{return [1,[0,[0,_59],_5j],new T(function(){return B(_5b(_5i));})];}}})(_5c);if(_5d!=null){return _5d;}}};return new F(function(){return _5b(_57);});},_5k=new T(function(){return B(_58(-5));}),_5l=function(_5m,_5n){var _5o=E(_5m),_5p=E(_5o[1])[1],_5q=E(_5o[2])[1],_5r=E(_5n),_5s=E(_5r[1])[1],_5t=E(_5r[2])[1],_5u=(imul(_5s,_5s)|0)+(imul(_5t,_5t)|0)|0,_5v=(imul(_5p,_5p)|0)+(imul(_5q,_5q)|0)|0;return _5v>=_5u?_5v!=_5u?2:1:0;},_5w=[1,_d,_d],_5x=function(_5y,_5z){var _5A=function(_5B,_5C){var _5D=E(_5B);if(!_5D[0]){return E(_5C);}else{var _5E=_5D[1],_5F=E(_5C);if(!_5F[0]){return E(_5D);}else{var _5G=_5F[1];return B(A(_5y,[_5E,_5G]))==2?[1,_5G,new T(function(){return B(_5A(_5D,_5F[2]));})]:[1,_5E,new T(function(){return B(_5A(_5D[2],_5F));})];}}},_5H=function(_5I){var _5J=E(_5I);if(!_5J[0]){return [0];}else{var _5K=E(_5J[2]);return _5K[0]==0?E(_5J):[1,new T(function(){return B(_5A(_5J[1],_5K[1]));}),new T(function(){return B(_5H(_5K[2]));})];}},_5L=function(_5M){while(1){var _5N=E(_5M);if(!_5N[0]){return E(new T(function(){return B(_5L(B(_5H(_d))));}));}else{if(!E(_5N[2])[0]){return E(_5N[1]);}else{_5M=B(_5H(_5N));continue;}}}},_5O=new T(function(){return B(_5P(_d));}),_5P=function(_5Q){var _5R=E(_5Q);if(!_5R[0]){return E(_5w);}else{var _5S=_5R[1],_5T=E(_5R[2]);if(!_5T[0]){return [1,_5R,_d];}else{var _5U=_5T[1],_5V=_5T[2];if(B(A(_5y,[_5S,_5U]))==2){return new F(function(){return (function(_5W,_5X,_5Y){while(1){var _5Z=(function(_60,_61,_62){var _63=E(_62);if(!_63[0]){return [1,[1,_60,_61],_5O];}else{var _64=_63[1];if(B(A(_5y,[_60,_64]))==2){_5W=_64;var _65=[1,_60,_61];_5Y=_63[2];_5X=_65;return null;}else{return [1,[1,_60,_61],new T(function(){return B(_5P(_63));})];}}})(_5W,_5X,_5Y);if(_5Z!=null){return _5Z;}}})(_5U,[1,_5S,_d],_5V);});}else{return new F(function(){return (function(_66,_67,_68){while(1){var _69=(function(_6a,_6b,_6c){var _6d=E(_6c);if(!_6d[0]){return [1,new T(function(){return B(A(_6b,[[1,_6a,_d]]));}),_5O];}else{var _6e=_6d[1],_6f=_6d[2];switch(B(A(_5y,[_6a,_6e]))){case 0:_66=_6e;_67=function(_6g){return new F(function(){return A(_6b,[[1,_6a,_6g]]);});};_68=_6f;return null;case 1:_66=_6e;_67=function(_6h){return new F(function(){return A(_6b,[[1,_6a,_6h]]);});};_68=_6f;return null;default:return [1,new T(function(){return B(A(_6b,[[1,_6a,_d]]));}),new T(function(){return B(_5P(_6d));})];}}})(_66,_67,_68);if(_69!=null){return _69;}}})(_5U,function(_6i){return [1,_5S,_6i];},_5V);});}}}};return new F(function(){return _5L(B(_5P(_5z)));});},_6j=new T(function(){return B(_5x(_5l,_5k));}),_6k=new T(function(){return B(unCStr("List.minimumBy: empty list"));}),_6l=new T(function(){return B(err(_6k));}),_6m=function(_6n,_6o){var _6p=E(_6o);return _6p[0]==0?[0]:[1,new T(function(){return B(A(_6n,[_6p[1]]));}),new T(function(){return B(_6m(_6n,_6p[2]));})];},_6q=function(_6r){var _6s=E(_6r),_6t=new T(function(){return [0,60*E(_6s[1])[1]];});return [0,new T(function(){return [0,0.5*Math.sqrt(3)*E(_6t)[1]+300];}),new T(function(){return [0, -(60*E(_6s[2])[1])+0.5*E(_6t)[1]+315];})];},_6u=new T(function(){return B(_6m(_6q,_6j));}),_6v=function(_6w,_6x,_6y){var _6z=E(_6x);if(!_6z[0]){return [0];}else{var _6A=E(_6y);return _6A[0]==0?[0]:[1,new T(function(){return B(A(_6w,[_6z[1],_6A[1]]));}),new T(function(){return B(_6v(_6w,_6z[2],_6A[2]));})];}},_6B=function(_6C,_6D){var _6E=B(_6v(function(_6F,_6G){return [0,new T(function(){var _6H=E(_6F),_6I=E(new T(function(){return [0,E(_6D)[1]];}))[1]-E(_6H[2])[1],_6J=E(new T(function(){return [0,E(_6C)[1]];}))[1]-E(_6H[1])[1];return [0,_6J*_6J+_6I*_6I];}),_6G];},_6u,_4Y));if(!_6E[0]){return E(_6l);}else{var _6K=E(_6E[1]),_6L=_6K[2],_6M=E(_6E[2]);if(!_6M[0]){var _6N=E(_6L)[1];return _6N>=0?B(_5(_6j,_6N)):E(_2);}else{var _6O=_6M[2],_6P=E(_6K[1])[1],_6Q=E(_6M[1]),_6R=E(_6Q[1])[1];if(_6P>=_6R){if(_6P!=_6R){var _6S=E(B(_4Z(_6R,_6Q[2],_6O))[2])[1];return _6S>=0?B(_5(_6j,_6S)):E(_2);}else{var _6T=E(B(_4Z(_6P,_6L,_6O))[2])[1];return _6T>=0?B(_5(_6j,_6T)):E(_2);}}else{var _6U=E(B(_4Z(_6P,_6L,_6O))[2])[1];return _6U>=0?B(_5(_6j,_6U)):E(_2);}}}},_6V=function(_6W,_6X){while(1){var _6Y=E(_6W);if(!_6Y[0]){return E(_6X);}else{_6W=_6Y[2];var _6Z=_6X+1|0;_6X=_6Z;continue;}}},_70=function(_71){return E(E(_71)[1]);},_72=function(_73,_74,_75,_76,_77,_78){return !B(A(_73,[_75,_77]))?true:!B(A(_70,[_74,_76,_78]))?true:false;},_79=function(_7a,_7b,_7c,_7d){var _7e=E(_7c),_7f=E(_7d);return new F(function(){return _72(E(_7a)[1],_7b,_7e[1],_7e[2],_7f[1],_7f[2]);});},_7g=function(_7h,_7i,_7j,_7k,_7l,_7m){return !B(A(_7h,[_7j,_7l]))?false:B(A(_70,[_7i,_7k,_7m]));},_7n=function(_7o,_7p,_7q,_7r){var _7s=E(_7q),_7t=E(_7r);return new F(function(){return _7g(E(_7o)[1],_7p,_7s[1],_7s[2],_7t[1],_7t[2]);});},_7u=function(_7v,_7w){return [0,function(_7x,_7y){return new F(function(){return _7n(_7v,_7w,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _79(_7v,_7w,_7x,_7y);});}];},_7z=function(_7A,_7B){return E(_7A)[1]==E(_7B)[1];},_7C=function(_7D,_7E){return E(_7D)[1]!=E(_7E)[1];},_7F=[0,_7z,_7C],_7G=new T(function(){return B(_7u(_7F,_7F));}),_7H=[1],_7I=new T(function(){return B(unCStr("Failure in Data.Map.balanceL"));}),_7J=function(_7K){return new F(function(){return err(_7I);});},_7L=new T(function(){return B(_7J(_));}),_7M=function(_7N,_7O,_7P,_7Q){var _7R=E(_7Q);if(!_7R[0]){var _7S=_7R[1],_7T=E(_7P);if(!_7T[0]){var _7U=_7T[1],_7V=_7T[2],_7W=_7T[3];if(_7U<=(imul(3,_7S)|0)){return [0,(1+_7U|0)+_7S|0,E(E(_7N)),_7O,E(_7T),E(_7R)];}else{var _7X=E(_7T[4]);if(!_7X[0]){var _7Y=_7X[1],_7Z=E(_7T[5]);if(!_7Z[0]){var _80=_7Z[1],_81=_7Z[2],_82=_7Z[3],_83=_7Z[4];if(_80>=(imul(2,_7Y)|0)){var _84=function(_85){var _86=E(_7Z[5]);return _86[0]==0?[0,(1+_7U|0)+_7S|0,E(_81),_82,E([0,(1+_7Y|0)+_85|0,E(_7V),_7W,E(_7X),E(_83)]),E([0,(1+_7S|0)+_86[1]|0,E(E(_7N)),_7O,E(_86),E(_7R)])]:[0,(1+_7U|0)+_7S|0,E(_81),_82,E([0,(1+_7Y|0)+_85|0,E(_7V),_7W,E(_7X),E(_83)]),E([0,1+_7S|0,E(E(_7N)),_7O,E(_7H),E(_7R)])];},_87=E(_83);return _87[0]==0?B(_84(_87[1])):B(_84(0));}else{return [0,(1+_7U|0)+_7S|0,E(_7V),_7W,E(_7X),E([0,(1+_7S|0)+_80|0,E(E(_7N)),_7O,E(_7Z),E(_7R)])];}}else{return E(_7L);}}else{return E(_7L);}}}else{return [0,1+_7S|0,E(E(_7N)),_7O,E(_7H),E(_7R)];}}else{var _88=E(_7P);if(!_88[0]){var _89=_88[1],_8a=_88[2],_8b=_88[3],_8c=_88[5],_8d=E(_88[4]);if(!_8d[0]){var _8e=_8d[1],_8f=E(_8c);if(!_8f[0]){var _8g=_8f[1],_8h=_8f[2],_8i=_8f[3],_8j=_8f[4];if(_8g>=(imul(2,_8e)|0)){var _8k=function(_8l){var _8m=E(_8f[5]);return _8m[0]==0?[0,1+_89|0,E(_8h),_8i,E([0,(1+_8e|0)+_8l|0,E(_8a),_8b,E(_8d),E(_8j)]),E([0,1+_8m[1]|0,E(E(_7N)),_7O,E(_8m),E(_7H)])]:[0,1+_89|0,E(_8h),_8i,E([0,(1+_8e|0)+_8l|0,E(_8a),_8b,E(_8d),E(_8j)]),E([0,1,E(E(_7N)),_7O,E(_7H),E(_7H)])];},_8n=E(_8j);return _8n[0]==0?B(_8k(_8n[1])):B(_8k(0));}else{return [0,1+_89|0,E(_8a),_8b,E(_8d),E([0,1+_8g|0,E(E(_7N)),_7O,E(_8f),E(_7H)])];}}else{return [0,3,E(_8a),_8b,E(_8d),E([0,1,E(E(_7N)),_7O,E(_7H),E(_7H)])];}}else{var _8o=E(_8c);return _8o[0]==0?[0,3,E(_8o[2]),_8o[3],E([0,1,E(_8a),_8b,E(_7H),E(_7H)]),E([0,1,E(E(_7N)),_7O,E(_7H),E(_7H)])]:[0,2,E(E(_7N)),_7O,E(_88),E(_7H)];}}else{return [0,1,E(E(_7N)),_7O,E(_7H),E(_7H)];}}},_8p=new T(function(){return B(unCStr("Failure in Data.Map.balanceR"));}),_8q=function(_8r){return new F(function(){return err(_8p);});},_8s=new T(function(){return B(_8q(_));}),_8t=function(_8u,_8v,_8w,_8x){var _8y=E(_8w);if(!_8y[0]){var _8z=_8y[1],_8A=E(_8x);if(!_8A[0]){var _8B=_8A[1],_8C=_8A[2],_8D=_8A[3];if(_8B<=(imul(3,_8z)|0)){return [0,(1+_8z|0)+_8B|0,E(E(_8u)),_8v,E(_8y),E(_8A)];}else{var _8E=E(_8A[4]);if(!_8E[0]){var _8F=_8E[1],_8G=_8E[2],_8H=_8E[3],_8I=_8E[4],_8J=E(_8A[5]);if(!_8J[0]){var _8K=_8J[1];if(_8F>=(imul(2,_8K)|0)){var _8L=function(_8M){var _8N=E(_8u),_8O=E(_8E[5]);return _8O[0]==0?[0,(1+_8z|0)+_8B|0,E(_8G),_8H,E([0,(1+_8z|0)+_8M|0,E(_8N),_8v,E(_8y),E(_8I)]),E([0,(1+_8K|0)+_8O[1]|0,E(_8C),_8D,E(_8O),E(_8J)])]:[0,(1+_8z|0)+_8B|0,E(_8G),_8H,E([0,(1+_8z|0)+_8M|0,E(_8N),_8v,E(_8y),E(_8I)]),E([0,1+_8K|0,E(_8C),_8D,E(_7H),E(_8J)])];},_8P=E(_8I);return _8P[0]==0?B(_8L(_8P[1])):B(_8L(0));}else{return [0,(1+_8z|0)+_8B|0,E(_8C),_8D,E([0,(1+_8z|0)+_8F|0,E(E(_8u)),_8v,E(_8y),E(_8E)]),E(_8J)];}}else{return E(_8s);}}else{return E(_8s);}}}else{return [0,1+_8z|0,E(E(_8u)),_8v,E(_8y),E(_7H)];}}else{var _8Q=E(_8x);if(!_8Q[0]){var _8R=_8Q[1],_8S=_8Q[2],_8T=_8Q[3],_8U=_8Q[5],_8V=E(_8Q[4]);if(!_8V[0]){var _8W=_8V[1],_8X=_8V[2],_8Y=_8V[3],_8Z=_8V[4],_90=E(_8U);if(!_90[0]){var _91=_90[1];if(_8W>=(imul(2,_91)|0)){var _92=function(_93){var _94=E(_8u),_95=E(_8V[5]);return _95[0]==0?[0,1+_8R|0,E(_8X),_8Y,E([0,1+_93|0,E(_94),_8v,E(_7H),E(_8Z)]),E([0,(1+_91|0)+_95[1]|0,E(_8S),_8T,E(_95),E(_90)])]:[0,1+_8R|0,E(_8X),_8Y,E([0,1+_93|0,E(_94),_8v,E(_7H),E(_8Z)]),E([0,1+_91|0,E(_8S),_8T,E(_7H),E(_90)])];},_96=E(_8Z);return _96[0]==0?B(_92(_96[1])):B(_92(0));}else{return [0,1+_8R|0,E(_8S),_8T,E([0,1+_8W|0,E(E(_8u)),_8v,E(_7H),E(_8V)]),E(_90)];}}else{return [0,3,E(_8X),_8Y,E([0,1,E(E(_8u)),_8v,E(_7H),E(_7H)]),E([0,1,E(_8S),_8T,E(_7H),E(_7H)])];}}else{var _97=E(_8U);return _97[0]==0?[0,3,E(_8S),_8T,E([0,1,E(E(_8u)),_8v,E(_7H),E(_7H)]),E(_97)]:[0,2,E(E(_8u)),_8v,E(_7H),E(_8Q)];}}else{return [0,1,E(E(_8u)),_8v,E(_7H),E(_7H)];}}},_98=function(_99,_9a,_9b,_9c,_9d){var _9e=E(_9d);if(!_9e[0]){var _9f=new T(function(){var _9g=B(_98(_9e[1],_9e[2],_9e[3],_9e[4],_9e[5]));return [0,_9g[1],_9g[2]];});return [0,new T(function(){return E(E(_9f)[1]);}),new T(function(){return B(_7M(_9a,_9b,_9c,E(_9f)[2]));})];}else{return [0,[0,_9a,_9b],_9c];}},_9h=function(_9i,_9j,_9k,_9l,_9m){var _9n=E(_9l);if(!_9n[0]){var _9o=new T(function(){var _9p=B(_9h(_9n[1],_9n[2],_9n[3],_9n[4],_9n[5]));return [0,_9p[1],_9p[2]];});return [0,new T(function(){return E(E(_9o)[1]);}),new T(function(){return B(_8t(_9j,_9k,E(_9o)[2],_9m));})];}else{return [0,[0,_9j,_9k],_9m];}},_9q=function(_9r,_9s){var _9t=E(_9r);if(!_9t[0]){var _9u=_9t[1],_9v=E(_9s);if(!_9v[0]){var _9w=_9v[1];if(_9u<=_9w){var _9x=B(_9h(_9w,_9v[2],_9v[3],_9v[4],_9v[5])),_9y=E(_9x[1]);return new F(function(){return _7M(_9y[1],_9y[2],_9t,_9x[2]);});}else{var _9z=B(_98(_9u,_9t[2],_9t[3],_9t[4],_9t[5])),_9A=E(_9z[1]);return new F(function(){return _8t(_9A[1],_9A[2],_9z[2],_9v);});}}else{return E(_9t);}}else{return E(_9s);}},_9B=function(_9C,_9D,_9E){var _9F=E(_9E);if(!_9F[0]){var _9G=_9F[3],_9H=_9F[4],_9I=_9F[5],_9J=E(_9F[2]),_9K=E(_9J[1])[1];if(_9C>=_9K){if(_9C!=_9K){return new F(function(){return _7M(_9J,_9G,_9H,B(_9B(_9C,_9D,_9I)));});}else{var _9L=E(_9J[2])[1];if(_9D>=_9L){if(_9D!=_9L){return new F(function(){return _7M(_9J,_9G,_9H,B(_9B(_9C,_9D,_9I)));});}else{return new F(function(){return _9q(_9H,_9I);});}}else{return new F(function(){return _8t(_9J,_9G,B(_9B(_9C,_9D,_9H)),_9I);});}}}else{return new F(function(){return _8t(_9J,_9G,B(_9B(_9C,_9D,_9H)),_9I);});}}else{return [1];}},_9M=function(_9N,_9O,_9P){var _9Q=E(_9P);if(!_9Q[0]){var _9R=_9Q[3],_9S=_9Q[4],_9T=_9Q[5],_9U=E(_9Q[2]),_9V=E(_9U[1])[1];if(_9N>=_9V){if(_9N!=_9V){return new F(function(){return _7M(_9U,_9R,_9S,B(_9M(_9N,_9O,_9T)));});}else{var _9W=E(_9O)[1],_9X=E(_9U[2])[1];if(_9W>=_9X){if(_9W!=_9X){return new F(function(){return _7M(_9U,_9R,_9S,B(_9B(_9N,_9W,_9T)));});}else{return new F(function(){return _9q(_9S,_9T);});}}else{return new F(function(){return _8t(_9U,_9R,B(_9B(_9N,_9W,_9S)),_9T);});}}}else{return new F(function(){return _8t(_9U,_9R,B(_9M(_9N,_9O,_9S)),_9T);});}}else{return [1];}},_9Y=function(_9Z,_a0,_a1,_a2){var _a3=E(_a2);if(!_a3[0]){var _a4=_a3[3],_a5=_a3[4],_a6=_a3[5],_a7=E(_a3[2]),_a8=E(_a7[1])[1];if(_9Z>=_a8){if(_9Z!=_a8){return new F(function(){return _8t(_a7,_a4,_a5,B(_9Y(_9Z,_a0,_a1,_a6)));});}else{var _a9=E(_a7[2])[1];if(_a0>=_a9){if(_a0!=_a9){return new F(function(){return _8t(_a7,_a4,_a5,B(_9Y(_9Z,_a0,_a1,_a6)));});}else{return [0,_a3[1],E([0,[0,_9Z],[0,_a0]]),_a1,E(_a5),E(_a6)];}}else{return new F(function(){return _7M(_a7,_a4,B(_9Y(_9Z,_a0,_a1,_a5)),_a6);});}}}else{return new F(function(){return _7M(_a7,_a4,B(_9Y(_9Z,_a0,_a1,_a5)),_a6);});}}else{return [0,1,E([0,[0,_9Z],[0,_a0]]),_a1,E(_7H),E(_7H)];}},_aa=function(_ab,_ac,_ad,_ae){var _af=E(_ae);if(!_af[0]){var _ag=_af[3],_ah=_af[4],_ai=_af[5],_aj=E(_af[2]),_ak=E(_aj[1])[1];if(_ab>=_ak){if(_ab!=_ak){return new F(function(){return _8t(_aj,_ag,_ah,B(_aa(_ab,_ac,_ad,_ai)));});}else{var _al=E(_ac),_am=_al[1],_an=E(_aj[2])[1];if(_am>=_an){if(_am!=_an){return new F(function(){return _8t(_aj,_ag,_ah,B(_9Y(_ab,_am,_ad,_ai)));});}else{return [0,_af[1],E([0,[0,_ab],_al]),_ad,E(_ah),E(_ai)];}}else{return new F(function(){return _7M(_aj,_ag,B(_9Y(_ab,_am,_ad,_ah)),_ai);});}}}else{return new F(function(){return _7M(_aj,_ag,B(_aa(_ab,_ac,_ad,_ah)),_ai);});}}else{return [0,1,E([0,[0,_ab],_ac]),_ad,E(_7H),E(_7H)];}},_ao=function(_ap,_aq,_ar,_as){var _at=E(_as);if(!_at[0]){var _au=_at[3],_av=_at[4],_aw=_at[5],_ax=E(_at[2]),_ay=E(_ap),_az=_ay[1],_aA=E(_ax[1])[1];if(_az>=_aA){if(_az!=_aA){return new F(function(){return _8t(_ax,_au,_av,B(_ao(_ay,_aq,_ar,_aw)));});}else{var _aB=E(_aq),_aC=_aB[1],_aD=E(_ax[2])[1];if(_aC>=_aD){if(_aC!=_aD){return new F(function(){return _8t(_ax,_au,_av,B(_ao(_ay,_aB,_ar,_aw)));});}else{return [0,_at[1],E([0,_ay,_aB]),_ar,E(_av),E(_aw)];}}else{return new F(function(){return _7M(_ax,_au,B(_ao(_ay,_aB,_ar,_av)),_aw);});}}}else{return new F(function(){return _7M(_ax,_au,B(_ao(_ay,_aq,_ar,_av)),_aw);});}}else{return [0,1,E([0,_ap,_aq]),_ar,E(_7H),E(_7H)];}},_aE=function(_aF,_aG){if(_aF<=0){if(_aF>=0){return new F(function(){return quot(_aF,_aG);});}else{if(_aG<=0){return new F(function(){return quot(_aF,_aG);});}else{return quot(_aF+1|0,_aG)-1|0;}}}else{if(_aG>=0){if(_aF>=0){return new F(function(){return quot(_aF,_aG);});}else{if(_aG<=0){return new F(function(){return quot(_aF,_aG);});}else{return quot(_aF+1|0,_aG)-1|0;}}}else{return quot(_aF-1|0,_aG)-1|0;}}},_aH=new T(function(){return B(unCStr("ArithException"));}),_aI=new T(function(){return B(unCStr("GHC.Exception"));}),_aJ=new T(function(){return B(unCStr("base"));}),_aK=new T(function(){var _aL=hs_wordToWord64(4194982440),_aM=_aL,_aN=hs_wordToWord64(3110813675),_aO=_aN;return [0,_aM,_aO,[0,_aM,_aO,_aJ,_aI,_aH],_d];}),_aP=function(_aQ){return E(_aK);},_aR=function(_aS){var _aT=E(_aS);return new F(function(){return _n(B(_l(_aT[1])),_aP,_aT[2]);});},_aU=new T(function(){return B(unCStr("arithmetic underflow"));}),_aV=new T(function(){return B(unCStr("arithmetic overflow"));}),_aW=new T(function(){return B(unCStr("Ratio has zero denominator"));}),_aX=new T(function(){return B(unCStr("denormal"));}),_aY=new T(function(){return B(unCStr("divide by zero"));}),_aZ=new T(function(){return B(unCStr("loss of precision"));}),_b0=function(_b1){switch(E(_b1)){case 0:return E(_aV);case 1:return E(_aU);case 2:return E(_aZ);case 3:return E(_aY);case 4:return E(_aX);default:return E(_aW);}},_b2=function(_b3){return new F(function(){return _D(_aU,_b3);});},_b4=function(_b3){return new F(function(){return _D(_aV,_b3);});},_b5=function(_b3){return new F(function(){return _D(_aW,_b3);});},_b6=function(_b3){return new F(function(){return _D(_aX,_b3);});},_b7=function(_b3){return new F(function(){return _D(_aY,_b3);});},_b8=function(_b3){return new F(function(){return _D(_aZ,_b3);});},_b9=function(_ba){switch(E(_ba)){case 0:return E(_b4);case 1:return E(_b2);case 2:return E(_b8);case 3:return E(_b7);case 4:return E(_b6);default:return E(_b5);}},_bb=function(_bc,_bd){return new F(function(){return _1t(_b9,_bc,_bd);});},_be=function(_bf,_bg){switch(E(_bg)){case 0:return E(_b4);case 1:return E(_b2);case 2:return E(_b8);case 3:return E(_b7);case 4:return E(_b6);default:return E(_b5);}},_bh=[0,_be,_b0,_bb],_bi=new T(function(){return [0,_aP,_bh,_bj,_aR];}),_bj=function(_b3){return [0,_bi,_b3];},_bk=3,_bl=new T(function(){return B(_bj(_bk));}),_bm=new T(function(){return die(_bl);}),_bn=0,_bo=new T(function(){return B(_bj(_bn));}),_bp=new T(function(){return die(_bo);}),_bq=function(_br,_bs){var _bt=E(_bs);switch(_bt){case -1:var _bu=E(_br);return _bu==(-2147483648)?E(_bp):B(_aE(_bu,-1));case 0:return E(_bm);default:return new F(function(){return _aE(_br,_bt);});}},_bv=function(_bw,_bx){return [0,_bx,new T(function(){var _by=B(_bv(_bw,new T(function(){return B(A(_bw,[_bx]));})));return [1,_by[1],_by[2]];})];},_bz=function(_bA,_bB){var _bC=E(_bA);if(!_bC){return [0];}else{var _bD=E(_bB);return _bD[0]==0?[0]:[1,_bD[1],new T(function(){return B(_bz(_bC-1|0,_bD[2]));})];}},_bE=function(_bF,_bG){return _bF<0?[0]:B(_bz(_bF,_bG));},_bH=function(_bI,_bJ,_bK,_bL){var _bM=_bK-_bI|0,_bN=_bL-_bJ|0,_bO=function(_bP){var _bQ=_bP-1|0;if(_bQ>0){return new F(function(){return _bE(_bQ,B(_bv(function(_bR){var _bS=E(_bR);return [0,[0,E(_bS[1])[1]+E(new T(function(){return [0,B(_bq(_bM,_bP))];}))[1]|0],[0,E(_bS[2])[1]+E(new T(function(){return [0,B(_bq(_bN,_bP))];}))[1]|0]];},[0,[0,_bI],[0,_bJ]]))[2]);});}else{return [0];}};if(_bM<0){var _bT= -_bM;if(_bN<0){var _bU= -_bN;return _bT>_bU?B(_bO(_bT)):B(_bO(_bU));}else{return _bT>_bN?B(_bO(_bT)):B(_bO(_bN));}}else{if(_bN<0){var _bV= -_bN;return _bM>_bV?B(_bO(_bM)):B(_bO(_bV));}else{return _bM>_bN?B(_bO(_bM)):B(_bO(_bN));}}},_bW=function(_bX,_bY,_bZ){while(1){var _c0=E(_bZ);if(!_c0[0]){var _c1=_c0[4],_c2=_c0[5],_c3=E(_c0[2]),_c4=E(_c3[1])[1];if(_bX>=_c4){if(_bX!=_c4){_bZ=_c2;continue;}else{var _c5=E(_c3[2])[1];if(_bY>=_c5){if(_bY!=_c5){_bZ=_c2;continue;}else{return [1,_c0[3]];}}else{_bZ=_c1;continue;}}}else{_bZ=_c1;continue;}}else{return [0];}}},_c6=function(_c7,_c8,_c9){while(1){var _ca=E(_c9);if(!_ca[0]){var _cb=_ca[4],_cc=_ca[5],_cd=E(_ca[2]),_ce=E(_cd[1])[1];if(_c7>=_ce){if(_c7!=_ce){_c9=_cc;continue;}else{var _cf=E(_c8)[1],_cg=E(_cd[2])[1];if(_cf>=_cg){return _cf!=_cg?B(_bW(_c7,_cf,_cc)):[1,_ca[3]];}else{return new F(function(){return _bW(_c7,_cf,_cb);});}}}else{_c9=_cb;continue;}}else{return [0];}}},_ch=function(_ci,_cj,_ck){var _cl=E(_ck);if(!_cl[0]){var _cm=_cl[4],_cn=_cl[5],_co=E(_cl[2]),_cp=E(_ci)[1],_cq=E(_co[1])[1];if(_cp>=_cq){if(_cp!=_cq){return new F(function(){return _c6(_cp,_cj,_cn);});}else{var _cr=E(_cj)[1],_cs=E(_co[2])[1];if(_cr>=_cs){return _cr!=_cs?B(_bW(_cp,_cr,_cn)):[1,_cl[3]];}else{return new F(function(){return _bW(_cp,_cr,_cm);});}}}else{return new F(function(){return _c6(_cp,_cj,_cm);});}}else{return [0];}},_ct=new T(function(){return B(unCStr("Map.!: given key is not an element in the map"));}),_cu=new T(function(){return B(err(_ct));}),_cv=function(_cw,_cx,_cy){while(1){var _cz=E(_cy);if(!_cz[0]){var _cA=_cz[4],_cB=_cz[5],_cC=E(_cz[2]),_cD=E(_cC[1])[1];if(_cw>=_cD){if(_cw!=_cD){_cy=_cB;continue;}else{var _cE=E(_cC[2])[1];if(_cx>=_cE){if(_cx!=_cE){_cy=_cB;continue;}else{return E(_cz[3]);}}else{_cy=_cA;continue;}}}else{_cy=_cA;continue;}}else{return E(_cu);}}},_cF=function(_cG,_cH,_cI){while(1){var _cJ=E(_cI);if(!_cJ[0]){var _cK=_cJ[4],_cL=_cJ[5],_cM=E(_cJ[2]),_cN=E(_cM[1])[1];if(_cG>=_cN){if(_cG!=_cN){_cI=_cL;continue;}else{var _cO=E(_cH)[1],_cP=E(_cM[2])[1];if(_cO>=_cP){return _cO!=_cP?B(_cv(_cG,_cO,_cL)):E(_cJ[3]);}else{return new F(function(){return _cv(_cG,_cO,_cK);});}}}else{_cI=_cK;continue;}}else{return E(_cu);}}},_cQ=function(_cR,_cS,_cT){var _cU=E(_cT);if(!_cU[0]){return [0];}else{var _cV=_cU[1],_cW=_cU[2];return !B(A(_cR,[_cS,_cV]))?[1,_cV,new T(function(){return B(_cQ(_cR,_cS,_cW));})]:E(_cW);}},_cX=new T(function(){return B(unCStr("trying to flip something that is not a marker (invalid ring move?)"));}),_cY=new T(function(){return B(err(_cX));}),_cZ=function(_d0,_d1){var _d2=E(_d0),_d3=E(_d1);return E(_d2[1])[1]!=E(_d3[1])[1]?false:B(_7z(_d2[2],_d3[2]));},_d4=0,_d5=[1,_d4],_d6=1,_d7=[1,_d6],_d8=function(_d9,_da,_db,_dc,_dd,_de){while(1){var _df=(function(_dg,_dh,_di,_dj,_dk,_dl){var _dm=E(_dl);if(!_dm[0]){return [0,_dg,_dh,_di,_dj,_dk];}else{var _dn=_dm[2],_do=E(_dm[1]),_dp=_do[1],_dq=_do[2],_dr=B(_ch(_dp,_dq,_dg));if(!_dr[0]){var _ds=_dg,_dt=_dh,_du=_di,_dv=_dj,_dw=_dk;_de=_dn;_d9=_ds;_da=_dt;_db=_du;_dc=_dv;_dd=_dw;return null;}else{var _dx=E(_dr[1]);if(!_dx[0]){return E(_cY);}else{if(!E(_dx[1])){var _dy=E(_dp)[1],_dz=B(_cF(_dy,_dq,_dg));if(!_dz[0]){if(!E(_dz[1])){_d9=new T(function(){return B(_aa(_dy,_dq,_d7,B(_9M(_dy,_dq,_dg))));});_da=new T(function(){return B(_cQ(_cZ,[0,[0,_dy],_dq],_dh));});var _du=_di,_dv=_dj,_dw=[1,_do,_dk];_de=_dn;_db=_du;_dc=_dv;_dd=_dw;return null;}else{_d9=new T(function(){return B(_aa(_dy,_dq,_d7,B(_9M(_dy,_dq,_dg))));});var _dt=_dh;_db=new T(function(){return B(_cQ(_cZ,[0,[0,_dy],_dq],_di));});var _dv=_dj,_dw=[1,_do,_dk];_de=_dn;_da=_dt;_dc=_dv;_dd=_dw;return null;}}else{if(!E(_dz[1])){_d9=new T(function(){return B(_aa(_dy,_dq,_d7,B(_9M(_dy,_dq,_dg))));});var _dt=_dh,_du=_di;_dc=new T(function(){return B(_cQ(_cZ,[0,[0,_dy],_dq],_dj));});var _dw=[1,_do,_dk];_de=_dn;_da=_dt;_db=_du;_dd=_dw;return null;}else{_d9=new T(function(){return B(_aa(_dy,_dq,_d7,B(_9M(_dy,_dq,_dg))));});var _dt=_dh,_du=_di,_dv=_dj;_dd=[1,_do,new T(function(){return B(_cQ(_cZ,[0,[0,_dy],_dq],_dk));})];_de=_dn;_da=_dt;_db=_du;_dc=_dv;return null;}}}else{var _dA=E(_dp)[1],_dB=B(_cF(_dA,_dq,_dg));if(!_dB[0]){if(!E(_dB[1])){_d9=new T(function(){return B(_aa(_dA,_dq,_d5,B(_9M(_dA,_dq,_dg))));});_da=new T(function(){return B(_cQ(_cZ,[0,[0,_dA],_dq],_dh));});var _du=_di,_dv=[1,_do,_dj],_dw=_dk;_de=_dn;_db=_du;_dc=_dv;_dd=_dw;return null;}else{_d9=new T(function(){return B(_aa(_dA,_dq,_d5,B(_9M(_dA,_dq,_dg))));});var _dt=_dh;_db=new T(function(){return B(_cQ(_cZ,[0,[0,_dA],_dq],_di));});var _dv=[1,_do,_dj],_dw=_dk;_de=_dn;_da=_dt;_dc=_dv;_dd=_dw;return null;}}else{if(!E(_dB[1])){_d9=new T(function(){return B(_aa(_dA,_dq,_d5,B(_9M(_dA,_dq,_dg))));});var _dt=_dh,_du=_di;_dc=[1,_do,new T(function(){return B(_cQ(_cZ,[0,[0,_dA],_dq],_dj));})];var _dw=_dk;_de=_dn;_da=_dt;_db=_du;_dd=_dw;return null;}else{_d9=new T(function(){return B(_aa(_dA,_dq,_d5,B(_9M(_dA,_dq,_dg))));});var _dt=_dh,_du=_di,_dv=[1,_do,_dj];_dd=new T(function(){return B(_cQ(_cZ,[0,[0,_dA],_dq],_dk));});_de=_dn;_da=_dt;_db=_du;_dc=_dv;return null;}}}}}}})(_d9,_da,_db,_dc,_dd,_de);if(_df!=null){return _df;}}},_dC=function(_dD,_dE,_dF,_dG,_dH,_dI){while(1){var _dJ=(function(_dK,_dL,_dM,_dN,_dO,_dP){var _dQ=E(_dP);if(!_dQ[0]){return [0,_dK,_dL,_dM,_dN,_dO];}else{var _dR=_dQ[2],_dS=E(_dQ[1]),_dT=_dS[2],_dU=E(_dS[1])[1],_dV=B(_cF(_dU,_dT,_dK));if(!_dV[0]){if(!E(_dV[1])){_dD=new T(function(){return B(_9M(_dU,_dT,_dK));});_dE=new T(function(){return B(_cQ(_cZ,[0,[0,_dU],_dT],_dL));});var _dW=_dM,_dX=_dN,_dY=_dO;_dI=_dR;_dF=_dW;_dG=_dX;_dH=_dY;return null;}else{_dD=new T(function(){return B(_9M(_dU,_dT,_dK));});var _dZ=_dL;_dF=new T(function(){return B(_cQ(_cZ,[0,[0,_dU],_dT],_dM));});var _dX=_dN,_dY=_dO;_dI=_dR;_dE=_dZ;_dG=_dX;_dH=_dY;return null;}}else{if(!E(_dV[1])){_dD=new T(function(){return B(_9M(_dU,_dT,_dK));});var _dZ=_dL,_dW=_dM;_dG=new T(function(){return B(_cQ(_cZ,[0,[0,_dU],_dT],_dN));});var _dY=_dO;_dI=_dR;_dE=_dZ;_dF=_dW;_dH=_dY;return null;}else{_dD=new T(function(){return B(_9M(_dU,_dT,_dK));});var _dZ=_dL,_dW=_dM,_dX=_dN;_dH=new T(function(){return B(_cQ(_cZ,[0,[0,_dU],_dT],_dO));});_dI=_dR;_dE=_dZ;_dF=_dW;_dG=_dX;return null;}}}})(_dD,_dE,_dF,_dG,_dH,_dI);if(_dJ!=null){return _dJ;}}},_e0=function(_e1,_e2,_e3){while(1){var _e4=E(_e3);if(!_e4[0]){var _e5=_e4[4],_e6=_e4[5],_e7=E(_e4[2]),_e8=E(_e7[1])[1];if(_e1>=_e8){if(_e1!=_e8){_e3=_e6;continue;}else{var _e9=E(_e7[2])[1];if(_e2>=_e9){if(_e2!=_e9){_e3=_e6;continue;}else{return true;}}else{_e3=_e5;continue;}}}else{_e3=_e5;continue;}}else{return false;}}},_ea=function(_eb,_ec,_ed){while(1){var _ee=E(_ed);if(!_ee[0]){var _ef=_ee[4],_eg=_ee[5],_eh=E(_ee[2]),_ei=E(_eh[1])[1];if(_eb>=_ei){if(_eb!=_ei){_ed=_eg;continue;}else{var _ej=E(_ec)[1],_ek=E(_eh[2])[1];if(_ej>=_ek){return _ej!=_ek?B(_e0(_eb,_ej,_eg)):true;}else{return new F(function(){return _e0(_eb,_ej,_ef);});}}}else{_ed=_ef;continue;}}else{return false;}}},_el=function(_em,_en,_eo){var _ep=E(_eo);if(!_ep[0]){var _eq=_ep[4],_er=_ep[5],_es=E(_ep[2]),_et=E(_em)[1],_eu=E(_es[1])[1];if(_et>=_eu){if(_et!=_eu){return new F(function(){return _ea(_et,_en,_er);});}else{var _ev=E(_en)[1],_ew=E(_es[2])[1];if(_ev>=_ew){return _ev!=_ew?B(_e0(_et,_ev,_er)):true;}else{return new F(function(){return _e0(_et,_ev,_eq);});}}}else{return new F(function(){return _ea(_et,_en,_eq);});}}else{return false;}},_ex=[1],_ey=function(_ez,_eA){while(1){var _eB=E(_eA);if(!_eB[0]){return false;}else{if(!B(A(_ez,[_eB[1]]))){_eA=_eB[2];continue;}else{return true;}}}},_eC=function(_eD,_eE,_eF){while(1){var _eG=E(_eF);if(!_eG[0]){return false;}else{if(!B(A(_70,[_eD,_eE,_eG[1]]))){_eF=_eG[2];continue;}else{return true;}}}},_eH=5,_eI=0,_eJ=1,_eK=[1,_eJ,_d],_eL=[1,_eI,_eK],_eM=[1,_eH,_eL],_eN=function(_eO,_eP){return new F(function(){return _bv(function(_eQ){switch(E(_eP)){case 0:var _eR=E(_eQ);return [0,E(_eR[1]),[0,1+E(_eR[2])[1]|0]];case 1:var _eS=E(_eQ);return [0,[0,1+E(_eS[1])[1]|0],[0,1+E(_eS[2])[1]|0]];case 2:var _eT=E(_eQ);return [0,[0,1+E(_eT[1])[1]|0],E(_eT[2])];case 3:var _eU=E(_eQ);return [0,E(_eU[1]),[0,-1+E(_eU[2])[1]|0]];case 4:var _eV=E(_eQ);return [0,[0,-1+E(_eV[1])[1]|0],[0,-1+E(_eV[2])[1]|0]];default:var _eW=E(_eQ);return [0,[0,-1+E(_eW[1])[1]|0],E(_eW[2])];}},_eO);});},_eX=true,_eY=function(_eZ,_f0,_f1,_f2,_f3){var _f4=function(_f5){return function(_f6){return !E(new T(function(){var _f7=E(_f5),_f8=B(_ch(_f7[1],_f7[2],_eZ));if(!_f8[0]){var _f9=false;}else{var _fa=E(_f8[1]),_f9=_fa[0]==0?false:E(_fa[1])==0?E(_f2)==0?true:false:E(_f2)==0?false:true;}var _fb=_f9;return _fb;}))?false:E(_f6);};},_fc=function(_fd,_fe){var _ff=E(_fd);if(!_ff[0]){return true;}else{var _fg=_ff[1];if(_fe>1){return new F(function(){return A(_f4,[_fg,new T(function(){return B(_fc(_ff[2],_fe-1|0));})]);});}else{return new F(function(){return A(_f4,[_fg,_eX]);});}}},_fh=function(_fi){var _fj=new T(function(){return B(_fc(B(_eN(_fi,new T(function(){switch(E(_f3)){case 0:var _fk=3;break;case 1:var _fk=4;break;case 2:var _fk=5;break;case 3:var _fk=0;break;case 4:var _fk=1;break;default:var _fk=2;}return _fk;})))[2],2));}),_fl=function(_fm,_fn){var _fo=E(_fm);if(!_fo[0]){return E(_fj);}else{var _fp=_fo[1];if(_fn>1){return new F(function(){return A(_f4,[_fp,new T(function(){return B(_fl(_fo[2],_fn-1|0));})]);});}else{return new F(function(){return A(_f4,[_fp,_fj]);});}}};return new F(function(){return _fl(B(_eN(_fi,_f3))[2],2);});};return E(_f2)==0?B(_ey(_fh,_f0)):B(_ey(_fh,_f1));},_fq=function(_fr,_fs,_ft){var _fu=E(_fr);return new F(function(){return _eY(_fu[1],_fu[4],_fu[5],_fs,_ft);});},_fv=function(_fw,_fx){var _fy=B(_eN(_fw,_fx));return [1,_fy[1],_fy[2]];},_fz=new T(function(){return B(unCStr("tail"));}),_fA=new T(function(){return B(_2D(_fz));}),_fB=function(_fC,_fD){var _fE=E(_fD);if(!_fE[0]){return [0];}else{var _fF=_fE[1];return !B(A(_fC,[_fF]))?[0]:[1,_fF,new T(function(){return B(_fB(_fC,_fE[2]));})];}},_fG=function(_fH,_fI){var _fJ=E(_fH);return _fJ[0]==0?E(_fI):[1,_fJ[1],new T(function(){return B(_fG(_fI,_fJ[2]));})];},_fK=function(_fL,_fM,_fN){return !B(_eC(_7G,_fM,_fL))?[0]:B(_bz(5,new T(function(){var _fO=function(_fP){return new F(function(){return _eC(_7G,_fP,_fL);});};return B(_fG(B(_fB(_fO,B(_fv(_fM,_fN)))),new T(function(){var _fQ=B(_eN(_fM,new T(function(){switch(E(_fN)){case 0:var _fR=3;break;case 1:var _fR=4;break;case 2:var _fR=5;break;case 3:var _fR=0;break;case 4:var _fR=1;break;default:var _fR=2;}return _fR;}))),_fS=B(_fB(_fO,[1,_fQ[1],_fQ[2]]));return _fS[0]==0?E(_fA):E(_fS[2]);})));})));},_fT=function(_fU,_fV){return new F(function(){return _ey(function(_fW){return B(_6V(B(_fK(_fU,_fV,_fW)),0))==5?true:false;},_eM);});},_fX=[0,41],_fY=[1,_fX,_d],_fZ=new T(function(){return B(_2v(0,5,_fY));}),_g0=new T(function(){return B(unAppCStr(") is outside of enumeration\'s range (0,",_fZ));}),_g1=function(_g2){return new F(function(){return err(B(unAppCStr("toEnum{Direction}: tag (",new T(function(){return B(_2v(0,_g2,_g0));}))));});},_g3=function(_g4){return [0,new T(function(){if(_g4<0){var _g5=B(_g1(_g4));}else{var _g5=_g4>5?B(_g1(_g4)):_g4;}var _g6=_g5;return _g6;}),new T(function(){var _g7=E(_g4);if(_g7==5){var _g8=[0];}else{var _g9=B(_g3(_g7+1|0)),_g8=[1,_g9[1],_g9[2]];}return _g8;})];},_ga=new T(function(){var _gb=B(_g3(0));return [1,_gb[1],_gb[2]];}),_gc=function(_gd,_ge){var _gf=E(_ge);if(!_gf[0]){return [0,_d,_d];}else{var _gg=_gf[1];if(!B(A(_gd,[_gg]))){return [0,_d,_gf];}else{var _gh=new T(function(){var _gi=B(_gc(_gd,_gf[2]));return [0,_gi[1],_gi[2]];});return [0,[1,_gg,new T(function(){return E(E(_gh)[1]);})],new T(function(){return E(E(_gh)[2]);})];}}},_gj=function(_gk,_gl){var _gm=E(_gl);return !B(_el(_gm[1],_gm[2],E(_gk)[1]))?true:false;},_gn=function(_go){var _gp=E(_go),_gq=E(_gp[1])[1];return Math.pow(0.5*Math.sqrt(3)*_gq,2)+Math.pow(0.5*_gq-E(_gp[2])[1],2)<=Math.pow(4.6,2);},_gr=function(_gs,_gt,_gu){var _gv=B(_fB(_gn,B(_fv(_gt,_gu))));if(!_gv[0]){return E(_fA);}else{var _gw=B(_gc(function(_2j){return new F(function(){return _gj(_gs,_2j);});},_gv[2]));return new F(function(){return _D(_gw[1],new T(function(){var _gx=E(_gw[2]);if(!_gx[0]){var _gy=[0];}else{var _gz=E(_gs)[1],_gA=E(_gx[1]),_gB=B(_ch(_gA[1],_gA[2],_gz));if(!_gB[0]){var _gC=[1,_gA,_d];}else{if(!E(_gB[1])[0]){var _gD=[0];}else{var _gD=B((function(_gE){while(1){var _gF=E(_gE);if(!_gF[0]){return [0];}else{var _gG=E(_gF[1]),_gH=B(_ch(_gG[1],_gG[2],_gz));if(!_gH[0]){return [1,_gG,_d];}else{if(!E(_gH[1])[0]){return [0];}else{_gE=_gF[2];continue;}}}}})(_gx[2]));}var _gC=_gD;}var _gI=_gC,_gJ=_gI,_gy=_gJ;}return _gy;}));});}},_gK=function(_gL,_gM){var _gN=function(_gO){while(1){var _gP=(function(_gQ){var _gR=E(_gQ);if(!_gR[0]){return [0];}else{var _gS=_gR[2],_gT=B(_gr(_gL,_gM,_gR[1]));if(!_gT[0]){_gO=_gS;return null;}else{return [1,_gT[1],new T(function(){return B(_D(_gT[2],new T(function(){return B(_gN(_gS));})));})];}}})(_gO);if(_gP!=null){return _gP;}}};return new F(function(){return _gN(_ga);});},_gU=function(_gV,_gW){return E(_gV)==0?E(E(_gW)[2]):E(E(_gW)[3]);},_gX=function(_gY,_gZ){var _h0=function(_h1){while(1){var _h2=(function(_h3){var _h4=E(_h3);if(!_h4[0]){return [0];}else{var _h5=_h4[2],_h6=B(_fK(_gY,_gZ,_h4[1]));if(B(_6V(_h6,0))==5){return [1,_h6,new T(function(){return B(_h0(_h5));})];}else{_h1=_h5;return null;}}})(_h1);if(_h2!=null){return _h2;}}},_h7=B((function(_h8,_h9){var _ha=B(_fK(_gY,_gZ,_h8));return B(_6V(_ha,0))==5?[1,_ha,new T(function(){return B(_h0(_h9));})]:B(_h0(_h9));})(_eH,_eL));return _h7[0]==0?[0]:E(_h7[1]);},_hb=[0,_d6],_hc=[0,_d4],_hd=function(_he,_hf,_hg,_hh,_hi,_hj){var _hk=E(_hf);switch(_hk[0]){case 0:var _hl=E(_hg),_hm=_hl[1],_hn=_hl[2],_ho=_hl[3],_hp=_hl[4],_hq=_hl[5],_hr=E(_hj),_hs=_hr[1],_ht=_hr[2];return !B(_el(_hs,_ht,_hm))?[1,[0,new T(function(){return E(_he)==0?1:0;}),new T(function(){return (B(_6V(_hn,0))+B(_6V(_ho,0))|0)>=9?[1]:[0];}),new T(function(){return E(_he)==0?[0,new T(function(){return B(_ao(_hs,_ht,_hc,_hm));}),[1,_hr,_hn],_ho,_hp,_hq]:[0,new T(function(){return B(_ao(_hs,_ht,_hb,_hm));}),_hn,[1,_hr,_ho],_hp,_hq];}),_hh,_hi]]:[0];case 1:return !B(_eC(_7G,_hj,B(_gU(_he,_hg))))?[0]:[1,[0,_he,[2,_hj],new T(function(){if(!E(_he)){var _hu=E(_hg),_hv=_hu[1],_hw=_hu[2],_hx=_hu[3],_hy=_hu[4],_hz=_hu[5],_hA=E(_hj),_hB=_hA[2],_hC=E(_hA[1])[1],_hD=B(_cF(_hC,_hB,_hv)),_hE=_hD[0]==0?E(_hD[1])==0?[0,new T(function(){return B(_aa(_hC,_hB,_d5,B(_9M(_hC,_hB,_hv))));}),new T(function(){return B(_cQ(_cZ,[0,[0,_hC],_hB],_hw));}),_hx,[1,_hA,_hy],_hz]:[0,new T(function(){return B(_aa(_hC,_hB,_d5,B(_9M(_hC,_hB,_hv))));}),_hw,new T(function(){return B(_cQ(_cZ,[0,[0,_hC],_hB],_hx));}),[1,_hA,_hy],_hz]:E(_hD[1])==0?[0,new T(function(){return B(_aa(_hC,_hB,_d5,B(_9M(_hC,_hB,_hv))));}),_hw,_hx,[1,_hA,new T(function(){return B(_cQ(_cZ,[0,[0,_hC],_hB],_hy));})],_hz]:[0,new T(function(){return B(_aa(_hC,_hB,_d5,B(_9M(_hC,_hB,_hv))));}),_hw,_hx,[1,_hA,_hy],new T(function(){return B(_cQ(_cZ,[0,[0,_hC],_hB],_hz));})];}else{var _hF=E(_hg),_hG=_hF[1],_hH=_hF[2],_hI=_hF[3],_hJ=_hF[4],_hK=_hF[5],_hL=E(_hj),_hM=_hL[2],_hN=E(_hL[1])[1],_hO=B(_cF(_hN,_hM,_hG)),_hE=_hO[0]==0?E(_hO[1])==0?[0,new T(function(){return B(_aa(_hN,_hM,_d7,B(_9M(_hN,_hM,_hG))));}),new T(function(){return B(_cQ(_cZ,[0,[0,_hN],_hM],_hH));}),_hI,_hJ,[1,_hL,_hK]]:[0,new T(function(){return B(_aa(_hN,_hM,_d7,B(_9M(_hN,_hM,_hG))));}),_hH,new T(function(){return B(_cQ(_cZ,[0,[0,_hN],_hM],_hI));}),_hJ,[1,_hL,_hK]]:E(_hO[1])==0?[0,new T(function(){return B(_aa(_hN,_hM,_d7,B(_9M(_hN,_hM,_hG))));}),_hH,_hI,new T(function(){return B(_cQ(_cZ,[0,[0,_hN],_hM],_hJ));}),[1,_hL,_hK]]:[0,new T(function(){return B(_aa(_hN,_hM,_d7,B(_9M(_hN,_hM,_hG))));}),_hH,_hI,_hJ,[1,_hL,new T(function(){return B(_cQ(_cZ,[0,[0,_hN],_hM],_hK));})]];}return _hE;}),_hh,_hi]];case 2:var _hP=_hk[1];if(!B(_eC(_7G,_hj,B(_gK(_hg,_hP))))){return [0];}else{var _hQ=new T(function(){var _hR=E(_hg),_hS=E(_hP),_hT=E(_hj),_hU=B(_d8(_hR[1],_hR[2],_hR[3],_hR[4],_hR[5],B(_bH(E(_hS[1])[1],E(_hS[2])[1],E(_hT[1])[1],E(_hT[2])[1]))));return [0,_hU[1],_hU[2],_hU[3],_hU[4],_hU[5]];}),_hV=new T(function(){return E(_he)==0?1:0;});return [1,[0,_hV,new T(function(){if(!B(_ey(function(_2j){return new F(function(){return _fq(_hQ,_he,_2j);});},_eM))){var _hW=!B(_ey(function(_2j){return new F(function(){return _fq(_hQ,_hV,_2j);});},_eM))?[1]:[3,_he];}else{var _hW=[5,_he];}return _hW;}),new T(function(){if(!E(_he)){var _hX=E(_hQ),_hY=[0,new T(function(){var _hZ=E(_hj);return B(_ao(_hZ[1],_hZ[2],_hc,_hX[1]));}),[1,_hj,_hX[2]],_hX[3],_hX[4],_hX[5]];}else{var _i0=E(_hQ),_hY=[0,new T(function(){var _i1=E(_hj);return B(_ao(_i1[1],_i1[2],_hb,_i0[1]));}),_i0[2],[1,_hj,_i0[3]],_i0[4],_i0[5]];}return _hY;}),_hh,_hi]];}break;case 3:var _i2=new T(function(){if(!E(_he)){var _i3=E(E(_hg)[4]);}else{var _i3=E(E(_hg)[5]);}return _i3;});return !B(_fT(_i2,_hj))?[0]:[1,[0,_he,[4,_hk[1]],new T(function(){var _i4=E(_hg),_i5=B(_dC(_i4[1],_i4[2],_i4[3],_i4[4],_i4[5],B(_gX(_i2,_hj))));return [0,_i5[1],_i5[2],_i5[3],_i5[4],_i5[5]];}),_hh,_hi]];case 4:var _i6=_hk[1];if(!B(_eC(_7G,_hj,B(_gU(_he,_hg))))){return [0];}else{var _i7=new T(function(){var _i8=E(_hg),_i9=_i8[1],_ia=_i8[2],_ib=_i8[3],_ic=_i8[4],_id=_i8[5],_ie=E(_hj),_if=_ie[2],_ig=E(_ie[1])[1],_ih=B(_cF(_ig,_if,_i9));return _ih[0]==0?E(_ih[1])==0?[0,new T(function(){return B(_9M(_ig,_if,_i9));}),new T(function(){return B(_cQ(_cZ,[0,[0,_ig],_if],_ia));}),_ib,_ic,_id]:[0,new T(function(){return B(_9M(_ig,_if,_i9));}),_ia,new T(function(){return B(_cQ(_cZ,[0,[0,_ig],_if],_ib));}),_ic,_id]:E(_ih[1])==0?[0,new T(function(){return B(_9M(_ig,_if,_i9));}),_ia,_ib,new T(function(){return B(_cQ(_cZ,[0,[0,_ig],_if],_ic));}),_id]:[0,new T(function(){return B(_9M(_ig,_if,_i9));}),_ia,_ib,_ic,new T(function(){return B(_cQ(_cZ,[0,[0,_ig],_if],_id));})];}),_ii=new T(function(){return E(_he)==0?1:0;});return [1,[0,_ii,new T(function(){if(!B(_ey(function(_2j){return new F(function(){return _fq(_i7,_he,_2j);});},_eM))){var _ij=!B(_ey(function(_2j){return new F(function(){return _fq(_i7,_ii,_2j);});},_eM))?E(_i6)==0?E(_he)==0?[1]:[6]:E(_he)==0?[6]:[1]:[3,_i6];}else{var _ij=[5,_i6];}return _ij;}),_i7,new T(function(){if(!E(_he)){var _ik=[0,E(_hh)[1]+1|0];}else{var _ik=E(_hh);}return _ik;}),new T(function(){if(!E(_he)){var _il=E(_hi);}else{var _il=[0,E(_hi)[1]+1|0];}return _il;})]];}break;case 5:return [1,[0,new T(function(){return E(_he)==0?1:0;}),[3,_hk[1]],_hg,_hh,_hi]];default:return [1,[0,new T(function(){return E(_he)==0?1:0;}),_ex,_hg,_hh,_hi]];}},_im=new T(function(){return B(unCStr("POST"));}),_in=new T(function(){return B(unCStr("GET"));}),_io=[0,38],_ip=[1,_io,_d],_iq=new T(function(){return [0,toJSStr(_ip)];}),_ir=[0,61],_is=[1,_ir,_d],_it=new T(function(){return [0,toJSStr(_is)];}),_iu=function(_iv,_iw){var _ix=jsCat([1,_iv,[1,_iw,_d]],E(_it)[1]),_iy=_ix;return E(_iy);},_iz=function(_iA){var _iB=E(_iA);return [0,B(_iu(_iB[1],_iB[2]))];},_iC=function(_iD){var _iE=jsCat(new T(function(){return B(_6m(_iz,_iD));}),E(_iq)[1]),_iF=_iE;return E(_iF);},_iG=0,_iH=function(_iI){return new F(function(){return fromJSStr(E(_iI)[1]);});},_iJ=function(_iK){return [0,toJSStr(E(_iK))];},_iL=function(_iM){var _iN=E(_iM);return [0,new T(function(){return B(_iJ(_iN[1]));}),new T(function(){return B(_iJ(_iN[2]));})];},_iO=[0,63],_iP=[1,_iO,_d],_iQ=new T(function(){return [0,toJSStr(_iP)];}),_iR=new T(function(){return [0,toJSStr(_d)];}),_iS=function(_iT,_iU,_iV,_iW,_iX,_iY,_iZ,_j0,_j1){return new F(function(){return A(_iT,[new T(function(){return B(A(_iX,[function(_){var _j2=function(_j3){var _j4=function(_j5){var _j6=ajaxReq(toJSStr(_j3),_j5,1,E(_iR)[1],function(_j7){return new F(function(){return A(_j1,[new T(function(){var _j8=E(_j7);return _j8[0]==0?[0]:[1,new T(function(){return B(_iH(_j8[1]));})];})]);});});return _iG;};if(!E(_j0)[0]){return new F(function(){return _j4(toJSStr(E(_iZ)));});}else{var _j9=jsCat([1,new T(function(){return B(_iJ(_iZ));}),[1,new T(function(){return [0,B(_iC(B(_6m(_iL,_j0))))];}),_d]],E(_iQ)[1]),_ja=_j9;return new F(function(){return _j4(_ja);});}};if(!E(_iY)){return new F(function(){return _j2(E(_in));});}else{return new F(function(){return _j2(E(_im));});}}]));}),function(_jb){return E(new T(function(){return B(A(_iV,[_iG]));}));}]);});},_jc=0,_jd=[2],_je=[1],_jf=new T(function(){return B(unCStr("Pattern match failure in do expression at src/frontend.hs:257:9-18"));}),_jg=new T(function(){return B(unCStr("Pattern match failure in do expression at src/frontend.hs:290:9-26"));}),_jh=function(_ji,_jj,_){var _jk=B(A(_ji,[_])),_jl=_jk;return new F(function(){return A(_jj,[_jl,_]);});},_jm=function(_jn){var _jo=E(_jn);return new F(function(){return _6B(_jo[1],_jo[2]);});},_jp=[0,_7H,_d,_d,_d,_d],_jq=new T(function(){return [0,"keydown"];}),_jr=new T(function(){return [0,"mousemove"];}),_js=new T(function(){return [0,"click"];}),_jt=[0,10],_ju=[1,_jt,_d],_jv=function(_jw,_jx,_){var _jy=jsWriteHandle(E(_jw)[1],toJSStr(E(_jx)));return _iG;},_jz=function(_jA,_jB,_){var _jC=E(_jA),_jD=jsWriteHandle(_jC[1],toJSStr(E(_jB)));return new F(function(){return _jv(_jC,_ju,_);});},_jE=function(_jF){return E(_jF);},_jG=function(_jH){return new F(function(){return _jE(_jH);});},_jI=new T(function(){return B(unCStr("https://david-peter.de:8000/"));}),_jJ=new T(function(){return B(unCStr("gamestate"));}),_jK=new T(function(){return B(unCStr("Pattern match failure in do expression at src/frontend.hs:241:5-12"));}),_jL=new T(function(){return B(unCStr("Pattern match failure in do expression at src/frontend.hs:242:5-11"));}),_jM=[0,1],_jN=[3,_jM],_jO=new T(function(){return B(unCStr("Prelude.read: no parse"));}),_jP=new T(function(){return B(err(_jO));}),_jQ=new T(function(){return B(unCStr("Prelude.read: ambiguous parse"));}),_jR=new T(function(){return B(err(_jQ));}),_jS=function(_jT){return E(E(_jT)[3]);},_jU=function(_jV,_jW,_jX,_jY,_jZ,_k0){switch(B(A(_jV,[_jX,_jZ]))){case 0:return true;case 1:return new F(function(){return A(_jS,[_jW,_jY,_k0]);});break;default:return false;}},_k1=function(_k2,_k3,_k4,_k5,_k6){var _k7=E(_k5),_k8=E(_k6);return new F(function(){return _jU(E(_k3)[2],_k4,_k7[1],_k7[2],_k8[1],_k8[2]);});},_k9=function(_ka){return E(E(_ka)[6]);},_kb=function(_kc,_kd,_ke,_kf,_kg,_kh){switch(B(A(_kc,[_ke,_kg]))){case 0:return true;case 1:return new F(function(){return A(_k9,[_kd,_kf,_kh]);});break;default:return false;}},_ki=function(_kj,_kk,_kl,_km,_kn){var _ko=E(_km),_kp=E(_kn);return new F(function(){return _kb(E(_kk)[2],_kl,_ko[1],_ko[2],_kp[1],_kp[2]);});},_kq=function(_kr){return E(E(_kr)[5]);},_ks=function(_kt,_ku,_kv,_kw,_kx,_ky){switch(B(A(_kt,[_kv,_kx]))){case 0:return false;case 1:return new F(function(){return A(_kq,[_ku,_kw,_ky]);});break;default:return true;}},_kz=function(_kA,_kB,_kC,_kD,_kE){var _kF=E(_kD),_kG=E(_kE);return new F(function(){return _ks(E(_kB)[2],_kC,_kF[1],_kF[2],_kG[1],_kG[2]);});},_kH=function(_kI){return E(E(_kI)[4]);},_kJ=function(_kK,_kL,_kM,_kN,_kO,_kP){switch(B(A(_kK,[_kM,_kO]))){case 0:return false;case 1:return new F(function(){return A(_kH,[_kL,_kN,_kP]);});break;default:return true;}},_kQ=function(_kR,_kS,_kT,_kU,_kV){var _kW=E(_kU),_kX=E(_kV);return new F(function(){return _kJ(E(_kS)[2],_kT,_kW[1],_kW[2],_kX[1],_kX[2]);});},_kY=function(_kZ){return E(E(_kZ)[2]);},_l0=function(_l1,_l2,_l3,_l4,_l5,_l6){switch(B(A(_l1,[_l3,_l5]))){case 0:return 0;case 1:return new F(function(){return A(_kY,[_l2,_l4,_l6]);});break;default:return 2;}},_l7=function(_l8,_l9,_la,_lb,_lc){var _ld=E(_lb),_le=E(_lc);return new F(function(){return _l0(E(_l9)[2],_la,_ld[1],_ld[2],_le[1],_le[2]);});},_lf=function(_lg,_lh,_li,_lj,_lk){var _ll=E(_lj),_lm=_ll[1],_ln=_ll[2],_lo=E(_lk),_lp=_lo[1],_lq=_lo[2];switch(B(A(E(_lh)[2],[_lm,_lp]))){case 0:return [0,_lp,_lq];case 1:return !B(A(_k9,[_li,_ln,_lq]))?[0,_lm,_ln]:[0,_lp,_lq];default:return [0,_lm,_ln];}},_lr=function(_ls,_lt,_lu,_lv,_lw){var _lx=E(_lv),_ly=_lx[1],_lz=_lx[2],_lA=E(_lw),_lB=_lA[1],_lC=_lA[2];switch(B(A(E(_lt)[2],[_ly,_lB]))){case 0:return [0,_ly,_lz];case 1:return !B(A(_k9,[_lu,_lz,_lC]))?[0,_lB,_lC]:[0,_ly,_lz];default:return [0,_lB,_lC];}},_lD=function(_lE,_lF,_lG){return [0,_lE,function(_7x,_7y){return new F(function(){return _l7(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _k1(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _kQ(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _kz(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _ki(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _lf(_lE,_lF,_lG,_7x,_7y);});},function(_7x,_7y){return new F(function(){return _lr(_lE,_lF,_lG,_7x,_7y);});}];},_lH=function(_lI,_lJ){var _lK=E(_lI),_lL=E(_lJ);return _lK[1]>_lL[1]?E(_lK):E(_lL);},_lM=function(_lN,_lO){var _lP=E(_lN),_lQ=E(_lO);return _lP[1]>_lQ[1]?E(_lQ):E(_lP);},_lR=function(_lS,_lT){return _lS>=_lT?_lS!=_lT?2:1:0;},_lU=function(_lV,_lW){return new F(function(){return _lR(E(_lV)[1],E(_lW)[1]);});},_lX=function(_lY,_lZ){return E(_lY)[1]>=E(_lZ)[1];},_m0=function(_m1,_m2){return E(_m1)[1]>E(_m2)[1];},_m3=function(_m4,_m5){return E(_m4)[1]<=E(_m5)[1];},_m6=function(_m7,_m8){return E(_m7)[1]_p0){return function(_p6){return new F(function(){return A(_p6,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>55){return function(_p7){return new F(function(){return A(_p7,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,_p0-48|0]);});}}break;case 10:if(48>_p0){return function(_p8){return new F(function(){return A(_p8,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>57){return function(_p9){return new F(function(){return A(_p9,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,_p0-48|0]);});}}break;case 16:if(48>_p0){if(97>_p0){if(65>_p0){return function(_pa){return new F(function(){return A(_pa,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>70){return function(_pb){return new F(function(){return A(_pb,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,(_p0-65|0)+10|0]);});}}}else{if(_p0>102){if(65>_p0){return function(_pc){return new F(function(){return A(_pc,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>70){return function(_pd){return new F(function(){return A(_pd,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,(_p0-65|0)+10|0]);});}}}else{return new F(function(){return _p1([0,(_p0-97|0)+10|0]);});}}}else{if(_p0>57){if(97>_p0){if(65>_p0){return function(_pe){return new F(function(){return A(_pe,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>70){return function(_pf){return new F(function(){return A(_pf,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,(_p0-65|0)+10|0]);});}}}else{if(_p0>102){if(65>_p0){return function(_pg){return new F(function(){return A(_pg,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{if(_p0>70){return function(_ph){return new F(function(){return A(_ph,[new T(function(){return B(A(_oX,[_d]));})]);});};}else{return new F(function(){return _p1([0,(_p0-65|0)+10|0]);});}}}else{return new F(function(){return _p1([0,(_p0-97|0)+10|0]);});}}}else{return new F(function(){return _p1([0,_p0-48|0]);});}}break;default:return E(_oR);}}};return function(_pi){return new F(function(){return A(_oV,[_pi,_jE,function(_pj){var _pk=E(_pj);return _pk[0]==0?[2]:B(A(_oU,[_pk]));}]);});};},_pl=[0,10],_pm=[0,1],_pn=[0,2147483647],_po=function(_pp,_pq){while(1){var _pr=E(_pp);if(!_pr[0]){var _ps=_pr[1],_pt=E(_pq);if(!_pt[0]){var _pu=_pt[1],_pv=addC(_ps,_pu);if(!E(_pv[2])){return [0,_pv[1]];}else{_pp=[1,I_fromInt(_ps)];_pq=[1,I_fromInt(_pu)];continue;}}else{_pp=[1,I_fromInt(_ps)];_pq=_pt;continue;}}else{var _pw=E(_pq);if(!_pw[0]){_pp=_pr;_pq=[1,I_fromInt(_pw[1])];continue;}else{return [1,I_add(_pr[1],_pw[1])];}}}},_px=new T(function(){return B(_po(_pn,_pm));}),_py=function(_pz){var _pA=E(_pz);if(!_pA[0]){var _pB=E(_pA[1]);return _pB==(-2147483648)?E(_px):[0, -_pB];}else{return [1,I_negate(_pA[1])];}},_pC=[0,10],_pD=[0,0],_pE=function(_pF){return [0,_pF];},_pG=function(_pH,_pI){while(1){var _pJ=E(_pH);if(!_pJ[0]){var _pK=_pJ[1],_pL=E(_pI);if(!_pL[0]){var _pM=_pL[1];if(!(imul(_pK,_pM)|0)){return [0,imul(_pK,_pM)|0];}else{_pH=[1,I_fromInt(_pK)];_pI=[1,I_fromInt(_pM)];continue;}}else{_pH=[1,I_fromInt(_pK)];_pI=_pL;continue;}}else{var _pN=E(_pI);if(!_pN[0]){_pH=_pJ;_pI=[1,I_fromInt(_pN[1])];continue;}else{return [1,I_mul(_pJ[1],_pN[1])];}}}},_pO=function(_pP,_pQ,_pR){while(1){var _pS=E(_pR);if(!_pS[0]){return E(_pQ);}else{var _pT=B(_po(B(_pG(_pQ,_pP)),B(_pE(E(_pS[1])[1]))));_pR=_pS[2];_pQ=_pT;continue;}}},_pU=function(_pV){var _pW=new T(function(){return B(_nw(B(_nw([0,function(_pX){return E(E(_pX)[1])==45?[1,B(_oS(_pl,function(_pY){return new F(function(){return A(_pV,[[1,new T(function(){return B(_py(B(_pO(_pC,_pD,_pY))));})]]);});}))]:[2];}],[0,function(_pZ){return E(E(_pZ)[1])==43?[1,B(_oS(_pl,function(_q0){return new F(function(){return A(_pV,[[1,new T(function(){return B(_pO(_pC,_pD,_q0));})]]);});}))]:[2];}])),new T(function(){return [1,B(_oS(_pl,function(_q1){return new F(function(){return A(_pV,[[1,new T(function(){return B(_pO(_pC,_pD,_q1));})]]);});}))];})));});return new F(function(){return _nw([0,function(_q2){return E(E(_q2)[1])==101?E(_pW):[2];}],[0,function(_q3){return E(E(_q3)[1])==69?E(_pW):[2];}]);});},_q4=function(_q5){return new F(function(){return A(_q5,[_0]);});},_q6=function(_q7){return new F(function(){return A(_q7,[_0]);});},_q8=function(_q9){return function(_qa){return E(E(_qa)[1])==46?[1,B(_oS(_pl,function(_qb){return new F(function(){return A(_q9,[[1,_qb]]);});}))]:[2];};},_qc=function(_qd){return [0,B(_q8(_qd))];},_qe=function(_qf){return new F(function(){return _oS(_pl,function(_qg){return [1,B(_oi(_qc,_q4,function(_qh){return [1,B(_oi(_pU,_q6,function(_qi){return new F(function(){return A(_qf,[[5,[1,_qg,_qh,_qi]]]);});}))];}))];});});},_qj=function(_qk){return [1,B(_qe(_qk))];},_ql=new T(function(){return B(unCStr("!@#$%&*+./<=>?\\^|:-~"));}),_qm=function(_qn){return new F(function(){return _eC(_mo,_qn,_ql);});},_qo=[0,8],_qp=[0,16],_qq=function(_qr){var _qs=function(_qt){return new F(function(){return A(_qr,[[5,[0,_qo,_qt]]]);});},_qu=function(_qv){return new F(function(){return A(_qr,[[5,[0,_qp,_qv]]]);});};return function(_qw){return E(E(_qw)[1])==48?E([0,function(_qx){switch(E(E(_qx)[1])){case 79:return [1,B(_oS(_qo,_qs))];case 88:return [1,B(_oS(_qp,_qu))];case 111:return [1,B(_oS(_qo,_qs))];case 120:return [1,B(_oS(_qp,_qu))];default:return [2];}}]):[2];};},_qy=function(_qz){return [0,B(_qq(_qz))];},_qA=false,_qB=function(_qC){var _qD=new T(function(){return B(A(_qC,[_qo]));}),_qE=new T(function(){return B(A(_qC,[_qp]));});return function(_qF){switch(E(E(_qF)[1])){case 79:return E(_qD);case 88:return E(_qE);case 111:return E(_qD);case 120:return E(_qE);default:return [2];}};},_qG=function(_qH){return [0,B(_qB(_qH))];},_qI=[0,92],_qJ=function(_qK){return new F(function(){return A(_qK,[_pl]);});},_qL=function(_qM){return new F(function(){return err(B(unAppCStr("Prelude.chr: bad argument: ",new T(function(){return B(_2v(9,_qM,_d));}))));});},_qN=function(_qO){var _qP=E(_qO);return _qP[0]==0?E(_qP[1]):I_toInt(_qP[1]);},_qQ=function(_qR,_qS){var _qT=E(_qR);if(!_qT[0]){var _qU=_qT[1],_qV=E(_qS);return _qV[0]==0?_qU<=_qV[1]:I_compareInt(_qV[1],_qU)>=0;}else{var _qW=_qT[1],_qX=E(_qS);return _qX[0]==0?I_compareInt(_qW,_qX[1])<=0:I_compare(_qW,_qX[1])<=0;}},_qY=function(_qZ){return [2];},_r0=function(_r1){var _r2=E(_r1);if(!_r2[0]){return E(_qY);}else{var _r3=_r2[1],_r4=E(_r2[2]);return _r4[0]==0?E(_r3):function(_r5){return new F(function(){return _nw(B(A(_r3,[_r5])),new T(function(){return B(A(new T(function(){return B(_r0(_r4));}),[_r5]));}));});};}},_r6=function(_r7){return [2];},_r8=function(_r9,_ra){var _rb=function(_rc,_rd){var _re=E(_rc);if(!_re[0]){return function(_rf){return new F(function(){return A(_rf,[_r9]);});};}else{var _rg=E(_rd);return _rg[0]==0?E(_r6):E(_re[1])[1]!=E(_rg[1])[1]?E(_r6):function(_rh){return [0,function(_ri){return E(new T(function(){return B(A(new T(function(){return B(_rb(_re[2],_rg[2]));}),[_rh]));}));}];};}};return function(_rj){return new F(function(){return A(_rb,[_r9,_rj,_ra]);});};},_rk=new T(function(){return B(unCStr("SOH"));}),_rl=[0,1],_rm=function(_rn){return [1,B(_r8(_rk,function(_ro){return E(new T(function(){return B(A(_rn,[_rl]));}));}))];},_rp=new T(function(){return B(unCStr("SO"));}),_rq=[0,14],_rr=function(_rs){return [1,B(_r8(_rp,function(_rt){return E(new T(function(){return B(A(_rs,[_rq]));}));}))];},_ru=function(_rv){return [1,B(_oi(_rm,_rr,_rv))];},_rw=new T(function(){return B(unCStr("NUL"));}),_rx=[0,0],_ry=function(_rz){return [1,B(_r8(_rw,function(_rA){return E(new T(function(){return B(A(_rz,[_rx]));}));}))];},_rB=new T(function(){return B(unCStr("STX"));}),_rC=[0,2],_rD=function(_rE){return [1,B(_r8(_rB,function(_rF){return E(new T(function(){return B(A(_rE,[_rC]));}));}))];},_rG=new T(function(){return B(unCStr("ETX"));}),_rH=[0,3],_rI=function(_rJ){return [1,B(_r8(_rG,function(_rK){return E(new T(function(){return B(A(_rJ,[_rH]));}));}))];},_rL=new T(function(){return B(unCStr("EOT"));}),_rM=[0,4],_rN=function(_rO){return [1,B(_r8(_rL,function(_rP){return E(new T(function(){return B(A(_rO,[_rM]));}));}))];},_rQ=new T(function(){return B(unCStr("ENQ"));}),_rR=[0,5],_rS=function(_rT){return [1,B(_r8(_rQ,function(_rU){return E(new T(function(){return B(A(_rT,[_rR]));}));}))];},_rV=new T(function(){return B(unCStr("ACK"));}),_rW=[0,6],_rX=function(_rY){return [1,B(_r8(_rV,function(_rZ){return E(new T(function(){return B(A(_rY,[_rW]));}));}))];},_s0=new T(function(){return B(unCStr("BEL"));}),_s1=[0,7],_s2=function(_s3){return [1,B(_r8(_s0,function(_s4){return E(new T(function(){return B(A(_s3,[_s1]));}));}))];},_s5=new T(function(){return B(unCStr("BS"));}),_s6=[0,8],_s7=function(_s8){return [1,B(_r8(_s5,function(_s9){return E(new T(function(){return B(A(_s8,[_s6]));}));}))];},_sa=new T(function(){return B(unCStr("HT"));}),_sb=[0,9],_sc=function(_sd){return [1,B(_r8(_sa,function(_se){return E(new T(function(){return B(A(_sd,[_sb]));}));}))];},_sf=new T(function(){return B(unCStr("LF"));}),_sg=[0,10],_sh=function(_si){return [1,B(_r8(_sf,function(_sj){return E(new T(function(){return B(A(_si,[_sg]));}));}))];},_sk=new T(function(){return B(unCStr("VT"));}),_sl=[0,11],_sm=function(_sn){return [1,B(_r8(_sk,function(_so){return E(new T(function(){return B(A(_sn,[_sl]));}));}))];},_sp=new T(function(){return B(unCStr("FF"));}),_sq=[0,12],_sr=function(_ss){return [1,B(_r8(_sp,function(_st){return E(new T(function(){return B(A(_ss,[_sq]));}));}))];},_su=new T(function(){return B(unCStr("CR"));}),_sv=[0,13],_sw=function(_sx){return [1,B(_r8(_su,function(_sy){return E(new T(function(){return B(A(_sx,[_sv]));}));}))];},_sz=new T(function(){return B(unCStr("SI"));}),_sA=[0,15],_sB=function(_sC){return [1,B(_r8(_sz,function(_sD){return E(new T(function(){return B(A(_sC,[_sA]));}));}))];},_sE=new T(function(){return B(unCStr("DLE"));}),_sF=[0,16],_sG=function(_sH){return [1,B(_r8(_sE,function(_sI){return E(new T(function(){return B(A(_sH,[_sF]));}));}))];},_sJ=new T(function(){return B(unCStr("DC1"));}),_sK=[0,17],_sL=function(_sM){return [1,B(_r8(_sJ,function(_sN){return E(new T(function(){return B(A(_sM,[_sK]));}));}))];},_sO=new T(function(){return B(unCStr("DC2"));}),_sP=[0,18],_sQ=function(_sR){return [1,B(_r8(_sO,function(_sS){return E(new T(function(){return B(A(_sR,[_sP]));}));}))];},_sT=new T(function(){return B(unCStr("DC3"));}),_sU=[0,19],_sV=function(_sW){return [1,B(_r8(_sT,function(_sX){return E(new T(function(){return B(A(_sW,[_sU]));}));}))];},_sY=new T(function(){return B(unCStr("DC4"));}),_sZ=[0,20],_t0=function(_t1){return [1,B(_r8(_sY,function(_t2){return E(new T(function(){return B(A(_t1,[_sZ]));}));}))];},_t3=new T(function(){return B(unCStr("NAK"));}),_t4=[0,21],_t5=function(_t6){return [1,B(_r8(_t3,function(_t7){return E(new T(function(){return B(A(_t6,[_t4]));}));}))];},_t8=new T(function(){return B(unCStr("SYN"));}),_t9=[0,22],_ta=function(_tb){return [1,B(_r8(_t8,function(_tc){return E(new T(function(){return B(A(_tb,[_t9]));}));}))];},_td=new T(function(){return B(unCStr("ETB"));}),_te=[0,23],_tf=function(_tg){return [1,B(_r8(_td,function(_th){return E(new T(function(){return B(A(_tg,[_te]));}));}))];},_ti=new T(function(){return B(unCStr("CAN"));}),_tj=[0,24],_tk=function(_tl){return [1,B(_r8(_ti,function(_tm){return E(new T(function(){return B(A(_tl,[_tj]));}));}))];},_tn=new T(function(){return B(unCStr("EM"));}),_to=[0,25],_tp=function(_tq){return [1,B(_r8(_tn,function(_tr){return E(new T(function(){return B(A(_tq,[_to]));}));}))];},_ts=new T(function(){return B(unCStr("SUB"));}),_tt=[0,26],_tu=function(_tv){return [1,B(_r8(_ts,function(_tw){return E(new T(function(){return B(A(_tv,[_tt]));}));}))];},_tx=new T(function(){return B(unCStr("ESC"));}),_ty=[0,27],_tz=function(_tA){return [1,B(_r8(_tx,function(_tB){return E(new T(function(){return B(A(_tA,[_ty]));}));}))];},_tC=new T(function(){return B(unCStr("FS"));}),_tD=[0,28],_tE=function(_tF){return [1,B(_r8(_tC,function(_tG){return E(new T(function(){return B(A(_tF,[_tD]));}));}))];},_tH=new T(function(){return B(unCStr("GS"));}),_tI=[0,29],_tJ=function(_tK){return [1,B(_r8(_tH,function(_tL){return E(new T(function(){return B(A(_tK,[_tI]));}));}))];},_tM=new T(function(){return B(unCStr("RS"));}),_tN=[0,30],_tO=function(_tP){return [1,B(_r8(_tM,function(_tQ){return E(new T(function(){return B(A(_tP,[_tN]));}));}))];},_tR=new T(function(){return B(unCStr("US"));}),_tS=[0,31],_tT=function(_tU){return [1,B(_r8(_tR,function(_tV){return E(new T(function(){return B(A(_tU,[_tS]));}));}))];},_tW=new T(function(){return B(unCStr("SP"));}),_tX=[0,32],_tY=function(_tZ){return [1,B(_r8(_tW,function(_u0){return E(new T(function(){return B(A(_tZ,[_tX]));}));}))];},_u1=new T(function(){return B(unCStr("DEL"));}),_u2=[0,127],_u3=function(_u4){return [1,B(_r8(_u1,function(_u5){return E(new T(function(){return B(A(_u4,[_u2]));}));}))];},_u6=[1,_u3,_d],_u7=[1,_tY,_u6],_u8=[1,_tT,_u7],_u9=[1,_tO,_u8],_ua=[1,_tJ,_u9],_ub=[1,_tE,_ua],_uc=[1,_tz,_ub],_ud=[1,_tu,_uc],_ue=[1,_tp,_ud],_uf=[1,_tk,_ue],_ug=[1,_tf,_uf],_uh=[1,_ta,_ug],_ui=[1,_t5,_uh],_uj=[1,_t0,_ui],_uk=[1,_sV,_uj],_ul=[1,_sQ,_uk],_um=[1,_sL,_ul],_un=[1,_sG,_um],_uo=[1,_sB,_un],_up=[1,_sw,_uo],_uq=[1,_sr,_up],_ur=[1,_sm,_uq],_us=[1,_sh,_ur],_ut=[1,_sc,_us],_uu=[1,_s7,_ut],_uv=[1,_s2,_uu],_uw=[1,_rX,_uv],_ux=[1,_rS,_uw],_uy=[1,_rN,_ux],_uz=[1,_rI,_uy],_uA=[1,_rD,_uz],_uB=[1,_ry,_uA],_uC=[1,_ru,_uB],_uD=new T(function(){return B(_r0(_uC));}),_uE=[0,1114111],_uF=[0,34],_uG=[0,39],_uH=function(_uI){var _uJ=new T(function(){return B(A(_uI,[_s1]));}),_uK=new T(function(){return B(A(_uI,[_s6]));}),_uL=new T(function(){return B(A(_uI,[_sb]));}),_uM=new T(function(){return B(A(_uI,[_sg]));}),_uN=new T(function(){return B(A(_uI,[_sl]));}),_uO=new T(function(){return B(A(_uI,[_sq]));}),_uP=new T(function(){return B(A(_uI,[_sv]));});return new F(function(){return _nw([0,function(_uQ){switch(E(E(_uQ)[1])){case 34:return E(new T(function(){return B(A(_uI,[_uF]));}));case 39:return E(new T(function(){return B(A(_uI,[_uG]));}));case 92:return E(new T(function(){return B(A(_uI,[_qI]));}));case 97:return E(_uJ);case 98:return E(_uK);case 102:return E(_uO);case 110:return E(_uM);case 114:return E(_uP);case 116:return E(_uL);case 118:return E(_uN);default:return [2];}}],new T(function(){return B(_nw([1,B(_oi(_qG,_qJ,function(_uR){return [1,B(_oS(_uR,function(_uS){var _uT=B(_pO(new T(function(){return B(_pE(E(_uR)[1]));}),_pD,_uS));return !B(_qQ(_uT,_uE))?[2]:B(A(_uI,[new T(function(){var _uU=B(_qN(_uT));if(_uU>>>0>1114111){var _uV=B(_qL(_uU));}else{var _uV=[0,_uU];}var _uW=_uV,_uX=_uW,_uY=_uX;return _uY;})]));}))];}))],new T(function(){return B(_nw([0,function(_uZ){return E(E(_uZ)[1])==94?E([0,function(_v0){switch(E(E(_v0)[1])){case 64:return E(new T(function(){return B(A(_uI,[_rx]));}));case 65:return E(new T(function(){return B(A(_uI,[_rl]));}));case 66:return E(new T(function(){return B(A(_uI,[_rC]));}));case 67:return E(new T(function(){return B(A(_uI,[_rH]));}));case 68:return E(new T(function(){return B(A(_uI,[_rM]));}));case 69:return E(new T(function(){return B(A(_uI,[_rR]));}));case 70:return E(new T(function(){return B(A(_uI,[_rW]));}));case 71:return E(_uJ);case 72:return E(_uK);case 73:return E(_uL);case 74:return E(_uM);case 75:return E(_uN);case 76:return E(_uO);case 77:return E(_uP);case 78:return E(new T(function(){return B(A(_uI,[_rq]));}));case 79:return E(new T(function(){return B(A(_uI,[_sA]));}));case 80:return E(new T(function(){return B(A(_uI,[_sF]));}));case 81:return E(new T(function(){return B(A(_uI,[_sK]));}));case 82:return E(new T(function(){return B(A(_uI,[_sP]));}));case 83:return E(new T(function(){return B(A(_uI,[_sU]));}));case 84:return E(new T(function(){return B(A(_uI,[_sZ]));}));case 85:return E(new T(function(){return B(A(_uI,[_t4]));}));case 86:return E(new T(function(){return B(A(_uI,[_t9]));}));case 87:return E(new T(function(){return B(A(_uI,[_te]));}));case 88:return E(new T(function(){return B(A(_uI,[_tj]));}));case 89:return E(new T(function(){return B(A(_uI,[_to]));}));case 90:return E(new T(function(){return B(A(_uI,[_tt]));}));case 91:return E(new T(function(){return B(A(_uI,[_ty]));}));case 92:return E(new T(function(){return B(A(_uI,[_tD]));}));case 93:return E(new T(function(){return B(A(_uI,[_tI]));}));case 94:return E(new T(function(){return B(A(_uI,[_tN]));}));case 95:return E(new T(function(){return B(A(_uI,[_tS]));}));default:return [2];}}]):[2];}],new T(function(){return B(A(_uD,[_uI]));})));})));}));});},_v1=function(_v2){return new F(function(){return A(_v2,[_iG]);});},_v3=function(_v4){var _v5=E(_v4);if(!_v5[0]){return E(_v1);}else{var _v6=_v5[2],_v7=E(E(_v5[1])[1]);switch(_v7){case 9:return function(_v8){return [0,function(_v9){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_v8]));}));}];};case 10:return function(_va){return [0,function(_vb){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_va]));}));}];};case 11:return function(_vc){return [0,function(_vd){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_vc]));}));}];};case 12:return function(_ve){return [0,function(_vf){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_ve]));}));}];};case 13:return function(_vg){return [0,function(_vh){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_vg]));}));}];};case 32:return function(_vi){return [0,function(_vj){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_vi]));}));}];};case 160:return function(_vk){return [0,function(_vl){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_vk]));}));}];};default:var _vm=u_iswspace(_v7),_vn=_vm;return E(_vn)==0?E(_v1):function(_vo){return [0,function(_vp){return E(new T(function(){return B(A(new T(function(){return B(_v3(_v6));}),[_vo]));}));}];};}}},_vq=function(_vr){var _vs=new T(function(){return B(_vq(_vr));}),_vt=[1,function(_vu){return new F(function(){return A(_v3,[_vu,function(_vv){return E([0,function(_vw){return E(E(_vw)[1])==92?E(_vs):[2];}]);}]);});}];return new F(function(){return _nw([0,function(_vx){return E(E(_vx)[1])==92?E([0,function(_vy){var _vz=E(E(_vy)[1]);switch(_vz){case 9:return E(_vt);case 10:return E(_vt);case 11:return E(_vt);case 12:return E(_vt);case 13:return E(_vt);case 32:return E(_vt);case 38:return E(_vs);case 160:return E(_vt);default:var _vA=u_iswspace(_vz),_vB=_vA;return E(_vB)==0?[2]:E(_vt);}}]):[2];}],[0,function(_vC){var _vD=E(_vC);return E(_vD[1])==92?E(new T(function(){return B(_uH(function(_vE){return new F(function(){return A(_vr,[[0,_vE,_eX]]);});}));})):B(A(_vr,[[0,_vD,_qA]]));}]);});},_vF=function(_vG,_vH){return new F(function(){return _vq(function(_vI){var _vJ=E(_vI),_vK=E(_vJ[1]);if(E(_vK[1])==34){if(!E(_vJ[2])){return E(new T(function(){return B(A(_vH,[[1,new T(function(){return B(A(_vG,[_d]));})]]));}));}else{return new F(function(){return _vF(function(_vL){return new F(function(){return A(_vG,[[1,_vK,_vL]]);});},_vH);});}}else{return new F(function(){return _vF(function(_vM){return new F(function(){return A(_vG,[[1,_vK,_vM]]);});},_vH);});}});});},_vN=new T(function(){return B(unCStr("_\'"));}),_vO=function(_vP){var _vQ=u_iswalnum(_vP),_vR=_vQ;return E(_vR)==0?B(_eC(_mo,[0,_vP],_vN)):true;},_vS=function(_vT){return new F(function(){return _vO(E(_vT)[1]);});},_vU=new T(function(){return B(unCStr(",;()[]{}`"));}),_vV=new T(function(){return B(unCStr(".."));}),_vW=new T(function(){return B(unCStr("::"));}),_vX=new T(function(){return B(unCStr("->"));}),_vY=[0,64],_vZ=[1,_vY,_d],_w0=[0,126],_w1=[1,_w0,_d],_w2=new T(function(){return B(unCStr("=>"));}),_w3=[1,_w2,_d],_w4=[1,_w1,_w3],_w5=[1,_vZ,_w4],_w6=[1,_vX,_w5],_w7=new T(function(){return B(unCStr("<-"));}),_w8=[1,_w7,_w6],_w9=[0,124],_wa=[1,_w9,_d],_wb=[1,_wa,_w8],_wc=[1,_qI,_d],_wd=[1,_wc,_wb],_we=[0,61],_wf=[1,_we,_d],_wg=[1,_wf,_wd],_wh=[1,_vW,_wg],_wi=[1,_vV,_wh],_wj=function(_wk){return new F(function(){return _nw([1,function(_wl){return E(_wl)[0]==0?E(new T(function(){return B(A(_wk,[_oP]));})):[2];}],new T(function(){return B(_nw([0,function(_wm){return E(E(_wm)[1])==39?E([0,function(_wn){var _wo=E(_wn);switch(E(_wo[1])){case 39:return [2];case 92:return E(new T(function(){return B(_uH(function(_wp){return [0,function(_wq){return E(E(_wq)[1])==39?E(new T(function(){return B(A(_wk,[[0,_wp]]));})):[2];}];}));}));default:return [0,function(_wr){return E(E(_wr)[1])==39?E(new T(function(){return B(A(_wk,[[0,_wo]]));})):[2];}];}}]):[2];}],new T(function(){return B(_nw([0,function(_ws){return E(E(_ws)[1])==34?E(new T(function(){return B(_vF(_jE,_wk));})):[2];}],new T(function(){return B(_nw([0,function(_wt){return !B(_eC(_mo,_wt,_vU))?[2]:B(A(_wk,[[2,[1,_wt,_d]]]));}],new T(function(){return B(_nw([0,function(_wu){return !B(_eC(_mo,_wu,_ql))?[2]:[1,B(_oE(_qm,function(_wv){var _ww=[1,_wu,_wv];return !B(_eC(_mx,_ww,_wi))?B(A(_wk,[[4,_ww]])):B(A(_wk,[[2,_ww]]));}))];}],new T(function(){return B(_nw([0,function(_wx){var _wy=E(_wx),_wz=_wy[1],_wA=u_iswalpha(_wz),_wB=_wA;return E(_wB)==0?E(_wz)==95?[1,B(_oE(_vS,function(_wC){return new F(function(){return A(_wk,[[3,[1,_wy,_wC]]]);});}))]:[2]:[1,B(_oE(_vS,function(_wD){return new F(function(){return A(_wk,[[3,[1,_wy,_wD]]]);});}))];}],new T(function(){return [1,B(_oi(_qy,_qj,_wk))];})));})));})));})));})));}));});},_wE=function(_wF){return E(E(_wF)[3]);},_wG=function(_wH,_wI,_wJ){return function(_wK){return new F(function(){return A(new T(function(){return B(A(_wE,[_wH,_wJ]));}),[function(_wL){return [1,function(_wM){return new F(function(){return A(_v3,[_wM,function(_wN){return E(new T(function(){return B(_wj(function(_wO){var _wP=E(_wO);return _wP[0]==2?!B(_md(_wP[1],_mc))?[2]:E(new T(function(){return B(A(new T(function(){return B(_wE(_wI));}),[_wJ,function(_wQ){return new F(function(){return A(_wK,[[0,_wL,_wQ]]);});}]));})):[2];}));}));}]);});}];}]);});};},_wR=[0,41],_wS=[1,_wR,_d],_wT=[0,40],_wU=[1,_wT,_d],_wV=[0,0],_wW=function(_wX,_wY){return function(_wZ){return new F(function(){return A(_v3,[_wZ,function(_x0){return E(new T(function(){return B(_wj(function(_x1){var _x2=E(_x1);return _x2[0]==2?!B(_md(_x2[1],_wU))?[2]:E(new T(function(){return B(A(_wX,[_wV,function(_x3){return [1,function(_x4){return new F(function(){return A(_v3,[_x4,function(_x5){return E(new T(function(){return B(_wj(function(_x6){var _x7=E(_x6);return _x7[0]==2?!B(_md(_x7[1],_wS))?[2]:E(new T(function(){return B(A(_wY,[_x3]));})):[2];}));}));}]);});}];}]));})):[2];}));}));}]);});};},_x8=function(_x9,_xa){var _xb=function(_xc){return new F(function(){return _nw([1,B(_wW(_x9,_xc))],new T(function(){return [1,B(_wW(function(_xd,_xe){return new F(function(){return _xb(_xe);});},_xc))];}));});};return new F(function(){return _xb(_xa);});},_xf=function(_xg,_xh,_xi,_xj){return new F(function(){return _x8(function(_xk){return new F(function(){return _wG(_xg,_xh,_xk);});},_xj);});},_xl=[0,91],_xm=[1,_xl,_d],_xn=function(_xo,_xp){var _xq=function(_xr,_xs){return [1,function(_xt){return new F(function(){return A(_v3,[_xt,function(_xu){return E(new T(function(){return B(_wj(function(_xv){var _xw=E(_xv);if(_xw[0]==2){var _xx=E(_xw[1]);if(!_xx[0]){return [2];}else{var _xy=_xx[2];switch(E(E(_xx[1])[1])){case 44:return E(_xy)[0]==0?!E(_xr)?[2]:E(new T(function(){return B(A(_xo,[_wV,function(_xz){return new F(function(){return _xq(_eX,function(_xA){return new F(function(){return A(_xs,[[1,_xz,_xA]]);});});});}]));})):[2];case 93:return E(_xy)[0]==0?E(new T(function(){return B(A(_xs,[_d]));})):[2];default:return [2];}}}else{return [2];}}));}));}]);});}];},_xB=function(_xC){return new F(function(){return _nw([1,function(_xD){return new F(function(){return A(_v3,[_xD,function(_xE){return E(new T(function(){return B(_wj(function(_xF){var _xG=E(_xF);return _xG[0]==2?!B(_md(_xG[1],_xm))?[2]:E(new T(function(){return B(_nw(B(_xq(_qA,_xC)),new T(function(){return B(A(_xo,[_wV,function(_xH){return new F(function(){return _xq(_eX,function(_xI){return new F(function(){return A(_xC,[[1,_xH,_xI]]);});});});}]));})));})):[2];}));}));}]);});}],new T(function(){return [1,B(_wW(function(_xJ,_xK){return new F(function(){return _xB(_xK);});},_xC))];}));});};return new F(function(){return _xB(_xp);});},_xL=function(_xM,_xN,_xO,_xP){return new F(function(){return _xn(function(_xQ,_xk){return new F(function(){return _xf(_xM,_xN,_xQ,_xk);});},_xP);});},_xR=function(_xS,_xT){return function(_oB){return new F(function(){return _nm(new T(function(){return B(_xn(function(_xQ,_xk){return new F(function(){return _xf(_xS,_xT,_xQ,_xk);});},_ob));}),_oB);});};},_xU=function(_xV,_xW,_xX){return function(_oB){return new F(function(){return _nm(new T(function(){return B(_x8(function(_xk){return new F(function(){return _wG(_xV,_xW,_xk);});},_ob));}),_oB);});};},_xY=function(_xZ,_y0){return [0,function(_xk){return new F(function(){return _xU(_xZ,_y0,_xk);});},new T(function(){return B(_xR(_xZ,_y0));}),function(_xQ,_xk){return new F(function(){return _xf(_xZ,_y0,_xQ,_xk);});},function(_xQ,_xk){return new F(function(){return _xL(_xZ,_y0,_xQ,_xk);});}];},_y1=function(_y2,_y3,_y4){var _y5=function(_y6,_y7){return new F(function(){return _nw([1,function(_y8){return new F(function(){return A(_v3,[_y8,function(_y9){return E(new T(function(){return B(_wj(function(_ya){var _yb=E(_ya);if(_yb[0]==4){var _yc=E(_yb[1]);if(!_yc[0]){return new F(function(){return A(_y2,[_yb,_y6,_y7]);});}else{return E(E(_yc[1])[1])==45?E(_yc[2])[0]==0?E([1,function(_yd){return new F(function(){return A(_v3,[_yd,function(_ye){return E(new T(function(){return B(_wj(function(_yf){return new F(function(){return A(_y2,[_yf,_y6,function(_yg){return new F(function(){return A(_y7,[new T(function(){return [0, -E(_yg)[1]];})]);});}]);});}));}));}]);});}]):B(A(_y2,[_yb,_y6,_y7])):B(A(_y2,[_yb,_y6,_y7]));}}else{return new F(function(){return A(_y2,[_yb,_y6,_y7]);});}}));}));}]);});}],new T(function(){return [1,B(_wW(_y5,_y7))];}));});};return new F(function(){return _y5(_y3,_y4);});},_yh=function(_yi,_yj){return [2];},_yk=function(_yl){var _ym=E(_yl);return _ym[0]==0?[1,new T(function(){return B(_pO(new T(function(){return B(_pE(E(_ym[1])[1]));}),_pD,_ym[2]));})]:E(_ym[2])[0]==0?E(_ym[3])[0]==0?[1,new T(function(){return B(_pO(_pC,_pD,_ym[1]));})]:[0]:[0];},_yn=function(_yo){var _yp=E(_yo);if(_yp[0]==5){var _yq=B(_yk(_yp[1]));return _yq[0]==0?E(_yh):function(_yr,_ys){return new F(function(){return A(_ys,[new T(function(){return [0,B(_qN(_yq[1]))];})]);});};}else{return E(_yh);}},_yt=function(_xQ,_xk){return new F(function(){return _y1(_yn,_xQ,_xk);});},_yu=function(_yv,_yw){return new F(function(){return _xn(_yt,_yw);});},_yx=function(_yy){return function(_oB){return new F(function(){return _nm(new T(function(){return B(_y1(_yn,_yy,_ob));}),_oB);});};},_yz=new T(function(){return B(_xn(_yt,_ob));}),_yA=function(_xk){return new F(function(){return _nm(_yz,_xk);});},_yB=[0,_yx,_yA,_yt,_yu],_yC=new T(function(){return B(_xY(_yB,_yB));}),_yD=new T(function(){return B(unCStr("Ring"));}),_yE=new T(function(){return B(unCStr("Marker"));}),_yF=[0,11],_yG=function(_yH,_yI){return new F(function(){return A(_yI,[_d4]);});},_yJ=[1,_1Z,_d],_yK=[0,_yJ,_yG],_yL=function(_yM,_yN){return new F(function(){return A(_yN,[_d6]);});},_yO=[1,_1Y,_d],_yP=[0,_yO,_yL],_yQ=[1,_yP,_d],_yR=[1,_yK,_yQ],_yS=function(_yT,_yU,_yV){var _yW=E(_yT);if(!_yW[0]){return [2];}else{var _yX=E(_yW[1]),_yY=_yX[1],_yZ=new T(function(){return B(A(_yX[2],[_yU,_yV]));});return new F(function(){return _nw([1,function(_z0){return new F(function(){return A(_v3,[_z0,function(_z1){return E(new T(function(){return B(_wj(function(_z2){var _z3=E(_z2);switch(_z3[0]){case 3:return !B(_md(_yY,_z3[1]))?[2]:E(_yZ);case 4:return !B(_md(_yY,_z3[1]))?[2]:E(_yZ);default:return [2];}}));}));}]);});}],new T(function(){return B(_yS(_yW[2],_yU,_yV));}));});}},_z4=function(_z5,_z6){return new F(function(){return _yS(_yR,_z5,_z6);});},_z7=function(_z8,_z9){var _za=function(_zb){return function(_zc){return new F(function(){return _nw(B(A(new T(function(){return B(A(_z8,[_zb]));}),[_zc])),new T(function(){return [1,B(_wW(_za,_zc))];}));});};};return new F(function(){return _za(_z9);});},_zd=function(_ze,_zf){var _zg=new T(function(){if(_ze>10){var _zh=[2];}else{var _zh=[1,function(_zi){return new F(function(){return A(_v3,[_zi,function(_zj){return E(new T(function(){return B(_wj(function(_zk){var _zl=E(_zk);return _zl[0]==3?!B(_md(_zl[1],_yE))?[2]:E(new T(function(){return B(A(_z7,[_z4,_yF,function(_zm){return new F(function(){return A(_zf,[[1,_zm]]);});}]));})):[2];}));}));}]);});}];}var _zn=_zh;return _zn;});if(_ze>10){return new F(function(){return _nw(_oa,_zg);});}else{return new F(function(){return _nw([1,function(_zo){return new F(function(){return A(_v3,[_zo,function(_zp){return E(new T(function(){return B(_wj(function(_zq){var _zr=E(_zq);return _zr[0]==3?!B(_md(_zr[1],_yD))?[2]:E(new T(function(){return B(A(_z7,[_z4,_yF,function(_zs){return new F(function(){return A(_zf,[[0,_zs]]);});}]));})):[2];}));}));}]);});}],_zg);});}},_zt=function(_zu,_zv){return new F(function(){return _zd(E(_zu)[1],_zv);});},_zw=function(_2j){return new F(function(){return _z7(_zt,_2j);});},_zx=function(_zy,_zz){return new F(function(){return _xn(_zw,_zz);});},_zA=new T(function(){return B(_xn(_zw,_ob));}),_zB=function(_2j){return new F(function(){return _nm(_zA,_2j);});},_zC=function(_zD){return function(_oB){return new F(function(){return _nm(new T(function(){return B(A(_z7,[_zt,_zD,_ob]));}),_oB);});};},_zE=[0,_zC,_zB,_zw,_zx],_zF=new T(function(){return B(unCStr("fromList"));}),_zG=function(_zH,_zI,_zJ,_zK){var _zL=E(_zI),_zM=E(_zK);if(!_zM[0]){var _zN=_zM[2],_zO=_zM[3],_zP=_zM[4],_zQ=_zM[5];switch(B(A(_kY,[_zH,_zL,_zN]))){case 0:return new F(function(){return _7M(_zN,_zO,B(_zG(_zH,_zL,_zJ,_zP)),_zQ);});break;case 1:return [0,_zM[1],E(_zL),_zJ,E(_zP),E(_zQ)];default:return new F(function(){return _8t(_zN,_zO,_zP,B(_zG(_zH,_zL,_zJ,_zQ)));});}}else{return [0,1,E(_zL),_zJ,E(_7H),E(_7H)];}},_zR=function(_zS,_zT,_zU,_zV){return new F(function(){return _zG(_zS,_zT,_zU,_zV);});},_zW=function(_zX,_zY,_zZ){return new F(function(){return (function(_A0,_A1){while(1){var _A2=E(_A1);if(!_A2[0]){return E(_A0);}else{var _A3=E(_A2[1]),_A4=B(_zR(_zX,_A3[1],_A3[2],_A0));_A1=_A2[2];_A0=_A4;continue;}}})(_zY,_zZ);});},_A5=function(_A6,_A7){return [0,1,E(E(_A6)),_A7,E(_7H),E(_7H)];},_A8=function(_A9,_Aa,_Ab){var _Ac=E(_Ab);if(!_Ac[0]){return new F(function(){return _8t(_Ac[2],_Ac[3],_Ac[4],B(_A8(_A9,_Aa,_Ac[5])));});}else{return new F(function(){return _A5(_A9,_Aa);});}},_Ad=function(_Ae,_Af,_Ag){var _Ah=E(_Ag);if(!_Ah[0]){return new F(function(){return _7M(_Ah[2],_Ah[3],B(_Ad(_Ae,_Af,_Ah[4])),_Ah[5]);});}else{return new F(function(){return _A5(_Ae,_Af);});}},_Ai=function(_Aj,_Ak,_Al,_Am,_An,_Ao,_Ap){return new F(function(){return _7M(_Am,_An,B(_Ad(_Aj,_Ak,_Ao)),_Ap);});},_Aq=function(_Ar,_As,_At,_Au,_Av,_Aw,_Ax,_Ay){var _Az=E(_At);if(!_Az[0]){var _AA=_Az[1],_AB=_Az[2],_AC=_Az[3],_AD=_Az[4],_AE=_Az[5];if((imul(3,_AA)|0)>=_Au){if((imul(3,_Au)|0)>=_AA){return [0,(_AA+_Au|0)+1|0,E(E(_Ar)),_As,E(_Az),E([0,_Au,E(_Av),_Aw,E(_Ax),E(_Ay)])];}else{return new F(function(){return _8t(_AB,_AC,_AD,B(_Aq(_Ar,_As,_AE,_Au,_Av,_Aw,_Ax,_Ay)));});}}else{return new F(function(){return _7M(_Av,_Aw,B(_AF(_Ar,_As,_AA,_AB,_AC,_AD,_AE,_Ax)),_Ay);});}}else{return new F(function(){return _Ai(_Ar,_As,_Au,_Av,_Aw,_Ax,_Ay);});}},_AF=function(_AG,_AH,_AI,_AJ,_AK,_AL,_AM,_AN){var _AO=E(_AN);if(!_AO[0]){var _AP=_AO[1],_AQ=_AO[2],_AR=_AO[3],_AS=_AO[4],_AT=_AO[5];if((imul(3,_AI)|0)>=_AP){if((imul(3,_AP)|0)>=_AI){return [0,(_AI+_AP|0)+1|0,E(E(_AG)),_AH,E([0,_AI,E(_AJ),_AK,E(_AL),E(_AM)]),E(_AO)];}else{return new F(function(){return _8t(_AJ,_AK,_AL,B(_Aq(_AG,_AH,_AM,_AP,_AQ,_AR,_AS,_AT)));});}}else{return new F(function(){return _7M(_AQ,_AR,B(_AF(_AG,_AH,_AI,_AJ,_AK,_AL,_AM,_AS)),_AT);});}}else{return new F(function(){return _A8(_AG,_AH,[0,_AI,E(_AJ),_AK,E(_AL),E(_AM)]);});}},_AU=function(_AV,_AW,_AX,_AY){var _AZ=E(_AX);if(!_AZ[0]){var _B0=_AZ[1],_B1=_AZ[2],_B2=_AZ[3],_B3=_AZ[4],_B4=_AZ[5],_B5=E(_AY);if(!_B5[0]){var _B6=_B5[1],_B7=_B5[2],_B8=_B5[3],_B9=_B5[4],_Ba=_B5[5];if((imul(3,_B0)|0)>=_B6){if((imul(3,_B6)|0)>=_B0){return [0,(_B0+_B6|0)+1|0,E(E(_AV)),_AW,E(_AZ),E(_B5)];}else{return new F(function(){return _8t(_B1,_B2,_B3,B(_Aq(_AV,_AW,_B4,_B6,_B7,_B8,_B9,_Ba)));});}}else{return new F(function(){return _7M(_B7,_B8,B(_AF(_AV,_AW,_B0,_B1,_B2,_B3,_B4,_B9)),_Ba);});}}else{return new F(function(){return _A8(_AV,_AW,_AZ);});}}else{return new F(function(){return _Ad(_AV,_AW,_AY);});}},_Bb=function(_Bc,_Bd){var _Be=new T(function(){return B(_kH(_Bc));}),_Bf=E(_Bd);if(!_Bf[0]){return [1];}else{var _Bg=E(_Bf[1]),_Bh=_Bg[1],_Bi=_Bg[2],_Bj=E(_Bf[2]);if(!_Bj[0]){return [0,1,E(E(_Bh)),_Bi,E(_7H),E(_7H)];}else{var _Bk=E(_Bj[1]),_Bl=_Bk[1];if(!B(A(_kH,[_Bc,_Bh,_Bl]))){var _Bm=function(_Bn,_Bo,_Bp,_Bq){var _Br=E(_Bn);if(_Br==1){var _Bs=E(_Bq);return _Bs[0]==0?[0,new T(function(){return [0,1,E(E(_Bo)),_Bp,E(_7H),E(_7H)];}),_d,_d]:!B(A(_Be,[_Bo,E(_Bs[1])[1]]))?[0,new T(function(){return [0,1,E(E(_Bo)),_Bp,E(_7H),E(_7H)];}),_Bs,_d]:[0,new T(function(){return [0,1,E(E(_Bo)),_Bp,E(_7H),E(_7H)];}),_d,_Bs];}else{var _Bt=B(_Bm(_Br>>1,_Bo,_Bp,_Bq)),_Bu=_Bt[1],_Bv=_Bt[3],_Bw=E(_Bt[2]);if(!_Bw[0]){return [0,_Bu,_d,_Bv];}else{var _Bx=E(_Bw[1]),_By=_Bx[1],_Bz=_Bx[2],_BA=E(_Bw[2]);if(!_BA[0]){return [0,new T(function(){return B(_A8(_By,_Bz,_Bu));}),_d,_Bv];}else{var _BB=E(_BA[1]),_BC=_BB[1];if(!B(A(_Be,[_By,_BC]))){var _BD=B(_Bm(_Br>>1,_BC,_BB[2],_BA[2]));return [0,new T(function(){return B(_AU(_By,_Bz,_Bu,_BD[1]));}),_BD[2],_BD[3]];}else{return [0,_Bu,_d,_Bw];}}}}};return new F(function(){return (function(_BE,_BF,_BG,_BH,_BI){var _BJ=E(_BI);if(!_BJ[0]){return new F(function(){return _A8(_BG,_BH,_BF);});}else{var _BK=E(_BJ[1]),_BL=_BK[1];if(!B(A(_Be,[_BG,_BL]))){var _BM=B(_Bm(_BE,_BL,_BK[2],_BJ[2])),_BN=_BM[1],_BO=E(_BM[3]);if(!_BO[0]){return new F(function(){return (function(_BP,_BQ,_BR){while(1){var _BS=E(_BR);if(!_BS[0]){return E(_BQ);}else{var _BT=E(_BS[1]),_BU=_BT[1],_BV=_BT[2],_BW=E(_BS[2]);if(!_BW[0]){return new F(function(){return _A8(_BU,_BV,_BQ);});}else{var _BX=E(_BW[1]),_BY=_BX[1];if(!B(A(_Be,[_BU,_BY]))){var _BZ=B(_Bm(_BP,_BY,_BX[2],_BW[2])),_C0=_BZ[1],_C1=E(_BZ[3]);if(!_C1[0]){var _C2=_BP<<1,_C3=B(_AU(_BU,_BV,_BQ,_C0));_BR=_BZ[2];_BP=_C2;_BQ=_C3;continue;}else{return new F(function(){return _zW(_Bc,B(_AU(_BU,_BV,_BQ,_C0)),_C1);});}}else{return new F(function(){return _zW(_Bc,_BQ,_BS);});}}}}})(_BE<<1,B(_AU(_BG,_BH,_BF,_BN)),_BM[2]);});}else{return new F(function(){return _zW(_Bc,B(_AU(_BG,_BH,_BF,_BN)),_BO);});}}else{return new F(function(){return _zW(_Bc,_BF,[1,[0,_BG,_BH],_BJ]);});}}})(1,[0,1,E(E(_Bh)),_Bi,E(_7H),E(_7H)],_Bl,_Bk[2],_Bj[2]);});}else{return new F(function(){return _zW(_Bc,[0,1,E(E(_Bh)),_Bi,E(_7H),E(_7H)],_Bj);});}}}},_C4=function(_C5,_C6,_C7,_C8){return new F(function(){return _z7(function(_C9){return E(_C9)[1]>10?E(_qY):function(_Ca){return [1,function(_Cb){return new F(function(){return A(_v3,[_Cb,function(_Cc){return E(new T(function(){return B(_wj(function(_Cd){var _Ce=E(_Cd);return _Ce[0]==3?!B(_md(_Ce[1],_zF))?[2]:E(new T(function(){return B(_xn(function(_Cf,_Cg){return new F(function(){return _xf(_C6,_C7,_Cf,_Cg);});},function(_Ch){return new F(function(){return A(_Ca,[new T(function(){return B(_Bb(_C5,_Ch));})]);});}));})):[2];}));}));}]);});}];};},_C8);});},_Ci=[0,123],_Cj=[1,_Ci,_d],_Ck=new T(function(){return B(unCStr("bmap"));}),_Cl=new T(function(){return B(unCStr("Board"));}),_Cm=new T(function(){return B(unCStr("markersW"));}),_Cn=new T(function(){return B(unCStr("markersB"));}),_Co=new T(function(){return B(unCStr("ringsW"));}),_Cp=new T(function(){return B(unCStr("ringsB"));}),_Cq=[1,_20,_d],_Cr=function(_2j){return new F(function(){return _wG(_yB,_yB,_2j);});},_Cs=function(_Ct,_Cu){return new F(function(){return _x8(_Cr,_Cu);});},_Cv=[0,61],_Cw=[1,_Cv,_d],_Cx=[0,44],_Cy=[1,_Cx,_d],_Cz=function(_CA,_CB){return _CA>11?[2]:[1,function(_CC){return new F(function(){return A(_v3,[_CC,function(_CD){return E(new T(function(){return B(_wj(function(_CE){var _CF=E(_CE);return _CF[0]==3?!B(_md(_CF[1],_Cl))?[2]:E([1,function(_CG){return new F(function(){return A(_v3,[_CG,function(_CH){return E(new T(function(){return B(_wj(function(_CI){var _CJ=E(_CI);return _CJ[0]==2?!B(_md(_CJ[1],_Cj))?[2]:E([1,function(_CK){return new F(function(){return A(_v3,[_CK,function(_CL){return E(new T(function(){return B(_wj(function(_CM){var _CN=E(_CM);return _CN[0]==3?!B(_md(_CN[1],_Ck))?[2]:E([1,function(_CO){return new F(function(){return A(_v3,[_CO,function(_CP){return E(new T(function(){return B(_wj(function(_CQ){var _CR=E(_CQ);return _CR[0]==2?!B(_md(_CR[1],_Cw))?[2]:E(new T(function(){return B(A(_C4,[_ma,_yC,_zE,_wV,function(_CS){return [1,function(_CT){return new F(function(){return A(_v3,[_CT,function(_CU){return E(new T(function(){return B(_wj(function(_CV){var _CW=E(_CV);return _CW[0]==2?!B(_md(_CW[1],_Cy))?[2]:E([1,function(_CX){return new F(function(){return A(_v3,[_CX,function(_CY){return E(new T(function(){return B(_wj(function(_CZ){var _D0=E(_CZ);return _D0[0]==3?!B(_md(_D0[1],_Cp))?[2]:E([1,function(_D1){return new F(function(){return A(_v3,[_D1,function(_D2){return E(new T(function(){return B(_wj(function(_D3){var _D4=E(_D3);return _D4[0]==2?!B(_md(_D4[1],_Cw))?[2]:E(new T(function(){return B(_xn(_Cs,function(_D5){return [1,function(_D6){return new F(function(){return A(_v3,[_D6,function(_D7){return E(new T(function(){return B(_wj(function(_D8){var _D9=E(_D8);return _D9[0]==2?!B(_md(_D9[1],_Cy))?[2]:E([1,function(_Da){return new F(function(){return A(_v3,[_Da,function(_Db){return E(new T(function(){return B(_wj(function(_Dc){var _Dd=E(_Dc);return _Dd[0]==3?!B(_md(_Dd[1],_Co))?[2]:E([1,function(_De){return new F(function(){return A(_v3,[_De,function(_Df){return E(new T(function(){return B(_wj(function(_Dg){var _Dh=E(_Dg);return _Dh[0]==2?!B(_md(_Dh[1],_Cw))?[2]:E(new T(function(){return B(_xn(_Cs,function(_Di){return [1,function(_Dj){return new F(function(){return A(_v3,[_Dj,function(_Dk){return E(new T(function(){return B(_wj(function(_Dl){var _Dm=E(_Dl);return _Dm[0]==2?!B(_md(_Dm[1],_Cy))?[2]:E([1,function(_Dn){return new F(function(){return A(_v3,[_Dn,function(_Do){return E(new T(function(){return B(_wj(function(_Dp){var _Dq=E(_Dp);return _Dq[0]==3?!B(_md(_Dq[1],_Cn))?[2]:E([1,function(_Dr){return new F(function(){return A(_v3,[_Dr,function(_Ds){return E(new T(function(){return B(_wj(function(_Dt){var _Du=E(_Dt);return _Du[0]==2?!B(_md(_Du[1],_Cw))?[2]:E(new T(function(){return B(_xn(_Cs,function(_Dv){return [1,function(_Dw){return new F(function(){return A(_v3,[_Dw,function(_Dx){return E(new T(function(){return B(_wj(function(_Dy){var _Dz=E(_Dy);return _Dz[0]==2?!B(_md(_Dz[1],_Cy))?[2]:E([1,function(_DA){return new F(function(){return A(_v3,[_DA,function(_DB){return E(new T(function(){return B(_wj(function(_DC){var _DD=E(_DC);return _DD[0]==3?!B(_md(_DD[1],_Cm))?[2]:E([1,function(_DE){return new F(function(){return A(_v3,[_DE,function(_DF){return E(new T(function(){return B(_wj(function(_DG){var _DH=E(_DG);return _DH[0]==2?!B(_md(_DH[1],_Cw))?[2]:E(new T(function(){return B(_xn(_Cs,function(_DI){return [1,function(_DJ){return new F(function(){return A(_v3,[_DJ,function(_DK){return E(new T(function(){return B(_wj(function(_DL){var _DM=E(_DL);return _DM[0]==2?!B(_md(_DM[1],_Cq))?[2]:E(new T(function(){return B(A(_CB,[[0,_CS,_D5,_Di,_Dv,_DI]]));})):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}]));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];},_DN=function(_DO,_DP){return new F(function(){return _Cz(E(_DO)[1],_DP);});},_DQ=[0],_DR=function(_DS,_DT){return new F(function(){return A(_DT,[_DQ]);});},_DU=[0,_2k,_DR],_DV=function(_DW,_DX){return new F(function(){return A(_DX,[_ex]);});},_DY=[0,_2h,_DV],_DZ=[6],_E0=function(_E1,_E2){return new F(function(){return A(_E2,[_DZ]);});},_E3=[0,_2m,_E0],_E4=[1,_E3,_d],_E5=[1,_DY,_E4],_E6=[1,_DU,_E5],_E7=new T(function(){return B(unCStr("WaitRemoveRun"));}),_E8=new T(function(){return B(unCStr("RemoveRing"));}),_E9=new T(function(){return B(unCStr("RemoveRun"));}),_Ea=new T(function(){return B(unCStr("MoveRing"));}),_Eb=function(_Ec,_Ed){return new F(function(){return _nw(B(_yS(_E6,_Ec,_Ed)),new T(function(){var _Ee=E(_Ec)[1],_Ef=new T(function(){var _Eg=new T(function(){var _Eh=new T(function(){if(_Ee>10){var _Ei=[2];}else{var _Ei=[1,function(_Ej){return new F(function(){return A(_v3,[_Ej,function(_Ek){return E(new T(function(){return B(_wj(function(_El){var _Em=E(_El);return _Em[0]==3?!B(_md(_Em[1],_E7))?[2]:E(new T(function(){return B(A(_z7,[_z4,_yF,function(_En){return new F(function(){return A(_Ed,[[5,_En]]);});}]));})):[2];}));}));}]);});}];}var _Eo=_Ei;return _Eo;});if(_Ee>10){var _Ep=B(_nw(_oa,_Eh));}else{var _Ep=B(_nw([1,function(_Eq){return new F(function(){return A(_v3,[_Eq,function(_Er){return E(new T(function(){return B(_wj(function(_Es){var _Et=E(_Es);return _Et[0]==3?!B(_md(_Et[1],_E8))?[2]:E(new T(function(){return B(A(_z7,[_z4,_yF,function(_Eu){return new F(function(){return A(_Ed,[[4,_Eu]]);});}]));})):[2];}));}));}]);});}],_Eh));}var _Ev=_Ep;return _Ev;});if(_Ee>10){var _Ew=B(_nw(_oa,_Eg));}else{var _Ew=B(_nw([1,function(_Ex){return new F(function(){return A(_v3,[_Ex,function(_Ey){return E(new T(function(){return B(_wj(function(_Ez){var _EA=E(_Ez);return _EA[0]==3?!B(_md(_EA[1],_E9))?[2]:E(new T(function(){return B(A(_z7,[_z4,_yF,function(_EB){return new F(function(){return A(_Ed,[[3,_EB]]);});}]));})):[2];}));}));}]);});}],_Eg));}var _EC=_Ew;return _EC;});if(_Ee>10){var _ED=B(_nw(_oa,_Ef));}else{var _ED=B(_nw([1,function(_EE){return new F(function(){return A(_v3,[_EE,function(_EF){return E(new T(function(){return B(_wj(function(_EG){var _EH=E(_EG);return _EH[0]==3?!B(_md(_EH[1],_Ea))?[2]:E(new T(function(){return B(_x8(_Cr,function(_EI){return new F(function(){return A(_Ed,[[2,_EI]]);});}));})):[2];}));}));}]);});}],_Ef));}var _EJ=_ED,_EK=_EJ;return _EK;}));});},_EL=new T(function(){return B(unCStr("activePlayer"));}),_EM=new T(function(){return B(unCStr("GameState"));}),_EN=new T(function(){return B(unCStr("board"));}),_EO=new T(function(){return B(unCStr("turnMode"));}),_EP=new T(function(){return B(unCStr("pointsW"));}),_EQ=new T(function(){return B(unCStr("pointsB"));}),_ER=function(_ES,_ET){return _ES>11?[2]:[1,function(_EU){return new F(function(){return A(_v3,[_EU,function(_EV){return E(new T(function(){return B(_wj(function(_EW){var _EX=E(_EW);return _EX[0]==3?!B(_md(_EX[1],_EM))?[2]:E([1,function(_EY){return new F(function(){return A(_v3,[_EY,function(_EZ){return E(new T(function(){return B(_wj(function(_F0){var _F1=E(_F0);return _F1[0]==2?!B(_md(_F1[1],_Cj))?[2]:E([1,function(_F2){return new F(function(){return A(_v3,[_F2,function(_F3){return E(new T(function(){return B(_wj(function(_F4){var _F5=E(_F4);return _F5[0]==3?!B(_md(_F5[1],_EL))?[2]:E([1,function(_F6){return new F(function(){return A(_v3,[_F6,function(_F7){return E(new T(function(){return B(_wj(function(_F8){var _F9=E(_F8);return _F9[0]==2?!B(_md(_F9[1],_Cw))?[2]:E(new T(function(){return B(A(_z7,[_z4,_wV,function(_Fa){return [1,function(_Fb){return new F(function(){return A(_v3,[_Fb,function(_Fc){return E(new T(function(){return B(_wj(function(_Fd){var _Fe=E(_Fd);return _Fe[0]==2?!B(_md(_Fe[1],_Cy))?[2]:E([1,function(_Ff){return new F(function(){return A(_v3,[_Ff,function(_Fg){return E(new T(function(){return B(_wj(function(_Fh){var _Fi=E(_Fh);return _Fi[0]==3?!B(_md(_Fi[1],_EO))?[2]:E([1,function(_Fj){return new F(function(){return A(_v3,[_Fj,function(_Fk){return E(new T(function(){return B(_wj(function(_Fl){var _Fm=E(_Fl);return _Fm[0]==2?!B(_md(_Fm[1],_Cw))?[2]:E(new T(function(){return B(A(_z7,[_Eb,_wV,function(_Fn){return [1,function(_Fo){return new F(function(){return A(_v3,[_Fo,function(_Fp){return E(new T(function(){return B(_wj(function(_Fq){var _Fr=E(_Fq);return _Fr[0]==2?!B(_md(_Fr[1],_Cy))?[2]:E([1,function(_Fs){return new F(function(){return A(_v3,[_Fs,function(_Ft){return E(new T(function(){return B(_wj(function(_Fu){var _Fv=E(_Fu);return _Fv[0]==3?!B(_md(_Fv[1],_EN))?[2]:E([1,function(_Fw){return new F(function(){return A(_v3,[_Fw,function(_Fx){return E(new T(function(){return B(_wj(function(_Fy){var _Fz=E(_Fy);return _Fz[0]==2?!B(_md(_Fz[1],_Cw))?[2]:E(new T(function(){return B(A(_z7,[_DN,_wV,function(_FA){return [1,function(_FB){return new F(function(){return A(_v3,[_FB,function(_FC){return E(new T(function(){return B(_wj(function(_FD){var _FE=E(_FD);return _FE[0]==2?!B(_md(_FE[1],_Cy))?[2]:E([1,function(_FF){return new F(function(){return A(_v3,[_FF,function(_FG){return E(new T(function(){return B(_wj(function(_FH){var _FI=E(_FH);return _FI[0]==3?!B(_md(_FI[1],_EQ))?[2]:E([1,function(_FJ){return new F(function(){return A(_v3,[_FJ,function(_FK){return E(new T(function(){return B(_wj(function(_FL){var _FM=E(_FL);return _FM[0]==2?!B(_md(_FM[1],_Cw))?[2]:E(new T(function(){return B(_y1(_yn,_wV,function(_FN){return [1,function(_FO){return new F(function(){return A(_v3,[_FO,function(_FP){return E(new T(function(){return B(_wj(function(_FQ){var _FR=E(_FQ);return _FR[0]==2?!B(_md(_FR[1],_Cy))?[2]:E([1,function(_FS){return new F(function(){return A(_v3,[_FS,function(_FT){return E(new T(function(){return B(_wj(function(_FU){var _FV=E(_FU);return _FV[0]==3?!B(_md(_FV[1],_EP))?[2]:E([1,function(_FW){return new F(function(){return A(_v3,[_FW,function(_FX){return E(new T(function(){return B(_wj(function(_FY){var _FZ=E(_FY);return _FZ[0]==2?!B(_md(_FZ[1],_Cw))?[2]:E(new T(function(){return B(_y1(_yn,_wV,function(_G0){return [1,function(_G1){return new F(function(){return A(_v3,[_G1,function(_G2){return E(new T(function(){return B(_wj(function(_G3){var _G4=E(_G3);return _G4[0]==2?!B(_md(_G4[1],_Cq))?[2]:E(new T(function(){return B(A(_ET,[[0,_Fa,_Fn,_FA,_FN,_G0]]));})):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}]));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}]));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];}]));})):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}]):[2];}));}));}]);});}];},_G5=function(_G6,_G7){return new F(function(){return _ER(E(_G6)[1],_G7);});},_G8=function(_G9){return [1,function(_Ga){return new F(function(){return A(_v3,[_Ga,function(_Gb){return E([3,_G9,_oa]);}]);});}];},_Gc=new T(function(){return B(A(_z7,[_G5,_wV,_G8]));}),_Gd=[0],_Ge=[0,_d4,_DQ,_jp,_28,_28],_Gf=[1,_Ge,_d],_Gg=[0,_Gf,_Gd],_Gh=function(_Gi,_Gj,_Gk,_Gl,_){var _Gm=jsPushState(_Gl),_Gn=jsTranslate(_Gl,_Gi,_Gj),_Go=B(A(_Gk,[[0,_Gl],_])),_Gp=_Go,_Gq=jsPopState(_Gl);return _iG;},_Gr=function(_Gs,_Gt,_){while(1){var _Gu=E(_Gs);if(!_Gu[0]){return _iG;}else{var _Gv=B(A(_Gu[1],[_Gt,_])),_Gw=_Gv;_Gs=_Gu[2];continue;}}},_Gx=function(_Gy,_Gz,_GA,_){var _GB=E(_Gy);return new F(function(){return _Gh(E(_GB[1])[1],E(_GB[2])[1],_Gz,E(_GA)[1],_);});},_GC=function(_GD,_GE){var _GF=E(_GD);return _GF[0]==0?[0]:[1,function(_GG,_){return new F(function(){return _Gx(_GF[1],_GE,_GG,_);});},new T(function(){return B(_GC(_GF[2],_GE));})];},_GH=[0,30],_GI=function(_GJ,_GK,_GL,_){var _GM=jsPushState(_GL),_GN=jsRotate(_GL,_GJ),_GO=B(A(_GK,[[0,_GL],_])),_GP=_GO,_GQ=jsPopState(_GL);return _iG;},_GR=function(_GS){return [0, -E(_GS)[1]];},_GT=[0,0],_GU=function(_GV,_){return _iG;},_GW=function(_GX){var _GY=E(_GX);if(!_GY[0]){return E(_GU);}else{var _GZ=E(_GY[1]);return function(_H0,_){var _H1=E(_H0)[1],_H2=jsMoveTo(_H1,E(_GZ[1])[1],E(_GZ[2])[1]);return new F(function(){return (function(_H3,_){while(1){var _H4=E(_H3);if(!_H4[0]){return _iG;}else{var _H5=E(_H4[1]),_H6=jsLineTo(_H1,E(_H5[1])[1],E(_H5[2])[1]);_H3=_H4[2];continue;}}})(_GY[2],_);});};}},_H7=function(_H8,_H9,_){var _Ha=jsBeginPath(_H9),_Hb=B(A(_H8,[[0,_H9],_])),_Hc=_Hb,_Hd=jsStroke(_H9);return _iG;},_He=function(_Hf,_Hg,_){return new F(function(){return _H7(_Hf,E(_Hg)[1],_);});},_Hh=function(_Hi){var _Hj=new T(function(){return B(_GW([1,[0,_GT,new T(function(){return B(_GR(_Hi));})],[1,[0,_GT,_Hi],_d]]));});return function(_Hk,_){var _Hl=E(_Hk)[1],_Hm=jsBeginPath(_Hl),_Hn=B(A(_Hj,[[0,_Hl],_])),_Ho=_Hn,_Hp=jsStroke(_Hl),_Hq=jsPushState(_Hl),_Hr=jsRotate(_Hl,2.0943951023931953),_Hs=jsBeginPath(_Hl),_Ht=B(A(_Hj,[[0,_Hl],_])),_Hu=_Ht,_Hv=jsStroke(_Hl),_Hw=jsPopState(_Hl);return new F(function(){return _GI(4.1887902047863905,function(_GG,_){return new F(function(){return _He(_Hj,_GG,_);});},_Hl,_);});};},_Hx=new T(function(){return B(_Hh(_GH));}),_Hy=new T(function(){return B(_GC(_6u,_Hx));}),_Hz=[1,_d6,_d],_HA=function(_HB,_){return _iG;},_HC=new T(function(){return [0,"rgb("];}),_HD=new T(function(){return [0,"rgba("];}),_HE=new T(function(){return [0,toJSStr(_d)];}),_HF=[0,41],_HG=[1,_HF,_d],_HH=new T(function(){return [0,toJSStr(_HG)];}),_HI=[1,_HH,_d],_HJ=[0,44],_HK=[1,_HJ,_d],_HL=new T(function(){return [0,toJSStr(_HK)];}),_HM=function(_HN){var _HO=String(E(_HN)[1]),_HP=_HO;return [0,_HP];},_HQ=function(_HR){var _HS=E(_HR);if(!_HS[0]){var _HT=jsCat([1,_HC,[1,new T(function(){return B(_HM(_HS[1]));}),[1,_HL,[1,new T(function(){return B(_HM(_HS[2]));}),[1,_HL,[1,new T(function(){return B(_HM(_HS[3]));}),_HI]]]]]],E(_HE)[1]),_HU=_HT;return E(_HU);}else{var _HV=jsCat([1,_HD,[1,new T(function(){return B(_HM(_HS[1]));}),[1,_HL,[1,new T(function(){return B(_HM(_HS[2]));}),[1,_HL,[1,new T(function(){return B(_HM(_HS[3]));}),[1,_HL,[1,new T(function(){return B(_HM(_HS[4]));}),_HI]]]]]]]],E(_HE)[1]),_HW=_HV;return E(_HW);}},_HX=[0,228],_HY=[0,173],_HZ=[0,38],_I0=[0,_HZ,_HY,_HX],_I1=new T(function(){return [0,"fillStyle"];}),_I2=[0,81],_I3=[0,231],_I4=[0,209],_I5=[0,_I4,_I3,_I2],_I6=function(_I7,_I8,_I9,_Ia,_){var _Ib=jsMoveTo(_Ia,_I7+_I9,_I8),_Ic=jsArc(_Ia,_I7,_I8,_I9,0,6.283185307179586);return _iG;},_Id=function(_Ie,_){return new F(function(){return _I6(0,0,20,E(_Ie)[1],_);});},_If=function(_Ig){return function(_Ih,_){var _Ii=E(_Ih)[1],_Ij=jsSet(_Ii,E(_I1)[1],E(new T(function(){if(!E(_Ig)){var _Ik=[0,B(_HQ(_I0))];}else{var _Ik=[0,B(_HQ(_I5))];}return _Ik;}))[1]),_Il=jsBeginPath(_Ii),_Im=jsMoveTo(_Ii,20,0),_In=jsArc(_Ii,0,0,20,0,6.283185307179586),_Io=jsFill(_Ii);return new F(function(){return _H7(_Id,_Ii,_);});};},_Ip=function(_Iq){return function(_Ir,_){var _Is=jsSet(E(_Ir)[1],E(_I1)[1],E(new T(function(){return [0,B(_HQ(_Iq))];}))[1]);return _iG;};},_It=[0,255],_Iu=[0,_It,_It,_It],_Iv=new T(function(){return B(_Ip(_Iu));}),_Iw=[0,22],_Ix=new T(function(){return B(_Hh(_Iw));}),_Iy=function(_Iz,_IA){return function(_IB,_){var _IC=E(_IB),_ID=_IC[1],_IE=jsSet(_ID,E(_I1)[1],E(new T(function(){if(!E(_Iz)){var _IF=[0,B(_HQ(_I0))];}else{var _IF=[0,B(_HQ(_I5))];}return _IF;}))[1]),_IG=jsBeginPath(_ID),_IH=jsMoveTo(_ID,28,0),_II=jsArc(_ID,0,0,28,0,6.283185307179586),_IJ=jsFill(_ID),_IK=jsBeginPath(_ID),_IL=jsMoveTo(_ID,28,0),_IM=jsArc(_ID,0,0,28,0,6.283185307179586),_IN=jsStroke(_ID),_IO=B(A(_Iv,[_IC,_])),_IP=_IO,_IQ=jsBeginPath(_ID),_IR=jsMoveTo(_ID,22,0),_IS=jsArc(_ID,0,0,22,0,6.283185307179586),_IT=jsFill(_ID),_IU=jsBeginPath(_ID),_IV=jsMoveTo(_ID,22,0),_IW=jsArc(_ID,0,0,22,0,6.283185307179586),_IX=jsStroke(_ID);return !E(_IA)?_iG:B(A(_Ix,[_IC,_]));};},_IY=function(_IZ){return function(_J0,_){var _J1=B(_Gr(_Hy,_J0,_)),_J2=_J1;return new F(function(){return A(new T(function(){var _J3=function(_J4){var _J5=E(_J4);if(!_J5[0]){return E(_HA);}else{var _J6=_J5[1],_J7=function(_J8,_J9,_){var _Ja=E(_J8),_Jb=60*E(_Ja[1])[1];return new F(function(){return _Gh(0.5*Math.sqrt(3)*_Jb+300, -(60*E(_Ja[2])[1])+0.5*_Jb+315,new T(function(){return B(_Iy(_J6,_eX));}),E(_J9)[1],_);});},_Jc=function(_Jd,_Je,_){var _Jf=E(_Jd),_Jg=60*E(_Jf[1])[1];return new F(function(){return _Gh(0.5*Math.sqrt(3)*_Jg+300, -(60*E(_Jf[2])[1])+0.5*_Jg+315,new T(function(){return B(_If(_J6));}),E(_Je)[1],_);});};return function(_Jh,_){var _Ji=B(A(new T(function(){if(!E(_J6)){var _Jj=function(_oB,_Jk){return new F(function(){return (function(_Jl,_Jm,_){while(1){var _Jn=E(_Jl);if(!_Jn[0]){return _iG;}else{var _Jo=B(_Jc(_Jn[1],_Jm,_)),_Jp=_Jo;_Jl=_Jn[2];continue;}}})(E(_IZ)[4],_oB,_Jk);});};}else{var _Jj=function(_oB,_Jk){return new F(function(){return (function(_Jq,_Jr,_){while(1){var _Js=E(_Jq);if(!_Js[0]){return _iG;}else{var _Jt=B(_Jc(_Js[1],_Jr,_)),_Ju=_Jt;_Jq=_Js[2];continue;}}})(E(_IZ)[5],_oB,_Jk);});};}return _Jj;}),[_Jh,_])),_Jv=_Ji,_Jw=B(A(new T(function(){if(!E(_J6)){var _Jx=function(_oB,_Jk){return new F(function(){return (function(_Jy,_Jz,_){while(1){var _JA=E(_Jy);if(!_JA[0]){return _iG;}else{var _JB=B(_J7(_JA[1],_Jz,_)),_JC=_JB;_Jy=_JA[2];continue;}}})(E(_IZ)[2],_oB,_Jk);});};}else{var _Jx=function(_oB,_Jk){return new F(function(){return (function(_JD,_JE,_){while(1){var _JF=E(_JD);if(!_JF[0]){return _iG;}else{var _JG=B(_J7(_JF[1],_JE,_)),_JH=_JG;_JD=_JF[2];continue;}}})(E(_IZ)[3],_oB,_Jk);});};}return _Jx;}),[_Jh,_])),_JI=_Jw;return new F(function(){return A(new T(function(){return B(_J3(_J5[2]));}),[_Jh,_]);});};}};return B((function(_JJ){return function(_JK,_){var _JL=B(A(new T(function(){return function(_oB,_Jk){return new F(function(){return (function(_JM,_JN,_){while(1){var _JO=E(_JM);if(!_JO[0]){return _iG;}else{var _JP=E(_JO[1]),_JQ=60*E(_JP[1])[1],_JR=E(_JN),_JS=_JR[1],_JT=jsPushState(_JS),_JU=jsTranslate(_JS,0.5*Math.sqrt(3)*_JQ+300, -(60*E(_JP[2])[1])+0.5*_JQ+315),_JV=B(A(new T(function(){return B(_If(_d4));}),[[0,_JS],_])),_JW=_JV,_JX=jsPopState(_JS);_JM=_JO[2];_JN=_JR;continue;}}})(E(_IZ)[4],_oB,_Jk);});};}),[_JK,_])),_JY=_JL,_JZ=B(A(new T(function(){return function(_oB,_Jk){return new F(function(){return (function(_K0,_K1,_){while(1){var _K2=E(_K0);if(!_K2[0]){return _iG;}else{var _K3=E(_K2[1]),_K4=60*E(_K3[1])[1],_K5=E(_K1),_K6=_K5[1],_K7=jsPushState(_K6),_K8=jsTranslate(_K6,0.5*Math.sqrt(3)*_K4+300, -(60*E(_K3[2])[1])+0.5*_K4+315),_K9=B(A(new T(function(){return B(_Iy(_d4,_eX));}),[[0,_K6],_])),_Ka=_K9,_Kb=jsPopState(_K6);_K0=_K2[2];_K1=_K5;continue;}}})(E(_IZ)[2],_oB,_Jk);});};}),[_JK,_])),_Kc=_JZ;return new F(function(){return A(new T(function(){return B(_J3(_JJ));}),[_JK,_]);});};})(_Hz));}),[_J0,_]);});};},_Kd=function(_Ke,_Kf,_Kg){var _Kh=E(_Kg)==0?E(_Ke):E(_Kf),_Ki=function(_Kj){while(1){var _Kk=(function(_Kl){var _Km=E(_Kl);if(!_Km[0]){return E(_HA);}else{var _Kn=_Km[1],_Ko=_Km[2];if(!B(_fT(_Kh,_Kn))){_Kj=_Ko;return null;}else{return function(_Kp,_){var _Kq=E(_Kn),_Kr=E(_Kp),_Ks=_Kr[1],_Kt=jsPushState(_Ks),_Ku=60*E(_Kq[1])[1],_Kv=jsTranslate(_Ks,0.5*Math.sqrt(3)*_Ku+300, -(60*E(_Kq[2])[1])+0.5*_Ku+315),_Kw=jsBeginPath(_Ks),_Kx=jsMoveTo(_Ks,22,0),_Ky=jsArc(_Ks,0,0,22,0,6.283185307179586),_Kz=jsFill(_Ks),_KA=jsPopState(_Ks);return new F(function(){return A(new T(function(){return B(_Ki(_Ko));}),[_Kr,_]);});};}}})(_Kj);if(_Kk!=null){return _Kk;}}};return new F(function(){return _Ki(_Kh);});},_KB=function(_KC,_KD,_KE){return new F(function(){return A(_KC,[_KE,new T(function(){return B(_KB(_KC,_KD,new T(function(){return B(A(_KD,[_KE]));})));})]);});},_KF=[0,45],_KG=new T(function(){return [0,0.5*Math.sqrt(3)*(-300)+300];}),_KH=[0,_KG,_KF],_KI=[0,585],_KJ=new T(function(){return [0,0.5*Math.sqrt(3)*300+300];}),_KK=[0,_KJ,_KI],_KL=function(_KM,_KN){if(_KN>0){var _KO=function(_KP,_KQ,_KR,_KS,_){var _KT=jsPushState(_KS),_KU=jsTranslate(_KS,_KP,_KQ),_KV=B(A(new T(function(){return B(_Iy(_KM,_qA));}),[[0,_KS],_])),_KW=_KV,_KX=jsPopState(_KS);return new F(function(){return A(_KR,[[0,_KS],_]);});};return new F(function(){return A(_KB,[function(_KY,_KZ,_L0){return _L0>1?function(_L1,_){var _L2=E(_KY);return new F(function(){return _KO(E(_L2[1])[1],E(_L2[2])[1],new T(function(){return B(A(_KZ,[_L0-1|0]));}),E(_L1)[1],_);});}:function(_L3,_){var _L4=E(_KY);return new F(function(){return _KO(E(_L4[1])[1],E(_L4[2])[1],_HA,E(_L3)[1],_);});};},function(_L5){if(!E(_KM)){var _L6=E(_L5);return [0,new T(function(){return [0,E(_L6[1])[1]-20];}),_L6[2]];}else{var _L7=E(_L5);return [0,new T(function(){return [0,E(_L7[1])[1]+20];}),_L7[2]];}},new T(function(){return E(_KM)==0?E(_KK):E(_KH);}),_KN]);});}else{return E(_HA);}},_L8=function(_L9,_La,_Lb){return function(_Lc,_){var _Ld=jsDrawText(E(_Lc)[1],E(new T(function(){return [0,toJSStr(E(_Lb))];}))[1],E(_L9)[1],E(_La)[1]);return _iG;};},_Le=new T(function(){return [0,"font"];}),_Lf=function(_Lg,_Lh){return function(_Li,_){var _Lj=E(_Li),_Lk=_Lj[1],_Ll=E(_Le)[1],_Lm=jsGet(_Lk,_Ll),_Ln=_Lm,_Lo=jsSet(_Lk,_Ll,E(new T(function(){return [0,toJSStr(E(_Lg))];}))[1]),_Lp=B(A(_Lh,[_Lj,_])),_Lq=_Lp,_Lr=jsSet(_Lk,_Ll,_Ln);return _iG;};},_Ls=new T(function(){return B(unCStr("15px \'Open Sans\', sans-serif"));}),_Lt=new T(function(){return B(unCStr("Floyd is thinking ..."));}),_Lu=new T(function(){return [0,toJSStr(E(_Lt))];}),_Lv=function(_Lw,_){var _Lx=jsDrawText(E(_Lw)[1],E(_Lu)[1],420,20);return _iG;},_Ly=new T(function(){return B(_Lf(_Ls,_Lv));}),_Lz=new T(function(){return B(unCStr("Floyd wins!"));}),_LA=new T(function(){return [0,toJSStr(E(_Lz))];}),_LB=function(_LC,_){var _LD=jsDrawText(E(_LC)[1],E(_LA)[1],420,20);return _iG;},_LE=new T(function(){return B(_Lf(_Ls,_LB));}),_LF=new T(function(){return B(unCStr("You win!"));}),_LG=new T(function(){return [0,toJSStr(E(_LF))];}),_LH=function(_LI,_){var _LJ=jsDrawText(E(_LI)[1],E(_LG)[1],420,20);return _iG;},_LK=new T(function(){return B(_Lf(_Ls,_LH));}),_LL=[1,_2t,_d],_LM=[0,550],_LN=[0,620],_LO=new T(function(){return B(_7u(_7F,_7F));}),_LP=[0,0],_LQ=[0,_LP,_LP,_LP],_LR=new T(function(){return B(_Ip(_LQ));}),_LS=function(_LT,_LU,_LV,_){while(1){var _LW=E(_LT);if(!_LW[0]){return _iG;}else{var _LX=E(_LW[1]),_LY=jsPushState(_LU),_LZ=60*E(_LX[1])[1],_M0=jsTranslate(_LU,0.5*Math.sqrt(3)*_LZ+300, -(60*E(_LX[2])[1])+0.5*_LZ+315),_M1=B(A(_LR,[[0,_LU],_])),_M2=_M1,_M3=jsBeginPath(_LU),_M4=jsMoveTo(_LU,5,0),_M5=jsArc(_LU,0,0,5,0,6.283185307179586),_M6=jsFill(_LU),_M7=jsPopState(_LU);_LT=_LW[2];var _M8=_;_LV=_M8;continue;}}},_M9=function(_Ma,_Mb,_Mc,_){while(1){var _Md=E(_Ma);if(!_Md[0]){return _iG;}else{var _Me=E(_Md[1]),_Mf=jsPushState(_Mb),_Mg=60*E(_Me[1])[1],_Mh=jsTranslate(_Mb,0.5*Math.sqrt(3)*_Mg+300, -(60*E(_Me[2])[1])+0.5*_Mg+315),_Mi=jsBeginPath(_Mb),_Mj=jsMoveTo(_Mb,22,0),_Mk=jsArc(_Mb,0,0,22,0,6.283185307179586),_Ml=jsFill(_Mb),_Mm=jsPopState(_Mb);_Ma=_Md[2];var _Mn=_;_Mc=_Mn;continue;}}},_Mo=[0,0.5],_Mp=[1,_It,_LP,_LP,_Mo],_Mq=new T(function(){return B(_Ip(_Mp));}),_Mr=function(_Ms,_Mt,_Mu,_Mv){var _Mw=E(_Mt);switch(_Mw[0]){case 0:var _Mx=E(_Mu),_My=_Mx[1],_Mz=_Mx[2];if(!B(_el(_My,_Mz,E(_Ms)[1]))){var _MA=new T(function(){return [0,60*E(_My)[1]];});return function(_MB,_){return new F(function(){return _Gh(E(new T(function(){return [0,0.5*Math.sqrt(3)*E(_MA)[1]+300];}))[1],E(new T(function(){return [0, -(60*E(_Mz)[1])+0.5*E(_MA)[1]+315];}))[1],new T(function(){return B(_Iy(_Mv,_eX));}),E(_MB)[1],_);});};}else{return E(_HA);}break;case 1:return !B(_eC(_LO,_Mu,B(_gU(_Mv,_Ms))))?E(_HA):function(_MC,_){var _MD=E(new T(function(){var _ME=E(_Mu),_MF=new T(function(){return [0,60*E(_ME[1])[1]];});return [0,new T(function(){return [0,0.5*Math.sqrt(3)*E(_MF)[1]+300];}),new T(function(){return [0, -(60*E(_ME[2])[1])+0.5*E(_MF)[1]+315];})];}));return new F(function(){return _Gh(E(_MD[1])[1],E(_MD[2])[1],new T(function(){return B(_If(_Mv));}),E(_MC)[1],_);});};case 2:var _MG=new T(function(){return B(_gK(_Ms,_Mw[1]));}),_MH=new T(function(){if(!B(_eC(_LO,_Mu,_MG))){var _MI=E(_HA);}else{var _MI=function(_MJ,_){var _MK=E(new T(function(){var _ML=E(_Mu),_MM=new T(function(){return [0,60*E(_ML[1])[1]];});return [0,new T(function(){return [0,0.5*Math.sqrt(3)*E(_MM)[1]+300];}),new T(function(){return [0, -(60*E(_ML[2])[1])+0.5*E(_MM)[1]+315];})];}));return new F(function(){return _Gh(E(_MK[1])[1],E(_MK[2])[1],new T(function(){return B(_Iy(_Mv,_eX));}),E(_MJ)[1],_);});};}return _MI;});return function(_MN,_){var _MO=E(_MG);if(!_MO[0]){return new F(function(){return A(_MH,[_MN,_]);});}else{var _MP=E(_MO[1]),_MQ=E(_MN),_MR=_MQ[1],_MS=jsPushState(_MR),_MT=60*E(_MP[1])[1],_MU=jsTranslate(_MR,0.5*Math.sqrt(3)*_MT+300, -(60*E(_MP[2])[1])+0.5*_MT+315),_MV=B(A(_LR,[[0,_MR],_])),_MW=_MV,_MX=jsBeginPath(_MR),_MY=jsMoveTo(_MR,5,0),_MZ=jsArc(_MR,0,0,5,0,6.283185307179586),_N0=jsFill(_MR),_N1=jsPopState(_MR),_N2=B(_LS(_MO[2],_MR,_,_)),_N3=_N2;return new F(function(){return A(_MH,[_MQ,_]);});}};case 3:return function(_N4,_){var _N5=B(A(_Mq,[_N4,_])),_N6=_N5,_N7=E(new T(function(){return B(_gX(new T(function(){if(!E(_Mv)){var _N8=E(E(_Ms)[4]);}else{var _N8=E(E(_Ms)[5]);}return _N8;}),_Mu));}));if(!_N7[0]){return _iG;}else{var _N9=E(_N7[1]),_Na=E(_N4)[1],_Nb=jsPushState(_Na),_Nc=60*E(_N9[1])[1],_Nd=jsTranslate(_Na,0.5*Math.sqrt(3)*_Nc+300, -(60*E(_N9[2])[1])+0.5*_Nc+315),_Ne=jsBeginPath(_Na),_Nf=jsMoveTo(_Na,22,0),_Ng=jsArc(_Na,0,0,22,0,6.283185307179586),_Nh=jsFill(_Na),_Ni=jsPopState(_Na);return new F(function(){return _M9(_N7[2],_Na,_,_);});}};default:return E(_HA);}},_Nj=function(_Nk,_Nl){var _Nm=new T(function(){var _Nn=E(_Nl);if(!_Nn[0]){var _No=E(_HA);}else{var _Np=_Nn[1],_Nq=E(_Nk),_Nr=_Nq[1];if(E(E(_Nq[4])[1])==3){var _Ns=E(_HA);}else{if(E(E(_Nq[5])[1])==3){var _Nt=E(_HA);}else{var _Nt=function(_Nu,_){var _Nv=B(A(new T(function(){return B(_Lf(_Ls,new T(function(){return B(_L8(_LM,_LN,new T(function(){var _Nw=E(_Np);return [1,_2u,new T(function(){return B(A(_2H,[_29,[1,function(_Nx){return new F(function(){return _2v(0,E(_Nw[1])[1],_Nx);});},[1,function(_Ny){return new F(function(){return _2v(0,E(_Nw[2])[1],_Ny);});},_d]],_LL]));})];})));})));}),[_Nu,_])),_Nz=_Nv,_NA=B(A(new T(function(){return B(_Mr(_Nq[3],_Nq[2],_Np,_Nr));}),[_Nu,_])),_NB=_NA;return E(_Nr)==0?_iG:B(A(_Ly,[_Nu,_]));};}var _NC=_Nt,_Ns=_NC;}var _ND=_Ns,_NE=_ND,_No=_NE;}return _No;}),_NF=new T(function(){var _NG=E(_Nk),_NH=_NG[3];if(E(_NG[2])[0]==3){var _NI=function(_NJ){var _NK=E(_NJ);return _NK[0]==0?E(_HA):function(_NL,_){var _NM=B(A(new T(function(){var _NN=E(_NH);return B(_Kd(_NN[4],_NN[5],_NK[1]));}),[_NL,_])),_NO=_NM;return new F(function(){return A(new T(function(){return B(_NI(_NK[2]));}),[_NL,_]);});};},_NP=B((function(_NQ,_NR){return function(_NS,_){var _NT=B(A(new T(function(){var _NU=E(_NH);return B(_Kd(_NU[4],_NU[5],_NQ));}),[_NS,_])),_NV=_NT;return new F(function(){return A(new T(function(){return B(_NI(_NR));}),[_NS,_]);});};})(_d4,_Hz));}else{var _NP=E(_HA);}var _NW=_NP;return _NW;}),_NX=new T(function(){return B(_KL(_d6,E(E(_Nk)[5])[1]));}),_NY=new T(function(){return B(_KL(_d4,E(E(_Nk)[4])[1]));}),_NZ=new T(function(){return B(_IY(new T(function(){return E(E(_Nk)[3]);})));});return function(_O0,_){var _O1=E(_Nk);if(E(E(_O1[4])[1])==3){var _O2=B(A(_LK,[_O0,_])),_O3=_O2,_O4=B(A(_NZ,[_O0,_])),_O5=_O4,_O6=B(A(_NY,[_O0,_])),_O7=_O6,_O8=B(A(_NX,[_O0,_])),_O9=_O8,_Oa=B(A(_NF,[_O0,_])),_Ob=_Oa;return new F(function(){return A(_Nm,[_O0,_]);});}else{if(E(E(_O1[5])[1])==3){var _Oc=B(A(_LE,[_O0,_])),_Od=_Oc,_Oe=B(A(_NZ,[_O0,_])),_Of=_Oe,_Og=B(A(_NY,[_O0,_])),_Oh=_Og,_Oi=B(A(_NX,[_O0,_])),_Oj=_Oi,_Ok=B(A(_NF,[_O0,_])),_Ol=_Ok;return new F(function(){return A(_Nm,[_O0,_]);});}else{var _Om=B(A(_NZ,[_O0,_])),_On=_Om,_Oo=B(A(_NY,[_O0,_])),_Op=_Oo,_Oq=B(A(_NX,[_O0,_])),_Or=_Oq,_Os=B(A(_NF,[_O0,_])),_Ot=_Os;return new F(function(){return A(_Nm,[_O0,_]);});}}};},_Ou=function(_Ov){while(1){var _Ow=(function(_Ox){var _Oy=E(_Ox);if(!_Oy[0]){return [0];}else{var _Oz=_Oy[2],_OA=E(_Oy[1]);if(!E(_OA[2])[0]){return [1,_OA[1],new T(function(){return B(_Ou(_Oz));})];}else{_Ov=_Oz;return null;}}})(_Ov);if(_Ow!=null){return _Ow;}}},_OB=function(_OC,_){return _OC;},_OD=function(_){var _=0,_OE=jsMkStdout(),_OF=_OE;return [0,_OF];},_OG=function(_OH){var _OI=B(A(_OH,[_])),_OJ=_OI;return E(_OJ);},_OK=new T(function(){return B(_OG(_OD));}),_OL=function(_OM,_ON,_){var _OO=B(A(_OM,[_])),_OP=_OO;return new F(function(){return A(_ON,[_]);});},_OQ=function(_,_OR){var _OS=E(_OR);if(!_OS[0]){return new F(function(){return _1S(_jK,_);});}else{var _OT=jsFind("canvas"),_OU=_OT,_OV=E(_OU);if(!_OV[0]){return new F(function(){return _1S(_jL,_);});}else{var _OW=nMV(_Gg),_OX=_OW,_OY=E(_OS[1]),_OZ=_OY[1],_P0=E(_OY[2])[1],_P1=jsResetCanvas(_P0),_P2=B(A(_IY,[_jp,_OZ,_])),_P3=_P2,_P4=E(_OV[1])[1],_P5=jsSetCB(_P4,E(_jr)[1],function(_P6,_){var _P7=rMV(_OX),_P8=_P7,_P9=E(_P8),_Pa=E(_P9[1]);if(!_Pa[0]){return new F(function(){return _1S(_jf,_);});}else{switch(E(_P9[2])[0]){case 0:var _Pb=jsResetCanvas(_P0);return new F(function(){return A(_Nj,[_Pa[1],[1,new T(function(){return B(_jm(_P6));})],_OZ,_]);});break;case 1:return _iG;case 2:return _iG;default:return _iG;}}}),_Pc=_P5,_Pd=jsSetCB(_P4,E(_jq)[1],function(_Pe,_){switch(E(E(_Pe)[1])){case 37:var _Pf=rMV(_OX),_Pg=_Pf,_Ph=E(_Pg),_Pi=_Ph[1],_Pj=_Ph[2],_Pk=B(_6V(_Pi,0));if(_Pk<=1){return _iG;}else{var _Pl=function(_Pm){var _=wMV(_OX,[0,_Pi,_jN]),_Pn=jsResetCanvas(_P0);return new F(function(){return A(_Nj,[new T(function(){return B(_5(_Pi,1));}),_0,_OZ,_]);});},_Po=function(_Pp){var _Pq=E(_Pj);if(_Pq[0]==3){var _Pr=E(_Pq[1])[1];if((_Pr+1|0)>=_Pk){return _iG;}else{var _=wMV(_OX,[0,_Pi,[3,[0,_Pr+1|0]]]),_Ps=jsResetCanvas(_P0),_Pt=new T(function(){var _Pu=_Pr+1|0;return _Pu>=0?B(_5(_Pi,_Pu)):E(_2);}),_Pv=B(A(_Nj,[_Pt,_0,_OZ,_])),_Pw=_Pv;return new F(function(){return _jz(_OK,B(unAppCStr("DEBUG: let gs = ",new T(function(){var _Px=E(_Pt);return B(A(_4F,[0,_Px[1],_Px[2],_Px[3],_Px[4],_Px[5],_d]));}))),_);});}}else{return _iG;}};switch(E(_Pj)[0]){case 0:var _Py=B(_Pl(_)),_Pz=_Py;return _iG;case 1:var _PA=B(_Po(_)),_PB=_PA;return _iG;case 2:var _PC=B(_Pl(_)),_PD=_PC;return _iG;default:var _PE=B(_Po(_)),_PF=_PE;return _iG;}}break;case 39:var _PG=rMV(_OX),_PH=_PG,_PI=E(_PH),_PJ=_PI[1],_PK=E(_PI[2]);if(_PK[0]==3){var _PL=_PK[1],_=wMV(_OX,[0,_PJ,new T(function(){var _PM=E(E(_PL)[1]);if(_PM==1){var _PN=[0];}else{var _PN=[3,[0,_PM-1|0]];}var _PO=_PN;return _PO;})]),_PP=jsResetCanvas(_P0),_PQ=new T(function(){var _PR=E(_PL)[1]-1|0;return _PR>=0?B(_5(_PJ,_PR)):E(_2);}),_PS=B(A(_Nj,[_PQ,_0,_OZ,_])),_PT=_PS;return new F(function(){return _jz(_OK,B(unAppCStr("DEBUG: let gs = ",new T(function(){var _PU=E(_PQ);return B(A(_4F,[0,_PU[1],_PU[2],_PU[3],_PU[4],_PU[5],_d]));}))),_);});}else{return _iG;}break;default:return _iG;}}),_PV=_Pd,_PW=jsSetCB(_P4,E(_js)[1],function(_PX,_PY,_){var _PZ=rMV(_OX),_Q0=_PZ,_Q1=E(_Q0),_Q2=E(_Q1[1]);if(!_Q2[0]){return new F(function(){return _1S(_jg,_);});}else{switch(E(_Q1[2])[0]){case 0:var _Q3=jsResetCanvas(_P0),_Q4=new T(function(){var _Q5=E(_Q2[1]),_Q6=B(_hd(_Q5[1],_Q5[2],_Q5[3],_Q5[4],_Q5[5],new T(function(){return B(_jm(_PY));})));return _Q6[0]==0?E(_Q5):E(_Q6[1]);}),_Q7=[1,new T(function(){var _Q8=E(_PY);return B(_6B(_Q8[1],_Q8[2]));})],_Q9=B(A(_Nj,[_Q4,_Q7,_OZ,_])),_Qa=_Q9,_Qb=B(_jz(_OK,B(unAppCStr("DEBUG: let gs = ",new T(function(){var _Qc=E(_Q4);return B(A(_4F,[0,_Qc[1],_Qc[2],_Qc[3],_Qc[4],_Qc[5],_d]));}))),_)),_Qd=_Qb,_Qe=E(_Q4),_Qf=_Qe[4],_Qg=_Qe[5];if(!E(_Qe[1])){var _=wMV(_OX,[0,[1,_Qe,_Q2],new T(function(){if(E(E(_Qf)[1])==3){var _Qh=[2];}else{var _Qh=E(E(_Qg)[1])==3?[2]:[0];}var _Qi=_Qh;return _Qi;})]);return _iG;}else{var _Qj=E(_Qf);if(E(_Qj[1])==3){var _=wMV(_OX,[0,[1,_Qe,_Q2],_jd]);return _iG;}else{var _Qk=E(_Qg);if(E(_Qk[1])==3){var _=wMV(_OX,[0,[1,_Qe,_Q2],_jd]);return _iG;}else{var _=wMV(_OX,[0,[1,_Qe,_Q2],_je]),_Ql=B(_iS(_jh,_OL,_OB,_1W,_jG,_jc,_jI,[1,[0,_jJ,new T(function(){return B(A(_4F,[0,_d6,_Qe[2],_Qe[3],_Qj,_Qk,_d]));})],_d],function(_Qm,_){var _Qn=E(_Qm);if(!_Qn[0]){return _iG;}else{var _Qo=jsResetCanvas(_P0),_Qp=new T(function(){var _Qq=B(_Ou(B(_nm(_Gc,_Qn[1]))));return _Qq[0]==0?E(_jP):E(_Qq[2])[0]==0?E(_Qq[1]):E(_jR);}),_Qr=B(A(_Nj,[_Qp,_Q7,_OZ,_])),_Qs=_Qr,_=wMV(_OX,[0,[1,_Qp,[1,_Qe,_Q2]],new T(function(){var _Qt=E(_Qp);if(E(E(_Qt[4])[1])==3){var _Qu=[2];}else{var _Qu=E(E(_Qt[5])[1])==3?[2]:[0];}var _Qv=_Qu,_Qw=_Qv;return _Qw;})]);return _iG;}})),_Qx=jsSetTimeout(0,_Ql);return _iG;}}}break;case 1:return _iG;case 2:return _iG;default:return _iG;}}}),_Qy=_PW;return _iG;}}},_Qz=function(_){var _QA=jsFind("canvas"),_QB=_QA,_QC=E(_QB);if(!_QC[0]){return new F(function(){return _OQ(_,_0);});}else{var _QD=E(_QC[1])[1],_QE=jsHasCtx2D(_QD),_QF=_QE;if(!E(_QF)){return new F(function(){return _OQ(_,_0);});}else{var _QG=jsGetCtx2D(_QD),_QH=_QG;return new F(function(){return _OQ(_,[1,[0,[0,_QH],[0,_QD]]]);});}}},_QI=function(_){return new F(function(){return _Qz(_);});}; -var hasteMain = function() {B(A(_QI, [0]));};window.onload = hasteMain; diff --git a/frontend/Main.hs b/frontend/Main.hs deleted file mode 100644 index 0282ae4..0000000 --- a/frontend/Main.hs +++ /dev/null @@ -1,323 +0,0 @@ -module Main where - -import Data.List (minimumBy) -import Data.Ord (comparing) -import Data.IORef -import Control.Monad (when, forM_) -import Data.Maybe (isJust, fromJust, fromMaybe) -import Haste (elemById, onEvent, Event(..), setTimeout) -import Haste.Ajax (textRequest, Method(..)) -import Haste.Graphics.Canvas - -import Yinsh -import AI -import Floyd - --- testing: --- import AIHistory - --- | Current state of the user interface -data DisplayState = WaitUser | WaitAI | ViewBoard | ViewHistory Int - deriving (Show, Eq) - --- | Pixel coordinate on the screen -type ScreenCoord = (Int, Int) - --- Color theme (http://www.colourlovers.com/palette/15/tech_light) -green = RGB 209 231 81 -blue = RGB 38 173 228 -white = RGB 255 255 255 -hl = RGBA 255 0 0 0.5 -black = RGB 0 0 0 - --- Font -frontendFont = "15px 'Open Sans', sans-serif" - --- Dimensions -spacing = 60 :: Double -markerWidth = 20 :: Double -ringInnerRadius = 22 :: Double -ringWidth = 6 :: Double -originX = 600 / 2 :: Double -- Half the canvas size -originY = 630 / 2 :: Double - --- Keyboard codes -keyLeft = 37 -keyRight = 39 - --- | Translate hex coordinates to screen coordinates -screenPoint :: YCoord -> Point -screenPoint (ya, yb) = (0.5 * sqrt 3 * x' + originX, - y' + 0.5 * x' + originY) - where x' = spacing * fromIntegral ya - y' = spacing * fromIntegral yb - --- | All grid points as screen coordinates -points :: [Point] -points = map screenPoint coords - --- | Translate by hex coordinate -translateC :: YCoord -> Picture () -> Picture () -translateC = translate . screenPoint - --- | Get the board coordinate which is closest to the given screen coordinate. -closestCoord :: ScreenCoord -> YCoord -closestCoord (xi, yi) = coords !! snd lsort - where lind = zipWith (\p i -> (dist p, i)) points [0..] - lsort = minimumBy (comparing fst) lind - dist (x', y') = (x - x')^2 + (y - y')^2 - x = fromIntegral xi - y = fromIntegral yi - --- | Marker and ring color for each player. -playerColor :: Player -> Color -playerColor B = blue -playerColor W = green - --- | Update the game state after interacting at a certain coordinate. If this --- is an illegal action, @newGameState@ returns @Nothing@ and the state is left --- unchanged. -updateState :: GameState -- ^ old state - -> YCoord -- ^ clicked coordinate - -> GameState -- ^ new state -updateState gs cc = fromMaybe gs (newGameState gs cc) - --- | Specify the AI player for the frontend -frontendAI :: AIFunction -frontendAI = aiFloyd 3 mhNumber rhZero - --- | Get new game state after AI turn. This also resolves @WaitRemoveRun@ and --- @WaitAddMarker@ turns for the *human* player. -aiTurn' :: GameState -> GameState -aiTurn' gs = let gs' = frontendAI gs in - case turnMode gs' of - (WaitRemoveRun _) -> frontendAI $ fromJust $ newGameState gs' (0, 0) - WaitAddMarker -> frontendAI $ fromJust $ newGameState gs' (0, 0) - _ -> gs' - --- Monadic code - -pSetPlayerColor :: Player -> Picture () -pSetPlayerColor = setFillColor . playerColor - --- | Draw ring. -pRing :: Player -- ^ Player (for color) - -> Bool -- ^ Draw the grid lines inside the ring? - -> Picture () -pRing p drawCross = do - -- Draw filled circle in player color - pSetPlayerColor p - fill circL - stroke circL - - -- Draw white inner circle - setFillColor white - fill circS - stroke circS - - -- Redraw the grid lines inside - when drawCross $ pCross ringInnerRadius - - where circL = circle (0, 0) (ringInnerRadius + ringWidth) - circS = circle (0, 0) ringInnerRadius - --- | Draw marker. -pMarker :: Player -> Picture () -pMarker p = do - pSetPlayerColor p - fill circ - stroke circ - where circ = circle (0, 0) markerWidth - --- | Draw board element (ring or marker) -pElement :: Element -> YCoord -> Picture () -pElement (Ring p) c = translateC c $ pRing p True -pElement (Marker p) c = translateC c $ pMarker p - --- | Draw three crossing grid lines at current position -pCross :: Double -- ^ Length of grid lines - -> Picture () -pCross len = do - l - rotate (2 * pi / 3) l - rotate (4 * pi / 3) l - where l = stroke $ line (0, -len) (0, len) - --- | Highlight a marker on the board with a ring around it. -pHighlightRing = fill $ circle (0, 0) (markerWidth + 2) - --- | Highlight markers making up a run. -pHighlight :: Board -> Player -> Picture () -pHighlight b p = mapM_ (`translateC` pHighlightRing) mcH - where mc = markers p b - mcH = filter (partOfRun mc) mc - --- | Draw small black dot at current position to indicate a valid ring move. -pDot :: Picture () -pDot = do setFillColor black - fill $ circle (0, 0) 5 - --- | Draw the whole board including the board elements. -pBoard :: Board -> Picture () -pBoard b = do - -- Draw grid - sequence_ $ mapM translate points (pCross (0.5 * spacing)) - - -- Draw board elements - forM_ [B, W] $ \p -> do - mapM_ (pElement (Marker p)) $ markers p b - mapM_ (pElement (Ring p)) $ rings p b - --- | Draw elements which are specific to the current turn mode. -pAction :: Board -- ^ Current board - -> TurnMode -- ^ turn mode - -> YCoord -- ^ coordinate closest to the mouse - -> Player -- ^ active player - -> Picture () -pAction b AddRing mc p = when (freeCoord b mc) $ pElement (Ring p) mc -pAction b AddMarker mc p = when (mc `elem` rings p b) $ pElement (Marker p) mc -pAction b (MoveRing start) mc p = do - let allowed = ringMoves b start - mapM_ (`translateC` pDot) allowed - when (mc `elem` allowed) $ pElement (Ring p) mc -pAction b (RemoveRun _) mc p = do - let runC = runCoords (markers p b) mc - setFillColor hl - mapM_ (`translateC` pHighlightRing) runC -pAction _ _ _ _ = return () - --- | Draw rings which are already removed from the board -pRings :: Player -> Int -> Picture () -pRings p rw = - mapM_ ringAt cs - where cs = take rw $ iterate (diff p) (initial p) - initial B = screenPoint (5, -2) - initial W = screenPoint (-5, 2) - diff B (x, y) = (x - 20, y) - diff W (x, y) = (x + 20, y) - ringAt point = translate point $ pRing p False - --- | Render all screen elements. -pDisplay :: GameState - -> Maybe YCoord -- ^ Coordinate close to mouse cursor - -> Picture () -pDisplay gs mmc = do - when (terminalState gs) $ - font frontendFont $ - text (420, 20) message - - pBoard (board gs) - - pRings B (pointsB gs) - pRings W (pointsW gs) - - -- Draw thick borders for markers which are part of a run - case turnMode gs of - (RemoveRun _) -> mapM_ (pHighlight (board gs)) [B, W] - _ -> return () - - -- Render screen action - when (isJust mmc && not (terminalState gs)) $ do - let (Just mc) = mmc - -- TODO: just debugging: - font frontendFont $ - text (550, 620) $ show mc - - pAction (board gs) (turnMode gs) mc (activePlayer gs) - - when (activePlayer gs == W) $ - font frontendFont $ - text (420, 20) "Floyd is thinking ..." - - where message | pointsB gs == pointsForWin = "You win!" - | otherwise = "Floyd wins!" - --- | Draw on canvas. -renderCanvas :: Canvas -> GameState -> Maybe ScreenCoord -> IO () -renderCanvas can gs mAction = render can $ pDisplay gs (closestCoord `fmap` mAction) - --- | Register IO events. -main :: IO () -main = do - Just can <- getCanvasById "canvas" - Just ce <- elemById "canvas" - - let initGS = initialGameState - -- let initGS = testGameState - let initBoard = board initGS - - -- 'ioState' holds a chronological list of game states and the display - -- state. - let initHistory = [initGS] - ioState <- newIORef (initHistory, WaitUser) - - -- draw initial board - render can (pBoard initBoard) - - _ <- ce `onEvent` OnMouseMove $ \point -> do - (gs:_, ds) <- readIORef ioState - when (ds == WaitUser) $ - renderCanvas can gs (Just point) - - _ <- ce `onEvent` OnKeyDown $ \key -> do - when (key == keyLeft) $ do - (gslist, ds) <- readIORef ioState - let numGS = length gslist - when (numGS > 1) $ - if ds == WaitUser || ds == ViewBoard then do - writeIORef ioState (gslist, ViewHistory 1) - renderCanvas can (gslist !! 1) Nothing - else - case ds of - ViewHistory h -> - when (h + 1 < numGS) $ do - writeIORef ioState (gslist, ViewHistory (h + 1)) - let gs = gslist !! (h + 1) - renderCanvas can gs Nothing - putStrLn $ "DEBUG: let gs = " ++ show gs - _ -> return () - when (key == keyRight) $ do - (gslist, ds) <- readIORef ioState - case ds of - ViewHistory h -> do - let newDS = if h == 1 then WaitUser else ViewHistory (h - 1) - writeIORef ioState (gslist, newDS) - let gs = gslist !! (h - 1) - renderCanvas can gs Nothing - putStrLn $ "DEBUG: let gs = " ++ show gs - _ -> return () - - _ <- ce `onEvent` OnClick $ \_ point -> do - (oldGS:gslist, ds) <- readIORef ioState - when (ds == WaitUser) $ do - let gs = updateState oldGS (closestCoord point) - let gameover = terminalState gs - renderCanvas can gs (Just point) - - putStrLn $ "DEBUG: let gs = " ++ show gs - - if activePlayer gs == W && not gameover - then do -- AI turn - writeIORef ioState (gs:oldGS:gslist, WaitAI) - -- setTimeout 0 $ do - -- let gs' = aiTurn' gs - -- let gameover' = terminalState gs' - -- let ds' = if gameover' then ViewBoard else WaitUser - -- renderCanvas can gs' (Just point) - -- writeIORef ioState (gs':gs:oldGS:gslist, ds') - setTimeout 0 $ - textRequest GET "http://localhost:8000/" [("gamestate", show gs)] $ - -- textRequest GET "http://yinsh-backend.herokuapp.com/" [("gamestate", show gs)] $ - \mResponse -> - case mResponse of - Nothing -> return () -- TODO !! - (Just strGS) -> do - let gs' = read strGS - let gameover' = terminalState gs' - let ds' = if gameover' then ViewBoard else WaitUser - renderCanvas can gs' (Just point) - writeIORef ioState (gs':gs:oldGS:gslist, ds') - else do -- users turn or game over - let ds' = if gameover then ViewBoard else WaitUser - writeIORef ioState (gs:oldGS:gslist, ds') - - return () diff --git a/index.html b/index.html deleted file mode 100644 index 83e34f0..0000000 --- a/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - Yinsh - - - - - - - - -

YINSH

-
- -
-

- You can use the left/right arrow keys to view the history of the game.
-
- This game is written in Haskell. The code is open source.
- David Peter, 2014-2023 -

- - - - diff --git a/info/screenshot.png b/info/screenshot.png deleted file mode 100644 index 50dadfd..0000000 Binary files a/info/screenshot.png and /dev/null differ diff --git a/info/turn-structure.svg b/info/turn-structure.svg deleted file mode 100644 index f42b7a0..0000000 --- a/info/turn-structure.svg +++ /dev/null @@ -1,675 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - RemoveRun + RemoveRing - - - - AddMarker + MoveRing - - - - WaitRemoveRun - - - - - 5x - - - - 5x - - - - 5x - - - - RemoveRun + RemoveRing - - - - - - - AddMarker + MoveRing - - - - - WaitRemoveRun - - - - WaitAddMarker - - - - - 5x - - - - - - 5x - - - - - - - - 5x - - - - - - - 5x - - - - - - 5x - - - - - - diff --git a/main.css b/main.css deleted file mode 100644 index f4e98f0..0000000 --- a/main.css +++ /dev/null @@ -1,50 +0,0 @@ -body { - margin: 0; - padding: 0; -} - -h1 { - margin: 0; - padding: 0; - text-align: center; - - font-family: 'Open Sans', sans-serif; - font-weight: 800; - font-size: 80px; - - color: #fff; - text-shadow: 0 0 10px #26ADE4; - - background-color: #4DBCE9; - border-bottom: 4px solid #26ADE4; -} - -.small { - font-size: 70px; -} - -#center { - margin-top: 40px; - margin-bottom: 40px; - text-align: center; -} - -canvas { - cursor: crosshair; - outline: none; -} - -.disclaimer { - text-align: center; - - font-family: 'Open Sans', sans-serif; - font-weight: 400; - font-size: 15px; - color: #aaa; - text-align: center; -} - -a { - color: #26ADE4; - text-decoration: none; -} diff --git a/src/AI.hs b/src/AI.hs deleted file mode 100644 index 31cf34f..0000000 --- a/src/AI.hs +++ /dev/null @@ -1,97 +0,0 @@ -{-# LANGUAGE FlexibleInstances #-} -{-# LANGUAGE UndecidableInstances #-} - -module AI where - -import qualified Data.Tree.Game_tree.Game_tree as GT -import qualified Data.Tree.Game_tree.Negascout as NS - -import Data.Maybe (fromJust) -import Data.List (nubBy, sort) - -import Yinsh - --- | Every AI should provide a function @ai..@, returning an AIFunction. -type AIFunction = GameState -> GameState - --- | Result of an heuristic evaluation function -type AIValue = Int - --- | Wrapper class for AI players which encapsules the current game state. -class AIPlayer a where - -- | Heuristic evaluation function for a game state. Everything is calulated - -- from the perspective of the white player. This is sufficient since - -- Yinsh is a zero sum game. - valueForWhite :: a -> AIValue - - -- | Number of turns to look ahead in the game tree. - getPlies :: a -> Int - - -- | Unwrap the gamestate inside the AI. - getGamestate :: a -> GameState - - -- | Update AI with new gamestate - update :: a -> GameState -> a - --- | Make the GameState (wrapped in the AIPlayer) an instance of Game_tree --- (actually rather an instance of a node in the game tree). -instance (AIPlayer a) => GT.Game_tree a where - is_terminal = terminalState . getGamestate - children ai = map (update ai) (gamestates (getGamestate ai)) - node_value ai = sign * valueForWhite ai - where sign | activePlayer gs == W = 1 - | otherwise = -1 - gs = getGamestate ai - --- | Possible new game states. The input and output game states are guaranteed --- to be in turn mode AddRing, AddMarker, RemoveRun or Wait*. -gamestates :: GameState -> [GameState] -gamestates gs | terminalState gs = [] - | otherwise = - case turnMode gs of - AddRing -> freeCoords >>= newGS gs - AddMarker -> rings' >>= newGS gs - (RemoveRun _) -> runCoords' >>= newGS gs - (WaitRemoveRun _) -> [fromJust (newGameState gs (0, 0))] - WaitAddMarker -> [fromJust (newGameState gs (0, 0))] - (MoveRing _) -> error "This is not supposed to happen" - (RemoveRing _) -> error "This is not supposed to happen" - where freeCoords = filter (freeCoord (board gs)) coords -- TODO: factor out, optimize - rings' = rings (activePlayer gs) (board gs) - runCoords' = removeDups $ filter (partOfRun markers') coords - markers' = markers (activePlayer gs) (board gs) - removeDups = nubBy (\c1 c2 -> sort (runCoords markers' c1) == sort (runCoords markers' c2)) - newGS gs' c = case turnMode nextGS of - AddRing -> [nextGS] - AddMarker -> [nextGS] - (RemoveRun _) -> [nextGS] - (WaitRemoveRun _) -> [nextGS] - WaitAddMarker -> [nextGS] - (MoveRing start) -> ringMoves (board nextGS) start >>= newGS nextGS - (RemoveRing _) -> rings (activePlayer nextGS) (board gs') >>= newGS nextGS - where nextGS = fromJust $ newGameState gs' c - --- | Get new game state after the AI turn. -aiTurn :: (AIPlayer ai) => ai -> GameState -aiTurn ai = case turnMode gs of - (WaitRemoveRun _) -> fromJust $ newGameState gs (0, 0) - WaitAddMarker -> fromJust $ newGameState gs (0, 0) - _ -> pv !! 1 - where pv = aiPV ai - gs = getGamestate ai - --- | Get the whole principal variation. -aiPV :: (AIPlayer ai) => ai -> [GameState] -aiPV ai = map getGamestate gss - where (gss, _) = NS.negascout ai ply - ply = getPlies ai --- TODO: negascout really seems to be the fastest. But test this for more game states --- NS.alpha_beta_search gs ply --- NS.principal_variation_search gs ply - --- | A large number for symbolizing a win. --- Very ugly: if this number is higher than 2^31, there is an integer overflow --- in haste/javascript, resulting in the AI playing *very* bad. --- So 2^31 - 1 ~ 2 * 10^9 is our hardcoded magic 'huge' number. -hugeNumber :: Int -hugeNumber = 2147483647 diff --git a/src/Floyd.hs b/src/Floyd.hs deleted file mode 100644 index 8535af7..0000000 --- a/src/Floyd.hs +++ /dev/null @@ -1,95 +0,0 @@ --- | Simply the best AI for Yinsh, seriously. - -module Floyd ( aiFloyd - , mhNumber - , rhRingMoves - , rhConnected - , rhControlledMarkers - , rhCombined - , rhZero - ) - where - -import AI -import Yinsh - --- TODO: adjust numbers: 5, 10 -floydHeuristic :: Floyd -> AIValue -floydHeuristic ai | points' W >= pointsForWin = hugeNumber - | points' B >= pointsForWin = -hugeNumber - | otherwise = value W - value B - where gs' = getGamestate ai - board' = board gs' - ap' = activePlayer gs' - tm' = turnMode gs' - points W = pointsW gs' - points B = pointsB gs' - - points' p = points p + futurePoints p - -- If we are in RemoveRun phase, already include the point for the - -- active player. - -- If we are is WaitRemoveRun, the *opponent* of the current player - -- will necessarily have one more point next turn. - futurePoints p = case tm' of - (RemoveRun _) -> if ap' == p then 1 else 0 - (WaitRemoveRun _) -> if ap' == p then 0 else 1 - _ -> 0 - - valuePoints p = 100000 * points' p - valueMarkers = markerH ai - valueRings = ringH ai - - value p = valuePoints p - + valueMarkers board' p - + valueRings board' p - - -type MarkerHeuristic = Board -> Player -> AIValue -type RingHeuristic = Board -> Player -> AIValue - -mhNumber :: MarkerHeuristic -mhNumber b p = (10 *) $ length $ markers p b - -rhRingMoves :: RingHeuristic -rhRingMoves b p = (1 *) $ sum $ map (length . ringMoves b) $ rings p b - -rhConnected :: RingHeuristic -rhConnected b p = (1 *) $ length $ filter connectedToRings coords - where connectedToRings c = any (c `connected`) (rings p b) - -rhControlledMarkers :: RingHeuristic -rhControlledMarkers b p = sum $ map controlledM (rings p b) - where controlledM :: YCoord -> Int - controlledM start = sum $ map markersBetween endPos - where endPos = ringMoves b start - markersBetween end = length $ filter (isMarker b) $ coordLine start end - -rhCombined :: [(Int, RingHeuristic)] -> RingHeuristic -rhCombined list b p = sum $ zipWith (*) points vs - where (vs, hs) = unzip list - points = map (\h -> h b p) hs - -rhZero :: RingHeuristic -rhZero _ _ = 0 - -data Floyd = Floyd { gs :: GameState - , plies :: Int - , markerH :: MarkerHeuristic - , ringH :: RingHeuristic - } - -instance AIPlayer Floyd where - valueForWhite = floydHeuristic - getGamestate = gs - getPlies = plies - update ai gs' = ai { gs = gs' } - -mkFloyd :: Int -> MarkerHeuristic -> RingHeuristic -> GameState -> Floyd -mkFloyd plies' mh' rh' gs' = Floyd { gs = gs' - , plies = plies' - , markerH = mh' - , ringH = rh' - } - -aiFloyd :: Int -> MarkerHeuristic -> RingHeuristic -> AIFunction -aiFloyd plies' mh' rh' gs' = aiTurn $ mkFloyd plies' mh' rh' gs' diff --git a/src/Pink.hs b/src/Pink.hs deleted file mode 100644 index 3cc7380..0000000 --- a/src/Pink.hs +++ /dev/null @@ -1,70 +0,0 @@ --- | Trying to complete with the best - -module Pink ( aiPink - -- , mhNumber - -- , rhRingMoves - -- , rhConnected - -- , rhZero - ) - where - -import AI -import Yinsh - -pinkHeuristic :: Pink -> AIValue -pinkHeuristic ai | points W >= pointsForWin = hugeNumber - | points B >= pointsForWin = -hugeNumber - | otherwise = value W - value B - where gs' = getGamestate ai - points W = pointsW gs' - points B = pointsB gs' - board' = board gs' - - valueMarkers = markerH ai - valueRings = ringH ai - - value p = valuePoints p - + valueMarkers board' p - + valueRings board' p - - valuePoints p = 100000 * points p - -type MarkerHeuristic = Board -> Player -> AIValue -type RingHeuristic = Board -> Player -> AIValue - -mhNumber :: MarkerHeuristic -mhNumber b p = (10 *) $ length $ markers p b - -rhRingMoves :: RingHeuristic -rhRingMoves b p = (1 *) $ sum $ map (length . ringMoves b) $ rings p b - -rhConnected :: RingHeuristic -rhConnected b p = (1 *) $ length $ filter connectedToRings coords - where connectedToRings c = any (c `connected`) (rings p b) - --- rhControlledMarkers :: RingHeuristic --- rhControlledMarkers b p = length $ nub $ controlledM =<< (rings p b) --- controlledM :: YCoord -> [YCoord] --- controlledM c = ringMoves b c - -rhZero :: RingHeuristic -rhZero _ _ = 0 - -data Pink = Pink { gs :: GameState - , plies :: Int - , markerH :: MarkerHeuristic - , ringH :: RingHeuristic - } - -instance AIPlayer Pink where - valueForWhite = pinkHeuristic - getGamestate = gs - getPlies = plies - update ai gs' = ai { gs = gs' } - -aiPink :: Int -> MarkerHeuristic -> RingHeuristic -> AIFunction -aiPink plies' mh' rh' gs' = aiTurn Pink { gs = gs' - , plies = plies' - , markerH = mh' - , ringH = rh' - } diff --git a/src/RaiCharles.hs b/src/RaiCharles.hs deleted file mode 100644 index f6117c2..0000000 --- a/src/RaiCharles.hs +++ /dev/null @@ -1,22 +0,0 @@ --- | Random AI (RAI) Charles, playing not really randomly. - -module RaiCharles (aiRaiCharles) where - -import AI -import Yinsh - -heuristic :: RaiCharles -> AIValue -heuristic _ = 42 -- yeah.. - -data RaiCharles = RaiCharles { gs :: GameState - , pl :: Int - } - -instance AIPlayer RaiCharles where - valueForWhite = heuristic - getGamestate = gs - getPlies = pl - update ai gs' = ai { gs = gs' } - -aiRaiCharles :: Int -> AIFunction -aiRaiCharles plies' gs' = aiTurn RaiCharles { gs = gs', pl = plies' } diff --git a/src/Yinsh.hs b/src/Yinsh.hs deleted file mode 100644 index f06aabb..0000000 --- a/src/Yinsh.hs +++ /dev/null @@ -1,431 +0,0 @@ -{-# LANGUAGE BangPatterns #-} - --- | --- Data structures and functions for playing the board game Yinsh. - -module Yinsh where - -import Control.Monad (guard) -import qualified Data.Map.Lazy as M -import Data.List (delete, foldl', sortBy) -import Data.Ord (comparing) - --- $setup --- >>> import Data.List (sort, nub) --- >>> import Test.QuickCheck hiding (vector) --- >>> let boardCoords = elements coords --- >>> instance Arbitrary Direction where arbitrary = elements directions - --- | Yinsh hex coordinates. -type YCoord = (Int, Int) - --- | The six hex directions. -data Direction = N | NE | SE | S | SW | NW - deriving (Eq, Enum, Bounded, Show, Read) - --- | Board element (ring or marker). -data Element = Ring Player - | Marker Player - deriving (Show, Eq, Read) - --- | Status of the game (required action). The two modes @WaitRemoveRun@ and --- @WaitAddMarker@ are introduced to preserve the alternating turn structure --- for the minmax-algorithm. The full structure is explained in the figure: --- --- <> -data TurnMode = AddRing -- ^ place a ring on a free field - | AddMarker -- ^ place a marker in one of your rings - | MoveRing YCoord -- ^ move the ring at the given position - | RemoveRun Player -- ^ remove (one of your) run(s). - -- the parameter holds the last player who - -- moved a ring - | RemoveRing Player -- ^ remove one of your rings - | WaitRemoveRun Player -- ^ do nothing - | WaitAddMarker -- ^ do nothing - deriving (Eq, Show, Read) - --- | Player types: black & white (or blue & green). -data Player = B | W - deriving (Eq, Enum, Bounded, Show, Read) - --- | Efficient data structure for the board with two-way access. --- The Map is used to get log(n) access to the element at a certain --- coordinate while the lists are used to get direct access to the --- coordinates of the markers and rings (which would need a reverse --- lookup otherwise). This comes at the cost of complete redundancy. --- Either bmap or the other four fields would be enough to reconstruct --- the whole board. -data Board = Board { bmap :: M.Map YCoord Element - , ringsB :: [YCoord] - , ringsW :: [YCoord] - , markersB :: [YCoord] - , markersW :: [YCoord] - } deriving (Eq, Show, Read) - --- | Yinsh game state. -data GameState = GameState - { activePlayer :: Player -- ^ player which has to move next - , turnMode :: TurnMode -- ^ required action - , board :: Board -- ^ current Yinsh board - , pointsB :: Int -- ^ number of runs / rings removed (black) - , pointsW :: Int -- ^ number of runs / rings removed (white) - } deriving (Eq, Show, Read) - --- | Get all marker coordinates of one player. -markers :: Player -> Board -> [YCoord] -markers B = markersB -markers W = markersW - --- | Get all ring coordinates of one player. -rings :: Player -> Board -> [YCoord] -rings B = ringsB -rings W = ringsW - --- | Returns (Just) the element at a certain position or Nothing if the --- coordinate is free (or invalid). -elementAt :: Board -> YCoord -> Maybe Element -elementAt b c = M.lookup c (bmap b) - --- | Returns True if the element at the given point is a marker of any color. -isMarker :: Board -> YCoord -> Bool -isMarker b c = case elementAt b c of - (Just (Marker _)) -> True - _ -> False - --- | Returns True if the element at the given point is a ring of any color. -isRing :: Board -> YCoord -> Bool -isRing b c = case elementAt b c of - (Just (Ring _)) -> True - _ -> False - --- | Returns True if a certain point on the board is free. Does not check the --- validity of the coordinate. -freeCoord :: Board -> YCoord -> Bool -freeCoord b c = not $ M.member c (bmap b) - --- | Returns a new board with the specified element added at the given --- coordinate. -addElement :: Board -> YCoord -> Element -> Board -addElement b c e = case e of - Ring B -> b { bmap = bmap' - , ringsB = c : ringsB b } - Ring W -> b { bmap = bmap' - , ringsW = c : ringsW b } - Marker B -> b { bmap = bmap' - , markersB = c : markersB b } - Marker W -> b { bmap = bmap' - , markersW = c : markersW b } - where bmap' = M.insert c e (bmap b) - --- | Returns a new board with the element at the given point removed. -removeElement :: Board -> YCoord -> Board -removeElement b c = case e of - Ring B -> b { bmap = bmap' - , ringsB = delete c (ringsB b) } - Ring W -> b { bmap = bmap' - , ringsW = delete c (ringsW b) } - Marker B -> b { bmap = bmap' - , markersB = delete c (markersB b) } - Marker W -> b { bmap = bmap' - , markersW = delete c (markersW b) } - where bmap' = M.delete c (bmap b) - e = bmap b M.! c - --- | Returns a new board with the element at the given point replaced. -modifyElement :: Board -> YCoord -> Element -> Board -modifyElement b c = addElement (removeElement b c) c --- TODO: this can certainly be optimizied: - --- | Yinsh board without any elements. -emptyBoard :: Board -emptyBoard = Board { bmap = M.empty - , ringsB = [] - , ringsW = [] - , markersB = [] - , markersW = [] - } - --- | Required runs for a win. -pointsForWin = 3 -pointsForWin :: Int - --- | Similar to Enum's succ, but for cyclic data structures. --- Wraps around to the beginning when it reaches the 'last' element. -next :: (Eq a, Enum a, Bounded a) => a -> a -next x | x == maxBound = minBound - | otherwise = succ x - --- | All six directions on the board. -directions :: [Direction] -directions = [minBound .. maxBound] - --- | Opposite direction (rotated by 180°). --- --- prop> (opposite . opposite) d == d -opposite :: Direction -> Direction -opposite = next . next . next - --- | Vector to the next point on the board in a given direction. -vector :: Direction -> YCoord -vector N = ( 0, 1) -vector NE = ( 1, 1) -vector SE = ( 1, 0) -vector S = ( 0, -1) -vector SW = (-1, -1) -vector NW = (-1, 0) - --- | Check if the point is within the boundaries of the board. --- All Yinsh coordinates lie on a hexagonal grid within a circle of radius 4.6. -validCoord :: YCoord -> Bool -validCoord (x', y') = (0.5 * sqrt 3 * x)**2 + (0.5 * x - y)**2 <= 4.6**2 - where x = fromIntegral x' - y = fromIntegral y' - --- | All points on the board. --- --- >>> length coords --- 85 --- -coords :: [YCoord] -coords = sortCoords [ (x, y) | x <- [-5 .. 5] - , y <- [-5 .. 5] - , validCoord (x, y) ] - --- | Sort the coords once with respect to the distance from the center --- for a better move ordering in the game tree. -sortCoords :: [YCoord] -> [YCoord] -sortCoords = sortBy (comparing norm2) - --- | Check if two points are connected by a line. --- --- >>> connected (3, 4) (8, 4) --- True --- --- prop> connected c1 c2 == connected c2 c1 --- -connected :: YCoord -> YCoord -> Bool -connected (x, y) (a, b) = x == a - || y == b - || x - y == a - b - --- | Vectorially add two coordinates. -add :: YCoord -> YCoord -> YCoord -add (!x1, !y1) (!x2, !y2) = (x1 + x2, y1 + y2) - --- | Vectorially subtract two coordinates. -sub :: YCoord -> YCoord -> YCoord -sub (!x1, !y1) (!x2, !y2) = (x1 - x2, y1 - y2) - --- | Squared norm. -norm2 :: YCoord -> Int -norm2 (x, y) = x * x + y * y - --- | Get a line of points from a given coordinate to the edge of the board. -ray :: YCoord -> Direction -> [YCoord] -ray s d = takeWhile validCoord $ adjacent s d - --- | All coordinates for a ring move in a given direction. -ringMovesD :: Board -> YCoord -> Direction -> [YCoord] -ringMovesD b s d = free ++ freeAfterJump - where line = tail (ray s d) - (free, rest) = span (freeCoord b) line - freeAfterJump = jumpPos rest - jumpPos [] = [] - jumpPos (c:cs) = case elementAt b c of - (Just (Ring _)) -> [] - (Just (Marker _)) -> jumpPos cs - Nothing -> [c] - --- | Get all valid ring moves starting from a given point. -ringMoves :: Board -> YCoord -> [YCoord] -ringMoves b start = ringMovesD b start =<< directions - --- | Check if a player has a run of five in a row. -hasRun :: Board -> Player -> Bool -hasRun b p = any (hasRunD b p) [NW, N, NE] - -isMarkerOf :: Board -> Player -> YCoord -> Bool -isMarkerOf b p c = case elementAt b c of - Just (Marker x) -> x == p - _ -> False - -hasRunD :: Board -> Player -> Direction -> Bool -hasRunD b p d = any middleOfRun ms - where ms = markers p b - middleOfRun c = all (isMarkerOf b p) surrounding - where surrounding = left ++ right - left = take 2 $ tail $ adjacent c d - right = take 2 $ tail $ adjacent c $ opposite d --- TODO: this can be improved.. we are checking for every marker if it sits --- in the middle of a run - --- | Check if a coordinate is one of five in a row. --- --- prop> partOfRun (take 5 $ adjacent c d) c == True -partOfRun :: [YCoord] -> YCoord -> Bool -partOfRun ms start = any partOfRunD [NW, N, NE] - where partOfRunD :: Direction -> Bool - partOfRunD dir = length (runCoordsD ms start dir) == 5 - --- | Return the coordinates of the markers making up a run. -runCoords :: [YCoord] -> YCoord -> [YCoord] -runCoords ms start = if null cs then [] else head cs - where cs = filter ((== 5) . length) $ map (runCoordsD ms start) [NW, N, NE] - --- | Combine two lists by taking elements alternatingly. If one list is longer, --- append the rest. --- --- prop> zipAlternate [] l == l --- prop> zipAlternate l [] == l --- prop> zipAlternate l l == (l >>= (\x -> [x, x])) -zipAlternate :: [a] -> [a] -> [a] -zipAlternate [] ys = ys -zipAlternate (x:xs) ys = x : zipAlternate ys xs - --- | Get adjacent coordinates in a given direction which could belong to a run. --- --- prop> runCoordsD (take 7 $ adjacent c d) c d == (take 5 $ adjacent c d) -runCoordsD :: [YCoord] -> YCoord -> Direction -> [YCoord] -runCoordsD ms start dir = if start `elem` ms - then take 5 $ zipAlternate right left - else [] - where right = takeAvailable dir - left = tail $ takeAvailable (opposite dir) -- use tail to avoid taking the start twice - takeAvailable d = takeWhile (`elem` ms) $ adjacent start d - --- | Get the adjacent (including start) coordinates in a given direction. -adjacent :: YCoord -> Direction -> [YCoord] -adjacent start dir = iterate step start - where step = add (vector dir) - --- | Get all coordinates connecting two points. -coordLine :: YCoord -> YCoord -> [YCoord] -coordLine p1 p2 = take (num - 1) . tail $ iterate (add step) p1 - where (!dx, !dy) = p2 `sub` p1 - !num = max (abs dx) (abs dy) - !step = (dx `div` num, dy `div` num) - --- | Flip all markers between two given coordinates. -flippedMarkers :: Board -> YCoord -> YCoord -> Board -flippedMarkers b s e = foldl' flipMaybe b (coordLine s e) - where flipMaybe b' c = case elementAt b' c of - Nothing -> b' - (Just (Marker B)) -> modifyElement b' c (Marker W) - (Just (Marker W)) -> modifyElement b' c (Marker B) - _ -> error "trying to flip something that is not a marker (invalid ring move?)" - --- | Check whether one player has won the game. -terminalState :: GameState -> Bool -terminalState gs = pointsB gs == pointsForWin || pointsW gs == pointsForWin --- TODO: we need to support draws (if no moves are possible) - --- | Get new game state after 'interacting' at a certain coordinate. Returns --- @Nothing@ if the action leads to an invalid turn. For details, see --- documentation of the @TurnMode@ type. -newGameState :: GameState -> YCoord -> Maybe GameState --- TODO: the guards should be (?) unnecessary when calling this function --- from 'gamestates'.. (for AI-only matches). unless the AI tries to cheat.. -newGameState gs cc = - case turnMode gs of - AddRing -> do - guard (freeCoord board' cc) - Just gs { activePlayer = nextPlayer - , turnMode = if numRings < 9 then AddRing else AddMarker - , board = addElement board' cc (Ring activePlayer') - } - where numRings = length (ringsB board') + length (ringsW board') - AddMarker -> do - guard (cc `elem` rings activePlayer' board') - Just gs { turnMode = MoveRing cc - , board = addElement removedRing cc (Marker activePlayer') - } - (MoveRing start) -> do - guard (cc `elem` ringMoves board' start) - Just gs { activePlayer = nextPlayer - , turnMode = nextTurnMode - , board = addElement flippedBoard cc (Ring activePlayer') - } - where nextTurnMode | hasRun flippedBoard activePlayer' = WaitRemoveRun activePlayer' - | hasRun flippedBoard nextPlayer = RemoveRun activePlayer' - | otherwise = AddMarker - flippedBoard = flippedMarkers board' start cc - (RemoveRun lastRingMove) -> do - guard (partOfRun playerMarkers cc) - Just gs { turnMode = RemoveRing lastRingMove - , board = removedRun - } - (RemoveRing lastRingMove) -> do - guard (cc `elem` rings activePlayer' board') - Just gs { activePlayer = nextPlayer - , turnMode = nextTurnMode - , board = removedRing - , pointsB = if activePlayer' == B then pointsB gs + 1 else pointsB gs - , pointsW = if activePlayer' == W then pointsW gs + 1 else pointsW gs - } - where nextTurnMode | hasRun removedRing activePlayer' - = WaitRemoveRun lastRingMove -- player has a second run - | hasRun removedRing nextPlayer - = RemoveRun lastRingMove -- opponent also has a run - | otherwise - = if lastRingMove == activePlayer' - then AddMarker - else WaitAddMarker - (WaitRemoveRun lastRingMove) -> - Just gs { activePlayer = nextPlayer - , turnMode = RemoveRun lastRingMove - } - WaitAddMarker -> - Just gs { activePlayer = nextPlayer - , turnMode = AddMarker - } - where activePlayer' = activePlayer gs - nextPlayer = next activePlayer' - removedRing = removeElement board' cc - removedRun = foldl' removeElement board' (runCoords playerMarkers cc) - board' = board gs - playerMarkers = markers activePlayer' board' - -initialGameState :: GameState -initialGameState = GameState { activePlayer = B - , turnMode = AddRing - , board = emptyBoard - , pointsW = 0 - , pointsB = 0 - } - --- Testing stuff - -testBoard :: Board -testBoard = foldl' (\b (c, e) -> addElement b c e) emptyBoard - [ ((3 - 6, 4 - 6), Ring B) - , ((4 - 6, 9 - 6), Ring B) - , ((7 - 6, 9 - 6), Ring B) - , ((8 - 6, 9 - 6), Ring B) - , ((7 - 6, 10 - 6), Ring B) - , ((8 - 6, 7 - 6), Ring W) - , ((6 - 6, 3 - 6), Ring W) - , ((4 - 6, 8 - 6), Ring W) - , ((4 - 6, 2 - 6), Ring W) - , ((2 - 6, 5 - 6), Ring W) - , ((6 - 6, 4 - 6), Marker W) - , ((6 - 6, 5 - 6), Marker W) - , ((6 - 6, 7 - 6), Marker W) - , ((5 - 6, 5 - 6), Marker W) - , ((4 - 6, 5 - 6), Marker W) - , ((3 - 6, 5 - 6), Marker W) - , ((6 - 6, 6 - 6), Marker B)] - -testGameState = GameState { activePlayer = B - , turnMode = AddMarker - , board = testBoard - , pointsW = 0 - , pointsB = 0 - } - -testGameStateW = GameState { activePlayer = W - , turnMode = AddMarker - , board = testBoard - , pointsW = 0 - , pointsB = 0 - } - diff --git a/src/ai/evaluator.rs b/src/ai/evaluator.rs new file mode 100644 index 0000000..5a146ad --- /dev/null +++ b/src/ai/evaluator.rs @@ -0,0 +1,51 @@ +use minimax::{Evaluation, Evaluator}; + +use crate::{GameState, Move, Player, TurnMode}; + +use super::game::Yinsh; + +pub trait Heuristic { + fn identifier(&self) -> String; + + fn evaluate_for_player_a(&self, state: &GameState) -> Evaluation; +} + +pub struct YinshEvaluator<'a, H: Heuristic> { + heuristic: &'a H, +} + +impl<'a, H: Heuristic> YinshEvaluator<'a, H> { + pub fn new(heuristic: &'a H) -> Self { + Self { heuristic } + } +} + +impl<'a, H: Heuristic> Evaluator for YinshEvaluator<'a, H> { + type G = Yinsh; + + fn evaluate(&self, state: &GameState) -> Evaluation { + match state.turn_mode { + TurnMode::WaitForRingMovement(_) + | TurnMode::WaitForRunRemoval(_) + | TurnMode::WaitForRingRemoval(_) + | TurnMode::WaitForMarkerPlacement => { + // Look one move ahead if we are in a waiting state. + let mut state_copy = state.clone(); + state_copy.perform_move(&Move::Wait); + return -self.evaluate(&state_copy); + } + TurnMode::RingPlacement + | TurnMode::MarkerPlacement + | TurnMode::RingMovement(_) + | TurnMode::RunRemoval(_) + | TurnMode::RingRemoval(_) => {} + } + + let score = self.heuristic.evaluate_for_player_a(state); + + match state.active_player { + Player::A => score, + Player::B => -score, + } + } +} diff --git a/src/ai/game.rs b/src/ai/game.rs new file mode 100644 index 0000000..e89d475 --- /dev/null +++ b/src/ai/game.rs @@ -0,0 +1,67 @@ +use std::iter; + +use minimax::{Game, Winner}; + +use crate::{GameState, Move, TurnMode}; + +pub struct Yinsh; + +impl Game for Yinsh { + type S = GameState; + + type M = Move; + + fn generate_moves(state: &Self::S, moves: &mut Vec) { + moves.extend(possible_moves(state)); + } + + fn apply(state: &mut Self::S, m: Self::M) -> Option { + let mut new_state = state.clone(); // TODO: is this necessary? + new_state.perform_move(&m); + Some(new_state) // TODO: we can avoid cloning here by returning None and implementing undo + } + + fn get_winner(state: &Self::S) -> Option { + match state.winner() { + Some(p) if p == state.active_player => Some(Winner::PlayerToMove), + Some(_) => Some(Winner::PlayerJustMoved), + None => None, + } + } +} + +pub fn possible_moves<'a>(state: &'a GameState) -> Box + 'a> { + match state.turn_mode { + TurnMode::RingPlacement => Box::new(state.board.free_coords().map(Move::PlaceRing)), + TurnMode::MarkerPlacement => Box::new( + state + .board + .marker_moves(state.active_player) + .map(Move::PlaceMarker), + ), + TurnMode::RingMovement(start) => Box::new( + state + .board + .ring_moves(start) + .into_iter() + .map(move |end| Move::MoveRing(start, end)), + ), + TurnMode::RunRemoval(_) => Box::new( + state + .board + .run_coords(state.active_player) + .into_iter() + .map(Move::RemoveRun), // TODO: this produces too many moves + ), + TurnMode::RingRemoval(_) => Box::new( + state + .board + .ring_coords(state.active_player) + .map(Move::RemoveRing), + ), + TurnMode::WaitForRunRemoval(_) + | TurnMode::WaitForMarkerPlacement + | TurnMode::WaitForRingMovement(_) + | TurnMode::WaitForRingRemoval(_) => Box::new(iter::once(Move::Wait)), + } +} diff --git a/src/ai/heuristics.rs b/src/ai/heuristics.rs new file mode 100644 index 0000000..dfcfbe1 --- /dev/null +++ b/src/ai/heuristics.rs @@ -0,0 +1,90 @@ +use minimax::Evaluation; + +use super::evaluator::Heuristic; + +use crate::{yinsh::GameState, Board, Coord, Player}; + +#[derive(Debug, Clone, Copy, Default)] +struct RingPositionStatistics { + controlled_markers_own: usize, + controlled_markers_opponent: usize, + accessible_fields: usize, +} + +fn ring_position_statistics(board: &Board, player: Player) -> RingPositionStatistics { + let mut statistics = RingPositionStatistics::default(); + + for ring in board.ring_coords(player) { + for move_end in board.ring_moves(ring) { + statistics.accessible_fields += 1; + + Coord::between(ring, move_end).iter().for_each(|coord| { + // TODO: We double-count here, but maybe that's not a problem (since it's good to control a marker with multiple rings?) + match board.element_color_at(*coord) { + Some(p) if p == player => statistics.controlled_markers_own += 1, + Some(_) => statistics.controlled_markers_opponent += 1, + None => {} + } + }); + } + } + + statistics +} + +#[derive(Debug, Clone, Copy)] +pub struct SimpleHeuristic { + pub f_points: Evaluation, + pub f_markers: Evaluation, + pub f_controlled_markers_own: Evaluation, + pub f_controlled_markers_opponent: Evaluation, + pub f_accessible_fields: Evaluation, +} + +impl Default for SimpleHeuristic { + fn default() -> Self { + Self { + f_points: 10_000, + f_markers: 100, + f_controlled_markers_own: 5, + f_controlled_markers_opponent: 10, + f_accessible_fields: 1, + // f_controlled_markers_own: 3, + // f_controlled_markers_opponent: 10, + // f_accessible_fields: 1, + } + } +} + +impl Heuristic for SimpleHeuristic { + fn evaluate_for_player_a(&self, state: &GameState) -> Evaluation { + type Score = Evaluation; + + let score_points = (state.points_a as Score) - (state.points_b as Score); + + let score_markers = (state.board.num_markers(Player::A) as Score) + - (state.board.num_markers(Player::B) as Score); + + let rps_a = ring_position_statistics(&state.board, Player::A); + let rps_b = ring_position_statistics(&state.board, Player::B); + + let score_rings = self.f_controlled_markers_own + * (Score::try_from(rps_a.controlled_markers_own).unwrap() + - Score::try_from(rps_b.controlled_markers_own).unwrap()) + + self.f_controlled_markers_opponent + * (Score::try_from(rps_a.controlled_markers_opponent).unwrap() + - Score::try_from(rps_b.controlled_markers_opponent).unwrap()) + + self.f_accessible_fields + * (Score::try_from(rps_a.accessible_fields).unwrap() + - Score::try_from(rps_b.accessible_fields).unwrap()); + + let score = self.f_points * score_points + self.f_markers * score_markers + score_rings; + + score + } + + fn identifier(&self) -> String { + format!("SimpleHeuristic {{ f_points: {}, f_markers: {}, f_controlled_markers_own: {}, f_controlled_markers_opponent: {}, f_accessible_fields: {} }}", + self.f_points, self.f_markers, self.f_controlled_markers_own, self.f_controlled_markers_opponent, self.f_accessible_fields) + } +} diff --git a/src/ai/mod.rs b/src/ai/mod.rs new file mode 100644 index 0000000..c1cf5af --- /dev/null +++ b/src/ai/mod.rs @@ -0,0 +1,76 @@ +mod evaluator; +mod game; +mod heuristics; + +pub use evaluator::Heuristic; +pub use game::possible_moves; +pub use heuristics::SimpleHeuristic; + +use evaluator::YinshEvaluator; +use minimax::{Negamax, Strategy}; + +use crate::yinsh::{GameState, Move, TurnMode}; + +pub struct YinshAi { + heuristic: H, + search_depth: usize, +} + +impl YinshAi { + pub fn new(heuristic: H, search_depth: usize) -> Self { + Self { + heuristic, + search_depth, + } + } +} + +pub trait YinshAiPlayer: Sync { + fn identifier(&self) -> String; + + fn search_depth(&self) -> usize; + + fn choose_move(&self, state: &GameState) -> Move; +} + +impl YinshAiPlayer for YinshAi { + fn identifier(&self) -> String { + self.heuristic.identifier() + } + + fn search_depth(&self) -> usize { + self.search_depth + } + + fn choose_move(&self, state: &GameState) -> Move { + // Early return if the only thing we can do is wait. Would be great + // if this could be handled by 'minimax' itself (if there is only one + // possible move in choose_move, return that immediately). + match state.turn_mode { + TurnMode::WaitForRunRemoval(_) + | TurnMode::WaitForRingMovement(_) + | TurnMode::WaitForRingRemoval(_) + | TurnMode::WaitForMarkerPlacement => { + return Move::Wait; + } + _ => {} + } + + let depth: u8 = if matches!(state.turn_mode, TurnMode::RingPlacement) { + 3 + } else { + self.search_depth.try_into().unwrap() + }; + + let mut strategy = Negamax::new(YinshEvaluator::new(&self.heuristic), depth); + let player_move = strategy.choose_move(&state).unwrap(); + + // dbg!(strategy.root_value()); + + player_move + } +} + +pub fn get_ai_move(search_depth: usize, state: &GameState) -> Move { + YinshAi::new(SimpleHeuristic::default(), search_depth).choose_move(state) +} diff --git a/src/gui/ai.rs b/src/gui/ai.rs new file mode 100644 index 0000000..ddc3c24 --- /dev/null +++ b/src/gui/ai.rs @@ -0,0 +1,76 @@ +use bevy::prelude::*; + +use bevy_async_task::{AsyncTaskRunner, AsyncTaskStatus}; +use yinsh::{GameState, Move, Player}; + +use super::state_update::{PlayerMoveEvent, StateUpdateSet}; + +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct AiSet; + +#[derive(Resource)] +pub struct AiPlayerStrength(pub usize); + +#[derive(Event)] +pub enum AiComputationEvent { + Start(Player, GameState), + + #[allow(unused)] + Cancel, +} + +fn perform_ai_moves( + mut task_runner: AsyncTaskRunner>, + mut events: EventReader, + strength: Res, + mut player_move_events: EventWriter, +) { + for event in events.read() { + match event { + AiComputationEvent::Start(player, ref game_state) => { + let player = *player; + let game_state = game_state.clone(); + let search_depth = strength.0; + task_runner.start(async move { + // TODO! This is a hack to make sure the AI takes at least as long as + // the animation. + #[cfg(not(target_arch = "wasm32"))] + { + use super::graphics::ANIMATION_DURATION; + use yinsh::TurnMode; + + if matches!(game_state.turn_mode, TurnMode::MarkerPlacement) { + std::thread::sleep(ANIMATION_DURATION); + } + } + + Some((player, yinsh::get_ai_move(search_depth, &game_state))) + }); + } + AiComputationEvent::Cancel => { + // Replace current computation with dummy task + task_runner.start(async move { None }); + } + } + } + + match task_runner.poll() { + AsyncTaskStatus::Idle | AsyncTaskStatus::Pending | AsyncTaskStatus::Finished(None) => {} + AsyncTaskStatus::Finished(Some((player, player_move))) => { + player_move_events.send(PlayerMoveEvent(player, player_move)); + } + } +} + +pub fn plugin(app: &mut App) { + app.insert_resource(AiPlayerStrength(if cfg!(debug_assertions) { + 9 + } else { + 15 + })) + .add_event::() + .add_systems( + Update, + (perform_ai_moves).in_set(AiSet).after(StateUpdateSet), + ); +} diff --git a/src/gui/board.rs b/src/gui/board.rs new file mode 100644 index 0000000..aba8924 --- /dev/null +++ b/src/gui/board.rs @@ -0,0 +1,12 @@ +use bevy::prelude::*; + +use yinsh::{Coord, Player}; + +#[derive(Component)] +pub struct BoardElement(pub Coord, pub Player); + +#[derive(Component)] +pub struct Ring; + +#[derive(Component)] +pub struct Marker; diff --git a/src/gui/board_update_event.rs b/src/gui/board_update_event.rs new file mode 100644 index 0000000..8dbb060 --- /dev/null +++ b/src/gui/board_update_event.rs @@ -0,0 +1,13 @@ +use bevy::prelude::Event; + +use yinsh::{Coord, Player}; + +#[derive(Event)] +pub enum BoardUpdateEvent { + AddRing(Coord, Player), + AddMarker(Coord, Player), + MoveRing(Coord, Coord), + RemoveRing(Coord), + RemoveRun(Vec), + FlipMarkers(Coord, Coord, Vec), +} diff --git a/src/gui/graphics.rs b/src/gui/graphics.rs new file mode 100644 index 0000000..17a2c57 --- /dev/null +++ b/src/gui/graphics.rs @@ -0,0 +1,266 @@ +use std::time::Duration; + +use bevy::{ + core_pipeline::bloom::BloomSettings, + prelude::*, + render::view::RenderLayers, + sprite::{MaterialMesh2dBundle, Mesh2dHandle}, + window::PrimaryWindow, +}; + +use yinsh::{Coord, Player}; + +use super::{ + board::{BoardElement, Marker, Ring}, + grid::draw_grid, + PLAYER_HUMAN, +}; + +pub const FOREGROUND_RENDER_LAYER: RenderLayers = RenderLayers::layer(2); +pub const BACKGROUND_RENDER_LAYER: RenderLayers = RenderLayers::layer(1); + +pub const COLOR_GRID: Color = Color::hsl(0.0, 0.0, 0.2); + +pub const COLOR_BACKGROUND: Color = Color::hsl(0.0, 0.0, 0.05); + +pub const COLOR_RING_MOVEMENT_INDICATOR: Color = Color::hsla(0.0, 0.0, 1.5, 0.1); + +pub const COLOR_HUMAN_R: f32 = 255.; +pub const COLOR_HUMAN_G: f32 = 226.; +pub const COLOR_HUMAN_B: f32 = 55.; + +pub const COLOR_HUMAN_BLOOM: f32 = 1.5; + +pub const COLOR_HUMAN: Color = Color::srgba( + COLOR_HUMAN_BLOOM * COLOR_HUMAN_R / 255., + COLOR_HUMAN_BLOOM * COLOR_HUMAN_G / 255., + COLOR_HUMAN_BLOOM * COLOR_HUMAN_B / 255., + 1.0, +); +pub const COLOR_HUMAN_HIGHLIGHTED: Color = Color::srgba( + 4.0 * COLOR_HUMAN_R / 255., + 4.0 * COLOR_HUMAN_G / 255., + 4.0 * COLOR_HUMAN_B / 255., + 1.0, +); +pub const COLOR_HUMAN_TRANSPARENT: Color = Color::srgba( + COLOR_HUMAN_BLOOM * COLOR_HUMAN_R / 255., + COLOR_HUMAN_BLOOM * COLOR_HUMAN_G / 255., + COLOR_HUMAN_BLOOM * COLOR_HUMAN_B / 255., + 0.2, +); + +pub const COLOR_AI_R: f32 = 81.; +pub const COLOR_AI_G: f32 = 151.; +pub const COLOR_AI_B: f32 = 242.; + +pub const COLOR_AI_BLOOM: f32 = 1.3; + +pub const COLOR_AI: Color = Color::srgba( + COLOR_AI_BLOOM * COLOR_AI_R / 255., + COLOR_AI_BLOOM * COLOR_AI_G / 255., + COLOR_AI_BLOOM * COLOR_AI_B / 255., + 1.0, +); + +pub fn color_for_player(player: Player) -> Color { + if player == PLAYER_HUMAN { + COLOR_HUMAN + } else { + COLOR_AI + } +} + +pub const ANIMATION_DURATION: Duration = Duration::from_millis(500); + +#[derive(Component)] +pub struct MainCamera; + +#[derive(Resource, Debug, Clone, Copy)] +pub struct ScaleFactor { + pub spacing: f32, + pub factor: f32, +} + +impl ScaleFactor { + pub fn screen_point(&self, coord: Coord) -> Vec3 { + Vec3::new( + self.spacing * (0.5 * 3_f32.sqrt() * coord.x as f32), + self.spacing * (-coord.y as f32 + 0.5 * coord.x as f32), + 0., + ) + } +} + +impl Default for ScaleFactor { + fn default() -> Self { + Self { + spacing: 80.0, + factor: 1.0, + } + } +} + +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct ScaleFactorSet; + +#[derive(Resource)] +pub struct PlayerColors { + pub human: Handle, + pub human_highlighted: Handle, + pub human_transparent: Handle, + pub ai: Handle, + pub animated_markers: [Handle; 8], +} + +pub fn ring_mesh( + meshes: &mut Assets, + color_material: Handle, + visibility: Visibility, +) -> MaterialMesh2dBundle { + MaterialMesh2dBundle { + mesh: Mesh2dHandle(meshes.add(Annulus::new(20., 25.))), + material: color_material, + visibility, + ..default() + } +} + +pub fn marker_mesh( + meshes: &mut Assets, + color_material: Handle, + visibility: Visibility, +) -> MaterialMesh2dBundle { + MaterialMesh2dBundle { + mesh: Mesh2dHandle(meshes.add(Circle::new(16.))), + material: color_material, + visibility, + ..default() + } +} + +pub fn spawn_ring( + commands: &mut Commands, + meshes: &mut Assets, + player_colors: &PlayerColors, + coord: Coord, + player: Player, +) { + let color = if player == PLAYER_HUMAN { + player_colors.human.clone() + } else { + player_colors.ai.clone() + }; + + commands.spawn(( + ring_mesh(meshes, color, Visibility::Visible), + BoardElement(coord, player), + Ring, + FOREGROUND_RENDER_LAYER, + )); +} + +pub fn spawn_marker( + commands: &mut Commands, + meshes: &mut Assets, + player_colors: &PlayerColors, + coord: Coord, + player: Player, +) { + let color = if player == PLAYER_HUMAN { + player_colors.human.clone() + } else { + player_colors.ai.clone() + }; + + commands.spawn(( + marker_mesh(meshes, color, Visibility::Visible), + BoardElement(coord, player), + Marker, + FOREGROUND_RENDER_LAYER, + )); +} + +fn setup_graphics( + mut commands: Commands, + mut config_store: ResMut, + mut materials: ResMut>, +) { + commands.insert_resource(ClearColor(COLOR_BACKGROUND)); + + // Render layer 1 is for the grid + commands.spawn(( + Camera2dBundle { + camera: Camera { + hdr: true, + order: 1, + ..default() + }, + ..default() + }, + BloomSettings::default(), + BACKGROUND_RENDER_LAYER, + )); + + // Render layer 2 is for the board elements + commands.spawn(( + Camera2dBundle { + camera: Camera { + hdr: true, + order: 2, + ..default() + }, + ..default() + }, + BloomSettings::default(), + FOREGROUND_RENDER_LAYER, + MainCamera, + )); + + commands.insert_resource(PlayerColors { + human: materials.add(COLOR_HUMAN), + human_highlighted: materials.add(COLOR_HUMAN_HIGHLIGHTED), + human_transparent: materials.add(COLOR_HUMAN_TRANSPARENT), + ai: materials.add(COLOR_AI), + animated_markers: [ + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + materials.add(COLOR_AI), + ], + }); + + let (config, _) = config_store.config_mut::(); + config.render_layers = BACKGROUND_RENDER_LAYER; +} + +pub fn set_scale_factor( + mut scale_factor: ResMut, + window: Query<&Window, With>, +) { + const BASE_SPACING_AT_800_PIXELS: f32 = 80.0; + + let window = window.single(); + let height = (window.physical_height() as f32) / (window.scale_factor() as f32); + let width = (window.physical_width() as f32) / (window.scale_factor() as f32); + let factor = ((height.min(width)) / 800.0).min(1.5); + scale_factor.factor = factor; + scale_factor.spacing = BASE_SPACING_AT_800_PIXELS * factor; +} + +pub fn plugin(app: &mut App) { + app.insert_resource(Msaa::Sample8) + .insert_resource(ScaleFactor::default()) + .add_systems(PreStartup, (setup_graphics, set_scale_factor)) + .add_systems( + Update, + ( + set_scale_factor.in_set(ScaleFactorSet), + draw_grid.after(ScaleFactorSet), + ), + ); +} diff --git a/src/gui/grid.rs b/src/gui/grid.rs new file mode 100644 index 0000000..9273912 --- /dev/null +++ b/src/gui/grid.rs @@ -0,0 +1,54 @@ +use bevy::prelude::*; + +use yinsh::Coord; + +use super::graphics::{ScaleFactor, COLOR_GRID}; + +pub fn draw_grid(mut gizmos: Gizmos, scale_factor: Res) { + let grid_line_color = COLOR_GRID; + + // Draw lines parallel to y-axis + for x in -5i8..=5i8 { + let coords: Vec<_> = (-5..=5) + .map(|y| Coord { x, y }) + .filter(|c| c.is_inside_board()) + .collect(); + + let min_y = coords.iter().map(|c| c.y).min().unwrap(); + let max_y = coords.iter().map(|c| c.y).max().unwrap(); + + let start = scale_factor.screen_point(Coord { x, y: min_y }); + let end = scale_factor.screen_point(Coord { x, y: max_y }); + gizmos.line(start, end, grid_line_color); + } + + // Draw lines parallel to x-axis + for y in -5i8..=5i8 { + let coords: Vec<_> = (-5..=5) + .map(|x| Coord { x, y }) + .filter(|c| c.is_inside_board()) + .collect(); + + let min_x = coords.iter().map(|c| c.x).min().unwrap(); + let max_x = coords.iter().map(|c| c.x).max().unwrap(); + + let start = scale_factor.screen_point(Coord { x: min_x, y }); + let end = scale_factor.screen_point(Coord { x: max_x, y }); + gizmos.line(start, end, grid_line_color); + } + + // Draw lines parallel to y = x + for d in -5i8..=5i8 { + let coords: Vec<_> = (-5..=5) + .map(|x| Coord { x, y: x + d }) + .filter(|c| c.is_inside_board()) + .collect(); + + let min = coords.iter().map(|c| c.x).min().unwrap(); + let max = coords.iter().map(|c| c.x).max().unwrap(); + + let start = scale_factor.screen_point(Coord { x: min, y: min + d }); + let end = scale_factor.screen_point(Coord { x: max, y: max + d }); + gizmos.line(start, end, grid_line_color); + } +} diff --git a/src/gui/history.rs b/src/gui/history.rs new file mode 100644 index 0000000..bc10b5b --- /dev/null +++ b/src/gui/history.rs @@ -0,0 +1,72 @@ +use bevy::prelude::*; +use yinsh::{Player, TurnMode}; + +use super::{ + ai::AiComputationEvent, + board::BoardElement, + board_update_event::BoardUpdateEvent, + graphics::ScaleFactorSet, + interaction::CursorElement, + state_update::{GameState, StateUpdateSet}, +}; + +pub fn save_and_load_game_state( + keyboard: Res>, + mut commands: Commands, + mut game_state: ResMut, + mut ai_computation_events: EventWriter, + mut board_update_events: EventWriter, + q_board_elements: Query, Without)>, +) { + let filename = "gamestate.yml"; + + if keyboard.just_pressed(KeyCode::KeyS) { + println!("Saving game state to {}", filename); + if matches!( + game_state.turn_mode, + TurnMode::RingPlacement | TurnMode::MarkerPlacement + ) { + game_state.save_to(filename); + } else { + println!( + "Cannot save game state in turn mode {:?}", + game_state.turn_mode + ); + } + } else if keyboard.just_pressed(KeyCode::KeyL) || keyboard.just_pressed(KeyCode::KeyR) { + println!("Loading game state from {}", filename); + *game_state.as_deref_mut() = yinsh::GameState::load_from(filename); + + assert!(matches!( + game_state.turn_mode, + TurnMode::RingPlacement | TurnMode::MarkerPlacement + )); + + ai_computation_events.send(AiComputationEvent::Cancel); + + // Despawn all board elements + for entity in q_board_elements.iter() { + commands.entity(entity).despawn(); + } + + // Respawn board elements + for p in [Player::A, Player::B] { + for coord in game_state.board.ring_coords(p) { + board_update_events.send(BoardUpdateEvent::AddRing(coord, p)); + } + + for coord in game_state.board.marker_coords(p) { + board_update_events.send(BoardUpdateEvent::AddMarker(coord, p)); + } + } + } +} + +pub fn plugin(app: &mut App) { + app.add_systems( + Update, + save_and_load_game_state + .before(StateUpdateSet) + .after(ScaleFactorSet), + ); +} diff --git a/src/gui/information_display.rs b/src/gui/information_display.rs new file mode 100644 index 0000000..de63a39 --- /dev/null +++ b/src/gui/information_display.rs @@ -0,0 +1,66 @@ +use bevy::prelude::*; + +use yinsh::Player; + +use super::{ + ai::AiPlayerStrength, + graphics::BACKGROUND_RENDER_LAYER, + interaction::CursorCoord, + state_update::{GameState, InteractionState}, +}; + +#[derive(Component)] +struct GameStateInformation; + +fn setup_information_display(mut commands: Commands) { + commands.spawn(( + TextBundle::from_section( + "", + TextStyle { + font_size: 18.0, + color: Color::hsl(0., 0., 0.3), + ..default() + }, + ) + .with_style(Style { + position_type: PositionType::Absolute, + top: Val::Px(10.), + left: Val::Px(10.), + ..default() + }), + GameStateInformation, + BACKGROUND_RENDER_LAYER, + )); +} + +fn update_information_display( + game_state: Res, + mut q_text: Query<&mut Text, With>, + cursor_coord: Res, + interaction_state: Res, + ai_player_strength: Res, +) { + q_text.single_mut().sections[0].value = + format!( + "Score: {points_a}:{points_b}\nMode: {mode}\nAI strength: {strength} [weaker: J, stronger: K]\n{coord}", + points_a=game_state.points_a, + points_b=game_state.points_b, + mode=match *interaction_state { + InteractionState::RingPlacement(_) => "Place a ring on the board", + InteractionState::MarkerPlacement(_) => "Place a marker in one of your rings", + InteractionState::RingMovement(_, _) => "Move the selected ring", + InteractionState::RunRemoval { .. } => "Select a run of five markers to remove", + InteractionState::RingRemoval(_) => "Select one of your rings to remove it", + InteractionState::AutoMove | InteractionState::WaitForAI => "Floyd is thinking...", + InteractionState::Winner(Player::A) => "Game over. You win!", + InteractionState::Winner(Player::B) => "Game over. Floyd wins!", + }, + strength=ai_player_strength.0, + coord=if let Some (coord) = cursor_coord.0 { format!("({x}, {y})", x=coord.x, y=coord.y) } else { "".to_string() }, + ); +} + +pub fn plugin(app: &mut App) { + app.add_systems(Startup, setup_information_display) + .add_systems(Update, update_information_display.ambiguous_with_all()); +} diff --git a/src/gui/interaction.rs b/src/gui/interaction.rs new file mode 100644 index 0000000..2816a9b --- /dev/null +++ b/src/gui/interaction.rs @@ -0,0 +1,443 @@ +use std::time::Duration; + +use bevy::prelude::*; + +use bevy::window::PrimaryWindow; + +use bevy_tweening::lens::ColorMaterialColorLens; +use bevy_tweening::{lens::TransformPositionLens, Animator, EaseFunction, Tween, TweeningPlugin}; +use bevy_tweening::{AnimationSystem, AssetAnimator, Delay, EaseMethod}; +use yinsh::{all_coords, Coord, Move}; + +use super::ai::AiSet; +use super::board::{BoardElement, Marker, Ring}; +use super::board_update_event::BoardUpdateEvent; +use super::graphics::{ + color_for_player, marker_mesh, ring_mesh, spawn_marker, spawn_ring, MainCamera, PlayerColors, + ScaleFactor, ScaleFactorSet, ANIMATION_DURATION, FOREGROUND_RENDER_LAYER, +}; +use super::state_update::{GameState, PlayerMoveEvent, StateUpdateSet}; +use super::PLAYER_HUMAN; +use super::{graphics::COLOR_RING_MOVEMENT_INDICATOR, state_update::InteractionState}; + +#[derive(Component)] +pub struct CursorElement; + +#[derive(Resource)] +pub struct CursorCoord(pub Option); + +fn setup_interaction_cursors( + mut commands: Commands, + mut meshes: ResMut>, + player_colors: Res, +) { + commands.spawn(( + ring_mesh( + &mut meshes, + player_colors.human_transparent.clone(), + Visibility::Hidden, + ), + BoardElement(Coord::new(0, 0), PLAYER_HUMAN), + Ring, + CursorElement, + FOREGROUND_RENDER_LAYER, + )); + + commands.spawn(( + marker_mesh( + &mut meshes, + player_colors.human_transparent.clone(), + Visibility::Hidden, + ), + BoardElement(Coord::new(0, 0), PLAYER_HUMAN), + Marker, + CursorElement, + FOREGROUND_RENDER_LAYER, + )); +} + +fn draw_ring_move_indicators( + scale_factor: Res, + mut gizmos: Gizmos, + interaction_state: Res, +) { + let indicator_color = COLOR_RING_MOVEMENT_INDICATOR; + + if let InteractionState::RingMovement(_, ref possible_moves) = *interaction_state { + for coord in possible_moves { + let screen_pos = scale_factor.screen_point(*coord); + gizmos.circle( + screen_pos, + Dir3::Z, + scale_factor.spacing / 8., + indicator_color, + ); + } + } +} + +fn update_board_elements( + mut board_update_events: EventReader, + mut commands: Commands, + scale_factor: Res, + mut meshes: ResMut>, + player_colors: Res, + mut q_rings: Query< + (Entity, &mut BoardElement), + (With, (Without, Without)), + >, + mut q_markers: Query< + (Entity, &mut BoardElement, &mut Handle), + (With, Without), + >, +) { + for event in board_update_events.read() { + match *event { + BoardUpdateEvent::AddRing(coord, player) => { + spawn_ring(&mut commands, &mut meshes, &player_colors, coord, player); + } + BoardUpdateEvent::AddMarker(coord, player) => { + spawn_marker(&mut commands, &mut meshes, &player_colors, coord, player); + } + BoardUpdateEvent::MoveRing(old_coord, new_coord) => { + for (entity, mut ring) in q_rings.iter_mut() { + if ring.0 == old_coord { + let tween = Tween::new( + EaseFunction::QuadraticInOut, + ANIMATION_DURATION, + TransformPositionLens { + start: scale_factor.screen_point(old_coord), + end: scale_factor.screen_point(new_coord), + }, + ); + + commands.entity(entity).insert(Animator::new(tween)); + + ring.0 = new_coord; // To make the change permanent + + break; + } + } + } + BoardUpdateEvent::RemoveRun(ref run_coords) => { + for (entity, element, _) in q_markers.iter_mut() { + if run_coords.contains(&element.0) { + commands.entity(entity).despawn(); + } + } + } + BoardUpdateEvent::RemoveRing(coord) => { + for (entity, element) in q_rings.iter_mut() { + if element.0 == coord { + commands.entity(entity).despawn(); + break; + } + } + } + BoardUpdateEvent::FlipMarkers(start, end, ref marker_coords) => { + let mut i = 0; + let total_distance = (end - start).norm(); + + for (entity, mut element, mut color_material) in q_markers.iter_mut() { + if marker_coords.contains(&element.0) { + let distance_from_start = (element.0 - start).norm(); + + let delay = + ANIMATION_DURATION.mul_f32(distance_from_start / total_distance); + + let tween = Tween::new( + EaseMethod::Linear, + Duration::from_secs_f32(1e-9), + ColorMaterialColorLens { + start: color_for_player(element.1), + end: color_for_player(element.1), + }, + ) + .then(Delay::new(delay).then(Tween::new( + EaseMethod::Linear, + ANIMATION_DURATION.div_f32(5.0), + ColorMaterialColorLens { + start: color_for_player(element.1), + end: color_for_player(element.1.next()), + }, + ))); + + *color_material = player_colors.animated_markers[i].clone(); + commands.entity(entity).insert(AssetAnimator::new(tween)); + + element.1.flip(); // To make the change permanent + + i += 1; + } + } + } + } + } +} + +fn clear_animators(mut q: Query<(Entity, &Animator)>, mut commands: Commands) { + for (entity, animator) in q.iter_mut() { + if animator.tweenable().times_completed() == 1 { + commands.entity(entity).remove::>(); + } + } +} + +fn clear_asset_animators( + mut q: Query<(Entity, &AssetAnimator)>, + mut commands: Commands, +) { + for (entity, animator) in q.iter_mut() { + if animator.tweenable().times_completed() == 1 { + commands + .entity(entity) + .remove::>(); + } + } +} + +fn move_board_elements( + scale_factor: Res, + mut query: Query<(&BoardElement, &mut Transform), Without>>, +) { + for (BoardElement(coord, _), mut transform) in query.iter_mut() { + transform.translation = scale_factor.screen_point(*coord); + } +} + +fn scale_board_elements( + scale_factor: Res, + mut query: Query<&mut Transform, With>, +) { + for mut transform in query.iter_mut() { + transform.scale = Vec3::splat(scale_factor.factor); + } +} + +fn colorize_board_elements( + mut query: Query<( + &BoardElement, + &mut Handle, + Option<&Ring>, + Option<&Marker>, + Option<&CursorElement>, + Option<&AssetAnimator>, + )>, + interaction_state: Res, + player_colors: Res, + mouse_cursor_coord: Res, +) { + for (BoardElement(coord, player), mut color_material, ring, marker, cursor_element, animated) in + query.iter_mut() + { + if animated.is_some() { + continue; + } + + *color_material = if player == &PLAYER_HUMAN { + if cursor_element.is_some() { + player_colors.human_transparent.clone() + } else { + match *interaction_state { + InteractionState::RingMovement(start, _) => { + if *coord == start && ring.is_some() { + player_colors.human_highlighted.clone() + } else { + player_colors.human.clone() + } + } + InteractionState::RunRemoval { + ref all_run_coords, + ref run_from_seed, + } => match mouse_cursor_coord.0 { + Some(cursor_coord) if all_run_coords.contains(&cursor_coord) => { + let run_from_cursor = run_from_seed.get(&cursor_coord).unwrap(); + if run_from_cursor.contains(coord) { + player_colors.human_highlighted.clone() + } else { + player_colors.human.clone() + } + } + _ => { + if marker.is_some() && all_run_coords.contains(coord) { + player_colors.human_highlighted.clone() + } else { + player_colors.human.clone() + } + } + }, + _ => player_colors.human.clone(), + } + } + } else { + player_colors.ai.clone() + }; + } +} + +fn grid_cursor_system( + scale_factor: Res, + mut q_window: Query<&mut Window, With>, + q_camera: Query<(&Camera, &GlobalTransform), With>, + mut cursor_ring: Query< + (&mut BoardElement, &mut Visibility), + (With, Without, With), + >, + mut cursor_marker: Query< + (&mut BoardElement, &mut Visibility), + (With, Without, With), + >, + interaction_state: Res, + mut mouse_cursor_coord: ResMut, +) { + let Ok(mut window) = q_window.get_single_mut() else { + return; + }; + + window.cursor.icon = match *interaction_state { + InteractionState::WaitForAI => CursorIcon::Progress, + InteractionState::Winner(_) => CursorIcon::Default, + _ => CursorIcon::Pointer, + }; + + if let Some(cursor_position) = window.cursor_position() { + let (camera, camera_transform) = q_camera.single(); + + if let Some(cursor_position) = camera + .viewport_to_world(camera_transform, cursor_position) + .map(|ray| ray.origin.truncate()) + { + let cursor_coord = yinsh::all_coords() + .into_iter() + .min_by_key(|c| { + let screen_pos = scale_factor.screen_point(*c); + let cursor_pos = Vec3::new(cursor_position.x, cursor_position.y, 0.0); + let diff = screen_pos - cursor_pos; + diff.length_squared() as i32 + }) + .unwrap(); + + let (mut cursor_ring_coord, mut cursor_ring_visibility) = cursor_ring.single_mut(); + *cursor_ring_visibility = Visibility::Hidden; + + let (mut cursor_marker_coord, mut cursor_marker_visibility) = + cursor_marker.single_mut(); + *cursor_marker_visibility = Visibility::Hidden; + + match *interaction_state { + InteractionState::RingPlacement(ref free_coords) => { + if free_coords.contains(&cursor_coord) { + *cursor_ring_visibility = Visibility::Visible; + cursor_ring_coord.0 = cursor_coord; + } + } + InteractionState::MarkerPlacement(ref ring_coords) => { + if ring_coords.contains(&cursor_coord) { + *cursor_marker_visibility = Visibility::Visible; + cursor_marker_coord.0 = cursor_coord; + } + } + InteractionState::RingMovement(_, ref possible_ring_moves) => { + if possible_ring_moves.contains(&cursor_coord) { + *cursor_ring_visibility = Visibility::Visible; + cursor_ring_coord.0 = cursor_coord; + } + } + InteractionState::RunRemoval { .. } => {} + InteractionState::RingRemoval(_) => {} + InteractionState::AutoMove => {} + InteractionState::WaitForAI => {} + InteractionState::Winner(_) => {} + } + + mouse_cursor_coord.0 = Some(cursor_coord); + } + } +} + +fn mouse_interaction_system( + buttons: Res>, + interaction_state: Res, + cursor_coord: Res, + mut player_move_events: EventWriter, +) { + if matches!(*interaction_state, InteractionState::AutoMove) { + // TODO + player_move_events.send(PlayerMoveEvent(PLAYER_HUMAN, Move::Wait)); + } + + if let Some(cursor_coord) = cursor_coord.0 { + if buttons.just_pressed(MouseButton::Left) { + match *interaction_state { + InteractionState::RingPlacement(ref free_coords) => { + if free_coords.contains(&cursor_coord) { + player_move_events + .send(PlayerMoveEvent(PLAYER_HUMAN, Move::PlaceRing(cursor_coord))); + } + } + InteractionState::MarkerPlacement(ref ring_coords) => { + if ring_coords.contains(&cursor_coord) { + player_move_events.send(PlayerMoveEvent( + PLAYER_HUMAN, + Move::PlaceMarker(cursor_coord), + )); + } + } + InteractionState::RingMovement(start, ref possible_ring_moves) => { + if possible_ring_moves.contains(&cursor_coord) { + player_move_events.send(PlayerMoveEvent( + PLAYER_HUMAN, + Move::MoveRing(start, cursor_coord), + )); + } + } + InteractionState::WaitForAI => {} + InteractionState::RunRemoval { + ref all_run_coords, .. + } => { + if all_run_coords.contains(&cursor_coord) { + player_move_events + .send(PlayerMoveEvent(PLAYER_HUMAN, Move::RemoveRun(cursor_coord))); + } + } + InteractionState::RingRemoval(ref ring_coords) => { + if ring_coords.contains(&cursor_coord) { + player_move_events.send(PlayerMoveEvent( + PLAYER_HUMAN, + Move::RemoveRing(cursor_coord), + )); + } + } + InteractionState::AutoMove => {} + InteractionState::Winner(_) => {} + } + } + } +} + +pub fn plugin(app: &mut App) { + app.add_plugins(TweeningPlugin) + .insert_resource(InteractionState::RingPlacement(all_coords())) + .insert_resource(CursorCoord(None)) + .insert_resource(GameState::initial()) + .add_systems(Startup, setup_interaction_cursors) + .add_systems( + Update, + ( + draw_ring_move_indicators, + ( + clear_animators, + clear_asset_animators, + grid_cursor_system, + update_board_elements, + move_board_elements.ambiguous_with(AnimationSystem::AnimationUpdate), + scale_board_elements.ambiguous_with(AnimationSystem::AnimationUpdate), + colorize_board_elements.ambiguous_with(AnimationSystem::AnimationUpdate), + mouse_interaction_system.ambiguous_with(AiSet), + ) + .chain(), + ) + .after(StateUpdateSet) + .after(ScaleFactorSet), + ); +} diff --git a/src/gui/keyboard_control.rs b/src/gui/keyboard_control.rs new file mode 100644 index 0000000..e02067a --- /dev/null +++ b/src/gui/keyboard_control.rs @@ -0,0 +1,30 @@ +use bevy::prelude::*; + +use super::{ + ai::{AiComputationEvent, AiPlayerStrength, AiSet}, + state_update::GameState, + PLAYER_HUMAN, +}; + +fn keyboard_control( + keyboard: Res>, + mut exit: EventWriter, + mut ai_player_strength: ResMut, + mut ai_computation_events: EventWriter, + game_state: Res, +) { + if keyboard.just_pressed(KeyCode::Escape) || keyboard.just_pressed(KeyCode::KeyQ) { + exit.send(AppExit::Success); + } else if keyboard.just_pressed(KeyCode::KeyK) { + ai_player_strength.0 = ai_player_strength.0 + 1; + } else if keyboard.just_pressed(KeyCode::KeyJ) { + ai_player_strength.0 = (ai_player_strength.0 - 1).max(1); + } else if keyboard.just_pressed(KeyCode::KeyA) { + ai_computation_events.send(AiComputationEvent::Start(PLAYER_HUMAN, game_state.clone())); + // TODO: remove this feature, or implement it properly + } +} + +pub fn plugin(app: &mut App) { + app.add_systems(Update, keyboard_control.ambiguous_with(AiSet)); +} diff --git a/src/gui/mod.rs b/src/gui/mod.rs new file mode 100644 index 0000000..abb1b59 --- /dev/null +++ b/src/gui/mod.rs @@ -0,0 +1,17 @@ +use yinsh::Player; + +pub mod ai; +pub mod board; +pub mod board_update_event; +pub mod graphics; +pub mod grid; +#[cfg(not(target_arch = "wasm32"))] +pub mod history; +pub mod information_display; +pub mod interaction; +pub mod keyboard_control; +pub mod resources; +pub mod state_update; + +pub const PLAYER_HUMAN: Player = Player::A; +pub const PLAYER_AI: Player = Player::B; diff --git a/src/gui/resources.rs b/src/gui/resources.rs new file mode 100644 index 0000000..e69de29 diff --git a/src/gui/state_update.rs b/src/gui/state_update.rs new file mode 100644 index 0000000..380df0c --- /dev/null +++ b/src/gui/state_update.rs @@ -0,0 +1,150 @@ +use std::ops::{Deref, DerefMut}; + +use yinsh::{Coord, Move, Player, TurnMode}; + +use bevy::{prelude::*, utils::HashMap}; + +use crate::gui::PLAYER_HUMAN; + +use super::{ai::AiComputationEvent, board_update_event::BoardUpdateEvent, PLAYER_AI}; + +#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)] +pub struct StateUpdateSet; + +#[derive(Resource)] +pub struct GameState(yinsh::GameState); + +impl Deref for GameState { + type Target = yinsh::GameState; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for GameState { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl GameState { + pub fn initial() -> Self { + Self(yinsh::GameState::initial()) + } +} + +#[derive(Resource)] +pub enum InteractionState { + RingPlacement(Vec), + MarkerPlacement(Vec), + RingMovement(Coord, Vec), + RunRemoval { + all_run_coords: Vec, + run_from_seed: HashMap>, + }, + RingRemoval(Vec), + AutoMove, + WaitForAI, + Winner(Player), +} + +impl InteractionState { + pub fn from_game_state(game_state: &yinsh::GameState) -> Self { + if let Some(winner) = game_state.winner() { + Self::Winner(winner) + } else if game_state.active_player == PLAYER_AI { + Self::WaitForAI + } else { + match game_state.turn_mode { + TurnMode::RingPlacement => { + Self::RingPlacement(game_state.board.free_coords().collect()) + } + TurnMode::MarkerPlacement => { + Self::MarkerPlacement(game_state.board.marker_moves(PLAYER_HUMAN).collect()) + } + TurnMode::RingMovement(start) => { + Self::RingMovement(start, game_state.board.ring_moves(start)) + } + TurnMode::RunRemoval(_) => { + let all_run_coords = game_state.board.run_coords(PLAYER_HUMAN); + Self::RunRemoval { + all_run_coords: all_run_coords.clone(), + run_from_seed: all_run_coords + .into_iter() + .map(|seed| (seed, game_state.board.run_coords_from(seed).unwrap())) + .collect(), + } + } + TurnMode::RingRemoval(_) => { + Self::RingRemoval(game_state.board.ring_coords(PLAYER_HUMAN).collect()) + } + TurnMode::WaitForRunRemoval(_) + | TurnMode::WaitForMarkerPlacement + | TurnMode::WaitForRingMovement(_) + | TurnMode::WaitForRingRemoval(_) => Self::AutoMove, + } + } + } +} + +#[derive(Event)] +pub struct PlayerMoveEvent(pub Player, pub Move); + +fn state_update( + mut player_move_events: EventReader, + mut game_state: ResMut, + mut interaction_state: ResMut, + mut ai_computation_events: EventWriter, + mut board_update_events: EventWriter, +) { + for PlayerMoveEvent(player, player_move) in player_move_events.read() { + assert!(player == &game_state.active_player); + + match player_move { + Move::PlaceRing(coord) => { + board_update_events.send(BoardUpdateEvent::AddRing(*coord, *player)); + } + Move::PlaceMarker(coord) => { + board_update_events.send(BoardUpdateEvent::AddMarker(*coord, *player)); + } + Move::MoveRing(start, end) => { + board_update_events.send(BoardUpdateEvent::MoveRing(*start, *end)); + board_update_events.send(BoardUpdateEvent::FlipMarkers( + *start, + *end, + Coord::between(*start, *end) + .into_iter() + .filter(|&coord| game_state.board.has_marker_at(coord)) + .collect(), + )); + } + Move::RemoveRun(seed) => { + board_update_events.send(BoardUpdateEvent::RemoveRun( + game_state.board.run_coords_from(*seed).unwrap(), + )); + } + Move::RemoveRing(coord) => { + board_update_events.send(BoardUpdateEvent::RemoveRing(*coord)); + } + Move::Wait => {} + } + + game_state.perform_move(player_move); + + if game_state.active_player == PLAYER_AI && game_state.winner().is_none() { + ai_computation_events.send(AiComputationEvent::Start(PLAYER_AI, game_state.clone())); + } + } + + *interaction_state = InteractionState::from_game_state(&game_state); +} + +pub fn plugin(app: &mut App) { + let initial_game_state = GameState::initial(); + app.insert_resource(InteractionState::from_game_state(&initial_game_state)) + .insert_resource(initial_game_state) + .add_event::() + .add_event::() + .add_systems(Update, state_update.in_set(StateUpdateSet)); +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..c51aca1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,5 @@ +mod ai; +mod yinsh; + +pub use ai::{get_ai_move, possible_moves, Heuristic, SimpleHeuristic, YinshAi, YinshAiPlayer}; +pub use yinsh::*; diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..cf14e81 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,38 @@ +mod gui; + +use bevy::{ + prelude::*, + window::{WindowMode, WindowResolution}, +}; + +fn main() { + App::new() + .add_plugins(( + DefaultPlugins.set(WindowPlugin { + primary_window: Some(Window { + title: "Yinsh".into(), + name: Some("yinsh".into()), + resolution: WindowResolution::new(760., 760.), + mode: WindowMode::Windowed, + canvas: Some("#yinsh-canvas".into()), + ..default() + }), + ..default() + }), + gui::state_update::plugin, + gui::ai::plugin, + gui::graphics::plugin, + gui::interaction::plugin, + gui::information_display::plugin, + gui::keyboard_control::plugin, + #[cfg(not(target_arch = "wasm32"))] + gui::history::plugin, + )) + // .edit_schedule(Update, |schedule| { + // schedule.set_build_settings(ScheduleBuildSettings { + // ambiguity_detection: LogLevel::Warn, + // ..default() + // }); + // }) + .run(); +} diff --git a/src/yinsh/board.rs b/src/yinsh/board.rs new file mode 100644 index 0000000..86395b6 --- /dev/null +++ b/src/yinsh/board.rs @@ -0,0 +1,511 @@ +use std::iter; + +use itertools::Itertools; +use serde::{Deserialize, Serialize}; + +use crate::yinsh::core::AXES; + +use super::{core::all_coords, Coord, Player, DIRECTIONS}; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum Element { + Ring(Player), + Marker(Player), + Empty, +} + +impl Element { + pub fn is_marker(&self) -> bool { + matches!(self, Element::Marker(_)) + } + + fn is_ring(&self) -> bool { + matches!(self, Element::Ring(_)) + } + + fn is_empty(&self) -> bool { + matches!(self, Element::Empty) + } + + fn player(&self) -> Option { + match self { + Element::Ring(player) => Some(*player), + Element::Marker(player) => Some(*player), + Element::Empty => None, + } + } +} + +impl Default for Element { + fn default() -> Self { + Element::Empty + } +} + +#[derive(Debug, Clone, Default)] +pub struct CheckRunResult { + a_has_run: bool, + b_has_run: bool, +} + +impl CheckRunResult { + fn or(&mut self, other: &Self) { + self.a_has_run |= other.a_has_run; + self.b_has_run |= other.b_has_run; + } + + pub fn has_run(&self, player: Player) -> bool { + match player { + Player::A => self.a_has_run, + Player::B => self.b_has_run, + } + } + + pub fn no_runs(&self) -> bool { + !self.a_has_run && !self.b_has_run + } +} + +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct Board { + #[serde(skip)] + board: [[Element; 11]; 11], + + rings_a: Vec, + rings_b: Vec, + markers_a: Vec, + markers_b: Vec, +} + +impl Board { + pub fn empty() -> Self { + Self::default() + } + + /// Returns the element at a certain position or None if the coordinate is free (or invalid). + /// Does not check for validity. + fn element_at_unchecked(&self, coord: Coord) -> Element { + self.board[(coord.y + 5) as usize][(coord.x + 5) as usize] + } + + /// Returns the element at a certain position or None if the coordinate is free (or invalid) + fn element_at(&self, coord: Coord) -> Element { + if coord.is_inside_board() { + self.board[(coord.y + 5) as usize][(coord.x + 5) as usize] + } else { + Element::Empty + } + } + + /// Returns the element at a certain position or None if the coordinate is free. Does not + /// check for validity. + fn element_at_mut_unchecked(&mut self, coord: Coord) -> &mut Element { + &mut self.board[(coord.y + 5) as usize][(coord.x + 5) as usize] + } + + fn insert_board_element_at(&mut self, coord: Coord, element: Element) { + debug_assert!(coord.is_inside_board()); + + *self.element_at_mut_unchecked(coord) = element; + } + + fn remove_board_element_at(&mut self, coord: &Coord) { + debug_assert!(coord.is_inside_board()); + + *self.element_at_mut_unchecked(*coord) = Element::Empty; + } + + /// Returns true if a certain point on the board is free. Does not check for validity. + pub fn is_free(&self, coord: Coord) -> bool { + self.element_at(coord).is_empty() + } + + /// Returns true if the element at the given point is a ring of any color. + pub fn has_ring_at(&self, coord: Coord, player: Player) -> bool { + self.check_invariants(); + + self.element_at(coord) == Element::Ring(player) + } + + /// Returns true if the element at the given point is a marker of any color. + pub fn has_marker_at(&self, coord: Coord) -> bool { + self.check_invariants(); + + self.element_at(coord).is_marker() + } + + /// Returns the color/player of the board element at the given coordinate. + pub fn element_color_at(&self, coord: Coord) -> Option { + self.check_invariants(); + + self.element_at(coord).player() + } + + pub fn add_ring(&mut self, player: Player, coord: Coord) { + self.check_invariants(); + debug_assert!(self.is_free(coord)); + + self.insert_board_element_at(coord, Element::Ring(player)); + match player { + Player::A => self.rings_a.push(coord), + Player::B => self.rings_b.push(coord), + } + } + + pub fn remove_ring(&mut self, coord: Coord) { + self.check_invariants(); + debug_assert!(self.element_at(coord).is_ring()); + + self.remove_board_element_at(&coord); + self.rings_a.retain(|&x| x != coord); + self.rings_b.retain(|&x| x != coord); + } + + pub fn num_rings(&self) -> usize { + self.check_invariants(); + + self.rings_a.len() + self.rings_b.len() + } + + pub fn add_marker(&mut self, player: Player, coord: Coord) { + self.check_invariants(); + debug_assert!(self.is_free(coord)); + + self.insert_board_element_at(coord, Element::Marker(player)); + match player { + Player::A => self.markers_a.push(coord), + Player::B => self.markers_b.push(coord), + } + } + + pub fn remove_marker(&mut self, coord: Coord) { + self.check_invariants(); + debug_assert!(self.has_marker_at(coord)); + + self.remove_board_element_at(&coord); + self.markers_a.retain(|&x| x != coord); + self.markers_b.retain(|&x| x != coord); + } + + pub fn num_markers(&self, player: Player) -> usize { + self.check_invariants(); + + match player { + Player::A => self.markers_a.len(), + Player::B => self.markers_b.len(), + } + } + + pub fn free_coords(&self) -> impl Iterator + '_ { + self.check_invariants(); + + all_coords() + .into_iter() + .filter(|&coord| self.is_free(coord)) + } + + pub fn ring_coords(&self, player: Player) -> impl Iterator + '_ { + self.check_invariants(); + + match player { + Player::A => self.rings_a.iter().copied(), + Player::B => self.rings_b.iter().copied(), + } + } + + pub fn marker_coords(&self, player: Player) -> impl Iterator + '_ { + self.check_invariants(); + + match player { + Player::A => self.markers_a.iter().copied(), + Player::B => self.markers_b.iter().copied(), + } + } + + pub fn ring_moves(&self, start: Coord) -> Vec { + self.check_invariants(); + + let mut moves = Vec::new(); + + for d in DIRECTIONS { + let mut current = start + d.direction(); + + // Skip over arbitrarily many free spaces + while current.is_inside_board() && self.is_free(current) { + moves.push(current); + current = current + d.direction(); + } + + // Skip over arbitrarily many markers, but stop immediately after + while self.has_marker_at(current) && current.is_inside_board() { + current = current + d.direction(); + } + + if current.is_inside_board() && self.is_free(current) { + moves.push(current); + } + } + + moves + } + + pub fn is_valid_ring_move(&self, start: Coord, end: Coord) -> bool { + self.check_invariants(); + + self.ring_moves(start).contains(&end) + } + + fn can_place_marker_at(&self, coord: Coord, player: Player) -> bool { + self.check_invariants(); + + // TODO: is this logic correct? + (self.element_at(coord) == Element::Ring(player)) && !self.ring_moves(coord).is_empty() + } + + pub fn marker_moves(&self, player: Player) -> impl Iterator + '_ { + self.check_invariants(); + + self.ring_coords(player) + .filter(move |c| self.can_place_marker_at(*c, player)) + } + + pub fn flip_markers_between(&mut self, start: Coord, end: Coord) { + self.check_invariants(); + + debug_assert!(start.is_inside_board()); + debug_assert!(end.is_inside_board()); + + for coord in Coord::between(start, end) { + if let Element::Marker(player) = self.element_at_mut_unchecked(coord) { + player.flip(); + + if *player == Player::A { + self.markers_a.push(coord); + self.markers_b.retain(|&x| x != coord); + } else { + self.markers_b.push(coord); + self.markers_a.retain(|&x| x != coord); + } + } + } + } + + /// Returns the coordinates of a run (if one exists), starting at the given seed. + pub fn run_coords_from(&self, start: Coord) -> Option> { + self.check_invariants(); + + let seed = self.element_at(start); + let player = seed.player().unwrap(); + + debug_assert!(seed.is_marker()); + + for a in AXES { + let markers_positive = (1i8..=4i8) + .map(|i| start + a.direction() * i) + .take_while(|c| self.element_at(*c) == Element::Marker(player)); + let markers_negative = (1i8..=4i8) + .map(|i| start - a.direction() * i) + .take_while(|c| self.element_at(*c) == Element::Marker(player)); + + let run_coords: Vec<_> = iter::once(start) + .chain(markers_positive.interleave(markers_negative)) + .take(5) + .collect(); + + if run_coords.len() == 5 { + return Some(run_coords); + } + } + + None + } + + fn check_run_along_line(&self, start: Coord, direction: Coord, steps: i8) -> CheckRunResult { + let mut num_consecutive = 0; + let mut player = None; + + let mut a_has_run = false; + let mut b_has_run = false; + + for n in 0..steps { + let coord = start + direction * n; + + match self.element_at_unchecked(coord) { + Element::Marker(p) => { + if Some(p) == player { + num_consecutive += 1; + + if num_consecutive == 5 { + if p == Player::A { + a_has_run = true; + } else { + b_has_run = true; + } + } + } else { + player = Some(p); + num_consecutive = 1; + } + } + _ => { + player = None; + num_consecutive = 0; + } + } + } + + CheckRunResult { + a_has_run, + b_has_run, + } + } + + /// Returns true if the player has a run + pub fn check_run(&self) -> CheckRunResult { + self.check_invariants(); + + let mut result = CheckRunResult { + a_has_run: false, + b_has_run: false, + }; + + // This is not pretty, but it's 10x faster than the naive implementation using run_coords_from + // and 5x faster than running across the [-5..5] x [-5..5] grid and checking for valid coordinates. + + // x direction + let x = Coord::new(1, 0); + result.or(&self.check_run_along_line(Coord::new(-1, 4), x, 7)); + result.or(&self.check_run_along_line(Coord::new(-2, 3), x, 8)); + result.or(&self.check_run_along_line(Coord::new(-3, 2), x, 9)); + result.or(&self.check_run_along_line(Coord::new(-4, 1), x, 10)); + result.or(&self.check_run_along_line(Coord::new(-4, 0), x, 9)); + result.or(&self.check_run_along_line(Coord::new(-5, -1), x, 10)); + result.or(&self.check_run_along_line(Coord::new(-5, -2), x, 9)); + result.or(&self.check_run_along_line(Coord::new(-5, -3), x, 8)); + result.or(&self.check_run_along_line(Coord::new(-5, -4), x, 7)); + + // y direction + let y = Coord::new(0, 1); + result.or(&self.check_run_along_line(Coord::new(-4, -5), y, 7)); + result.or(&self.check_run_along_line(Coord::new(-3, -5), y, 8)); + result.or(&self.check_run_along_line(Coord::new(-2, -5), y, 9)); + result.or(&self.check_run_along_line(Coord::new(-1, -5), y, 10)); + result.or(&self.check_run_along_line(Coord::new(0, -4), y, 9)); + result.or(&self.check_run_along_line(Coord::new(1, -4), y, 10)); + result.or(&self.check_run_along_line(Coord::new(2, -3), y, 9)); + result.or(&self.check_run_along_line(Coord::new(3, -2), y, 8)); + result.or(&self.check_run_along_line(Coord::new(4, -1), y, 7)); + + // diagonal direction + let d = Coord::new(1, 1); + result.or(&self.check_run_along_line(Coord::new(-5, -1), d, 7)); + result.or(&self.check_run_along_line(Coord::new(-5, -2), d, 8)); + result.or(&self.check_run_along_line(Coord::new(-5, -3), d, 9)); + result.or(&self.check_run_along_line(Coord::new(-5, -4), d, 10)); + result.or(&self.check_run_along_line(Coord::new(-4, -4), d, 9)); + result.or(&self.check_run_along_line(Coord::new(-4, -5), d, 10)); + result.or(&self.check_run_along_line(Coord::new(-3, -5), d, 9)); + result.or(&self.check_run_along_line(Coord::new(-2, -5), d, 8)); + result.or(&self.check_run_along_line(Coord::new(-1, -5), d, 7)); + + result + } + + /// Return coordinates that belong to a run. Multiple runs can exist at the same time. + pub fn run_coords(&self, player: Player) -> Vec { + self.check_invariants(); + + let mut run_coords = Vec::new(); + for coord in self.marker_coords(player) { + if let Some(coords) = self.run_coords_from(coord) { + run_coords.extend(coords); + } + } + run_coords + } + + pub fn remove_run(&mut self, seed: Coord) { + self.check_invariants(); + + let run_coords = self + .run_coords_from(seed) + .expect("remove_run called with invalid seed"); + for coord in run_coords { + self.remove_marker(coord); + } + } + + #[cfg(debug_assertions)] + fn check_invariants(&self) { + for coord in all_coords() { + match self.element_at(coord) { + Element::Ring(Player::A) => { + debug_assert!(self.rings_a.contains(&coord)); + debug_assert!(!self.rings_b.contains(&coord)); + } + Element::Ring(Player::B) => { + debug_assert!(self.rings_b.contains(&coord)); + debug_assert!(!self.rings_a.contains(&coord)); + } + Element::Marker(Player::A) => { + debug_assert!(self.markers_a.contains(&coord)); + debug_assert!(!self.markers_b.contains(&coord)); + } + Element::Marker(Player::B) => { + debug_assert!(self.markers_b.contains(&coord)); + debug_assert!(!self.markers_a.contains(&coord)); + } + Element::Empty => { + debug_assert!(!self.rings_a.contains(&coord)); + debug_assert!(!self.rings_b.contains(&coord)); + debug_assert!(!self.markers_a.contains(&coord)); + debug_assert!(!self.markers_b.contains(&coord)); + } + } + } + + for coord in self.rings_a.iter().copied() { + debug_assert!(self.element_at(coord) == Element::Ring(Player::A)); + } + + for coord in self.rings_b.iter().copied() { + debug_assert!(self.element_at(coord) == Element::Ring(Player::B)); + } + + for coord in self.markers_a.iter().copied() { + debug_assert!(self.element_at(coord) == Element::Marker(Player::A)); + } + + for coord in self.markers_b.iter().copied() { + debug_assert!(self.element_at(coord) == Element::Marker(Player::B)); + } + } + + pub fn fill_board_from_lists(&mut self) { + let rings_a = self.rings_a.clone(); + let rings_b = self.rings_b.clone(); + let markers_a = self.markers_a.clone(); + let markers_b = self.markers_b.clone(); + + for coord in rings_a { + self.insert_board_element_at(coord, Element::Ring(Player::A)); + } + + for coord in rings_b { + self.insert_board_element_at(coord, Element::Ring(Player::B)); + } + + for coord in markers_a { + self.insert_board_element_at(coord, Element::Marker(Player::A)); + } + + for coord in markers_b { + self.insert_board_element_at(coord, Element::Marker(Player::B)); + } + + self.check_invariants(); + } + + #[cfg(not(debug_assertions))] + fn check_invariants(&self) {} +} diff --git a/src/yinsh/core.rs b/src/yinsh/core.rs new file mode 100644 index 0000000..03d5f37 --- /dev/null +++ b/src/yinsh/core.rs @@ -0,0 +1,164 @@ +use std::ops::{Add, Mul, Sub}; + +use serde::{Deserialize, Serialize}; + +/// All Yinsh coordinates lie on a hexagonal grid within a circle of radius 4.6. +const BOARD_RADIUS_SQUARED: f32 = 4.6_f32 * 4.6_f32; + +/// Yinsh hex coordinates +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +pub struct Coord { + pub x: i8, + pub y: i8, +} + +impl Coord { + pub fn new(x: i8, y: i8) -> Self { + Coord { x, y } + } + + /// Check if the point lies within the boundaries of the board. + pub fn is_inside_board(&self) -> bool { + let sqrt_3 = 3.0_f32.sqrt(); + let x = self.x as f32; + let y = self.y as f32; + (0.5 * sqrt_3 * x).powi(2) + (0.5 * x - y).powi(2) <= BOARD_RADIUS_SQUARED + } + + pub fn is_on_same_line_as(&self, other: Coord) -> bool { + (self.x == other.x) || (self.y == other.y) || ((self.x - self.y) == (other.x - other.y)) + } + + fn shorten(&self) -> Coord { + Coord { + x: self.x.max(-1).min(1), + y: self.y.max(-1).min(1), + } + } + + pub fn between(a: Coord, b: Coord) -> Vec { + let mut coords = Vec::new(); + let delta = (b - a).shorten(); + let mut current = a + delta; + while current != b { + coords.push(current); + current = current + delta; + } + coords + } + + pub fn norm(&self) -> f32 { + ((self.x as f32).powi(2) + (self.y as f32).powi(2)).sqrt() + } +} + +impl Add for Coord { + type Output = Coord; + + fn add(self, other: Coord) -> Coord { + Coord { + x: self.x + other.x, + y: self.y + other.y, + } + } +} + +impl Sub for Coord { + type Output = Coord; + + fn sub(self, rhs: Coord) -> Self::Output { + Coord { + x: self.x - rhs.x, + y: self.y - rhs.y, + } + } +} + +impl Mul for Coord { + type Output = Coord; + + fn mul(self, rhs: i8) -> Self::Output { + Coord { + x: self.x * rhs, + y: self.y * rhs, + } + } +} + +/// The six hex directions +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Direction { + N, + NE, + SE, + S, + SW, + NW, +} + +impl Direction { + pub fn direction(&self) -> Coord { + match self { + Direction::N => Coord { x: -1, y: 0 }, + Direction::S => Coord { x: 1, y: 0 }, + Direction::NE => Coord { x: -1, y: -1 }, + Direction::SW => Coord { x: 1, y: 1 }, + Direction::NW => Coord { x: 0, y: 1 }, + Direction::SE => Coord { x: 0, y: -1 }, + } + } +} + +pub const DIRECTIONS: &'static [Direction; 6] = &[ + Direction::N, + Direction::NE, + Direction::SE, + Direction::S, + Direction::SW, + Direction::NW, +]; + +pub const AXES: &'static [Direction; 3] = &[Direction::N, Direction::NE, Direction::NW]; + +/// Player types (white and black) +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] +pub enum Player { + A, + B, +} + +impl Player { + pub fn next(self) -> Self { + match self { + Player::A => Player::B, + Player::B => Player::A, + } + } + + pub fn flip(&mut self) { + *self = self.next(); + } +} + +pub fn all_coords() -> Vec { + let mut coords = Vec::new(); + for x in -5..=5 { + for y in -5..=5 { + let coord = Coord { x, y }; + if coord.is_inside_board() { + coords.push(coord); + } + } + } + coords +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn number_of_grid_intersections() { + assert_eq!(all_coords().len(), 85); + } +} diff --git a/src/yinsh/game_state.rs b/src/yinsh/game_state.rs new file mode 100644 index 0000000..8dfa2e6 --- /dev/null +++ b/src/yinsh/game_state.rs @@ -0,0 +1,181 @@ +use std::path::Path; + +use serde::{Deserialize, Serialize}; + +use super::{Board, Coord, Player}; + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum TurnMode { + /// place a ring on a free field + RingPlacement, + + /// place a marker in one of your rings + MarkerPlacement, + + /// wait for ring movement + WaitForRingMovement(Coord), + + /// move the ring at the given position + RingMovement(Coord), + + /// Remove (one of your) run(s). The parameter + /// holds the last player who moved a ring. + RunRemoval(Player), + + /// Wait for run removal + WaitForRunRemoval(Player), + + /// Remove one of your rings + RingRemoval(Player), + + WaitForRingRemoval(Player), + + /// Do nothing + WaitForMarkerPlacement, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Move { + PlaceRing(Coord), + PlaceMarker(Coord), + MoveRing(Coord, Coord), + RemoveRun(Coord), + RemoveRing(Coord), + Wait, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct GameState { + pub active_player: Player, + pub turn_mode: TurnMode, + pub board: Board, + pub points_a: usize, + pub points_b: usize, +} + +impl GameState { + pub fn initial() -> Self { + Self { + active_player: Player::A, + turn_mode: TurnMode::RingPlacement, + board: Board::empty(), + points_a: 0, + points_b: 0, + } + } + + pub fn perform_move(&mut self, player_move: &Move) { + // println!(); + // println!("Current turn mode: {:?}", self.turn_mode); + // println!("Current active player: {:?}", self.active_player); + // println!("Move: {:?}", player_move); + + match (&self.turn_mode, player_move) { + (TurnMode::RingPlacement, Move::PlaceRing(coord)) => { + self.board.add_ring(self.active_player, *coord); + + self.turn_mode = if self.board.num_rings() <= 9 { + TurnMode::RingPlacement + } else { + TurnMode::MarkerPlacement + }; + } + (TurnMode::MarkerPlacement, Move::PlaceMarker(coord)) => { + self.board.remove_ring(*coord); + self.board.add_marker(self.active_player, *coord); + + self.turn_mode = TurnMode::WaitForRingMovement(*coord); + } + (TurnMode::WaitForRingMovement(start), Move::Wait) => { + self.turn_mode = TurnMode::RingMovement(*start); + } + (TurnMode::RingMovement(_), Move::MoveRing(start, end)) => { + self.board.add_ring(self.active_player, *end); + + self.board.flip_markers_between(*start, *end); + + let result = self.board.check_run(); + + if result.has_run(self.active_player) { + self.turn_mode = TurnMode::WaitForRunRemoval(self.active_player); + } else if result.has_run(self.active_player.next()) { + self.turn_mode = TurnMode::RunRemoval(self.active_player); + } else { + self.turn_mode = TurnMode::MarkerPlacement; + } + } + (TurnMode::WaitForRunRemoval(player_last_ring_move), Move::Wait) => { + self.turn_mode = TurnMode::RunRemoval(*player_last_ring_move); + } + (TurnMode::RunRemoval(player_last_ring_move), Move::RemoveRun(coord)) => { + self.board.remove_run(*coord); + + if self.active_player == Player::A { + self.points_a += 1; + } else { + self.points_b += 1; + } + + self.turn_mode = TurnMode::WaitForRingRemoval(*player_last_ring_move); + } + (TurnMode::WaitForRingRemoval(player_last_ring_move), Move::Wait) => { + self.turn_mode = TurnMode::RingRemoval(*player_last_ring_move); + } + (TurnMode::RingRemoval(player_last_ring_move), Move::RemoveRing(coord)) => { + self.board.remove_ring(*coord); + + let result = self.board.check_run(); + + self.turn_mode = if result.has_run(self.active_player) { + // Active player has a second run, other player needs to wait + TurnMode::WaitForRunRemoval(*player_last_ring_move) + } else if result.has_run(self.active_player.next()) { + // Other player has a run, active player needs to remove it + TurnMode::RunRemoval(*player_last_ring_move) + } else if self.active_player == *player_last_ring_move { + TurnMode::MarkerPlacement + } else { + TurnMode::WaitForMarkerPlacement + }; + } + (TurnMode::WaitForMarkerPlacement, Move::Wait) => { + self.turn_mode = TurnMode::MarkerPlacement; + } + (turn_mode, player_move) => { + unreachable!( + "Received unexpected player move {player_move:?} in mode {turn_mode:?}" + ) + } + } + + self.active_player.flip(); + + // println!("New turn mode: {:?}", self.turn_mode); + // println!("New active player: {:?}", self.active_player); + } + + pub fn winner(&self) -> Option { + if self.points_a >= 3 { + Some(Player::A) + } else if self.points_b >= 3 { + Some(Player::B) + } else { + None + } + } + + pub fn save_to>(&self, path: P) { + let file = std::fs::File::create(path).unwrap(); + serde_yaml::to_writer(file, &self).unwrap(); + } + + pub fn load_from>(path: P) -> Self { + let file = std::fs::File::open(path).unwrap(); + let mut game_state: GameState = serde_yaml::from_reader(file).unwrap(); + + // Patch up the 2D board, which is not serialized/deserialized + game_state.board.fill_board_from_lists(); + + game_state + } +} diff --git a/src/yinsh/mod.rs b/src/yinsh/mod.rs new file mode 100644 index 0000000..4be0fd0 --- /dev/null +++ b/src/yinsh/mod.rs @@ -0,0 +1,8 @@ +mod board; +mod core; +mod game_state; + +pub use board::Board; +pub use core::all_coords; +pub use core::{Coord, Player, DIRECTIONS}; +pub use game_state::{Move, GameState, TurnMode}; diff --git a/tests/ai.rs b/tests/ai.rs new file mode 100644 index 0000000..41a0344 --- /dev/null +++ b/tests/ai.rs @@ -0,0 +1,56 @@ +use yinsh::{Coord, GameState, Heuristic, Move, Player, SimpleHeuristic}; + +#[test] +fn midgame_1() { + let heuristic = SimpleHeuristic { + f_points: 1_000, + f_markers: 10, + f_controlled_markers_own: 0, + f_controlled_markers_opponent: 0, + f_accessible_fields: 0, + }; + + let mut game_state = GameState::load_from("tests/midgame_1.yml"); + + assert_eq!(game_state.active_player, Player::A); + + game_state.perform_move(&Move::PlaceMarker(Coord::new(2, 1))); + game_state.perform_move(&Move::Wait); + game_state.perform_move(&Move::MoveRing(Coord::new(2, 1), Coord::new(2, 2))); + + assert_eq!(game_state.active_player, Player::B); + + game_state.perform_move(&Move::PlaceMarker(Coord::new(-3, -4))); + game_state.perform_move(&Move::Wait); + game_state.perform_move(&Move::MoveRing(Coord::new(-3, -4), Coord::new(-4, -4))); + + assert_eq!(game_state.active_player, Player::A); + + game_state.perform_move(&Move::PlaceMarker(Coord::new(2, 2))); + game_state.perform_move(&Move::Wait); + game_state.perform_move(&Move::MoveRing(Coord::new(2, 2), Coord::new(2, 3))); + + assert_eq!(game_state.active_player, Player::B); + + game_state.perform_move(&Move::Wait); + + assert_eq!(heuristic.evaluate_for_player_a(&game_state), -1080); + + game_state.perform_move(&Move::RemoveRun(Coord::new(2, 2))); + game_state.perform_move(&Move::Wait); + + assert_eq!( + heuristic.evaluate_for_player_a(&game_state), + -1080 + 1000 - 5 * 10 + ); + + game_state.perform_move(&Move::RemoveRing(Coord::new(0, -3))); + game_state.perform_move(&Move::PlaceMarker(Coord::new(-1, 1))); + game_state.perform_move(&Move::Wait); + game_state.perform_move(&Move::MoveRing(Coord::new(-1, 1), Coord::new(-1, 2))); + + assert_eq!( + heuristic.evaluate_for_player_a(&game_state), + -1080 + 1000 - 5 * 10 - 10 + ); +} diff --git a/tests/board.rs b/tests/board.rs new file mode 100644 index 0000000..25ef418 --- /dev/null +++ b/tests/board.rs @@ -0,0 +1,90 @@ +use yinsh::{Board, Coord, Player, DIRECTIONS}; + +#[test] +fn basic_marker_placement() { + let mut board = Board::empty(); + + for c in yinsh::all_coords() { + assert!(board.is_free(c)); + } + + let marker_coord = Coord::new(3, -2); + board.add_marker(Player::A, marker_coord); + + assert!(!board.is_free(marker_coord)); + assert_eq!(board.num_markers(Player::A), 1); + assert_eq!(board.num_markers(Player::B), 0); + + board.remove_marker(marker_coord); + + assert!(board.is_free(marker_coord)); + + assert_eq!(board, Board::empty()); +} + +#[test] +fn basic_ring_placement() { + let mut board = Board::empty(); + + let ring_coord = Coord::new(3, -2); + board.add_ring(Player::A, ring_coord); + + assert!(!board.is_free(ring_coord)); + + assert!(board.has_ring_at(ring_coord, Player::A)); + + board.remove_ring(ring_coord); + + assert!(board.is_free(ring_coord)); + + assert_eq!(board, Board::empty()); +} + +#[test] +fn check_run_basic() { + let mut board = Board::empty(); + + assert!(board.check_run().no_runs()); + + board.add_marker(Player::A, Coord::new(0, -2)); + board.add_marker(Player::A, Coord::new(0, -1)); + board.add_marker(Player::A, Coord::new(0, 0)); + board.add_marker(Player::A, Coord::new(0, 1)); + + assert!(board.check_run().no_runs()); + + board.add_marker(Player::A, Coord::new(0, 2)); + + assert!(board.check_run().has_run(Player::A)); + assert!(!board.check_run().has_run(Player::B)); + + board.add_marker(Player::B, Coord::new(-1, -1)); + board.add_marker(Player::B, Coord::new(-1, 0)); + board.add_marker(Player::B, Coord::new(-1, 1)); + board.add_marker(Player::B, Coord::new(-1, 2)); + + assert!(!board.check_run().has_run(Player::B)); + + board.add_marker(Player::B, Coord::new(-1, -2)); + + assert!(board.check_run().has_run(Player::A)); + assert!(board.check_run().has_run(Player::B)); +} + +#[test] +fn check_run_exhaustive() { + for c in yinsh::all_coords() { + for d in DIRECTIONS { + if (c + d.direction() * 4).is_inside_board() { + dbg!(c, d.direction()); + let mut board = Board::empty(); + + for i in 0..=4i8 { + board.add_marker(Player::A, c + d.direction() * i); + } + + assert!(board.check_run().has_run(Player::A)); + } + } + } +} diff --git a/tests/midgame_1.yml b/tests/midgame_1.yml new file mode 100644 index 0000000..42907ab --- /dev/null +++ b/tests/midgame_1.yml @@ -0,0 +1,81 @@ +active_player: A +turn_mode: MarkerPlacement +board: + rings_a: + - x: -1 + y: -2 + - x: 0 + y: -3 + - x: 0 + y: 1 + - x: -2 + y: -4 + - x: 2 + y: 1 + rings_b: + - x: -1 + y: 1 + - x: -3 + y: -4 + - x: -2 + y: -1 + - x: 1 + y: -1 + markers_a: + - x: -2 + y: -2 + - x: 1 + y: -2 + - x: -5 + y: -4 + - x: -2 + y: -3 + - x: -3 + y: -3 + - x: 1 + y: -3 + - x: 2 + y: -2 + - x: 2 + y: -1 + - x: 2 + y: 0 + markers_b: + - x: 3 + y: 4 + - x: 1 + y: 4 + - x: 3 + y: 1 + - x: -4 + y: -5 + - x: 3 + y: 3 + - x: -2 + y: -5 + - x: 1 + y: 2 + - x: 1 + y: 3 + - x: 0 + y: 2 + - x: -4 + y: -2 + - x: -4 + y: -1 + - x: -4 + y: -3 + - x: -1 + y: 0 + - x: 1 + y: 0 + - x: -3 + y: 0 + - x: -3 + y: -2 + - x: -1 + y: -3 + - x: 0 + y: -2 +points_a: 0 +points_b: 1 diff --git a/web/.gitignore b/web/.gitignore new file mode 100644 index 0000000..3c68218 --- /dev/null +++ b/web/.gitignore @@ -0,0 +1,2 @@ +/yinsh_bg.wasm +/yinsh.js diff --git a/web/index.html b/web/index.html new file mode 100644 index 0000000..0f0c06f --- /dev/null +++ b/web/index.html @@ -0,0 +1,38 @@ + + + + + + +
+ +
+ + + diff --git a/yinsh.cabal b/yinsh.cabal deleted file mode 100644 index 4190a19..0000000 --- a/yinsh.cabal +++ /dev/null @@ -1,41 +0,0 @@ -cabal-version: 2.4 -name: yinsh -version: 0.2.0.0 -synopsis: The board game Yinsh, including AI opponent -bug-reports: https://github.com/sharkdp/yinsh -license: MIT -author: David Peter -maintainer: mail@david-peter.de -category: Game -extra-source-files: - README.md - -library - exposed-modules: - Yinsh - AI - Floyd - - other-extensions: BangPatterns FlexibleInstances UndecidableInstances - build-depends: - base ^>=4.16.4.0, - containers ^>=0.6.5.1, - game-tree ^>=0.1.0.0 - - hs-source-dirs: src - default-language: Haskell2010 - -executable yinsh-backend - main-is: Main.hs - - other-extensions: BangPatterns FlexibleInstances UndecidableInstances - build-depends: - base ^>=4.16.4.0, - containers ^>=0.6.5.1, - happstack-server ^>=7.8.0.2, - happstack-server-tls ^>=7.2.1.3, - yinsh - - hs-source-dirs: backend - default-language: Haskell2010 - ghc-options: -threaded -rtsopts