diff --git a/.github/workflows/auto.yaml b/.github/workflows/auto.yaml index e156e95..8ec323c 100644 --- a/.github/workflows/auto.yaml +++ b/.github/workflows/auto.yaml @@ -85,7 +85,7 @@ jobs: touch .env && rm .env echo " - MAIN_MODULE="code-challenges" + MAIN_MODULE="CodeChallenges" PYTHON_PATH="python${{ env.PYTHON_VERSION }}" ARCHITECTURE="${{ env.ARCHITECTURE }}" RUST_BACKTRACE=full diff --git a/.github/workflows/manual.yaml b/.github/workflows/manual.yaml index fa2d0ff..c3f7675 100644 --- a/.github/workflows/manual.yaml +++ b/.github/workflows/manual.yaml @@ -83,7 +83,7 @@ jobs: touch .env && rm .env echo " - MAIN_MODULE="code-challenges" + MAIN_MODULE="CodeChallenges" PYTHON_PATH="python${{ env.PYTHON_VERSION }}" ARCHITECTURE="${{ env.ARCHITECTURE }}" RUST_BACKTRACE=full diff --git a/.gitignore b/.gitignore index eb47120..81d8062 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ /** !/.gitignore !/.gitattributes -!/.funcignore # ---------------------------------------------------------------- # ROOT diff --git a/Cargo.lock b/Cargo.lock index 86d095a..4b30973 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,6 +109,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +[[package]] +name = "bumpalo" +version = "3.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" + [[package]] name = "camino" version = "1.1.9" @@ -251,6 +257,19 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" +[[package]] +name = "console" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e09ced7ebbccb63b4c65413d821f2e00ce54c5ca4514ddc6b3c892fdbcbc69d" +dependencies = [ + "encode_unicode", + "libc", + "once_cell", + "unicode-width 0.2.1", + "windows-sys 0.60.2", +] + [[package]] name = "crc" version = "3.3.0" @@ -321,6 +340,12 @@ version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "env_home" version = "0.1.0" @@ -360,7 +385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b1a357c911c352439b460d7b375b5c85977b9db395b703dfee5a94dfb4d66a2" dependencies = [ "num-traits", - "rand", + "rand 0.6.5", "rustc_version 0.2.3", "semver 0.9.0", "serde", @@ -440,10 +465,17 @@ dependencies = [ "cargo-zigbuild", "dedent", "dict_derive", + "indicatif", + "indoc", + "itertools", + "ndarray", + "rand 0.9.2", + "rand_chacha 0.9.0", "rstest", "rustfmt", "serde", "serde_json", + "strip-ansi-escapes", ] [[package]] @@ -452,7 +484,7 @@ version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -463,7 +495,19 @@ checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasi 0.14.3+wasi-0.2.4", ] [[package]] @@ -505,18 +549,56 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd" +dependencies = [ + "console", + "portable-atomic", + "unicode-width 0.2.1", + "unit-prefix", + "web-time", +] + +[[package]] +name = "indoc" +version = "2.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd" + [[package]] name = "is_terminal_polyfill" version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "js-sys" +version = "0.3.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0b063578492ceec17683ef2f8c5e89121fbd0b172cbc280635ab7567db2738" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -570,12 +652,55 @@ version = "0.4.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg 1.4.0", + "rawpointer", +] + [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -621,6 +746,30 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + [[package]] name = "proc-macro-crate" version = "3.3.0" @@ -648,6 +797,12 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.6.5" @@ -656,7 +811,7 @@ checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" dependencies = [ "autocfg 0.1.8", "libc", - "rand_chacha", + "rand_chacha 0.1.1", "rand_core 0.4.2", "rand_hc", "rand_isaac", @@ -667,6 +822,16 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "rand" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", +] + [[package]] name = "rand_chacha" version = "0.1.1" @@ -677,6 +842,16 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", +] + [[package]] name = "rand_core" version = "0.3.1" @@ -692,6 +867,15 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.3", +] + [[package]] name = "rand_hc" version = "0.1.0" @@ -754,6 +938,12 @@ dependencies = [ "rand_core 0.3.1", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rdrand" version = "0.4.0" @@ -769,7 +959,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom", + "getrandom 0.2.16", "libredox", "thiserror 1.0.69", ] @@ -1037,6 +1227,15 @@ dependencies = [ "log 0.3.9", ] +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.11.1" @@ -1236,12 +1435,24 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" + [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +[[package]] +name = "unit-prefix" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "323402cff2dd658f39ca17c789b502021b3f18707c91cdf22e3838e1b4023817" + [[package]] name = "utf8-ranges" version = "1.0.5" @@ -1254,12 +1465,98 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.14.3+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a51ae83037bdd272a9e28ce236db8c07016dd0d50c27038b3f407533c030c95" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e14915cadd45b529bb8d1f343c4ed0ac1de926144b746e2710f9cd05df6603b" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28d1ba982ca7923fd01448d5c30c6864d0a14109560296a162f80f305fb93bb" +dependencies = [ + "bumpalo", + "log 0.4.27", + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c3d463ae3eff775b0c45df9da45d68837702ac35af998361e2c84e7c5ec1b0d" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb4ce89b08211f923caf51d527662b75bdc9c9c7aab40f86dcb9fb85ac552aa" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f143854a3b13752c6950862c906306adb27c7e839f7414cec8fea35beab624c1" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "which" version = "7.0.3" @@ -1306,6 +1603,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-link" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" + [[package]] name = "windows-sys" version = "0.48.0" @@ -1324,6 +1627,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.3", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -1348,13 +1660,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "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_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_msvc 0.53.0", + "windows_x86_64_gnu 0.53.0", + "windows_x86_64_gnullvm 0.53.0", + "windows_x86_64_msvc 0.53.0", +] + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -1367,6 +1696,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -1379,6 +1714,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -1391,12 +1732,24 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -1409,6 +1762,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -1421,6 +1780,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -1433,6 +1798,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -1445,6 +1816,12 @@ 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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" + [[package]] name = "winnow" version = "0.7.10" @@ -1459,3 +1836,29 @@ name = "winsafe" version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" + +[[package]] +name = "wit-bindgen" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "052283831dbae3d879dc7f51f3d92703a316ca49f91540417d38591826127814" + +[[package]] +name = "zerocopy" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.101", +] diff --git a/Cargo.toml b/Cargo.toml index e336cd3..0566c02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ name = "general" version = "0.1.0" edition = "2024" description = "Code for challenges from various platforms" +homepage = "github.com/raj-open/code-challenges" rust-version = "1.86" authors = [ "raj-open ", @@ -35,12 +36,17 @@ members = [ # ] debug = true strip = false +opt-level = 3 +lto = true # link-time optimisation +codegen-units = 1 [profile.dev] # rustflags = [ # "-A", "unused_imports", # "-A", "dead_code", # ] +opt-level = 0 +lto = false # link-time optimisation [profile.test] # rustflags = [ @@ -53,6 +59,14 @@ serde = {version = "^1.0.219", features = ["derive"]} serde_json = {version = "^1.0.143"} dict_derive = {version = "^0.6.0" } dedent = {version="^0.1.1"} +itertools = {version = "^0.14.0"} +indoc = {version="^2.0.6"} +indicatif = {version = "^0.18.0"} +strip-ansi-escapes = {version="^0.2.1"} +rand = {version="^0.9.2"} +rand_chacha = {version = "^0.9.0"} +# numpy = {version = "^0.26.0"} +ndarray = {version = "^0.16.1"} [dev-dependencies] cargo-zigbuild = {version = "^0.20.1"} @@ -61,9 +75,13 @@ rustfmt = {version = "^0.10.0", features = []} # just = {version = "^1.40.0"} [[bin]] -name = "code-challenges" +name = "CodeChallenges" path = "src/main.rs" [[bin]] -name = "hackerrank_mathematics" +name = "HackerRankMathematics" path = "src/problems/hackerrank/mathematics/main.rs" + +[[bin]] +name = "GeniusSquare" +path = "src/bin/games/genius_square/main.rs" diff --git a/README.md b/README.md index 82cd8e1..ca3ea8a 100644 --- a/README.md +++ b/README.md @@ -83,3 +83,128 @@ just tests-unit The `tests` folder contains integration tests for rust code, and unit tests for python code. + +## Execution of Binaries ## + +This repository contains some binaries (see [Cargo.toml](./Cargo.toml)): + +- `CodeChallenges` +- `HackerRankMathematics` +- `GeniusSquare` + +To run a binary call + +```bash +# runs with optimisation (slower compile time) +just run-rust {NAME_OF_BINARY} [flags] +# runs without optimisation (faster compile time, slower run time) +just dev-rust {NAME_OF_BINARY} [flags] +``` + +### Genius Squares ### + +The binary `GeniusSquare` solves instances of +the _Smart Games_ puzzle [Genius Square](https://smarttoysandgames.co.uk/uk/genius-square). +Usage is as follows: + +```bash +# provides random instance of the puzzle and solves it: +just run-rust GeniusSquare +# ... with random seeding for repeatability: +just run-rust GeniusSquare {Seed} +# solves an instance of the game for a particular initialisation (roll of the dice): +just run-rust GeniusSquare {Dice1} {Dice2} ... {Dice7} +``` + +e.g. + +```bash +just run-rust GeniusSquare 1234 # with random seed +just run-rust GeniusSquare B1 C4 D6 F1 F2 F3 F5 # with given initialisation +``` + +The `run` command builds and runs the binary. +To perform this separately, use + +```bash +just build-compile GeniusSquare +``` + +which produces the binary in [target/release/GeniusSquare](target/release/GeniusSquare). +The standalone binary can be called as above: + +```bash +./target/release/GeniusSquare +# with random seed +./target/release/GeniusSquare {Seed} +./target/release/GeniusSquare 1234 +# with given initialisation +./target/release/GeniusSquare {Dice1} {Dice2} ... {Dice7} +./target/release/GeniusSquare B1 C4 D6 F1 F2 F3 F5 +``` + +#### Example #### + +Calling + +```bash +just run-rust GeniusSquare B1 C4 D6 F1 F2 F3 F5 +``` + +results in + +```bash +Roll: B1, C4, D6, F1, F2, F3, F5. + + +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 │ +╙───╨───┴───┴───┴───┴───┴───┘ +``` + +in the console. +The solver currently relies on a brute force tree-search algorithm, +and provides solutions at the `Wizard` level, +viz. no collisions occur and none of the pieces + +```text +1 2 3 CC + 2 3 C + 3 +``` + +are adjacent (in the sense of touching edges). diff --git a/justfile b/justfile index 8f73b6f..3b6a9a7 100644 --- a/justfile +++ b/justfile @@ -146,7 +146,7 @@ run-py module="main" *args="": run-rust module="${MAIN_MODULE}" *args="": @just build-compile "{{module}}" @# "./target/release/{{module}}" {{args}} - @cargo run --bin "{{module}}" + @cargo run --release --bin "{{module}}" {{args}} # -------------------------------- # TARGETS: development @@ -155,6 +155,11 @@ run-rust module="${MAIN_MODULE}" *args="": dev *args: @echo "Not yet implemented" +dev-rust module="${MAIN_MODULE}" *args="": + @just build-compile "{{module}}" + @# "./target/release/{{module}}" {{args}} + @cargo run --bin "{{module}}" {{args}} + # -------------------------------- # TARGETS: tests # -------------------------------- diff --git a/src/_core/mod.rs b/src/_core/mod.rs index a385ff7..a715ece 100644 --- a/src/_core/mod.rs +++ b/src/_core/mod.rs @@ -1,2 +1,3 @@ pub mod errors; +pub mod rand; pub mod strings; diff --git a/src/_core/rand.rs b/src/_core/rand.rs new file mode 100644 index 0000000..5191f06 --- /dev/null +++ b/src/_core/rand.rs @@ -0,0 +1,31 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use rand; +use rand::SeedableRng; +use rand_chacha::ChaCha8Rng; + +/// ---------------------------------------------------------------- +/// METHODS +/// ---------------------------------------------------------------- + +#[allow(unused)] +pub fn seed_rng(x: Option) -> ChaCha8Rng { + match x { + Some(seed_str) => { + // string -> bytes + let mut seed = [0u8; 32]; + let seed_bytes = seed_str.as_bytes(); + let len = seed_bytes.len().min(32); + seed[..len].copy_from_slice(&seed_bytes[..len]); + + // 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 b313a66..9673e89 100644 --- a/src/_core/strings.rs +++ b/src/_core/strings.rs @@ -2,7 +2,7 @@ /// IMPORTS /// ---------------------------------------------------------------- -/// +use strip_ansi_escapes::strip; /// ---------------------------------------------------------------- /// METHODS @@ -11,3 +11,15 @@ pub fn greet(name: &str) { println!("Hello, {}!", name); } + +#[allow(unused)] +/// Strips potential ANSII characters +pub fn purify_string(text: &String) -> String { + String::from_utf8(strip(text)).unwrap_or(text.clone()) +} + +#[allow(unused)] +/// Computes length of purified string +pub fn purify_string_length(text: &String) -> usize { + purify_string(text).len() +} diff --git a/src/app/messages.rs b/src/app/messages.rs new file mode 100644 index 0000000..b6ea18c --- /dev/null +++ b/src/app/messages.rs @@ -0,0 +1,45 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use std::env; + +use super::super::_core::strings::purify_string_length; + +/// ---------------------------------------------------------------- +/// METHODS +/// ---------------------------------------------------------------- + +#[allow(unused)] +pub fn welcome_screen() { + let exe = env::current_exe().unwrap(); + 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}"), + ]; + display_bordered_message(lines); +} + +/// ---------------------------------------------------------------- +/// AUXILIARY METHODS +/// ---------------------------------------------------------------- + +fn display_bordered_message(lines: Vec) { + // determine padding + let n = lines.iter().map(purify_string_length).max().unwrap_or(0); + let hspace = " ".repeat(n + 2); + let hbar = "\u{2500}".repeat(n + 2); + + 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(); + println!("\u{2502}{hspace}\u{2502}"); + println!("\u{2514}{hbar}\u{2518}"); +} diff --git a/src/app/mod.rs b/src/app/mod.rs new file mode 100644 index 0000000..2de8453 --- /dev/null +++ b/src/app/mod.rs @@ -0,0 +1,3 @@ +/// 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 new file mode 100644 index 0000000..06fb1e9 --- /dev/null +++ b/src/bin/games/genius_square/algorithms/mod.rs @@ -0,0 +1,3 @@ +/// 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 new file mode 100644 index 0000000..89e6eae --- /dev/null +++ b/src/bin/games/genius_square/algorithms/solve.rs @@ -0,0 +1,93 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use indicatif::ProgressBar; +use indicatif::ProgressStyle; + +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; + +/// ---------------------------------------------------------------- +/// 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(); + } + } +} + +/// ---------------------------------------------------------------- +/// AUXILIARY METHODS +/// ---------------------------------------------------------------- + +fn recursion( + board: &GameBoard, + obst: &Piece, + option_kinds: Option<&[EnumPiece]>, + option_pbar: Option<&ProgressBar>, +) -> Option { + let kinds = option_kinds.unwrap_or(ENUM_PIECES); + let n = kinds.len() as u64; + + let pbar0 = ProgressBar::new(n); + let pbar: &ProgressBar; + 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})"); + 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 { + pbar.finish_and_clear(); + println!("...completed in {:.2?}", pbar.elapsed()); + return Some(board.to_owned()); + } + } else { + // 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)); + }, + } + } + } + + return None; +} diff --git a/src/bin/games/genius_square/features/mod.rs b/src/bin/games/genius_square/features/mod.rs new file mode 100644 index 0000000..aee96f5 --- /dev/null +++ b/src/bin/games/genius_square/features/mod.rs @@ -0,0 +1,3 @@ +/// Highest logic of application. + +pub mod setup_game; diff --git a/src/bin/games/genius_square/features/setup_game.rs b/src/bin/games/genius_square/features/setup_game.rs new file mode 100644 index 0000000..d3d85f3 --- /dev/null +++ b/src/bin/games/genius_square/features/setup_game.rs @@ -0,0 +1,39 @@ +/// ---------------------------------------------------------------- +/// 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/lib.rs b/src/bin/games/genius_square/lib.rs new file mode 100644 index 0000000..8c3bf74 --- /dev/null +++ b/src/bin/games/genius_square/lib.rs @@ -0,0 +1,5 @@ +/// Modules available for Genius Square binary + +pub mod algorithms; +pub mod features; +pub mod models; diff --git a/src/bin/games/genius_square/main.rs b/src/bin/games/genius_square/main.rs new file mode 100644 index 0000000..760e790 --- /dev/null +++ b/src/bin/games/genius_square/main.rs @@ -0,0 +1,28 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use std::env; + +use general::app::messages::welcome_screen; +use general::_core; + +mod algorithms; +mod models; +mod features; + +use models::constants::dice::NUM_DICE; +use features::setup_game::feature_setup_game; + +/// ---------------------------------------------------------------- +/// 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 mut rng = _core::rand::seed_rng(option_seed); + welcome_screen(); + feature_setup_game(&mut rng, option_roll); +} diff --git a/src/bin/games/genius_square/mod.rs b/src/bin/games/genius_square/mod.rs new file mode 100644 index 0000000..d0c2985 --- /dev/null +++ b/src/bin/games/genius_square/mod.rs @@ -0,0 +1,5 @@ +/// Modules for code base Genius Square + +pub mod algorithms; +pub mod features; +pub mod models; diff --git a/src/bin/games/genius_square/models/arrays/mod.rs b/src/bin/games/genius_square/models/arrays/mod.rs new file mode 100644 index 0000000..93e2fc4 --- /dev/null +++ b/src/bin/games/genius_square/models/arrays/mod.rs @@ -0,0 +1,3 @@ +/// Models for handling arrays + +pub mod models; diff --git a/src/bin/games/genius_square/models/arrays/models.rs b/src/bin/games/genius_square/models/arrays/models.rs new file mode 100644 index 0000000..1208bec --- /dev/null +++ b/src/bin/games/genius_square/models/arrays/models.rs @@ -0,0 +1,298 @@ +/// ---------------------------------------------------------------- +/// 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::Mul; +use itertools::iproduct; +use itertools::Itertools; + +/// ---------------------------------------------------------------- +/// STRUCTS +/// ---------------------------------------------------------------- + +#[derive(Clone, Debug)] +pub struct BinArray { + m: usize, + n: usize, + values: Array2, +} + +/// ---------------------------------------------------------------- +/// IMPLEMENTATIONS +/// ---------------------------------------------------------------- + +impl BinArray { + 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} + } + + /// 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)) }) + .collect() + } + + /// Determines a single co-ordinate to be used as an anchor point. + /// If none exists, defaults to (0, 0). + pub fn get_anchor(&self) -> (usize, usize) { + self.values + .indexed_iter() + .find_or_first(|&(_, &v)| v != 0) + .map_or((0, 0), |((i, j), _)| (i, j)) + } + + pub fn get_weight(&self) -> isize { + self.values + .mapv(|x| if x == 0 {0} else {1}) + .sum() + } + + pub fn get_coweight(&self) -> isize { + self.transform_invert().get_weight() + } + + pub fn get_shape(&self) -> (usize, usize) { + (self.m, self.n) + } + + pub fn get_values(&self) -> Array2 { + self.values.clone() + } + + /// Shifts array as far as possible to top left + pub fn recentre(&self) -> Self { + // determine maximal h+v-shifts + let coords = self.to_coords(); + let i_min: usize = *coords.iter().map(|(i, _)| i).min().unwrap_or(&0); + let j_min: usize = *coords.iter().map(|(_, j)| j).min().unwrap_or(&0); + // shift coords + let result = self.transform_shift(-(i_min as isize), -(j_min as isize)); + return result; + } + + /// Flips 0s and 1s + 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}; + } + + 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)); + + // slot in values in location shifted from the middle + let i0 = self.m as isize + di; + let i1 = (self.m as isize) + i0; + let j0 = self.n as isize + dj; + let j1 = (self.n as isize) + j0; + let mut view = slate.slice_mut(slice![i0..i1, j0..j1]); + view.assign(&self.values); + + // restrict to "middle" part + let i0 = self.m; + let i1 = self.m + i0; + 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}; + return result; + } + + 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}; + if recentre { + result = result.recentre(); + } + return result; + } + + pub fn transform_vflip(&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}; + 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}; + if recentre { + result = result.recentre(); + } + return result; + } + + pub fn transform_rotate(&self, k: i8, recentre: bool) -> Self { + match k { + 1 => { + return self.transform_transpose(false).transform_vflip(recentre); + }, + -1 => { + return self.transform_vflip(false).transform_transpose(recentre); + }, + _ => { + return self.clone(); + } + } + } + + /// For collision comparison + pub fn transform_dither(&self) -> Self { + let (m, n) = self.get_shape(); + let coords = self.to_coords(); + let mut arr = BinArray::from_coords(coords, m + 2, n + 2); + arr = arr.transform_shift(1, 1); + let arr1 = arr.transform_shift(-1, 0); + let arr2 = arr.transform_shift(1, 0); + 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}; + return result; + } + + /// Determines all possible configurations + /// of the same array subject to + /// + /// - rotations, + /// - v- and h-flips, + /// - v- and h-shifts + /// + /// provided the moves preserve the "weight" of the shadow in the array + /// and provided + /// + /// - no collisions occur with an optional obstacle. + 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], + ) + // iterate through all orientations + .map(|(rot, vflip, hflip)| { + // recover original + let mut arr = self.clone(); + if rot != 0 { + arr = arr.transform_rotate(rot, false); + } + if vflip { + arr = arr.transform_vflip(false); + } + 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(); + // } + return arr; + }) + // by fixing an anchor point and viewing the non-occupied positions + // get all possible shifts of the array + .map(move |arr| { + // an anchor point of the piece + let (i0, j0) = arr.get_anchor(); + let i0 = i0 as isize; + let j0 = j0 as isize; + // all non-occupied points on gameboard + let shifts = free + .to_coords() + .iter() + .map(|&(i, j)| { + let di = (i as isize) - i0; + let dj = (j as isize) - j0; + let arr_ = arr.transform_shift(di, dj); + return arr_; + }) + .collect::>(); + return shifts; + }) + // since returned a vector of possibilities, need to flatten + .flatten() + // if geometric operations shift shape off the grid, skip + .filter(|arr| { + let wt = self.get_weight(); + return arr.get_weight() >= wt; + }) + // if geometric operations collide with obstacle, skip + .filter(move |arr| { + let collision = arr.to_owned() * obst.to_owned(); + let penalty = -collision.get_weight(); + return penalty >= 0; + }); + return iterator; + } +} + +impl Display for BinArray { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.values) + } +} + +impl Add for BinArray { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + let m = self.m; + 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}; + } +} + +impl Mul for BinArray { + type Output = Self; + + fn mul(self, other: Self) -> Self::Output { + let m = self.m; + let n = self.n; + let values = self.values.to_owned() * other.values.to_owned(); + return Self {m, n, values}; + } +} diff --git a/src/bin/games/genius_square/models/board/mod.rs b/src/bin/games/genius_square/models/board/mod.rs new file mode 100644 index 0000000..a5034f1 --- /dev/null +++ b/src/bin/games/genius_square/models/board/mod.rs @@ -0,0 +1,3 @@ +/// Models for handling game board + +pub mod models; diff --git a/src/bin/games/genius_square/models/board/models.rs b/src/bin/games/genius_square/models/board/models.rs new file mode 100644 index 0000000..c0cc9e1 --- /dev/null +++ b/src/bin/games/genius_square/models/board/models.rs @@ -0,0 +1,209 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use ndarray::Array2; +use std::fmt::Debug; +use std::fmt::Display; +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::*; + +/// ---------------------------------------------------------------- +/// STRUCTS +/// ---------------------------------------------------------------- + +#[derive(Clone, Debug)] +pub struct GameBoard { + block: Piece, + pieces: HashMap, +} + +/// ---------------------------------------------------------------- +/// IMPLEMENTATIONS +/// ---------------------------------------------------------------- + +impl GameBoard { + pub fn new(block: &Piece) -> Self { + let pieces: HashMap = HashMap::new(); + return Self {block: block.clone(), pieces} + } + + #[allow(unused)] + pub fn add_piece(&mut self, symb: &EnumPiece, piece: &Piece) { + self.pieces.insert(symb.clone(), piece.clone()); + } + + #[allow(unused)] + pub fn set_pieces(&mut self, pieces: &HashMap) { + self.pieces = pieces.clone(); + } + + pub fn get_block(&self) -> &Piece { + &self.block + } + + pub fn to_string(&self) -> String { + let field = self.to_array_of_strings(false); + let text = Self::array_to_string(&field); + return text; + } + + #[allow(unused)] + pub fn to_formatted(&self) -> String { + let field = self.to_array_of_strings(true); + let text = Self::array_to_string(&field); + return text; + } + + 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}"); + + return text; + } + + 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 piece = self.get_block(); + for (i, j) in piece.to_coords() { + 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() }; + trace[[i, j]] = alpha; + } + } + return trace; + } + + fn array_to_string(field: &Array2) -> String { + let n = GRID_WIDTH; + 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() + .into_iter() + .map(|row| { + let line = row.iter().map(|s| s.as_str()).collect::(); + return format!("\u{2502} {line} \u{2502}"); + }) + .collect::>() + .join("\n"); + let text = format!("{top}\n{middle}\n{bot}"); + return text; + } + + /// Determines all possible configurations + /// of the same piece subject to + /// + /// - rotations, + /// - v- and h-flips, + /// - v- and h-shifts + /// + /// provided the moves preserve the "weight" of the shadow in the array + /// and provided + /// + /// - 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![]; + 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; + }) + // 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; + }); + return it; + } +} + +impl Display for GameBoard { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.to_string()) + } +} diff --git a/src/bin/games/genius_square/models/constants/board.rs b/src/bin/games/genius_square/models/constants/board.rs new file mode 100644 index 0000000..9fb056d --- /dev/null +++ b/src/bin/games/genius_square/models/constants/board.rs @@ -0,0 +1,12 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +// + +/// ---------------------------------------------------------------- +/// 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 new file mode 100644 index 0000000..e2c50a9 --- /dev/null +++ b/src/bin/games/genius_square/models/constants/dice.rs @@ -0,0 +1,57 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +// + +/// ---------------------------------------------------------------- +/// CONSTANTS +/// ---------------------------------------------------------------- + +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", +]; + +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", +]; + +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"], +]; + +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 new file mode 100644 index 0000000..2f27ee6 --- /dev/null +++ b/src/bin/games/genius_square/models/constants/enums.rs @@ -0,0 +1,124 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fmt::Result; + +use crate::models::arrays::models::BinArray; +use super::board::*; +use super::pieces::*; + +/// ---------------------------------------------------------------- +/// STRUCTS AND CONSTANTS +/// ---------------------------------------------------------------- + +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub enum EnumPiece { + Blank, + Block, + Symb1, + Symb2, + Symb3, + Symb4, + C, + L, + T, + X, + Z, +} + +pub const ENUM_PIECES: &[EnumPiece] = &[ + EnumPiece::Symb1, + EnumPiece::Symb2, + EnumPiece::Symb3, + EnumPiece::Symb4, + EnumPiece::C, + EnumPiece::L, + EnumPiece::T, + EnumPiece::X, + EnumPiece::Z, +]; + +pub const NON_ADJACENT: &[EnumPiece] = &[ + EnumPiece::Symb1, + EnumPiece::Symb2, + EnumPiece::Symb3, + EnumPiece::C, +]; + +/// ---------------------------------------------------------------- +/// IMPLEMENTATIONS +/// ---------------------------------------------------------------- + +impl EnumPiece { + #[allow(unused)] + pub const fn as_str(&self) -> &'static str { + match self { + EnumPiece::Blank => " ", + EnumPiece::Block => SYMB_BLOCK, + EnumPiece::Symb1 => SYMB_PIECE_1, + EnumPiece::Symb2 => SYMB_PIECE_2, + EnumPiece::Symb3 => SYMB_PIECE_3, + EnumPiece::Symb4 => SYMB_PIECE_4, + EnumPiece::C => SYMB_PIECE_C, + EnumPiece::L => SYMB_PIECE_L, + EnumPiece::T => SYMB_PIECE_T, + EnumPiece::X => SYMB_PIECE_X, + EnumPiece::Z => SYMB_PIECE_Z, + } + } + + #[allow(unused)] + pub const fn to_formatted(&self) -> &'static str { + match self { + EnumPiece::Blank => " ", + EnumPiece::Block => SYMB_FMT_BLOCK, + EnumPiece::Symb1 => SYMB_FMT_PIECE_1, + EnumPiece::Symb2 => SYMB_FMT_PIECE_2, + EnumPiece::Symb3 => SYMB_FMT_PIECE_3, + EnumPiece::Symb4 => SYMB_FMT_PIECE_4, + EnumPiece::C => SYMB_FMT_PIECE_C, + EnumPiece::L => SYMB_FMT_PIECE_L, + EnumPiece::T => SYMB_FMT_PIECE_T, + EnumPiece::X => SYMB_FMT_PIECE_X, + EnumPiece::Z => SYMB_FMT_PIECE_Z, + } + } + + pub fn get_positions(&self) -> BinArray { + let raw = match self { + EnumPiece::Blank => " ", + EnumPiece::Block => BLOCK, + EnumPiece::Symb1 => PIECE_1, + EnumPiece::Symb2 => PIECE_2, + EnumPiece::Symb3 => PIECE_3, + EnumPiece::Symb4 => PIECE_4, + EnumPiece::C => PIECE_C, + EnumPiece::L => PIECE_L, + EnumPiece::T => PIECE_T, + EnumPiece::X => PIECE_X, + EnumPiece::Z => PIECE_Z, + }; + let mut coords: Vec<(usize, usize)> = vec![]; + for (i, line) in raw.lines().enumerate() { + for (j, a) in line.chars().enumerate() { + if a.to_string() == "+" { + coords.push((i, j)); + } + } + } + let m = GRID_HEIGHT; + let n = GRID_WIDTH; + let positions = BinArray::from_coords(coords, m, n); + return positions; + } +} + +impl Display for EnumPiece { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.to_formatted()) + } +} diff --git a/src/bin/games/genius_square/models/constants/mod.rs b/src/bin/games/genius_square/models/constants/mod.rs new file mode 100644 index 0000000..416606a --- /dev/null +++ b/src/bin/games/genius_square/models/constants/mod.rs @@ -0,0 +1,6 @@ +/// Models for handling constants + +pub mod board; +pub mod dice; +pub mod enums; +pub mod pieces; diff --git a/src/bin/games/genius_square/models/constants/pieces.rs b/src/bin/games/genius_square/models/constants/pieces.rs new file mode 100644 index 0000000..01b890f --- /dev/null +++ b/src/bin/games/genius_square/models/constants/pieces.rs @@ -0,0 +1,109 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use indoc::indoc; + +/// ---------------------------------------------------------------- +/// CONSTANTS +/// ---------------------------------------------------------------- + +pub const SYMB_BLOCK: &str = "\u{25A0}"; +pub const SYMB_FMT_BLOCK: &str = "\u{25A0}"; +pub const BLOCK: &str = indoc! {" + +..... + ...... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_1: &str = "1"; +pub const SYMB_FMT_PIECE_1: &str = "1"; +pub const PIECE_1: &str = indoc! {" + +..... + ...... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_2: &str = "2"; +pub const SYMB_FMT_PIECE_2: &str = "2"; +pub const PIECE_2: &str = indoc! {" + ++.... + ...... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_3: &str = "3"; +pub const SYMB_FMT_PIECE_3: &str = "3"; +pub const PIECE_3: &str = indoc! {" + +++... + ...... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_4: &str = "4"; +pub const SYMB_FMT_PIECE_4: &str = "4"; +pub const PIECE_4: &str = indoc! {" + ++++.. + ...... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_C: &str = "C"; +pub const SYMB_FMT_PIECE_C: &str = "C"; +pub const PIECE_C: &str = indoc! {" + ++.... + +..... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_L: &str = "L"; +pub const SYMB_FMT_PIECE_L: &str = "L"; +pub const PIECE_L: &str = indoc! {" + ++.... + +..... + +..... + ...... + ...... +"}; + +pub const SYMB_PIECE_T: &str = "T"; +pub const SYMB_FMT_PIECE_T: &str = "T"; +pub const PIECE_T: &str = indoc! {" + +++... + .+.... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_X: &str = "X"; +pub const SYMB_FMT_PIECE_X: &str = "X"; +pub const PIECE_X: &str = indoc! {" + ++.... + ++.... + ...... + ...... + ...... +"}; + +pub const SYMB_PIECE_Z: &str = "Z"; +pub const SYMB_FMT_PIECE_Z: &str = "Z"; +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 new file mode 100644 index 0000000..d4839a1 --- /dev/null +++ b/src/bin/games/genius_square/models/dice/methods.rs @@ -0,0 +1,21 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use rand_chacha::ChaCha8Rng; +use rand::prelude::IndexedRandom; + +use crate::models::constants::dice::*; + +/// ---------------------------------------------------------------- +/// METHODS +/// ---------------------------------------------------------------- + +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 new file mode 100644 index 0000000..d66666c --- /dev/null +++ b/src/bin/games/genius_square/models/dice/mod.rs @@ -0,0 +1,4 @@ +/// Models for handling dice + +pub mod methods; +pub mod models; diff --git a/src/bin/games/genius_square/models/dice/models.rs b/src/bin/games/genius_square/models/dice/models.rs new file mode 100644 index 0000000..650325f --- /dev/null +++ b/src/bin/games/genius_square/models/dice/models.rs @@ -0,0 +1,60 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fmt::Result; + +use crate::models::constants::dice::*; + +/// ---------------------------------------------------------------- +/// STRUCTS +/// ---------------------------------------------------------------- + +#[derive(Copy, Clone, Debug)] +pub struct Die { + i: usize, + j: usize, +} + +/// ---------------------------------------------------------------- +/// IMPLEMENTATIONS +/// ---------------------------------------------------------------- + +impl Die { + pub fn from_string(face: &String) -> Die { + let chars: Vec = face.chars().map(|c| c.to_string()).collect(); + let char1 = chars.get(0).unwrap(); + 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, + } + } + + pub fn to_string(&self) -> String { + let char1: String = FACE1[self.j].to_string(); + let char2: String = FACE2[self.i].to_string(); + return format!("{char1}{char2}"); + } + + #[allow(unused)] + pub fn from_coords(i: usize, j: usize) -> Die { + return Die {i, j} + } + + #[allow(unused)] + pub fn to_coords(&self) -> (usize, usize) { + return (self.i, self.j) + } +} + +impl Display for Die { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.to_string()) + } +} diff --git a/src/bin/games/genius_square/models/mod.rs b/src/bin/games/genius_square/models/mod.rs new file mode 100644 index 0000000..33a3833 --- /dev/null +++ b/src/bin/games/genius_square/models/mod.rs @@ -0,0 +1,7 @@ +/// Models used in game. + +pub mod arrays; +pub mod board; +pub mod constants; +pub mod dice; +pub mod pieces; diff --git a/src/bin/games/genius_square/models/pieces/methods.rs b/src/bin/games/genius_square/models/pieces/methods.rs new file mode 100644 index 0000000..9e382d4 --- /dev/null +++ b/src/bin/games/genius_square/models/pieces/methods.rs @@ -0,0 +1,14 @@ +/// ---------------------------------------------------------------- +/// 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 new file mode 100644 index 0000000..2ea0b25 --- /dev/null +++ b/src/bin/games/genius_square/models/pieces/mod.rs @@ -0,0 +1,4 @@ +/// Models for handling pieces + +pub mod methods; +pub mod models; diff --git a/src/bin/games/genius_square/models/pieces/models.rs b/src/bin/games/genius_square/models/pieces/models.rs new file mode 100644 index 0000000..a0deed6 --- /dev/null +++ b/src/bin/games/genius_square/models/pieces/models.rs @@ -0,0 +1,188 @@ +/// ---------------------------------------------------------------- +/// IMPORTS +/// ---------------------------------------------------------------- + +use std::fmt::Debug; +use std::fmt::Display; +use std::fmt::Formatter; +use std::fmt::Result; +use std::ops::Add; +use std::ops::Mul; + +use crate::models::arrays::models::BinArray; +use crate::models::constants::board::*; +use crate::models::constants::enums::*; + +/// ---------------------------------------------------------------- +/// STRUCTS +/// ---------------------------------------------------------------- + +#[derive(Clone, Debug)] +pub struct Piece { + kind: EnumPiece, + positions: BinArray, +} + +/// ---------------------------------------------------------------- +/// 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} + } + + 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} + } + + pub fn to_coords(&self) -> Vec<(usize, usize)> { + self.positions.to_coords() + } + + pub fn get_kind(&self) -> EnumPiece { + self.kind.clone() + } + + pub fn get_symb(&self) -> String { + self.kind.as_str().to_string() + } + + pub fn get_symb_fmt(&self) -> String { + self.kind.to_formatted().to_string() + } + + pub fn get_positions(&self) -> &BinArray { + &self.positions + } + + #[allow(unused)] + pub fn set_positions(&mut self, positions: &BinArray) { + self.positions = positions.clone(); + } + + #[allow(unused)] + pub fn get_weight(&self) -> isize { + self.positions.get_weight() + } + + #[allow(unused)] + pub fn get_coweight(&self) -> isize { + self.positions.get_coweight() + } + + pub fn to_string(&self) -> String { + let n = GRID_WIDTH; + 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() + .into_iter() + .map(|row| { + let line = row + .iter() + .map(|&val| { + if val == 1 { + "+".to_string() + } else { + ".".to_string() + } + }) + .collect::>() + .join(""); + return format!("\u{2502} {line} \u{2502}"); + }) + .collect::>() + .join("\n"); + let text = format!("{top}\n{middle}\n{bot}"); + return text; + } + + #[allow(unused)] + 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}; + return result; + } + + #[allow(unused)] + 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}; + 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}; + return result; + } + + #[allow(unused)] + 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}; + return result; + } + + #[allow(unused)] + 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}; + return result; + } + + #[allow(unused)] + pub fn transform_dither(&self) -> Self { + let kind = self.get_kind(); + let positions = self.positions.transform_dither(); + let result = Self {kind, positions}; + return result; + } +} + +impl Display for Piece { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "{}", self.to_string()) + } +} + +impl Add for Piece { + type Output = Self; + + 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}; + } +} + +impl Mul for Piece { + type Output = Self; + + 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}; + } +} diff --git a/src/lib.rs b/src/lib.rs index 077fd81..46446e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,6 @@ +/// Modules available from General crate for other crates + +pub mod app; pub mod _core; pub mod models; pub mod problems; diff --git a/src/mod.rs b/src/mod.rs index 63c7f2b..108d231 100644 --- a/src/mod.rs +++ b/src/mod.rs @@ -1,2 +1,5 @@ +/// Modules available for General code base + +pub mod app; pub mod models; pub mod problems; diff --git a/templates/template.env b/templates/template.env index d3a3044..1616d08 100644 --- a/templates/template.env +++ b/templates/template.env @@ -2,7 +2,7 @@ # PROJECT SETTINGS # ---------------------------------------------------------------- -MAIN_MODULE="code_challenges" +MAIN_MODULE="CodeChallenges" # ---------------------------------------------------------------- # LOCAL SYSTEM SETTINGS