diff --git a/.github/workflows/auto.yaml b/.github/workflows/auto.yaml index 8ec323c..929b862 100644 --- a/.github/workflows/auto.yaml +++ b/.github/workflows/auto.yaml @@ -41,7 +41,7 @@ jobs: env: {} steps: - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - name: Action - install justfile tool uses: extractions/setup-just@v3 @@ -54,7 +54,7 @@ jobs: version: "0.12.0" # - name: Action - install rust - # uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 + # uses: actions-rust-lang/setup-rust-toolchain@v1.14.1 - name: Action - install rust and set to stable uses: actions-rs/toolchain@v1.0.6 @@ -63,7 +63,7 @@ jobs: override: true - name: Action - install Python - uses: actions/setup-python@v5.6.0 + uses: actions/setup-python@v6.0.0 with: python-version: "${{ env.PYTHON_VERSION }}" diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 6980fce..0fd6a00 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -32,7 +32,7 @@ jobs: env: {} steps: - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - name: Action - install justfile tool uses: extractions/setup-just@v3 @@ -45,7 +45,7 @@ jobs: version: "0.12.0" # - name: Action - install rust - # uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 + # uses: actions-rust-lang/setup-rust-toolchain@v1.14.1 - name: Action - install rust and set to stable uses: actions-rs/toolchain@v1.0.6 @@ -54,7 +54,7 @@ jobs: override: true - name: Action - install Python - uses: actions/setup-python@v5.6.0 + uses: actions/setup-python@v6.0.0 with: python-version: "${{ env.PYTHON_VERSION }}" diff --git a/.github/workflows/manual.yaml b/.github/workflows/manual.yaml index c3f7675..e7bd725 100644 --- a/.github/workflows/manual.yaml +++ b/.github/workflows/manual.yaml @@ -39,7 +39,7 @@ jobs: env: {} steps: - - uses: actions/checkout@v4.2.2 + - uses: actions/checkout@v5.0.0 - name: Action - install justfile tool uses: extractions/setup-just@v3 @@ -52,7 +52,7 @@ jobs: version: "0.12.0" # - name: Action - install rust - # uses: actions-rust-lang/setup-rust-toolchain@v1.12.0 + # uses: actions-rust-lang/setup-rust-toolchain@v1.14.1 - name: Action - install rust and set to stable uses: actions-rs/toolchain@v1.0.6 @@ -61,7 +61,7 @@ jobs: override: true - name: Action - install Python - uses: actions/setup-python@v5.6.0 + uses: actions/setup-python@v6.0.0 with: python-version: "${{ env.PYTHON_VERSION }}" diff --git a/Cargo.lock b/Cargo.lock index 92af14d..582ee91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.18" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" +checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" dependencies = [ "anstyle", "anstyle-parse", @@ -37,44 +37,44 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" +checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" [[package]] name = "anstyle-parse" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" +checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.7" +version = "3.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" +checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" dependencies = [ "anstyle", - "once_cell", - "windows-sys 0.59.0", + "once_cell_polyfill", + "windows-sys 0.60.2", ] [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "b0674a1ddeecb70197781e945de4b3b8ffb61fa939a5597bcf48503737663100" [[package]] name = "autocfg" @@ -82,14 +82,14 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dde43e75fd43e8a1bf86103336bc699aa8d17ad1be60c76c0bdfd4828e19b78" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", ] [[package]] name = "autocfg" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "bitflags" @@ -105,9 +105,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "2261d10cca569e4643e526d8dc2e62e433cc8aba21ab764233731f8d369bf394" [[package]] name = "bumpalo" @@ -117,30 +117,30 @@ checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "camino" -version = "1.1.9" +version = "1.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +checksum = "dd0b03af37dad7a14518b7691d81acb0f8222604ad3d1b02f6b4bed5188c0cd5" dependencies = [ "serde", ] [[package]] name = "cargo-config2" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dc3749a36e0423c991f1e7a3e4ab0c36a1f489658313db4b187d401d79cc461" +checksum = "bdb1d44c72604e6dac5d86fb04a07489b78d2e766a6e06c69c0af09af6e294fc" dependencies = [ "serde", "serde_derive", - "toml_edit", - "windows-sys 0.59.0", + "toml 0.9.5", + "windows-sys 0.61.0", ] [[package]] name = "cargo-options" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7488e41578691cf26aa5c8eccd183cb31752fcb68b9c5b1e88e6727a83c78171" +checksum = "f89e1d6d6f65fe04d5e21be9de19d31a074e3b7e43aa39ee5b85f4cee16c3188" dependencies = [ "anstyle", "clap", @@ -192,20 +192,20 @@ dependencies = [ "semver 1.0.26", "serde", "serde_json", - "thiserror 2.0.12", + "thiserror 2.0.16", ] [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" [[package]] name = "clap" -version = "4.5.38" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000" +checksum = "7eac00902d9d136acd712710d71823fb8ac8004ca445a89e73a41d45aa712931" dependencies = [ "clap_builder", "clap_derive", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.38" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120" +checksum = "2ad9bbf750e73b5884fb8a211a9424a1906c1e156724260fdae972f31d70e1d6" dependencies = [ "anstream", "anstyle", @@ -226,21 +226,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.32" +version = "4.5.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7" +checksum = "bbfd7eae0b0f1a6e63d4b13c9c478de77c2eb546fba158ad50b4203dc24b9f9c" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "clap_lex" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" +checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" [[package]] name = "cloudabi" @@ -253,9 +253,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "console" @@ -266,7 +266,7 @@ dependencies = [ "encode_unicode", "libc", "once_cell", - "unicode-width 0.2.1", + "unicode-width", "windows-sys 0.60.2", ] @@ -285,6 +285,31 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "dedent" version = "0.1.1" @@ -293,7 +318,7 @@ checksum = "a8a3dee4e932355439992a45dc631b0979abf9c677958674bd94298bf9002870" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -370,12 +395,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976dd42dc7e85965fe702eb8164f21f450704bdde31faefd6471dba214cb594e" +checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -402,11 +427,11 @@ dependencies = [ [[package]] name = "fs-err" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f89bda4c2a21204059a977ed3bfe746677dfd137b83c339e702b0ac91d482aa" +checksum = "88d7be93788013f265201256d58f04936a8079ad5dc898743aa20525f503b683" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", ] [[package]] @@ -429,7 +454,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -460,7 +485,7 @@ dependencies = [ [[package]] name = "general" -version = "0.2.0" +version = "0.3.0" dependencies = [ "cargo-zigbuild", "dedent", @@ -471,6 +496,8 @@ dependencies = [ "ndarray", "rand 0.9.2", "rand_chacha 0.9.0", + "rayon", + "regex 1.11.2", "rstest", "rustfmt", "serde", @@ -480,11 +507,11 @@ dependencies = [ [[package]] name = "getopts" -version = "0.2.21" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" dependencies = [ - "unicode-width 0.1.14", + "unicode-width", ] [[package]] @@ -495,7 +522,7 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", ] [[package]] @@ -507,14 +534,14 @@ dependencies = [ "cfg-if", "libc", "r-efi", - "wasi 0.14.3+wasi-0.2.4", + "wasi 0.14.4+wasi-0.2.4", ] [[package]] name = "glob" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] name = "goblin" @@ -522,16 +549,16 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daa0a64d21a7eb230583b4c5f4e23b7e4e57974f96620f42a7e75e08ae66d745" dependencies = [ - "log 0.4.27", + "log 0.4.28", "plain", "scroll", ] [[package]] name = "hashbrown" -version = "0.15.3" +version = "0.15.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" [[package]] name = "heck" @@ -541,9 +568,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "indexmap" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" dependencies = [ "equivalent", "hashbrown", @@ -557,7 +584,7 @@ checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd" dependencies = [ "console", "portable-atomic", - "unicode-width 0.2.1", + "unicode-width", "unit-prefix", "web-time", ] @@ -617,17 +644,17 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.172" +version = "0.2.175" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" +checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" [[package]] name = "libredox" -version = "0.1.3" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +checksum = "391290121bad3d37fbddad76d8f5d1c1c314cfc646d143d7e07a3086ddff0ce3" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "libc", ] @@ -643,14 +670,14 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" dependencies = [ - "log 0.4.27", + "log 0.4.28", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" [[package]] name = "matrixmultiply" @@ -658,15 +685,15 @@ version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", "rawpointer", ] [[package]] name = "memchr" -version = "2.7.4" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "ndarray" @@ -707,7 +734,7 @@ version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ - "autocfg 1.4.0", + "autocfg 1.5.0", ] [[package]] @@ -716,6 +743,12 @@ version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +[[package]] +name = "once_cell_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" + [[package]] name = "option-ext" version = "0.2.0" @@ -781,9 +814,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" dependencies = [ "unicode-ident", ] @@ -944,6 +977,26 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" +[[package]] +name = "rayon" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -979,25 +1032,25 @@ dependencies = [ [[package]] name = "regex" -version = "1.11.1" +version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" dependencies = [ "aho-corasick 1.1.3", "memchr", "regex-automata", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" dependencies = [ "aho-corasick 1.1.3", "memchr", - "regex-syntax 0.8.5", + "regex-syntax 0.8.6", ] [[package]] @@ -1011,9 +1064,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" [[package]] name = "relative-path" @@ -1043,10 +1096,10 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "regex 1.11.1", + "regex 1.11.2", "relative-path", "rustc_version 0.4.1", - "syn 2.0.101", + "syn 2.0.106", "unicode-ident", ] @@ -1094,22 +1147,22 @@ dependencies = [ "syntex_errors", "syntex_syntax", "term", - "toml", + "toml 0.4.10", "unicode-segmentation", "winapi 0.2.8", ] [[package]] name = "rustix" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266" +checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.4", "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1135,7 +1188,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1179,7 +1232,7 @@ checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1196,9 +1249,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.8" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" dependencies = [ "serde", ] @@ -1211,12 +1264,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "slab" -version = "0.4.9" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg 1.4.0", -] +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "strings" @@ -1255,9 +1305,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.101" +version = "2.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" dependencies = [ "proc-macro2", "quote", @@ -1323,12 +1373,12 @@ dependencies = [ [[package]] name = "terminal_size" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45c6481c4829e4cc63825e62c49186a34538b7b2750b73b266581ffb612fb5ed" +checksum = "60b8cb979cb11c32ce1603f8137b22262a9d131aaa5c37b5678025f22b8becd0" dependencies = [ "rustix", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -1342,11 +1392,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.16", ] [[package]] @@ -1357,18 +1407,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] [[package]] @@ -1389,25 +1439,51 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.7.0", + "toml_parser", + "winnow", +] + [[package]] name = "toml_datetime" -version = "0.6.9" +version = "0.6.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" + +[[package]] +name = "toml_datetime" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.26" +version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ "indexmap", - "serde", - "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +dependencies = [ "winnow", ] @@ -1429,12 +1505,6 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - [[package]] name = "unicode-width" version = "0.2.1" @@ -1476,15 +1546,15 @@ dependencies = [ [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasi" -version = "0.14.3+wasi-0.2.4" +version = "0.14.4+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +checksum = "88a5f4a424faf49c3c2c344f166f0662341d470ea185e939657aaff130f0ec4a" dependencies = [ "wit-bindgen", ] @@ -1508,10 +1578,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" dependencies = [ "bumpalo", - "log 0.4.27", + "log 0.4.28", "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "wasm-bindgen-shared", ] @@ -1533,7 +1603,7 @@ checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -1609,6 +1679,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +[[package]] +name = "windows-link" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" + [[package]] name = "windows-sys" version = "0.48.0" @@ -1620,20 +1696,20 @@ dependencies = [ [[package]] name = "windows-sys" -version = "0.59.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.52.6", + "windows-targets 0.53.3", ] [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.61.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" dependencies = [ - "windows-targets 0.53.3", + "windows-link 0.2.0", ] [[package]] @@ -1651,33 +1727,17 @@ dependencies = [ "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 0.52.6", - "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-targets" version = "0.53.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" dependencies = [ - "windows-link", + "windows-link 0.1.3", "windows_aarch64_gnullvm 0.53.0", "windows_aarch64_msvc 0.53.0", "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", + "windows_i686_gnullvm", "windows_i686_msvc 0.53.0", "windows_x86_64_gnu 0.53.0", "windows_x86_64_gnullvm 0.53.0", @@ -1690,12 +1750,6 @@ 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_gnullvm" version = "0.53.0" @@ -1708,12 +1762,6 @@ 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_aarch64_msvc" version = "0.53.0" @@ -1726,24 +1774,12 @@ 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_gnu" version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" -[[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_gnullvm" version = "0.53.0" @@ -1756,12 +1792,6 @@ 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_i686_msvc" version = "0.53.0" @@ -1774,12 +1804,6 @@ 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_gnu" version = "0.53.0" @@ -1792,12 +1816,6 @@ 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_gnullvm" version = "0.53.0" @@ -1810,12 +1828,6 @@ 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 = "windows_x86_64_msvc" version = "0.53.0" @@ -1824,9 +1836,9 @@ checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" [[package]] name = "winnow" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" dependencies = [ "memchr", ] @@ -1839,26 +1851,26 @@ checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" [[package]] name = "wit-bindgen" -version = "0.45.0" +version = "0.45.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" +checksum = "5c573471f125075647d03df72e026074b7203790d41351cd6edc96f46bcccd36" [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "0894878a5fa3edfd6da3f88c4805f4c8558e2b996227a3d864f47fe11e38282c" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "88d2b8d9c68ad2b9e4340d7832716a4d21a22a1154777ad56ea55c51a9cf3831" dependencies = [ "proc-macro2", "quote", - "syn 2.0.101", + "syn 2.0.106", ] diff --git a/Cargo.toml b/Cargo.toml index 85a5fcc..e0d7141 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ [package] name = "general" -version = "0.2.0" +version = "0.3.0" edition = "2024" description = "Code for challenges from various platforms" homepage = "github.com/raj-open/code-challenges" @@ -55,6 +55,7 @@ lto = false # link-time optimisation # ] [dependencies] +regex = {version = "^1.11.2"} serde = {version = "^1.0.219", features = ["derive"]} serde_json = {version = "^1.0.143"} dict_derive = {version = "^0.6.0" } @@ -62,6 +63,7 @@ dedent = {version="^0.1.1"} itertools = {version = "^0.14.0"} indoc = {version="^2.0.6"} indicatif = {version = "^0.18.0"} +rayon = {version = "^1.11.0"} strip-ansi-escapes = {version="^0.2.1"} rand = {version="^0.9.2"} rand_chacha = {version = "^0.9.0"} diff --git a/README.md b/README.md index ca3ea8a..0d487c8 100644 --- a/README.md +++ b/README.md @@ -130,81 +130,93 @@ To perform this separately, use just build-compile GeniusSquare ``` -which produces the binary in [target/release/GeniusSquare](target/release/GeniusSquare). +which copy the binary in [target/release/GeniusSquare](target/release/GeniusSquare) to the [dist](dist) folder. The standalone binary can be called as above: ```bash -./target/release/GeniusSquare +./dist/GeniusSquare # with random seed -./target/release/GeniusSquare {Seed} -./target/release/GeniusSquare 1234 +./dist/GeniusSquare {Seed} +./dist/GeniusSquare 1234 # with given initialisation -./target/release/GeniusSquare {Dice1} {Dice2} ... {Dice7} -./target/release/GeniusSquare B1 C4 D6 F1 F2 F3 F5 +./dist/GeniusSquare {Dice1} {Dice2} ... {Dice7} +./dist/GeniusSquare B1 C4 D6 F1 F2 F3 F5 ``` +#### Note on the algorithm #### + +The solver currently relies on a depth-first tree-search algorithm, +with adaptive sorting, i.e. once pieces have been placed, +the order of computation of the remaining pieces +are locally sorted (in ascending order) based on the number of next possible moves. + #### Example #### Calling ```bash -just run-rust GeniusSquare B1 C4 D6 F1 F2 F3 F5 +just run-rust GeniusSquare B1 C4 D2 D6 E5 F1 F3 ``` results in ```bash -Roll: B1, C4, D6, F1, F2, F3, F5. - +Roll: B1 C4 D2 D6 E5 F1 F3. Problem: -╔═══╦═══╤═══╤═══╤═══╤═══╤═══╕ -║ ║ A │ B │ C │ D │ E │ F │ -╠═══╬═══╪═══╪═══╪═══╪═══╪═══╡ -║ 1 ║ │ ■ │ │ │ │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 2 ║ │ │ │ │ │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 3 ║ │ │ │ │ │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 4 ║ │ │ ■ │ │ │ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 5 ║ │ │ │ │ │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 6 ║ │ │ │ ■ │ │ │ -╙───╨───┴───┴───┴───┴───┴───┘ - -Compute solution... - -...completed in 725.18ms - -Solution: -╔═══╦═══╤═══╤═══╤═══╤═══╤═══╕ -║ ║ A │ B │ C │ D │ E │ F │ -╠═══╬═══╪═══╪═══╪═══╪═══╪═══╡ -║ 1 ║ 1 │ ■ │ 2 │ 2 │ Z │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 2 ║ L │ X │ X │ Z │ Z │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 3 ║ L │ X │ X │ Z │ T │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 4 ║ L │ L │ ■ │ T │ T │ T │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 5 ║ 4 │ 4 │ 4 │ 4 │ C │ ■ │ -╠───╬───┼───┼───┼───┼───┼───┤ -║ 6 ║ 3 │ 3 │ 3 │ ■ │ C │ C │ -╙───╨───┴───┴───┴───┴───┴───┘ + ╔═══╦═══╦═══╦═══╦═══╦═══╗ + ║ A ║ B ║ C ║ D ║ E ║ F ║ + ╚═══╩═══╩═══╩═══╩═══╩═══╝ +╔═══╗ ┼───┼ ┼───┼ +║ 1 ║ │ ■ │ │ ■ │ +╠═══╣ ┼───┼ ┼───┼ ┼───┼ +║ 2 ║ │ ■ │ +╠═══╣ ┼───┼ ┼───┼ +║ 3 ║ │ ■ │ +╠═══╣ ┼───┼ ┼───┼ +║ 4 ║ │ ■ │ +╠═══╣ ┼───┼ ┼───┼ +║ 5 ║ │ ■ │ +╠═══╣ ┼───┼───┼ +║ 6 ║ │ ■ │ +╚═══╝ ┼───┼ + +Compute solution ... found 33 solutions. +Time for 1st solution: 3.929ms +Average time per solution: 2.48506ms +Total time: 82.007ms + +Solution 1: + ╔═══╦═══╦═══╦═══╦═══╦═══╗ + ║ A ║ B ║ C ║ D ║ E ║ F ║ + ╚═══╩═══╩═══╩═══╩═══╩═══╝ +╔═══╗ ┼───┼───┼───┼───┼───┼───┼ +║ 1 ║ │ 2 │ ■ │ Z Z │ C │ ■ │ +╠═══╣ ┼ ┼───┼ ┼───┼ ┼───┼ +║ 2 ║ │ 2 │ Z Z │ ■ │ C C │ +╠═══╣ ┼───┼───┼───┼───┼───┼───┼ +║ 3 ║ │ T T T │ X X │ ■ │ +╠═══╣ ┼───┼ ┼───┼ ┼───┼ +║ 4 ║ │ 1 │ T │ ■ │ X X │ L │ +╠═══╣ ┼───┼───┼───┼───┼───┼ ┼ +║ 5 ║ │ 4 4 4 4 │ ■ │ L │ +╠═══╣ ┼───┼───┼───┼───┼───┼ ┼ +║ 6 ║ │ 3 3 3 │ ■ │ L L │ +╚═══╝ ┼───┼───┼───┼───┼───┼───┼ ``` in the console. -The solver currently relies on a brute force tree-search algorithm, -and provides solutions at the `Wizard` level, +The algoirithm provides solutions at the `Wizard` level, viz. no collisions occur and none of the pieces ```text -1 2 3 CC - 2 3 C - 3 +┌───┐ ┌───┐ ┌───┐ ┌───┬───┐ +│ 1 │ │ 2 │ │ 3 │ │ C C │ +└───┘ ├ ┤ ├ ┤ ├ ┼───┘ + │ 2 │ │ 3 │ │ C │ + └───┘ ├ ┤ └───┘ + │ 3 │ + └───┘ ``` are adjacent (in the sense of touching edges). diff --git a/dist/VERSION b/dist/VERSION index 0ea3a94..0d91a54 100644 --- a/dist/VERSION +++ b/dist/VERSION @@ -1 +1 @@ -0.2.0 +0.3.0 diff --git a/justfile b/justfile index 3b6a9a7..b111518 100644 --- a/justfile +++ b/justfile @@ -101,6 +101,9 @@ _rust_path_to_test_module path: setup: @echo "TASK: SETUP" @- cp -n "templates/template.env" ".env" + @rustup toolchain install stable + @rustup update + @rustup override set stable build: @just build-venv @@ -117,9 +120,9 @@ build-requirements: @just build-requirements-dependencies build-requirements-basic: - @cargo update --verbose - @cargo install --locked --force cargo-zigbuild - @# cargo install --locked --force rustfmt + @cargo +stable update --verbose + @cargo +stable install --locked --force cargo-zigbuild + @# cargo +stable install --locked --force rustfmt @{{PYVENV_ON}} && {{PYVENV}} -m pip install --upgrade pip @{{PYVENV_ON}} && {{PYVENV}} -m pip install ruff uv @@ -133,8 +136,11 @@ build-requirements-dependencies: @{{PYVENV_ON}} && {{PYVENV}} -m uv sync build-compile module="${MAIN_MODULE}": - @# cargo zigbuild --target-dir "target" --release --lib - @cargo zigbuild --target-dir "target" --release --bin "${MAIN_MODULE}" + @rustup override set stable + @# cargo +stable zigbuild --target-dir "target" --release --lib + @- rm "dist/{{module}}" 2> /dev/null + @cargo +stable zigbuild --target-dir "target" --release --bin "{{module}}" + @cp "target/release/{{module}}" dist # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # TARGETS: execution @@ -145,8 +151,8 @@ run-py module="main" *args="": run-rust module="${MAIN_MODULE}" *args="": @just build-compile "{{module}}" - @# "./target/release/{{module}}" {{args}} - @cargo run --release --bin "{{module}}" {{args}} + @# "dist/{{module}}" {{args}} + @cargo +stable run --release --bin "{{module}}" {{args}} # -------------------------------- # TARGETS: development @@ -158,7 +164,7 @@ dev *args: dev-rust module="${MAIN_MODULE}" *args="": @just build-compile "{{module}}" @# "./target/release/{{module}}" {{args}} - @cargo run --bin "{{module}}" {{args}} + @cargo +stable run --bin "{{module}}" {{args}} # -------------------------------- # TARGETS: tests @@ -173,39 +179,39 @@ tests-logs log_path="logs": @just _display-logs test-unit path *args: - @cargo zigbuild --tests + @cargo +stable zigbuild --tests @echo "run unit tests in $( just _rust_path_to_test_module "{{path}}")" - @cargo test --lib "$( just _rust_path_to_test_module "{{path}}")" {{args}} -- --nocapture + @cargo +stable test --lib "$( just _rust_path_to_test_module "{{path}}")" {{args}} -- --nocapture @# echo "run unit tests in $( just _rust_path_to_module "{{path}}")" - @# cargo test --lib "$( just _rust_path_to_module "{{path}}")" {{args}} -- --nocapture + @# cargo +stable test --lib "$( just _rust_path_to_module "{{path}}")" {{args}} -- --nocapture test-unit-optimised path *args: - @cargo zigbuild --tests --release + @cargo +stable zigbuild --tests --release @echo "run unit tests in $( just _rust_path_to_test_module "{{path}}")" - @cargo test --lib "$( just _rust_path_to_test_module "{{path}}")" {{args}} -- --nocapture + @cargo +stable test --lib "$( just _rust_path_to_test_module "{{path}}")" {{args}} -- --nocapture @# echo "run unit tests in $( just _rust_path_to_module "{{path}}")" - @# cargo test --lib "$( just _rust_path_to_module "{{path}}")" {{args}} -- --nocapture + @# cargo +stable test --lib "$( just _rust_path_to_module "{{path}}")" {{args}} -- --nocapture tests-unit *args: @just _reset-logs - @cargo zigbuild --tests - @cargo test --lib {{args}} -- --nocapture + @cargo +stable zigbuild --tests + @cargo +stable test --lib {{args}} -- --nocapture tests-unit-optimised *args: @just _reset-logs - @cargo zigbuild --tests --release - @cargo test --lib {{args}} -- --nocapture + @cargo +stable zigbuild --tests --release + @cargo +stable test --lib {{args}} -- --nocapture # -------------------------------- # TARGETS: prettify # -------------------------------- prettify: - @cargo fmt --verbose + @cargo +nightly fmt --all --verbose -- --config-path rustfmt.toml prettify-dry: @echo "Not yet implemented" - @# cargo fmt --verbose --check + @# cargo +stable fmt --verbose --check # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # TARGETS: clean @@ -219,7 +225,7 @@ clean-basic log_path="logs": @echo "All system artefacts will be force removed." @- just _clean-all-files "." ".DS_Store" 2> /dev/null @echo "All build artefacts will be force removed." - @cargo clean + @cargo +stable clean @just _clean-all-files "." "*.rs.bk" @- rm -rf ".venv" 2> /dev/null @- rm -rf "target" 2> /dev/null @@ -277,14 +283,14 @@ watch-logs-all n="10": check-system: @echo "Operating System detected: {{os_family()}}" - @echo "Cargo command: $( cargo --version )" + @echo "cargo +stable command: $( cargo +stable --version )" @echo "Rustc command: $( rustc --version )" @echo "Python command used: ${PYTHON_PATH}" @echo "Python command for venv: {{PYVENV}}" @echo "Python path for venv: $( {{PYVENV_ON}} && which {{PYVENV}} )" - @echo "Cargo Zigbuild: $( cargo-zigbuild --version )" + @echo "cargo +stable Zigbuild: $( cargo-zigbuild --version )" check-system-requirements: - @just _check-tool "cargo" "cargo" - @# just _check-tool "cargo fmt -- --force" "cargo fmt" + @just _check-tool "cargo +stable" "cargo +stable" + @# just _check-tool "cargo +stable fmt -- --force" "cargo +stable fmt" @just _check-tool "cargo-zigbuild" "cargo-zigbuild" diff --git a/pyproject.toml b/pyproject.toml index 184aee3..5bbc418 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = 'code_challenges' -version = "0.2.0" +version = "0.3.0" description = 'Code for challenges from various platforms' authors = [ {name="raj-open", email="raj-open@users.noreply.github.com"}, @@ -34,16 +34,16 @@ dependencies = [ # -------------------------------- # compiler # -------------------------------- - "pip>=25.1.1", + "pip>=25.2", # -------------------------------- # models # -------------------------------- - "pydantic>=2.11.4", - "pydantic-yaml>=1.4.0", + "pydantic>=2.11.7", + "pydantic-yaml>=1.6.0", ] [dependency-groups] dev = [ - "ruff>=0.11.8", - "uv>=0.7.2", + "ruff>=0.12.12", + "uv>=0.8.15", ] diff --git a/rustfmt.toml b/rustfmt.toml index 19061f4..49e45a6 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -2,9 +2,9 @@ reorder_imports = false combine_control_expr = false condense_wildcard_suffixes = false disable_all_formatting = false -# use_small_heuristics = "Off" +use_small_heuristics = "Off" -fn_args_layout = "Tall" +fn_params_layout = "Tall" fn_single_line = false hard_tabs = false @@ -19,7 +19,5 @@ fn_call_width = 60 max_width = 100 comment_width = 200 normalize_comments = false -doc_comment_width = 200 normalize_doc_attributes = false wrap_comments = false -wrap_doc_comments = false diff --git a/src/_core/errors.rs b/src/_core/errors.rs index d991c12..a350b5c 100644 --- a/src/_core/errors.rs +++ b/src/_core/errors.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::fmt::Debug; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- /// Converts error-like entities to strings #[allow(unused)] diff --git a/src/_core/mod.rs b/src/_core/mod.rs index a715ece..914a732 100644 --- a/src/_core/mod.rs +++ b/src/_core/mod.rs @@ -1,3 +1,4 @@ pub mod errors; pub mod rand; pub mod strings; +pub mod time; diff --git a/src/_core/rand.rs b/src/_core/rand.rs index 5191f06..9f13423 100644 --- a/src/_core/rand.rs +++ b/src/_core/rand.rs @@ -1,14 +1,14 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use rand; use rand::SeedableRng; use rand_chacha::ChaCha8Rng; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- #[allow(unused)] pub fn seed_rng(x: Option) -> ChaCha8Rng { @@ -23,9 +23,9 @@ pub fn seed_rng(x: Option) -> ChaCha8Rng { // create RNG let rng = ChaCha8Rng::from_seed(seed); return rng; - }, + } None => { return ChaCha8Rng::from_os_rng(); - }, + } } } diff --git a/src/_core/strings.rs b/src/_core/strings.rs index 9673e89..b7a39eb 100644 --- a/src/_core/strings.rs +++ b/src/_core/strings.rs @@ -1,12 +1,14 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- +use itertools::Itertools; +use regex::Regex; use strip_ansi_escapes::strip; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- pub fn greet(name: &str) { println!("Hello, {}!", name); @@ -21,5 +23,72 @@ pub fn purify_string(text: &String) -> String { #[allow(unused)] /// Computes length of purified string pub fn purify_string_length(text: &String) -> usize { - purify_string(text).len() + // remove ansii characters + let text = purify_string(text); + // since unicode chars can have length > 1, convert to chars + let chars = text.chars(); + let n = chars.count(); + return n; +} + +#[allow(unused)] +/// Performs a horizontal string join for multline strings +pub fn join_multiline_strings( + blocks: &Vec, + sep_block: Option<&String>, + sep_single: &str, +) -> String { + // split blocks into lines and pad to ensure consistency of widths + let blocks: Vec> = blocks.iter().map(pad_widths).collect(); + + // pad to ensure consistencey of heights + let height = blocks.iter().map(|lines| lines.len()).max().unwrap_or(0); + let blocks: Vec> = blocks.iter().map(|lines| pad_height(lines, height)).collect(); + + // determine a separator + let sep_block0 = ([sep_single].repeat(height)).join("\n"); + let sep_block = sep_block.map_or_else(|| sep_block0, |x| x.clone()); + let sep_block = pad_widths(&sep_block); + let sep_block = pad_height(&sep_block, height); + + // join blocks line-wise + let result = (0..height) + .map(|i| { + let empty = "".to_string(); + let sep = sep_block.get(i).unwrap_or(&empty); + blocks.iter().map(|lines| lines.get(i).unwrap_or(&empty)).join(sep) + }) + .join("\n"); + + return result; +} + +/// Splits a string into lines and pads to ensure uniformity of widths +fn pad_widths(text: &String) -> Vec { + let re = Regex::new(r"\r?\n").unwrap(); + let lines: Vec = re.split(text).map(|x| x.to_string()).collect(); + let width = lines.iter().map(purify_string_length).max().unwrap_or(0); + let lines: Vec = lines + .iter() + .map(|x| { + let n = purify_string_length(x); + let space = " ".repeat(width - n); + return format!("{x}{space}"); + }) + .collect(); + return lines; +} + +/// Splits a string into lines and pads to ensure uniformity of widths +fn pad_height(lines: &Vec, height: usize) -> Vec { + let n = lines.len(); + if n >= height { + return lines.clone(); + } + let line = lines.get(0).map(|x| x.clone()).unwrap_or("".to_string()); + let width = purify_string_length(&line); + let space = " ".repeat(width); + let pad = vec![space.clone(); height - n]; + let lines = [lines.to_owned(), pad].concat(); + return lines; } diff --git a/src/_core/time.rs b/src/_core/time.rs new file mode 100644 index 0000000..d5b57db --- /dev/null +++ b/src/_core/time.rs @@ -0,0 +1,15 @@ +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use std::thread; +use std::time::Duration; + +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- + +#[allow(unused)] +pub fn sleep_ms(time_ms: u64) { + thread::sleep(Duration::from_millis(time_ms)); +} diff --git a/src/app/messages.rs b/src/app/messages.rs index b6ea18c..6260fe2 100644 --- a/src/app/messages.rs +++ b/src/app/messages.rs @@ -1,14 +1,14 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::env; use super::super::_core::strings::purify_string_length; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- #[allow(unused)] pub fn welcome_screen() { @@ -16,16 +16,14 @@ pub fn welcome_screen() { let app_name: &str = exe.file_name().unwrap().to_str().unwrap(); const VERSION: &str = env!("CARGO_PKG_VERSION"); const URL: &str = env!("CARGO_PKG_HOMEPAGE"); - let lines: Vec = vec![ - format!("{app_name} \x1b[92;1mv{VERSION}\x1b[0m"), - format!("{URL}"), - ]; + let lines: Vec = + vec![format!("{app_name} \x1b[92;1mv{VERSION}\x1b[0m"), format!("{URL}")]; display_bordered_message(lines); } -/// ---------------------------------------------------------------- -/// AUXILIARY METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// AUXILIARY METHODS +// ---------------------------------------------------------------- fn display_bordered_message(lines: Vec) { // determine padding @@ -35,11 +33,14 @@ fn display_bordered_message(lines: Vec) { println!("\u{250C}{hbar}\u{2510}"); println!("\u{2502}{hspace}\u{2502}"); - let _: Vec<_> = lines.iter().map(|line| { - let k = purify_string_length(line); - let pad = " ".repeat(n - k); - println!("\u{2502} {line}{pad} \u{2502}"); - }).collect(); + let _: Vec<_> = lines + .iter() + .map(|line| { + let k = purify_string_length(line); + let pad = " ".repeat(n - k); + println!("\u{2502} {line}{pad} \u{2502}"); + }) + .collect(); println!("\u{2502}{hspace}\u{2502}"); println!("\u{2514}{hbar}\u{2518}"); } diff --git a/src/app/mod.rs b/src/app/mod.rs index 2de8453..440f7a3 100644 --- a/src/app/mod.rs +++ b/src/app/mod.rs @@ -1,3 +1,2 @@ /// Submodules for app-level methods - pub mod messages; diff --git a/src/bin/games/genius_square/algorithms/mod.rs b/src/bin/games/genius_square/algorithms/mod.rs index 06fb1e9..72732cd 100644 --- a/src/bin/games/genius_square/algorithms/mod.rs +++ b/src/bin/games/genius_square/algorithms/mod.rs @@ -1,3 +1,2 @@ /// Algorithms used to solve a game state. - pub mod solve; diff --git a/src/bin/games/genius_square/algorithms/solve.rs b/src/bin/games/genius_square/algorithms/solve.rs index 89e6eae..0c789ca 100644 --- a/src/bin/games/genius_square/algorithms/solve.rs +++ b/src/bin/games/genius_square/algorithms/solve.rs @@ -1,44 +1,49 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use indicatif::ProgressBar; use indicatif::ProgressStyle; +use itertools::Itertools; +use std::thread::spawn; +use std::sync::mpsc::channel; +use std::sync::mpsc::Sender; +use std::sync::mpsc::Receiver; +use rayon::iter::IntoParallelIterator; +use rayon::iter::ParallelIterator; -use crate::models::constants::enums::ENUM_PIECES; -use crate::models::constants::enums::EnumPiece; -use crate::models::pieces::models::Piece; -use crate::models::board::models::GameBoard; +use crate::models::constants::ENUM_PIECES; +use crate::models::constants::EnumPiece; +use crate::models::pieces::Piece; +use crate::models::board::GameBoard; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- /// Recursively solves by check all possibilities -pub fn solve_brute_force( - board: &GameBoard, -) -> GameBoard { - let obst = board.get_block().to_owned(); - match recursion(board, &obst, None, None) { - Some(board_) => { - return board_; - }, - None => { - return board.to_owned(); - } - } +pub fn solve_brute_force(board: &GameBoard, with_parallelisation: bool) -> Receiver { + let (tx, rx) = channel::(); + let mut board = board.clone(); + board.initialise_obstacle(); + // DEV-NOTE: This is necessary to ensure that no locking occurs. + spawn(move || { + recursion(&tx, &board, None, None, with_parallelisation); + }); + return rx; } -/// ---------------------------------------------------------------- -/// AUXILIARY METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// SECONDARY METHODS +// ---------------------------------------------------------------- fn recursion( + tx: &Sender, board: &GameBoard, - obst: &Piece, option_kinds: Option<&[EnumPiece]>, option_pbar: Option<&ProgressBar>, -) -> Option { + with_parallelisation: bool, +) { let kinds = option_kinds.unwrap_or(ENUM_PIECES); let n = kinds.len() as u64; @@ -47,47 +52,79 @@ fn recursion( match option_pbar { Some(pbar_) => { pbar = &pbar_; - }, + } None => { pbar = &pbar0; - let style = ProgressStyle::with_template("{spinner:.white} [{elapsed_precise}] [{wide_bar:.white}] {pos}/{len} ({eta_precise})"); + let style = ProgressStyle::with_template( + "{spinner:.white} [{elapsed_precise}] [{wide_bar:.white}] {pos}/{len} ({eta_precise})", + ); pbar.set_style(style.unwrap()) } } if n == 0 { // if nothing left to solve, then return pieces, provide everything is filled - if obst.get_coweight() == 0 { + if board.get_obstacle_coweight() == 0 { pbar.finish_and_clear(); - println!("...completed in {:.2?}", pbar.elapsed()); - return Some(board.to_owned()); + let message = board.to_owned(); + tx.send(message).unwrap(); } } else { + // find the next piece which has the fewest number of next possible moves + let kinds: Vec = kinds + .iter() + .map(|kind| { + let piece = Piece::from_kind(kind, None); + let iterator = board.get_configurations(&piece); + let n = iterator.count(); + return (kind, n); + }) + // sort by ascending values of size of possibilities + .sorted_by_key(|&(_, n)| n as isize) + .map(|(kind, _)| kind.clone()) + .collect(); + // otherwise go through all permissible moves for next piece and then proceed recursively let kind = &kinds[0].clone(); let kinds = &kinds[1..]; let piece0 = Piece::from_kind(kind, None); // initialised piece - for piece in board.get_configurations(&piece0, &obst) { - pbar.inc(1); - // update the obstacle - let obst_ = obst.clone() + piece.clone(); - - // update the solution - let mut board_ = board.clone(); - board_.add_piece(&kind.clone(), &piece); - - // compute remainder of solution recursively - match recursion(&mut board_, &obst_, Some(kinds), Some(&pbar)) { - Some(board_) => { - return Some(board_); - }, - None => { - let k = pbar.position(); - pbar.set_position((k - 1).max(0)); - }, - } + if with_parallelisation { + board + .get_configurations(&piece0) + .collect::>() + // DEV-NOTE: uses from Rayon + .into_par_iter() + .for_each(|piece| { + recursion_body(tx, board, &piece, kinds, kind, pbar, with_parallelisation); + }) + } else { + board.get_configurations(&piece0).for_each(|piece| { + recursion_body(tx, board, &piece, kinds, kind, pbar, with_parallelisation); + }) } } +} + +fn recursion_body( + tx: &Sender, + board: &GameBoard, + piece: &Piece, + kinds: &[EnumPiece], + kind: &EnumPiece, + pbar: &ProgressBar, + with_parallelisation: bool, +) { + pbar.inc(1); + let mut board_ = board.clone(); + + // update the solution + board_.add_piece(&kind.clone(), &piece); + + // update the obstacle + board_.update_obstacle(&piece); - return None; + // compute remainder of solution recursively + recursion(tx, &board_, Some(kinds), Some(&pbar), with_parallelisation); + let k = pbar.position(); + pbar.set_position((k - 1).max(0)); } diff --git a/src/bin/games/genius_square/features/constants.rs b/src/bin/games/genius_square/features/constants.rs new file mode 100644 index 0000000..d55d0ec --- /dev/null +++ b/src/bin/games/genius_square/features/constants.rs @@ -0,0 +1,11 @@ +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use std::time::Duration; + +// ---------------------------------------------------------------- +// CONSTANTS +// ---------------------------------------------------------------- + +pub const TIMEOUT: Duration = Duration::from_secs(10); diff --git a/src/bin/games/genius_square/features/feat_initialise_game.rs b/src/bin/games/genius_square/features/feat_initialise_game.rs new file mode 100644 index 0000000..ef35846 --- /dev/null +++ b/src/bin/games/genius_square/features/feat_initialise_game.rs @@ -0,0 +1,35 @@ +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use rand_chacha::ChaCha8Rng; + +use crate::models::dice::roll_dice; +use crate::models::dice::Die; +use crate::models::constants::EnumPiece; +use crate::models::pieces::Piece; +use crate::models::board::GameBoard; + +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- + +/// Feature to set up the game +pub fn feature_initialise_game( + rng: &mut ChaCha8Rng, + option_roll: Option>, +) -> GameBoard { + // Roll the dice + let mut faces = option_roll.unwrap_or_else(|| roll_dice(rng)); + faces.sort(); + let dice: Vec = faces.iter().map(|face| Die::from_string(face)).collect(); + println!("\nRoll: {}", faces.join(" ")); + + // Establish the problem + let coords = dice.iter().map(|die| die.to_coords()).collect(); + let block = Piece::from_coords(coords, Some(EnumPiece::Block)); + let board = GameBoard::new(&block); + println!("\nProblem:\n{}", board.pretty()); + + return board; +} diff --git a/src/bin/games/genius_square/features/feat_solve_game.rs b/src/bin/games/genius_square/features/feat_solve_game.rs new file mode 100644 index 0000000..6f5b38c --- /dev/null +++ b/src/bin/games/genius_square/features/feat_solve_game.rs @@ -0,0 +1,55 @@ +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use std::time::Duration; +use std::time::SystemTime; + +use crate::models::board::GameBoard; +use crate::algorithms::solve::solve_brute_force; +use super::constants::TIMEOUT; + +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- + +/// Feature to solve the problem +pub fn feature_solve_game(board: &GameBoard) -> Option { + print!("\nCompute solution ... "); + let rx = solve_brute_force(&board, true); + let mut solution: Option = None; + let mut dt: Option = None; + let mut n = 0; + let time = SystemTime::now(); + + while let Ok(board) = rx.recv_timeout(TIMEOUT) { + if n == 0 { + dt = Some(time.elapsed().unwrap()); + solution = Some(board); + } + n += 1; + } + + let dt_total = time.elapsed().unwrap(); + let dt_mean: Duration = if n > 0 { + dt_total / n + } else { + Duration::from_secs(0) + }; + let dt = dt.unwrap_or(dt_total); + match solution { + // DEV-NOTE: use 'ref' to borrow + Some(ref board) => { + println!("found {n} solutions."); + println!("Time for 1st solution: {dt:2?}"); + println!("Average time per solution: {dt_mean:2?}"); + println!("Total time: {dt_total:2?}"); + println!("\nSolution 1:\n{}\n", board.pretty()); + } + None => { + println!("\x1b[91mno solution found!\x1b[0m\n"); + } + } + + return solution; +} diff --git a/src/bin/games/genius_square/features/mod.rs b/src/bin/games/genius_square/features/mod.rs index aee96f5..5987a37 100644 --- a/src/bin/games/genius_square/features/mod.rs +++ b/src/bin/games/genius_square/features/mod.rs @@ -1,3 +1,7 @@ /// Highest logic of application. +pub mod constants; +pub mod feat_initialise_game; +pub mod feat_solve_game; -pub mod setup_game; +pub use feat_initialise_game::feature_initialise_game; +pub use feat_solve_game::feature_solve_game; diff --git a/src/bin/games/genius_square/features/setup_game.rs b/src/bin/games/genius_square/features/setup_game.rs deleted file mode 100644 index d3d85f3..0000000 --- a/src/bin/games/genius_square/features/setup_game.rs +++ /dev/null @@ -1,39 +0,0 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- - -use rand_chacha::ChaCha8Rng; - -use crate::models::dice::methods::roll_dice; -use crate::models::dice::models::Die; -use crate::models::constants::enums::EnumPiece; -use crate::models::pieces::models::Piece; -use crate::models::board::models::GameBoard; -use crate::algorithms::solve::solve_brute_force; - -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- - -pub fn feature_setup_game( - rng: &mut ChaCha8Rng, - option_roll: Option>, -) { - // Roll the dice - let faces = option_roll.unwrap_or_else(|| roll_dice(rng)); - let dice: Vec = faces.iter() - .map(|face| Die::from_string(face)) - .collect(); - println!("\nRoll: {}.\n", faces.join(", ")); - - // Establish the problem - let coords = dice.iter().map(|die| die.to_coords()).collect(); - let block = Piece::from_coords(coords, Some(EnumPiece::Block)); - let mut board = GameBoard::new(&block); - println!("\nProblem:\n{}", board.pretty()); - - // Solve the problem - println!("\nCompute solution...\n"); - board = solve_brute_force(&board); - println!("\nSolution:\n{}\n", board.pretty()); -} diff --git a/src/bin/games/genius_square/main.rs b/src/bin/games/genius_square/main.rs index 760e790..247af42 100644 --- a/src/bin/games/genius_square/main.rs +++ b/src/bin/games/genius_square/main.rs @@ -1,6 +1,6 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::env; @@ -8,21 +8,31 @@ use general::app::messages::welcome_screen; use general::_core; mod algorithms; -mod models; mod features; +mod models; -use models::constants::dice::NUM_DICE; -use features::setup_game::feature_setup_game; +use models::constants::NUM_DICE; +use features::feature_initialise_game; +use features::feature_solve_game; -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- fn main() { let args: Vec = env::args().skip(1).collect(); - let option_roll = if args.len() >= NUM_DICE { Some(args[0..NUM_DICE].to_vec()) } else { None }; - let option_seed = if args.len() >= 1 { Some(args[args.len() - 1].clone()) } else { None }; + let option_roll = if args.len() >= NUM_DICE { + Some(args[0..NUM_DICE].to_vec()) + } else { + None + }; + let option_seed = if args.len() >= 1 { + Some(args[args.len() - 1].clone()) + } else { + None + }; let mut rng = _core::rand::seed_rng(option_seed); welcome_screen(); - feature_setup_game(&mut rng, option_roll); + let board = feature_initialise_game(&mut rng, option_roll); + feature_solve_game(&board); } diff --git a/src/bin/games/genius_square/models/arrays/mod.rs b/src/bin/games/genius_square/models/arrays/mod.rs deleted file mode 100644 index 93e2fc4..0000000 --- a/src/bin/games/genius_square/models/arrays/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -/// Models for handling arrays - -pub mod models; diff --git a/src/bin/games/genius_square/models/binary_arrays/mod.rs b/src/bin/games/genius_square/models/binary_arrays/mod.rs new file mode 100644 index 0000000..886c867 --- /dev/null +++ b/src/bin/games/genius_square/models/binary_arrays/mod.rs @@ -0,0 +1,6 @@ +/// Models for handling arrays +pub mod models_arrays; +pub mod models_grids; + +pub use models_arrays::BinArray; +pub use models_grids::BinGrid; diff --git a/src/bin/games/genius_square/models/arrays/models.rs b/src/bin/games/genius_square/models/binary_arrays/models_arrays.rs similarity index 73% rename from src/bin/games/genius_square/models/arrays/models.rs rename to src/bin/games/genius_square/models/binary_arrays/models_arrays.rs index 1208bec..1d831e3 100644 --- a/src/bin/games/genius_square/models/arrays/models.rs +++ b/src/bin/games/genius_square/models/binary_arrays/models_arrays.rs @@ -1,6 +1,6 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use ndarray::Array2; use ndarray::s as slice; @@ -9,13 +9,15 @@ use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Result; use std::ops::Add; +use std::ops::AddAssign; use std::ops::Mul; +use std::ops::MulAssign; use itertools::iproduct; use itertools::Itertools; -/// ---------------------------------------------------------------- -/// STRUCTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// STRUCTS +// ---------------------------------------------------------------- #[derive(Clone, Debug)] pub struct BinArray { @@ -24,28 +26,30 @@ pub struct BinArray { values: Array2, } -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl BinArray { - pub fn from_coords( - coords: Vec<(usize, usize)>, - m: usize, - n: usize, - ) -> Self { + pub fn from_coords(coords: Vec<(usize, usize)>, m: usize, n: usize) -> Self { let mut values = Array2::::zeros((m, n)); for coord in coords { values[[coord.0, coord.1]] = 1; } - Self {m, n, values} + Self { m, n, values } } /// Gets the list of co-ordinates of the entries which are non-zero pub fn to_coords(&self) -> Vec<(usize, usize)> { self.values .indexed_iter() - .filter_map(|((i, j), &v)| if v == 0 { None } else { Some((i, j)) }) + .filter_map(|((i, j), &v)| { + if v == 0 { + None + } else { + Some((i, j)) + } + }) .collect() } @@ -60,7 +64,13 @@ impl BinArray { pub fn get_weight(&self) -> isize { self.values - .mapv(|x| if x == 0 {0} else {1}) + .mapv(|x| { + if x == 0 { + 0 + } else { + 1 + } + }) .sum() } @@ -91,19 +101,21 @@ impl BinArray { pub fn transform_invert(&self) -> Self { let m = self.m; let n = self.n; - let values = self.values.mapv(|x| if x == 0 {1} else {0}); - return Self {m, n, values}; + let values = self.values.mapv(|x| { + if x == 0 { + 1 + } else { + 0 + } + }); + return Self { m, n, values }; } - pub fn transform_shift( - &self, - di: isize, - dj: isize, - ) -> Self { + pub fn transform_shift(&self, di: isize, dj: isize) -> Self { // create blank 3 x 3 meta block let m = self.m; let n = self.n; - let mut slate = Array2::::zeros((3*m, 3*n)); + let mut slate = Array2::::zeros((3 * m, 3 * n)); // slot in values in location shifted from the middle let i0 = self.m as isize + di; @@ -119,15 +131,15 @@ impl BinArray { let j0 = self.n; let j1 = self.n + j0; let values = slate.slice_mut(slice![i0..i1, j0..j1]).to_owned(); - let result = Self {m, n, values}; + let result = Self { m, n, values }; return result; } - pub fn transform_hflip(&self, recentre: bool) -> Self{ + pub fn transform_hflip(&self, recentre: bool) -> Self { let m = self.m; let n = self.n; let values = self.values.slice(slice![.., ..;-1]).to_owned(); - let mut result = Self {m, n, values}; + let mut result = Self { m, n, values }; if recentre { result = result.recentre(); } @@ -138,19 +150,18 @@ impl BinArray { let m = self.m; let n = self.n; let values = self.values.slice(slice![..;-1, ..]).to_owned(); - let mut result = Self {m, n, values}; + let mut result = Self { m, n, values }; if recentre { result = result.recentre(); } return result; - } pub fn transform_transpose(&self, recentre: bool) -> Self { let m = self.m; let n = self.n; let values = self.values.t().to_owned(); - let mut result = Self {m, n, values}; + let mut result = Self { m, n, values }; if recentre { result = result.recentre(); } @@ -161,10 +172,10 @@ impl BinArray { match k { 1 => { return self.transform_transpose(false).transform_vflip(recentre); - }, + } -1 => { return self.transform_vflip(false).transform_transpose(recentre); - }, + } _ => { return self.clone(); } @@ -182,10 +193,8 @@ impl BinArray { let arr3 = arr.transform_shift(0, -1); let arr4 = arr.transform_shift(0, 1); arr = arr + arr1 + arr2 + arr3 + arr4; - let values = arr.values - .slice(slice![1..-1, 1..-1]) - .to_owned(); - let result = Self {m, n, values}; + let values = arr.values.slice(slice![1..-1, 1..-1]).to_owned(); + let result = Self { m, n, values }; return result; } @@ -200,18 +209,13 @@ impl BinArray { /// and provided /// /// - no collisions occur with an optional obstacle. - pub fn get_configurations( - &self, - option_obst: Option<&BinArray>, - ) -> impl Iterator { + pub fn get_configurations(&self, option_obst: Option<&BinArray>) -> impl Iterator { let (m, n) = self.get_shape(); let obst = option_obst.map_or_else(|| BinArray::from_coords(vec![], m, n), |x| x.clone()); let free = obst.transform_invert(); - let iterator = iproduct!( - [0, 1, -1], - [false, true], - [false, true], - ) + let mut used: Vec = vec![]; + + let iterator = iproduct!([0, 1, -1], [false, true], [false, true],) // iterate through all orientations .map(|(rot, vflip, hflip)| { // recover original @@ -225,12 +229,19 @@ impl BinArray { if hflip { arr = arr.transform_hflip(false); } - // NOTE: No longer need this as anchor point will be shifted - // if hflip | vflip | (rot != 0) { - // arr = arr.recentre(); - // } + // recentre for comparison to ensure uniqueness of pieces + if hflip | vflip | (rot != 0) { + arr = arr.recentre(); + } return arr; }) + // skip duplicate orientations + .filter(move |arr| { + let text = arr.to_string(); + let dupl = used.contains(&text); + used.push(text); + return !dupl; + }) // by fixing an anchor point and viewing the non-occupied positions // get all possible shifts of the array .map(move |arr| { @@ -282,7 +293,13 @@ impl Add for BinArray { let n = self.n; let mut values = self.values.to_owned() + other.values.to_owned(); values = values.mapv(|x| x.min(1)); - return Self {m, n, values}; + return Self { m, n, values }; + } +} + +impl AddAssign for BinArray { + fn add_assign(&mut self, other: Self) { + *self = self.to_owned() + other; } } @@ -293,6 +310,12 @@ impl Mul for BinArray { let m = self.m; let n = self.n; let values = self.values.to_owned() * other.values.to_owned(); - return Self {m, n, values}; + return Self { m, n, values }; + } +} + +impl MulAssign for BinArray { + fn mul_assign(&mut self, other: Self) { + *self = self.to_owned() * other; } } diff --git a/src/bin/games/genius_square/models/binary_arrays/models_grids.rs b/src/bin/games/genius_square/models/binary_arrays/models_grids.rs new file mode 100644 index 0000000..12ff31d --- /dev/null +++ b/src/bin/games/genius_square/models/binary_arrays/models_grids.rs @@ -0,0 +1,345 @@ +use itertools::Itertools; +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- + +use ndarray::Array2; +use ndarray::s as slice; +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fmt::Result; +use std::ops::Add; +use std::ops::AddAssign; + +use super::models_arrays::BinArray; + +// ---------------------------------------------------------------- +// STRUCTS +// ---------------------------------------------------------------- + +#[derive(Clone, Debug)] +pub struct Boundary { + prev: i8, + next: i8, +} + +#[derive(Clone, Debug)] +pub struct Boundaries { + h: Boundary, + v: Boundary, +} + +#[derive(Clone, Debug)] +pub struct Node { + label: Option, + bd: Boundaries, +} + +#[derive(Clone, Debug)] +/// A binary grid encases a elements of a binary array with boxes +pub struct BinGrid { + m: usize, + n: usize, + clusters: Vec>, +} + +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- + +impl Boundary { + pub fn new(prev: i8, next: i8) -> Self { + Self { prev, next } + } + + pub fn empty() -> Self { + Self::new(0, 0) + } +} + +impl Boundaries { + pub fn new(left: i8, right: i8, top: i8, bot: i8) -> Self { + let h = Boundary::new(left, right); + let v = Boundary::new(bot, top); + Self { h, v } + } + + pub fn empty() -> Self { + let h = Boundary::empty(); + let v = Boundary::empty(); + Self { h, v } + } +} + +impl Node { + pub fn new(label: Option, bd: &Boundaries) -> Self { + let bd = bd.clone(); + Self { label, bd } + } + + pub fn empty() -> Self { + Node::new(None, &Boundaries::empty()) + } + + pub fn from_label(label: &String) -> Self { + Node::new(Some(label.clone()), &Boundaries::new(-1, 1, -1, 1)) + } + + pub fn display_in_grid(&self) -> Array2 { + let mut field = Array2::from_elem((3, 5), " ".to_string()); + field[(1, 2)] = self.label.clone().map_or_else(|| " ".to_string(), |x| x); + + let bd = self.bd.clone(); + let has_top_boundary = bd.v.prev != 0; + let has_bot_boundary = bd.v.next != 0; + let has_left_boundary = bd.h.prev != 0; + let has_right_boundary = bd.h.next != 0; + + if has_top_boundary { + field[(0, 0)] = "\u{0253C}".to_string(); + field[(0, 1)] = "\u{02500}".to_string(); + field[(0, 2)] = "\u{02500}".to_string(); + field[(0, 3)] = "\u{02500}".to_string(); + field[(0, 4)] = "\u{0253C}".to_string(); + } + + if has_bot_boundary { + field[(2, 0)] = "\u{0253C}".to_string(); + field[(2, 1)] = "\u{02500}".to_string(); + field[(2, 2)] = "\u{02500}".to_string(); + field[(2, 3)] = "\u{02500}".to_string(); + field[(2, 4)] = "\u{0253C}".to_string(); + } + + if has_left_boundary { + field[(0, 0)] = "\u{0253C}".to_string(); + field[(1, 0)] = "\u{02502}".to_string(); + field[(2, 0)] = "\u{0253C}".to_string(); + } + + if has_right_boundary { + field[(0, 4)] = "\u{0253C}".to_string(); + field[(1, 4)] = "\u{02502}".to_string(); + field[(2, 4)] = "\u{0253C}".to_string(); + } + + return field; + } +} + +impl BinGrid { + pub fn new(m: usize, n: usize) -> Self { + let clusters = vec![]; + Self { m, n, clusters } + } + + #[allow(unused)] + pub fn get_shape(&self) -> (usize, usize) { + (self.m, self.n) + } + + pub fn get_edge_orientation_top(cluster: &Array2) -> Array2 { + cluster.mapv(|x| x.bd.v.prev) + } + + pub fn get_edge_orientation_bottom(cluster: &Array2) -> Array2 { + cluster.mapv(|x| x.bd.v.next) + } + + pub fn get_edge_orientation_left(cluster: &Array2) -> Array2 { + cluster.mapv(|x| x.bd.h.prev) + } + + pub fn get_edge_orientation_right(cluster: &Array2) -> Array2 { + cluster.mapv(|x| x.bd.h.next) + } + + pub fn from_coord(label: &String, i: usize, j: usize, m: usize, n: usize) -> Self { + let object = BinArray::from_coords(vec![(i, j)], m, n); + return Self::from_array(label, &object); + } + + pub fn from_array(label: &String, object: &BinArray) -> Self { + let (m, n) = object.get_shape(); + let mut cluster = Array2::from_elem((m, n), Node::empty()); + let mut result = Self::new(m, n); + object.get_values().indexed_iter().for_each(|((i, j), &v)| { + if v != 0 { + cluster[(i, j)] = Node::from_label(label); + } + }); + + // coalesce edges + let edges_top = Self::get_edge_orientation_top(&cluster); + let edges_bot = Self::get_edge_orientation_bottom(&cluster); + let edges_left = Self::get_edge_orientation_left(&cluster); + let edges_right = Self::get_edge_orientation_right(&cluster); + + let mut coallesce_top = edges_top.clone(); + let mut coallesce_bot = edges_bot.clone(); + let curr = edges_top.slice(slice![1.., ..]); + let other = edges_bot.slice(slice![..-1, ..]); + let sum = &curr + &other; + coallesce_top.slice_mut(slice![1.., ..]).assign(&sum); + coallesce_bot.slice_mut(slice![..-1, ..]).assign(&sum); + + let mut coallesce_left = edges_left.clone(); + let mut coallesce_right = edges_right.clone(); + let curr = edges_left.slice(slice![.., 1..]); + let other = edges_right.slice(slice![.., ..-1]); + let sum = &curr + &other; + coallesce_left.slice_mut(slice![.., 1..]).assign(&sum); + coallesce_right.slice_mut(slice![.., ..-1]).assign(&sum); + + coallesce_top.indexed_iter().for_each(|((i, j), &v)| { + cluster[(i, j)].bd.v.prev = v; + }); + + coallesce_bot.indexed_iter().for_each(|((i, j), &v)| { + cluster[(i, j)].bd.v.next = v; + }); + + coallesce_left.indexed_iter().for_each(|((i, j), &v)| { + cluster[(i, j)].bd.h.prev = v; + }); + + coallesce_right.indexed_iter().for_each(|((i, j), &v)| { + cluster[(i, j)].bd.h.next = v; + }); + + result.clusters = vec![cluster]; + + return result; + } + + pub fn get_node(&self, i: usize, j: usize) -> Node { + let mut bd = Boundaries::empty(); + let mut label: Option = None; + for cluster in self.clusters.iter() { + let node_ = cluster[(i, j)].clone(); + let label_ = node_.label; + let bd_ = node_.bd; + if let Some(x) = label_ { + label = Some(x); + } + if bd.v.next == 0 { + bd.v.next = bd_.v.next; + } + if bd.v.prev == 0 { + bd.v.prev = bd_.v.prev; + } + if bd.h.next == 0 { + bd.h.next = bd_.h.next; + } + if bd.h.prev == 0 { + bd.h.prev = bd_.h.prev; + } + } + let node = Node::new(label, &bd); + return node; + } +} + +impl Display for BinGrid { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let (m, n) = self.get_shape(); + + // compute fields of characters + let fields: Vec> = (0..m) + .map(|i| { + // compute fields of characters + let fields: Vec> = (0..n) + // get array of chars representing part of grid + .map(|j| self.get_node(i, j).display_in_grid()) + .collect(); + + // determine size of merge + let m = fields.iter().map(|field_| field_.nrows()).max().unwrap_or(0); + let n = 1 + fields.iter().map(|field_| field_.ncols() - 1).sum::(); + let mut field = Array2::from_elem((m, n), " ".to_string()); + + // h-join chars in grid, taking care of boundaries + let mut j0 = 0; + for (k, field_) in fields.iter().enumerate() { + let m_ = field_.nrows(); + let n_ = field_.ncols(); + let j1 = if k > 0 && n_ > 0 { + j0 + n_ - 1 + } else { + j0 + n_ + }; + let mut view = field.slice_mut(slice![..m_, j0..j1]); + if k == 0 { + view.assign(&field_); + } else { + view.assign(&field_.slice(slice![.., 1..])); + } + // on boundary allow empty values to be overwritten + if j0 > 0 { + for i in 0..m_ { + if field[(i, j0 - 1)].trim() == "" { + field[(i, j0 - 1)] = field_[(i, 0)].clone(); + } + } + } + j0 = j1; + } + + return field; + }) + .collect(); + + // determine size of merge + let m = 1 + fields.iter().map(|field_| field_.nrows() - 1).sum::(); + let n = fields.iter().map(|field_| field_.ncols()).max().unwrap_or(0); + let mut field = Array2::from_elem((m, n), " ".to_string()); + + // v-join chars in grid, taking care of boundaries + let mut i0 = 0; + for (k, field_) in fields.iter().enumerate() { + let m_ = field_.nrows(); + let n_ = field_.ncols(); + let i1 = if k > 0 && m_ > 0 { + i0 + m_ - 1 + } else { + i0 + m_ + }; + let mut view = field.slice_mut(slice![i0..i1, ..n_]); + if k == 0 { + view.assign(&field_); + } else { + view.assign(&field_.slice(slice![1.., ..])); + } + // on boundary allow empty values to be overwritten + if i0 > 0 { + for j in 0..n_ { + if field[(i0 - 1, j)].trim() == "" { + field[(i0 - 1, j)] = field_[(0, j)].clone(); + } + } + } + i0 = i1; + } + + // finally, join field chars: + let text = field.rows().into_iter().map(|row| row.iter().join("")).join("\n"); + write!(f, "{}", text) + } +} + +impl AddAssign for BinGrid { + fn add_assign(&mut self, other: Self) { + self.clusters.extend(other.clusters.clone()); + } +} + +impl Add for BinGrid { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + let mut result = self.clone(); + result += other; + return result; + } +} diff --git a/src/bin/games/genius_square/models/board/mod.rs b/src/bin/games/genius_square/models/board/mod.rs index a5034f1..007ab63 100644 --- a/src/bin/games/genius_square/models/board/mod.rs +++ b/src/bin/games/genius_square/models/board/mod.rs @@ -1,3 +1,4 @@ /// Models for handling game board - pub mod models; + +pub use models::GameBoard; diff --git a/src/bin/games/genius_square/models/board/models.rs b/src/bin/games/genius_square/models/board/models.rs index c0cc9e1..ee37faf 100644 --- a/src/bin/games/genius_square/models/board/models.rs +++ b/src/bin/games/genius_square/models/board/models.rs @@ -1,6 +1,6 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use ndarray::Array2; use std::fmt::Debug; @@ -9,32 +9,52 @@ use std::fmt::Formatter; use std::fmt::Result; use std::collections::HashMap; -use crate::models::constants::board::*; -use crate::models::constants::dice::*; -use crate::models::constants::enums::*; -use crate::models::pieces::models::*; +use general::_core::strings::join_multiline_strings; -/// ---------------------------------------------------------------- -/// STRUCTS -/// ---------------------------------------------------------------- +use crate::models::constants::EnumPiece; +use crate::models::constants::FACE1_FMT; +use crate::models::constants::FACE2_FMT; +use crate::models::constants::GRID_HEIGHT; +use crate::models::constants::GRID_WIDTH; +use crate::models::constants::NON_ADJACENT; +use crate::models::pieces::Piece; +use crate::models::binary_arrays::BinGrid; + +// ---------------------------------------------------------------- +// STRUCTS +// ---------------------------------------------------------------- #[derive(Clone, Debug)] pub struct GameBoard { block: Piece, pieces: HashMap, + // for dynamic computations + obstacle_basic: Piece, + obstacle_dithered: Piece, } -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl GameBoard { pub fn new(block: &Piece) -> Self { let pieces: HashMap = HashMap::new(); - return Self {block: block.clone(), pieces} + let block = block.clone(); + let obstacle_basic = block.clone(); + let obstacle_dithered = block.clone(); + return Self { + block, + obstacle_basic, + obstacle_dithered, + pieces, + }; + } + + pub fn get_shape(&self) -> (usize, usize) { + self.block.get_shape() } - #[allow(unused)] pub fn add_piece(&mut self, symb: &EnumPiece, piece: &Piece) { self.pieces.insert(symb.clone(), piece.clone()); } @@ -48,6 +68,39 @@ impl GameBoard { &self.block } + pub fn initialise_obstacle(&mut self) { + self.obstacle_basic = self.block.to_owned(); + self.obstacle_dithered = self.block.to_owned(); + } + + pub fn get_obstacle(&self, kind: &EnumPiece) -> &Piece { + if NON_ADJACENT.contains(&kind) { + &self.obstacle_dithered + } else { + &self.obstacle_basic + } + } + + pub fn update_obstacle(&mut self, piece: &Piece) { + let symb = piece.get_kind(); + self.obstacle_basic += piece.to_owned(); + if NON_ADJACENT.contains(&symb) { + let piece_dithered = piece.transform_dither(); + self.obstacle_dithered += piece_dithered; + } else { + self.obstacle_dithered += piece.to_owned(); + } + } + + #[allow(unused)] + pub fn get_obstacle_weight(&self) -> isize { + self.obstacle_basic.get_weight() + } + + pub fn get_obstacle_coweight(&self) -> isize { + self.obstacle_basic.get_coweight() + } + pub fn to_string(&self) -> String { let field = self.to_array_of_strings(false); let text = Self::array_to_string(&field); @@ -62,43 +115,43 @@ impl GameBoard { } pub fn pretty(&self) -> String { - let _m = GRID_HEIGHT; - let n = GRID_WIDTH; - let field = self.to_array_of_strings(true); - - fn create_border( - lcorner1: &str, - fill1: &str, - lcorner2: &str, - fill2: &str, - mid2: &str, - rcorner: &str, - n: usize, - ) -> String { - let middle = format!("{fill2}{mid2}{fill2}{fill2}").repeat(n-1); - format!("{lcorner1}{fill1}{fill1}{fill1}{lcorner2}{fill2}{fill2}{middle}{fill2}{rcorner}") - } - - let top1 = create_border("\u{02554}", "\u{2550}", "\u{02566}", "\u{2550}", "\u{2564}", "\u{2555}", n); - let top2 = create_border("\u{02560}", "\u{2550}", "\u{0256C}", "\u{2550}", "\u{256A}", "\u{2561}", n); - let mid = create_border("\u{02560}", "\u{2500}", "\u{0256C}", "\u{2500}", "\u{253C}", "\u{2524}", n); - let bot = create_border("\u{02559}", "\u{2500}", "\u{02568}", "\u{2500}", "\u{02534}", "\u{02518}", n); - - let head = FACE1_FMT.join(" \u{2502} ").to_string(); - let head = format!("{top1}\n\u{02551} \u{02551} {head} \u{2502}\n{top2}"); - - let middle = field.rows() - .into_iter() - .enumerate() - .map(|(i, row)| { - let index = FACE2_FMT[i]; - let line = row.iter().map(|s| s.to_string()).collect::>().join(" \u{2502} "); - return format!("\u{02551} {index} \u{02551} {line} \u{2502}"); - }) - .collect::>() - .join(format!("\n{mid}\n").as_str()); - - let text = format!("{head}\n{middle}\n{bot}"); + let (m, n) = self.get_shape(); + + let space = " "; + let end1 = + format!("{space}\u{02554}\u{02550}\n{space}\u{02551} \n{space}\u{0255A}\u{02550}"); + let end2 = format!("\u{02550}\u{02557}\n \u{02551}\n\u{02550}\u{0255D}"); + let blocks: Vec = + FACE1_FMT.iter().map(|&x| format!("\u{02550}\n{x}\n\u{02550}")).collect(); + let sep = format!("\u{02550}\u{02566}\u{02550}\n \u{02551} \n\u{02550}\u{02569}\u{02550}"); + let xlabels = join_multiline_strings(&blocks, Some(&sep), ""); + let xlabels = join_multiline_strings(&[end1, xlabels, end2].to_vec(), None, ""); + + let end1 = format!("\u{02554}\u{02550}\u{02550}\u{02550}\u{02557}"); + let end2 = format!("\u{0255A}\u{02550}\u{02550}\u{02550}\u{0255D}"); + let blocks: Vec = + FACE2_FMT.iter().map(|&x| format!("\u{02551} {x} \u{02551}")).collect(); + let sep = format!("\n\u{02560}\u{02550}\u{02550}\u{02550}\u{02563}\n"); + let ylabels = blocks.join(&sep); + let ylabels = [end1, ylabels, end2].join("\n"); + + let mut grid = BinGrid::new(m, n); + let symb = self.block.get_symb_fmt(); + self.block.to_coords().iter().for_each(|&(i, j)| { + grid += BinGrid::from_coord(&symb, i, j, m, n); + }); + + self.pieces.values().for_each(|piece| { + let symb = piece.get_symb_fmt(); + let pos = piece.get_positions(); + grid += BinGrid::from_array(&symb, pos); + }); + + let middle = grid.to_string(); + + let middle = join_multiline_strings(&[ylabels.to_owned(), middle].to_vec(), None, " "); + + let text = format!("{xlabels}\n{middle}"); return text; } @@ -106,15 +159,23 @@ impl GameBoard { fn to_array_of_strings(&self, formatted: bool) -> Array2 { let m = GRID_HEIGHT; let n = GRID_WIDTH; - let mut trace: Array2 = Array2::from_elem((m, n), " ".to_string()); + let mut trace = Array2::from_elem((m, n), " ".to_string()); let piece = self.get_block(); for (i, j) in piece.to_coords() { - let alpha = if formatted { piece.get_symb_fmt() } else { piece.get_symb() }; + let alpha = if formatted { + piece.get_symb_fmt() + } else { + piece.get_symb() + }; trace[[i, j]] = alpha; } for (_, piece) in self.pieces.iter() { for (i, j) in piece.to_coords() { - let alpha = if formatted { piece.get_symb_fmt() } else { piece.get_symb() }; + let alpha = if formatted { + piece.get_symb_fmt() + } else { + piece.get_symb() + }; trace[[i, j]] = alpha; } } @@ -126,7 +187,8 @@ impl GameBoard { let hbar = "\u{2500}".repeat(n + 2); let top = format!("\u{250C}{hbar}\u{2510}"); let bot = format!("\u{2514}{hbar}\u{2518}"); - let middle = field.rows() + let middle = field + .rows() .into_iter() .map(|row| { let line = row.iter().map(|s| s.as_str()).collect::(); @@ -150,54 +212,19 @@ impl GameBoard { /// /// - no collisions occur with already placed pieces (marked by `obst`) /// - the piece is not adjacent to certain other pieces. - pub fn get_configurations( - &self, - piece: &Piece, - obst: &Piece, - ) -> impl Iterator { - let mut used: Vec = vec![]; + pub fn get_configurations(&self, piece: &Piece) -> impl Iterator { + // get obstacle in depenence on type of piece + let kind = piece.get_kind(); + let obst = self.get_obstacle(&kind).get_positions(); + + // construct iterator let it = piece // convert to positions .get_positions() // get all possible orientations + shifts which do not collide with obstacle - .get_configurations(Some(obst.get_positions())) - // skip all moves which lead to forbidden adjacent pieces - .filter(|pos| { - // only need to check for collisions of pieces of a paritcular kind - let kind = piece.get_kind(); - if !(NON_ADJACENT.contains(&kind)) { - return true; - } - let pos_dither = pos.transform_dither(); - for (s, q) in self.pieces.iter() { - // only need to check for collisions of pieces of a paritcular kind - if !(NON_ADJACENT.contains(s)) { - continue; - } - if *s == kind { - continue; - } - - let collision = pos_dither.to_owned() * q.get_positions().to_owned(); - let penalty = -collision.get_weight(); - if penalty < 0 { - return false; - } - } - return true; - }) + .get_configurations(Some(obst)) // convert to piece - .map(|pos| { - let kind = piece.get_kind(); - Piece::from_kind(&kind, Some(pos)) - }) - // skip duplicates - .filter(move |p| { - let value = p.to_string(); - let dupl = used.contains(&value); - used.push(value); - return !dupl; - }); + .map(move |pos| Piece::from_kind(&kind, Some(pos))); return it; } } diff --git a/src/bin/games/genius_square/models/constants/board.rs b/src/bin/games/genius_square/models/constants/board.rs index 9fb056d..bcc1ad2 100644 --- a/src/bin/games/genius_square/models/constants/board.rs +++ b/src/bin/games/genius_square/models/constants/board.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- // -/// ---------------------------------------------------------------- -/// CONSTANTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// CONSTANTS +// ---------------------------------------------------------------- pub const GRID_HEIGHT: usize = 6; pub const GRID_WIDTH: usize = 6; diff --git a/src/bin/games/genius_square/models/constants/dice.rs b/src/bin/games/genius_square/models/constants/dice.rs index e2c50a9..a6ab8da 100644 --- a/src/bin/games/genius_square/models/constants/dice.rs +++ b/src/bin/games/genius_square/models/constants/dice.rs @@ -1,57 +1,43 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- // -/// ---------------------------------------------------------------- -/// CONSTANTS -/// ---------------------------------------------------------------- - -pub const FACE1: &[&str] = &[ - "A", - "B", - "C", - "D", - "E", - "F", -]; +// ---------------------------------------------------------------- +// CONSTANTS +// ---------------------------------------------------------------- -pub const FACE2: &[&str] = &[ - "1", - "2", - "3", - "4", - "5", - "6", -]; +pub const FACE1: &[&str] = &["A", "B", "C", "D", "E", "F"]; + +pub const FACE2: &[&str] = &["1", "2", "3", "4", "5", "6"]; pub const FACE1_FMT: &[&str] = &[ - "\x1b[91,1mA\x1b[0m", - "\x1b[91,1mB\x1b[0m", - "\x1b[91,1mC\x1b[0m", - "\x1b[91,1mD\x1b[0m", - "\x1b[91,1mE\x1b[0m", - "\x1b[91,1mF\x1b[0m", + "\x1b[3mA\x1b[0m", + "\x1b[3mB\x1b[0m", + "\x1b[3mC\x1b[0m", + "\x1b[3mD\x1b[0m", + "\x1b[3mE\x1b[0m", + "\x1b[3mF\x1b[0m", ]; pub const FACE2_FMT: &[&str] = &[ - "\x1b[91,1m1\x1b[0m", - "\x1b[91,1m2\x1b[0m", - "\x1b[91,1m3\x1b[0m", - "\x1b[91,1m4\x1b[0m", - "\x1b[91,1m5\x1b[0m", - "\x1b[91,1m6\x1b[0m", + "\x1b[3m1\x1b[0m", + "\x1b[3m2\x1b[0m", + "\x1b[3m3\x1b[0m", + "\x1b[3m4\x1b[0m", + "\x1b[3m5\x1b[0m", + "\x1b[3m6\x1b[0m", ]; pub const DICE: &[&[&str]] = &[ - &["A5","A5","F2","F2","E1","B6"], - &["A6","A6","A6","F1","F1","F1"], - &["D5","E4","E5","E6","F4","F5"], - &["A2","A3","B1","B2","B3","C2"], - &["A1","C1","D1","D2","E2","F3"], - &["B4","C3","C4","D3","D4","E3"], - &["A4","B5","C5","C6","D6","F6"], + &["A5", "A5", "F2", "F2", "E1", "B6"], + &["A6", "A6", "A6", "F1", "F1", "F1"], + &["D5", "E4", "E5", "E6", "F4", "F5"], + &["A2", "A3", "B1", "B2", "B3", "C2"], + &["A1", "C1", "D1", "D2", "E2", "F3"], + &["B4", "C3", "C4", "D3", "D4", "E3"], + &["A4", "B5", "C5", "C6", "D6", "F6"], ]; pub const NUM_DICE: usize = DICE.len(); diff --git a/src/bin/games/genius_square/models/constants/enums.rs b/src/bin/games/genius_square/models/constants/enums.rs index 2f27ee6..1ae05f7 100644 --- a/src/bin/games/genius_square/models/constants/enums.rs +++ b/src/bin/games/genius_square/models/constants/enums.rs @@ -1,19 +1,19 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Result; -use crate::models::arrays::models::BinArray; +use crate::models::binary_arrays::BinArray; use super::board::*; use super::pieces::*; -/// ---------------------------------------------------------------- -/// STRUCTS AND CONSTANTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// STRUCTS AND CONSTANTS +// ---------------------------------------------------------------- #[derive(Clone, Debug, Eq, Hash, PartialEq)] pub enum EnumPiece { @@ -42,16 +42,12 @@ pub const ENUM_PIECES: &[EnumPiece] = &[ EnumPiece::Z, ]; -pub const NON_ADJACENT: &[EnumPiece] = &[ - EnumPiece::Symb1, - EnumPiece::Symb2, - EnumPiece::Symb3, - EnumPiece::C, -]; +pub const NON_ADJACENT: &[EnumPiece] = + &[EnumPiece::Symb1, EnumPiece::Symb2, EnumPiece::Symb3, EnumPiece::C]; -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl EnumPiece { #[allow(unused)] diff --git a/src/bin/games/genius_square/models/constants/mod.rs b/src/bin/games/genius_square/models/constants/mod.rs index 416606a..db6cf88 100644 --- a/src/bin/games/genius_square/models/constants/mod.rs +++ b/src/bin/games/genius_square/models/constants/mod.rs @@ -1,6 +1,11 @@ /// Models for handling constants - pub mod board; pub mod dice; pub mod enums; pub mod pieces; + +pub use board::*; +pub use dice::*; +pub use enums::*; +#[allow(unused)] +pub use pieces::*; diff --git a/src/bin/games/genius_square/models/constants/pieces.rs b/src/bin/games/genius_square/models/constants/pieces.rs index 01b890f..abdeff9 100644 --- a/src/bin/games/genius_square/models/constants/pieces.rs +++ b/src/bin/games/genius_square/models/constants/pieces.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use indoc::indoc; -/// ---------------------------------------------------------------- -/// CONSTANTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// CONSTANTS +// ---------------------------------------------------------------- pub const SYMB_BLOCK: &str = "\u{25A0}"; pub const SYMB_FMT_BLOCK: &str = "\u{25A0}"; @@ -19,7 +19,7 @@ pub const BLOCK: &str = indoc! {" "}; pub const SYMB_PIECE_1: &str = "1"; -pub const SYMB_FMT_PIECE_1: &str = "1"; +pub const SYMB_FMT_PIECE_1: &str = "\x1b[94;1;4m1\x1b[0m"; pub const PIECE_1: &str = indoc! {" +..... ...... @@ -29,7 +29,7 @@ pub const PIECE_1: &str = indoc! {" "}; pub const SYMB_PIECE_2: &str = "2"; -pub const SYMB_FMT_PIECE_2: &str = "2"; +pub const SYMB_FMT_PIECE_2: &str = "\x1b[1;4m2\x1b[0m"; pub const PIECE_2: &str = indoc! {" ++.... ...... @@ -39,7 +39,7 @@ pub const PIECE_2: &str = indoc! {" "}; pub const SYMB_PIECE_3: &str = "3"; -pub const SYMB_FMT_PIECE_3: &str = "3"; +pub const SYMB_FMT_PIECE_3: &str = "\x1b[1;4m3\x1b[0m"; pub const PIECE_3: &str = indoc! {" +++... ...... @@ -49,7 +49,7 @@ pub const PIECE_3: &str = indoc! {" "}; pub const SYMB_PIECE_4: &str = "4"; -pub const SYMB_FMT_PIECE_4: &str = "4"; +pub const SYMB_FMT_PIECE_4: &str = "\x1b[90m4\x1b[0m"; pub const PIECE_4: &str = indoc! {" ++++.. ...... @@ -59,7 +59,7 @@ pub const PIECE_4: &str = indoc! {" "}; pub const SYMB_PIECE_C: &str = "C"; -pub const SYMB_FMT_PIECE_C: &str = "C"; +pub const SYMB_FMT_PIECE_C: &str = "\x1b[95;1;4mC\x1b[0m"; pub const PIECE_C: &str = indoc! {" ++.... +..... @@ -69,7 +69,7 @@ pub const PIECE_C: &str = indoc! {" "}; pub const SYMB_PIECE_L: &str = "L"; -pub const SYMB_FMT_PIECE_L: &str = "L"; +pub const SYMB_FMT_PIECE_L: &str = "\x1b[96mL\x1b[0m"; pub const PIECE_L: &str = indoc! {" ++.... +..... @@ -79,7 +79,7 @@ pub const PIECE_L: &str = indoc! {" "}; pub const SYMB_PIECE_T: &str = "T"; -pub const SYMB_FMT_PIECE_T: &str = "T"; +pub const SYMB_FMT_PIECE_T: &str = "\x1b[93mT\x1b[0m"; pub const PIECE_T: &str = indoc! {" +++... .+.... @@ -89,7 +89,7 @@ pub const PIECE_T: &str = indoc! {" "}; pub const SYMB_PIECE_X: &str = "X"; -pub const SYMB_FMT_PIECE_X: &str = "X"; +pub const SYMB_FMT_PIECE_X: &str = "\x1b[92mX\x1b[0m"; pub const PIECE_X: &str = indoc! {" ++.... ++.... @@ -99,7 +99,7 @@ pub const PIECE_X: &str = indoc! {" "}; pub const SYMB_PIECE_Z: &str = "Z"; -pub const SYMB_FMT_PIECE_Z: &str = "Z"; +pub const SYMB_FMT_PIECE_Z: &str = "\x1b[91mZ\x1b[0m"; pub const PIECE_Z: &str = indoc! {" .++... ++.... diff --git a/src/bin/games/genius_square/models/dice/methods.rs b/src/bin/games/genius_square/models/dice/methods.rs index d4839a1..4c751ef 100644 --- a/src/bin/games/genius_square/models/dice/methods.rs +++ b/src/bin/games/genius_square/models/dice/methods.rs @@ -1,21 +1,16 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use rand_chacha::ChaCha8Rng; use rand::prelude::IndexedRandom; -use crate::models::constants::dice::*; +use crate::models::constants::DICE; -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// METHODS +// ---------------------------------------------------------------- -pub fn roll_dice( - rng: &mut ChaCha8Rng, -) -> Vec { - DICE - .iter() - .map(|die| die.choose(rng).unwrap().to_string()) - .collect() +pub fn roll_dice(rng: &mut ChaCha8Rng) -> Vec { + DICE.iter().map(|die| die.choose(rng).unwrap().to_string()).collect() } diff --git a/src/bin/games/genius_square/models/dice/mod.rs b/src/bin/games/genius_square/models/dice/mod.rs index d66666c..507e6f8 100644 --- a/src/bin/games/genius_square/models/dice/mod.rs +++ b/src/bin/games/genius_square/models/dice/mod.rs @@ -1,4 +1,6 @@ /// Models for handling dice - pub mod methods; pub mod models; + +pub use models::Die; +pub use methods::roll_dice; diff --git a/src/bin/games/genius_square/models/dice/models.rs b/src/bin/games/genius_square/models/dice/models.rs index 650325f..6265ca3 100644 --- a/src/bin/games/genius_square/models/dice/models.rs +++ b/src/bin/games/genius_square/models/dice/models.rs @@ -1,17 +1,18 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Result; -use crate::models::constants::dice::*; +use crate::models::constants::FACE1; +use crate::models::constants::FACE2; -/// ---------------------------------------------------------------- -/// STRUCTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// STRUCTS +// ---------------------------------------------------------------- #[derive(Copy, Clone, Debug)] pub struct Die { @@ -19,9 +20,9 @@ pub struct Die { j: usize, } -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl Die { pub fn from_string(face: &String) -> Die { @@ -30,10 +31,7 @@ impl Die { let char2 = chars.get(1).unwrap(); let index1 = FACE1.iter().position(|x| x == char1).unwrap(); let index2 = FACE2.iter().position(|x| x == char2).unwrap(); - return Die { - i: index2, - j: index1, - } + return Die { i: index2, j: index1 }; } pub fn to_string(&self) -> String { @@ -44,12 +42,12 @@ impl Die { #[allow(unused)] pub fn from_coords(i: usize, j: usize) -> Die { - return Die {i, j} + return Die { i, j }; } #[allow(unused)] pub fn to_coords(&self) -> (usize, usize) { - return (self.i, self.j) + return (self.i, self.j); } } diff --git a/src/bin/games/genius_square/models/mod.rs b/src/bin/games/genius_square/models/mod.rs index 33a3833..79f0a37 100644 --- a/src/bin/games/genius_square/models/mod.rs +++ b/src/bin/games/genius_square/models/mod.rs @@ -1,6 +1,5 @@ /// Models used in game. - -pub mod arrays; +pub mod binary_arrays; pub mod board; pub mod constants; pub mod dice; diff --git a/src/bin/games/genius_square/models/pieces/methods.rs b/src/bin/games/genius_square/models/pieces/methods.rs deleted file mode 100644 index 9e382d4..0000000 --- a/src/bin/games/genius_square/models/pieces/methods.rs +++ /dev/null @@ -1,14 +0,0 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- - -// use super::constants; - -/// ---------------------------------------------------------------- -/// METHODS -/// ---------------------------------------------------------------- - -#[allow(unused)] -pub fn method() { - panic!("not implemented"); -} diff --git a/src/bin/games/genius_square/models/pieces/mod.rs b/src/bin/games/genius_square/models/pieces/mod.rs index 2ea0b25..7e360fd 100644 --- a/src/bin/games/genius_square/models/pieces/mod.rs +++ b/src/bin/games/genius_square/models/pieces/mod.rs @@ -1,4 +1,4 @@ /// Models for handling pieces - -pub mod methods; pub mod models; + +pub use models::Piece; diff --git a/src/bin/games/genius_square/models/pieces/models.rs b/src/bin/games/genius_square/models/pieces/models.rs index a0deed6..42079d9 100644 --- a/src/bin/games/genius_square/models/pieces/models.rs +++ b/src/bin/games/genius_square/models/pieces/models.rs @@ -1,21 +1,24 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::fmt::Debug; use std::fmt::Display; use std::fmt::Formatter; use std::fmt::Result; use std::ops::Add; +use std::ops::AddAssign; use std::ops::Mul; +use std::ops::MulAssign; -use crate::models::arrays::models::BinArray; -use crate::models::constants::board::*; -use crate::models::constants::enums::*; +use crate::models::binary_arrays::BinArray; +use crate::models::constants::EnumPiece; +use crate::models::constants::GRID_HEIGHT; +use crate::models::constants::GRID_WIDTH; -/// ---------------------------------------------------------------- -/// STRUCTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// STRUCTS +// ---------------------------------------------------------------- #[derive(Clone, Debug)] pub struct Piece { @@ -23,26 +26,27 @@ pub struct Piece { positions: BinArray, } -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl Piece { pub fn from_kind(kind: &EnumPiece, positions: Option) -> Self { let kind = kind.clone(); let positions = positions.unwrap_or_else(|| kind.get_positions()); - Self {kind, positions} + Self { kind, positions } } - pub fn from_coords( - coords: Vec<(usize, usize)>, - option_kind: Option, - ) -> Self { + pub fn get_shape(&self) -> (usize, usize) { + self.positions.get_shape() + } + + pub fn from_coords(coords: Vec<(usize, usize)>, option_kind: Option) -> Self { let m = GRID_HEIGHT; let n = GRID_WIDTH; let positions = BinArray::from_coords(coords, m, n); let kind = option_kind.unwrap_or(EnumPiece::Blank); - Self {kind, positions} + Self { kind, positions } } pub fn to_coords(&self) -> Vec<(usize, usize)> { @@ -85,7 +89,10 @@ impl Piece { let hbar = "\u{2500}".repeat(n + 2); let top = format!("\u{250C}{hbar}\u{2510}"); let bot = format!("\u{2514}{hbar}\u{2518}"); - let middle = self.positions.get_values().rows() + let middle = self + .positions + .get_values() + .rows() .into_iter() .map(|row| { let line = row @@ -111,7 +118,7 @@ impl Piece { pub fn transform_hflip(&self, recentre: bool) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_hflip(recentre); - let result = Self{kind, positions}; + let result = Self { kind, positions }; return result; } @@ -119,16 +126,15 @@ impl Piece { pub fn transform_vflip(&self, recentre: bool) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_vflip(recentre); - let result = Self {kind, positions}; + let result = Self { kind, positions }; return result; - } #[allow(unused)] pub fn transform_transpose(&self, recentre: bool) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_transpose(recentre); - let result = Self {kind, positions}; + let result = Self { kind, positions }; return result; } @@ -136,19 +142,15 @@ impl Piece { pub fn transform_rotate(&self, k: i8, recentre: bool) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_rotate(k, recentre); - let result = Self {kind, positions}; + let result = Self { kind, positions }; return result; } #[allow(unused)] - pub fn transform_shift( - &self, - di: isize, - dj: isize, - ) -> Self { + pub fn transform_shift(&self, di: isize, dj: isize) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_shift(di, dj); - let result = Self {kind, positions}; + let result = Self { kind, positions }; return result; } @@ -156,7 +158,7 @@ impl Piece { pub fn transform_dither(&self) -> Self { let kind = self.get_kind(); let positions = self.positions.transform_dither(); - let result = Self {kind, positions}; + let result = Self { kind, positions }; return result; } } @@ -173,7 +175,13 @@ impl Add for Piece { fn add(self, other: Self) -> Self::Output { let kind = self.get_kind(); let positions = self.get_positions().to_owned() + other.get_positions().to_owned(); - return Self {kind, positions}; + return Self { kind, positions }; + } +} + +impl AddAssign for Piece { + fn add_assign(&mut self, other: Self) { + *self = self.to_owned() + other; } } @@ -183,6 +191,12 @@ impl Mul for Piece { fn mul(self, other: Self) -> Self::Output { let kind = self.get_kind(); let positions = self.get_positions().to_owned() * other.get_positions().to_owned(); - return Self {kind, positions}; + return Self { kind, positions }; + } +} + +impl MulAssign for Piece { + fn mul_assign(&mut self, other: Self) { + *self = self.to_owned() * other; } } diff --git a/src/lib.rs b/src/lib.rs index 46446e8..3ec320f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,5 @@ /// Modules available from General crate for other crates - -pub mod app; pub mod _core; +pub mod app; pub mod models; pub mod problems; diff --git a/src/main.rs b/src/main.rs index 7510e1c..438e1e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- mod _core; -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- fn main() { _core::strings::greet("world"); diff --git a/src/models/tree/base.rs b/src/models/tree/base.rs index f5962b2..5cbd02a 100644 --- a/src/models/tree/base.rs +++ b/src/models/tree/base.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- /// -/// ---------------------------------------------------------------- -/// TRAITS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// TRAITS +// ---------------------------------------------------------------- /// Struct to handle generic trees #[allow(unused)] diff --git a/src/models/tree/model.rs b/src/models/tree/model.rs index b918e32..e3a6690 100644 --- a/src/models/tree/model.rs +++ b/src/models/tree/model.rs @@ -1,15 +1,15 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::vec; use super::base::GenericTree; use super::base::GenericTreeOrRoot; use super::base::GenericTreeLike; -/// ---------------------------------------------------------------- -/// BASIC IMPLEMENTATION FOR GenericTree -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// BASIC IMPLEMENTATION FOR GenericTree +// ---------------------------------------------------------------- /// Implementation of a tree #[allow(unused)] @@ -55,9 +55,9 @@ where } } -/// ---------------------------------------------------------------- -/// BASIC IMPLEMENTATION OF TRAIT FOR GenericTree -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// BASIC IMPLEMENTATION OF TRAIT FOR GenericTree +// ---------------------------------------------------------------- impl GenericTreeLike for GenericTree where @@ -121,7 +121,11 @@ where let n = self.num_children(); for (k, child) in self.children.iter().enumerate() { let is_final = k == n - 1; - let connector = if child.has_children() { "╮ " } else { "─ " }; + let connector = if child.has_children() { + "╮ " + } else { + "─ " + }; let sep_ = if is_final { format!("╰──{}", connector) } else { diff --git a/src/models/tree/tests_model.rs b/src/models/tree/tests_model.rs index 653efc8..2b96c49 100644 --- a/src/models/tree/tests_model.rs +++ b/src/models/tree/tests_model.rs @@ -53,7 +53,8 @@ mod tests { ├─── alice: 23 ╰─── bob: 24 "# - ).to_string(); + ) + .to_string(); assert_eq!(t.to_string(), expected); } @@ -94,14 +95,15 @@ mod tests { │ ╰─── _: 3 ╰─── bob: 24 "# - ).to_string(); + ) + .to_string(); assert_eq!(t.to_string(), expected); } } -/// ---------------------------------------------------------------- -/// AUXILIARY -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// AUXILIARY +// ---------------------------------------------------------------- /// A dummy node type for test purposes #[derive(Clone)] diff --git a/src/problems/hackerrank/mathematics/main.rs b/src/problems/hackerrank/mathematics/main.rs index c5196c2..5320ed1 100644 --- a/src/problems/hackerrank/mathematics/main.rs +++ b/src/problems/hackerrank/mathematics/main.rs @@ -1,9 +1,9 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- fn main() {} diff --git a/src/problems/hackerrank/mathematics/mod.rs b/src/problems/hackerrank/mathematics/mod.rs index 5f03c25..277f45b 100644 --- a/src/problems/hackerrank/mathematics/mod.rs +++ b/src/problems/hackerrank/mathematics/mod.rs @@ -1,5 +1,4 @@ /// Contains solutions to challenges in the Mathematics /// section of Hackerrank. /// Source: . - pub mod scalar_products; diff --git a/src/problems/hackerrank/mathematics/scalar_products/approach1.rs b/src/problems/hackerrank/mathematics/scalar_products/approach1.rs index 47c4f8f..4794f13 100644 --- a/src/problems/hackerrank/mathematics/scalar_products/approach1.rs +++ b/src/problems/hackerrank/mathematics/scalar_products/approach1.rs @@ -4,11 +4,11 @@ /// but rather designe do provid a more "rust native" approach. /// /// In paricular we rely on constructing iterables. +// -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- - +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use core::iter::IntoIterator; use core::iter::Iterator; // use core::convert::TryFrom; @@ -20,9 +20,9 @@ use std::io::Stdin; use std::slice::Iter; use std::str::FromStr; -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- /// entry point when used as a script #[allow(unused)] @@ -69,9 +69,9 @@ pub fn run(c: i32, m: i32, n: usize) -> usize { return num_unique; } -/// ---------------------------------------------------------------- -/// SECONDARY -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// SECONDARY +// ---------------------------------------------------------------- #[derive(Clone, Debug)] struct SeqPair { modulus: i64, @@ -138,9 +138,9 @@ impl IntoIterator for SeqPair { } } -/// ---------------------------------------------------------------- -/// AUXILIARY -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// AUXILIARY +// ---------------------------------------------------------------- /// Obtains input lines from stdin /// as a vector of strings. diff --git a/src/problems/hackerrank/mathematics/scalar_products/approach2.rs b/src/problems/hackerrank/mathematics/scalar_products/approach2.rs index 776843e..211d296 100644 --- a/src/problems/hackerrank/mathematics/scalar_products/approach2.rs +++ b/src/problems/hackerrank/mathematics/scalar_products/approach2.rs @@ -47,11 +47,11 @@ /// ``` /// O(n) + O(n) = O(n) /// ``` +// -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- - +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::fmt::Debug; use std::fmt::Display; use std::io; @@ -65,9 +65,9 @@ use std::ops::Rem; use std::slice::Iter; use std::str::FromStr; -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- /// entry point when used as a script #[allow(unused)] @@ -96,16 +96,13 @@ pub fn run(c: i64, m: i64, n: usize) -> usize { let matrix_g = matrix_f.pow2(); // compute system[k] = (_, G^k * v0) - let system = DynamicalSystem { - evolution: matrix_g, - state: v0, - }; + let system = DynamicalSystem { evolution: matrix_g, state: v0 }; let n_max = 2 * (n as i64); let system_powers = compute_powers(&system, n_max); // compute all powers of G: let mut values: HashSet = HashSet::new(); - for k in 3.. n_max { + for k in 3..n_max { // k = i + j // compute v := G^k * v_0 let system_pow_k = system_powers.get(&(k as i64)).unwrap(); @@ -118,9 +115,9 @@ pub fn run(c: i64, m: i64, n: usize) -> usize { return values.len(); } -/// ---------------------------------------------------------------- -/// ALGORITHMS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// ALGORITHMS +// ---------------------------------------------------------------- /// computes x^(2^k) for 1 <= k <= n pub fn power_of_2_powers(x: &T, n: i64) -> HashMap @@ -130,7 +127,7 @@ where let mut results: HashMap = HashMap::new(); let mut x_pow_2_pow = x.clone(); results.insert(0, x_pow_2_pow.clone()); - (1.. n).for_each(|k| { + (1..n).for_each(|k| { x_pow_2_pow = x_pow_2_pow.pow2(); results.insert(k as i64, x_pow_2_pow.clone()); }); @@ -166,25 +163,22 @@ where let x_pow_2_pow = power_of_2_powers(x, l); // now compute along levels of a binary tree - let powers = (0.. l).fold( - powers, - |mut prev, k| { - let num_leaves = prev.len() as i64; - let x_pow_2_pow_k = x_pow_2_pow.get(&k).unwrap().clone(); - for (&j, value) in prev.clone().iter() { - let value_ = x_pow_2_pow_k.clone() * value.clone(); - prev.insert(j + num_leaves, value_); - }; - return prev; + let powers = (0..l).fold(powers, |mut prev, k| { + let num_leaves = prev.len() as i64; + let x_pow_2_pow_k = x_pow_2_pow.get(&k).unwrap().clone(); + for (&j, value) in prev.clone().iter() { + let value_ = x_pow_2_pow_k.clone() * value.clone(); + prev.insert(j + num_leaves, value_); } - ); + return prev; + }); return powers; } -/// ---------------------------------------------------------------- -/// STRUCTURES -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// STRUCTURES +// ---------------------------------------------------------------- /// Helper structure for modulo computations #[derive(Copy, Clone, PartialEq, Eq)] @@ -217,9 +211,9 @@ pub struct DynamicalSystem { pub state: Vector2, } -/// ---------------------------------------------------------------- -/// TRAITS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// TRAITS +// ---------------------------------------------------------------- pub trait NumberLike { fn positive(&self) -> bool; @@ -231,9 +225,9 @@ pub trait BinaryPowers { fn pow2(&self) -> Self; } -/// ---------------------------------------------------------------- -/// IMPLEMENTATIONS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPLEMENTATIONS +// ---------------------------------------------------------------- impl NumberLike for i64 { fn positive(&self) -> bool { @@ -299,14 +293,7 @@ where impl Add for Modulo where - T: Display - + Copy - + Clone - + PartialEq - + Eq - + NumberLike - + Add - + Rem, + T: Display + Copy + Clone + PartialEq + Eq + NumberLike + Add + Rem, { type Output = Self; @@ -319,14 +306,7 @@ where impl Mul for Modulo where - T: Display - + Copy - + Clone - + PartialEq - + Eq - + NumberLike - + Mul - + Rem, + T: Display + Copy + Clone + PartialEq + Eq + NumberLike + Mul + Rem, { type Output = Self; @@ -390,12 +370,7 @@ where T: Copy + Mul + Add, { fn mul_vector(&self, u: &Vector2) -> Vector2 { - Vector2( - [ - (self.a * u.get(0) + self.b * u.get(1)), - (self.b * u.get(0) + self.d * u.get(1)), - ], - ) + Vector2([(self.a * u.get(0) + self.b * u.get(1)), (self.b * u.get(0) + self.d * u.get(1))]) } } @@ -490,11 +465,7 @@ where impl BinaryPowers for DynamicalSystem where - T: Copy - + Clone - + Add - + Mul - + BinaryPowers, + T: Copy + Clone + Add + Mul + BinaryPowers, { fn zerolike(&self) -> Self { Self { @@ -518,9 +489,9 @@ where } } -/// ---------------------------------------------------------------- -/// AUXILIARY -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// AUXILIARY +// ---------------------------------------------------------------- /// Obtains input lines from stdin /// as a vector of strings. diff --git a/src/problems/hackerrank/mathematics/scalar_products/mod.rs b/src/problems/hackerrank/mathematics/scalar_products/mod.rs index e5293f5..4020928 100644 --- a/src/problems/hackerrank/mathematics/scalar_products/mod.rs +++ b/src/problems/hackerrank/mathematics/scalar_products/mod.rs @@ -1,6 +1,5 @@ /// Solutions to the Hackerrank Mathematics challenge: /// . - pub mod approach1; pub mod approach2; diff --git a/src/problems/hackerrank/mathematics/scalar_products/tests_approach1.rs b/src/problems/hackerrank/mathematics/scalar_products/tests_approach1.rs index a42a044..79830de 100644 --- a/src/problems/hackerrank/mathematics/scalar_products/tests_approach1.rs +++ b/src/problems/hackerrank/mathematics/scalar_products/tests_approach1.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use super::approach1 as approach; -/// ---------------------------------------------------------------- -/// TESTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// TESTS +// ---------------------------------------------------------------- /// bundle of tests #[cfg(test)] diff --git a/src/problems/hackerrank/mathematics/scalar_products/tests_approach2.rs b/src/problems/hackerrank/mathematics/scalar_products/tests_approach2.rs index 96e8373..4b66551 100644 --- a/src/problems/hackerrank/mathematics/scalar_products/tests_approach2.rs +++ b/src/problems/hackerrank/mathematics/scalar_products/tests_approach2.rs @@ -1,12 +1,12 @@ -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use super::approach2 as approach; -/// ---------------------------------------------------------------- -/// TESTS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// TESTS +// ---------------------------------------------------------------- /// bundle of tests #[cfg(test)] diff --git a/src/problems/hackerrank/mod.rs b/src/problems/hackerrank/mod.rs index 986e5ab..c0e03aa 100644 --- a/src/problems/hackerrank/mod.rs +++ b/src/problems/hackerrank/mod.rs @@ -1,5 +1,4 @@ pub mod mathematics; /// Contains solutions to Hackerrank challenges. /// Source: . - pub mod project_euler; diff --git a/src/problems/hackerrank/project_euler/mod.rs b/src/problems/hackerrank/project_euler/mod.rs index f6972f6..38df9f3 100644 --- a/src/problems/hackerrank/project_euler/mod.rs +++ b/src/problems/hackerrank/project_euler/mod.rs @@ -1,5 +1,4 @@ /// Contains solutions to challenges in the Mathematics /// section of Hackerrank. /// Source: . - pub mod problem10_prime_summation; diff --git a/src/problems/hackerrank/project_euler/problem10_prime_summation/approach1.rs b/src/problems/hackerrank/project_euler/problem10_prime_summation/approach1.rs index 9d18f0c..ee7c642 100644 --- a/src/problems/hackerrank/project_euler/problem10_prime_summation/approach1.rs +++ b/src/problems/hackerrank/project_euler/problem10_prime_summation/approach1.rs @@ -3,11 +3,11 @@ /// Computes Primes using the Sieve of Eratosthenes. /// Then efficiently computes the cumulutative sum of primes /// below certain integers. +// -/// ---------------------------------------------------------------- -/// IMPORTS -/// ---------------------------------------------------------------- - +// ---------------------------------------------------------------- +// IMPORTS +// ---------------------------------------------------------------- use std::io; use std::io::BufRead; use std::clone::Clone; @@ -17,9 +17,9 @@ use std::collections::HashMap; use std::io::Stdin; use std::str::FromStr; -/// ---------------------------------------------------------------- -/// MAIN -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// MAIN +// ---------------------------------------------------------------- /// entry point when used as a script #[allow(unused)] @@ -44,9 +44,9 @@ pub fn run(numbers: &Vec) -> HashMap { return sums; } -/// ---------------------------------------------------------------- -/// HELPER METHODS -/// ---------------------------------------------------------------- +// ---------------------------------------------------------------- +// HELPER METHODS +// ---------------------------------------------------------------- /// computes the list of primes up to a value fn get_primes(n_max: i64) -> Vec { @@ -78,9 +78,9 @@ fn compute_aggregates(numbers: &Vec, primes: &Vec) -> HashMap