diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bdf3460 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +/release +TODO.md diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..4d92b33 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,21 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "lldb", + "request": "launch", + "name": "Start debugging", + "cargo": { + "args": [ + "build" + ], + "filter": { + "name": "minesweeper-rs", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + } + ] +} diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..6378e9b --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1152 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + +[[package]] +name = "ahash" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" + +[[package]] +name = "alsa" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c4da790adcb2ce5e758c064b4f3ec17a30349f9961d3e5e6c9688b052a9e18" +dependencies = [ + "alsa-sys", + "bitflags", + "libc", + "nix", +] + +[[package]] +name = "alsa-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bindgen" +version = "0.56.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2da379dbebc0b76ef63ca68d8fc6e71c0f13e59432e0987e508c1820e6ab5239" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "peeking_take_while", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" + +[[package]] +name = "bytemuck" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + +[[package]] +name = "cc" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cexpr" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clang-sys" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853eda514c284c2287f4bf20ae614f8781f40a81d32ecda6e91449304dfe077c" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "combine" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4369b5e4c0cddf64ad8981c0111e7df4f7078f4d6ba98fb31f2e17c4c57b7e" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "core-foundation-sys" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" + +[[package]] +name = "coreaudio-rs" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11894b20ebfe1ff903cbdc52259693389eea03b94918a2def2c30c3bf227ad88" +dependencies = [ + "bitflags", + "coreaudio-sys", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b7e3347be6a09b46aba228d6608386739fb70beff4f61e07422da87b0bb31fa" +dependencies = [ + "bindgen", +] + +[[package]] +name = "cpal" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8351ddf2aaa3c583fa388029f8b3d26f3c7035a20911fdd5f2e2ed7ab57dad25" +dependencies = [ + "alsa", + "core-foundation-sys", + "coreaudio-rs", + "jni", + "js-sys", + "lazy_static", + "libc", + "mach", + "ndk", + "ndk-glue", + "nix", + "oboe", + "parking_lot", + "stdweb", + "thiserror", + "web-sys", + "winapi", +] + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "darling" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fontdue" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75712fff1702bac51b7eaa5a5ca9f9853b8055ef5906088a32f4fe196595a1d" +dependencies = [ + "hashbrown", + "ttf-parser", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "glam" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "333928d5eb103c5d4050533cec0384302db6be8ef7d3cebd30ec6a35350353da" + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" +dependencies = [ + "ahash", +] + +[[package]] +name = "hound" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a164bb2ceaeff4f42542bdb847c41517c78a60f5649671b2a07312b6e117549" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "num-iter", + "num-rational", + "num-traits", + "png", +] + +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "jni" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "972f5ae5d1cb9c6ae417789196c803205313edde988685da5e3aae0827b9e7fd" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "lewton" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030" +dependencies = [ + "byteorder", + "ogg", + "tinyvec", +] + +[[package]] +name = "libc" +version = "0.2.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5600b4e6efc5421841a2138a6b082e07fe12f9aaa12783d50e5d13325b26b4fc" + +[[package]] +name = "libloading" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f84d96438c15fcd6c3f244c8fce01d1e2b9c6b5623e9c711dc9286d8fc92d6a" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "lock_api" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0382880606dff6d15c9476c416d18690b72742aa7b605bb6dd6ec9030fbf07eb" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + +[[package]] +name = "macroquad" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44e80d397cc7d03fea79ae6e6365def8ed3672c491bacd11b51c3f49094e0cee" +dependencies = [ + "bumpalo", + "fontdue", + "glam", + "image", + "macroquad_macro", + "miniquad", + "quad-rand", + "rodio", +] + +[[package]] +name = "macroquad_macro" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ecb8935bc6a74b8374439c0bd8d2857ae1499fde9fbba76bb00722f7213b42d" + +[[package]] +name = "memchr" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16bd47d9e329435e309c58469fe0791c2d0d1ba96ec0954152a5ae2b04387dc" + +[[package]] +name = "minesweeper-rs" +version = "1.0.0" +dependencies = [ + "macroquad", + "rand", + "rust-grid", +] + +[[package]] +name = "miniquad" +version = "0.3.0-alpha.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e755f1ed3d4a14ef76475e638ea4c7a408b4531a1199b4232ebefff6facd0e7" +dependencies = [ + "sapp-android", + "sapp-darwin", + "sapp-dummy", + "sapp-ios", + "sapp-linux", + "sapp-wasm", + "sapp-windows", +] + +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "ndk" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8794322172319b972f528bf90c6b467be0079f1fa82780ffb431088e741a73ab" +dependencies = [ + "jni-sys", + "ndk-sys", + "num_enum", + "thiserror", +] + +[[package]] +name = "ndk-glue" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5caf0c24d51ac1c905c27d4eda4fa0635bbe0de596b8f79235e0b17a4d29385" +dependencies = [ + "lazy_static", + "libc", + "log", + "ndk", + "ndk-macro", + "ndk-sys", +] + +[[package]] +name = "ndk-macro" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" +dependencies = [ + "darling", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ndk-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c44922cb3dbb1c70b5e5f443d63b64363a898564d739ba5198e3a9138442868d" + +[[package]] +name = "nix" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa9b4819da1bc61c0ea48b63b7bc8604064dd43013e7cc325df098d49cd7c18a" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" +dependencies = [ + "memchr", + "version_check", +] + +[[package]] +name = "num-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226b45a5c2ac4dd696ed30fa6b94b057ad909c7b7fc2e0d0808192bced894066" +dependencies = [ + "derivative", + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c0fd9eba1d5db0994a239e09c1be402d35622277e35468ba891aa5e3188ce7e" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "oboe" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa187b38ae20374617b7ad418034ed3dc90ac980181d211518bd03537ae8f8d" +dependencies = [ + "jni", + "ndk", + "ndk-glue", + "num-derive", + "num-traits", + "oboe-sys", +] + +[[package]] +name = "oboe-sys" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88e64835aa3f579c08d182526dc34e3907343d5b97e87b71a40ba5bca7aca9e" +dependencies = [ + "cc", +] + +[[package]] +name = "ogg" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" +dependencies = [ + "byteorder", +] + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro2" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quad-rand" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658fa1faf7a4cc5f057c9ee5ef560f717ad9d8dc66d975267f709624d6e1ab88" + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +dependencies = [ + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" + +[[package]] +name = "rodio" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b65c2eda643191f6d1bb12ea323a9db8d9ba95374e9be3780b5a9fb5cfb8520f" +dependencies = [ + "cpal", + "hound", + "lewton", +] + +[[package]] +name = "rust-grid" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "047df427e018996fe5bd0f75f919d216ba4a5ecb49110ef8c472cfee239d6685" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "sapp-android" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d288879b4f43deceb21d5bb3be1740b2817cd5e3f3dcd633478937a3facd672" +dependencies = [ + "libc", + "ndk-sys", +] + +[[package]] +name = "sapp-darwin" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0310e2445f307468aa13f1cde94d6fba6b8fd329afbb642dedbe3faf1a145f31" +dependencies = [ + "cc", +] + +[[package]] +name = "sapp-dummy" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66f1ad26a5b6c682b9ca27c66db9aa91002b8d98a82ac7101ded57285215a478" +dependencies = [ + "libc", +] + +[[package]] +name = "sapp-ios" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "081e6e5261c9ac2e938979b6a854a53b439f065fc3c897205ce7e69d3028b4a9" +dependencies = [ + "cc", +] + +[[package]] +name = "sapp-linux" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbdb2f8011955c62544d9e626a58333e788810d00bd7411d52b81611b92af142" +dependencies = [ + "libc", +] + +[[package]] +name = "sapp-wasm" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00e859e8645a3bcb85aecd40bab883438e4105f21b21bccbeac2348760f508bb" + +[[package]] +name = "sapp-windows" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251bb2122b7f5d8babf7c58bee7255af89251f1d8e3bd20f2db0c332992564d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "serde" +version = "1.0.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" + +[[package]] +name = "shlex" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" + +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" + +[[package]] +name = "strsim" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" + +[[package]] +name = "syn" +version = "1.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "thiserror" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa6f76457f59514c7eeb4e59d891395fab0b2fd1d40723ae737d64153392e9c6" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a36768c0fbf1bb15eca10defa29526bda730a2376c2ab4393ccfa16fb1a318d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinyvec" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b5220f05bb7de7f3f53c7c065e1199b3172696fe2db9f9c4d8ad9b4ee74c342" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "toml" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +dependencies = [ + "serde", +] + +[[package]] +name = "ttf-parser" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc71742ead70703a55d184f82087302f2f9ffa3793e64db46a78bf75dd723f4" + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "wasm-bindgen" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" + +[[package]] +name = "web-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5c5b323 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "minesweeper-rs" +version = "1.0.0" +authors = ["wait_what_"] +edition = "2018" + +[profile.release] +lto = 'thin' + +[dependencies] +macroquad = "0.3.5" +rand = "0.8.3" +rust-grid = "0.1.1" diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2042498 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Copyright © 2021 wait_what_ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to +do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +MPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..d687bb2 --- /dev/null +++ b/README.md @@ -0,0 +1,45 @@ +# Minesweeper rs + +## [DOWNLOAD](https://github.com/wait-what/minesweeper-rs/releases) + +![Screenshot](./screenshot.png) + +## Features + +- Adjustable width and height +- Adjustable mine count (using percentage) +- Adjustable colours +- Timer +- Area highlighting when right-clicking number +- Automatic restarts until a 0 cell is clicked + +## Controls + +- Left click to reveal cell +- Right click unexplored area to place a flag +- Right click a number to highlight the area it belongs to +- Space to open settings +- R to restart + +## Pre-built downloads + +[**DOWNLOAD HERE**](https://github.com/wait-what/minesweeper-rs/releases) if you don't feel like building it yourself + +Windows and Defender will probabably get mad at the files! If you do not trust my builds, that's on you - compile it yourself + +> The pre-built binaries are treated with `strip ./bin` (from `GNU binutils`) and `upx --best --lzma ./bin` + +## Building + +- Make sure you have rust installed and properly configured +- Clone the repostitory +- `cargo run --release` + +## Contributing + +Please check out [the issues](https://github.com/wait-what/minesweeper-rs/issues) if you would like to contribute to the project! +If you decide to take on an issue, be sure to comment that you are. + +## License + +The project is licensed under [MIT](./LICENSE) diff --git a/release.sh b/release.sh new file mode 100644 index 0000000..8f43b0b --- /dev/null +++ b/release.sh @@ -0,0 +1,28 @@ +#!/bin/bash +BLUE="\033[34m" +GREEN="\033[32m" +RED="\033[31m" +PURPLE="\033[35m" +LIME="\033[36m" +RESET="\033[0m" + +NAME="minesweeper-rs" + +printf "\n ==> ${PURPLE}Removing artifacts and setting up workspace${RESET}\n\n" +rm -rvf release +mkdir -p release + +printf "\n ==> ${BLUE}Building a release version of the project${RESET}\n\n" +cargo build --release +cargo build --release --target x86_64-pc-windows-gnu + +cp target/release/"$NAME" release/"$NAME"_linux64 +cp target/x86_64-pc-windows-gnu/release/"$NAME".exe release/"$NAME"_windows64.exe + +printf "\n ==> ${GREEN}Stripping binaries${RESET}\n\n" +strip release/"$NAME"_linux64 release/"$NAME"_windows64.exe + +printf "\n ==> ${RED}Compressing binaries${RESET}\n\n" +upx --best --lzma release/"$NAME"_linux64 # release/"$NAME"_windows64.exe (Windows defender flags the UPX stub as a threat) + +printf "\n ==> ${LIME}All done.${RESET}\n\n" diff --git a/src/board.rs b/src/board.rs new file mode 100644 index 0000000..0eee9fd --- /dev/null +++ b/src/board.rs @@ -0,0 +1,223 @@ +extern crate rand; +use macroquad::prelude::Color; + +use rand::Rng; +use rust_grid::*; +use std::time::Instant; + +#[derive(PartialEq)] +pub enum GameState { + Ongoing, + Win, + Fail, +} + +#[derive(PartialEq, Copy, Clone)] +pub enum CellState { + Number(u8), + Mine, +} + +#[derive(Copy, Clone)] +pub struct Cell { + pub state: CellState, + pub flagged: bool, + pub revealed: bool, +} + +pub struct Board { + pub grid: Grid, + pub mine_count: usize, + pub revealed_cell_count: usize, + pub flag_count: usize, + pub start_time: Instant, + pub state: GameState, + pub color: Color, + pub hovering: (usize, usize), +} + +impl Board { + pub fn new((width, height): (usize, usize), mine_count: usize, color: Color) -> Self { + let cell = Cell { + state: CellState::Number(0), + flagged: false, + revealed: false, + }; + + let mut grid = Grid::new(width, height, cell); + + let mut rng = rand::thread_rng(); + for _ in 0..mine_count { + loop { + let (width, height) = grid.size(); + + let coordinates = (rng.gen_range(0..width), rng.gen_range(0..height)); + + if grid[coordinates].state == CellState::Mine { + continue; + } else { + grid[coordinates].state = CellState::Mine; + break; + }; + } + } + + for x in 0..width { + for y in 0..height { + if grid[y][x].state == CellState::Mine { + continue; + }; + + let mut neighbouring_mines: u8 = 0; + + for offset_x in -1..=1 as isize { + if (x == 0 && offset_x == -1) || (x == width - 1 && offset_x == 1) { + continue; + }; + + for offset_y in -1..=1 as isize { + if (y == 0 && offset_y == -1) || (y == height - 1 && offset_y == 1) { + continue; + }; + + let coordinates = ( + (x as isize + offset_x) as usize, + (y as isize + offset_y) as usize, + ); + + if grid[coordinates].state == CellState::Mine { + neighbouring_mines += 1; + }; + } + } + + grid[y][x].state = CellState::Number(neighbouring_mines); + } + } + + Board { + grid, + mine_count, + revealed_cell_count: 0, + flag_count: 0, + start_time: Instant::now(), + state: GameState::Ongoing, + color, + hovering: (0, 0), + } + } + + pub fn reveal_cell(&mut self, coordinates: (usize, usize)) { + let (width, height) = self.grid.size(); + + if self.state != GameState::Ongoing { + return; + }; + + if self.grid[coordinates].flagged { + return; + }; + + if self.revealed_cell_count == 0 && self.grid[coordinates].state != CellState::Number(0) { + let (width, height) = self.grid.size(); + + loop { + let new_board = Board::new((width, height), self.mine_count, self.color); + if new_board.grid[coordinates].state == CellState::Number(0) { + self.grid = new_board.grid; + break; + }; + } + } + + if self.grid[coordinates].state == CellState::Mine { + self.state = GameState::Fail; + return; + }; + + if self.grid[coordinates].revealed { + return; + }; + + self.grid[coordinates].revealed = true; + let mut revealed_last_round = 1; + loop { + if revealed_last_round == 0 { + break; + } + + self.revealed_cell_count += revealed_last_round; + revealed_last_round = 0; + + for x in 0..width { + for y in 0..height { + if self.grid[y][x].revealed { + continue; + }; + + let mut has_neighbours = false; + for offset_x in -1..=1 { + if has_neighbours { + break; + }; + + if (x == 0 && offset_x == -1) || (x == width - 1 && offset_x == 1) { + continue; + }; + + for offset_y in -1..=1 { + if (y == 0 && offset_y == -1) || (y == height - 1 && offset_y == 1) { + continue; + }; + + let coordinates = ( + (x as isize + offset_x) as usize, + (y as isize + offset_y) as usize, + ); + + if self.grid[coordinates].state == CellState::Number(0) + && self.grid[coordinates].revealed + { + has_neighbours = true; + break; + }; + } + } + + if has_neighbours { + revealed_last_round += 1; + self.grid[y][x].revealed = true; + + if self.grid[y][x].flagged { + self.grid[y][x].flagged = false; + self.flag_count -= 1; + } + }; + } + } + } + + if width * height - self.revealed_cell_count == self.mine_count { + self.state = GameState::Win; + return; + }; + } + + pub fn toggle_flag(&mut self, coordinates: (usize, usize)) { + if self.state != GameState::Ongoing { + return; + }; + + if self.grid[coordinates].revealed { + return; + }; + + if self.grid[coordinates].flagged { + self.flag_count -= 1; + self.grid[coordinates].flagged = false; + } else { + self.flag_count += 1; + self.grid[coordinates].flagged = true; + }; + } +} diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..7b3bdde --- /dev/null +++ b/src/input.rs @@ -0,0 +1,42 @@ +use crate::{ board::Board, ui::Ui }; +use macroquad::prelude::*; + +pub fn get_input(board: &mut Board, ui: &mut Ui) { + if is_key_pressed(KeyCode::Space) { + ui.showing = !ui.showing; + }; + + if ui.showing { + return; + } + + if is_key_pressed(KeyCode::R) { + *board = Board::new((ui.width, ui.height), ui.mine_count(), ui.color()); + } + + let (board_width, board_height) = board.grid.size(); + let square = if screen_width() / board_width as f32 > screen_height() / board_height as f32 { + screen_height() / board_height as f32 + } else { + screen_width() / board_width as f32 + }; + + let coordinates = ( + (mouse_position().0 / square) as usize, + (mouse_position().1 / square) as usize, + ); + + if coordinates.0 >= board_width || coordinates.1 >= board_height { + return; + } + + board.hovering = coordinates; + + if is_mouse_button_pressed(MouseButton::Left) { + board.reveal_cell(coordinates); + }; + + if is_mouse_button_pressed(MouseButton::Right) { + board.toggle_flag(coordinates); + }; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..7b681d2 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,40 @@ +#![windows_subsystem = "windows"] + +use macroquad::prelude::*; + +pub mod board; +pub mod input; +pub mod ui; +mod view; + +use board::Board; +use ui::Ui; + +fn window_conf() -> Conf { + Conf { + window_title: "minesweeper-rs".to_owned(), + window_width: 20 * 30, + window_height: 15 * 30, + ..Default::default() + } +} + +#[macroquad::main(window_conf)] +async fn main() { + let atlas = Texture2D::from_file_with_format(include_bytes!("texture.png"), None); + atlas.set_filter(FilterMode::Nearest); + + let mut ui = Ui::new(); + let mut board = Board::new((ui.width, ui.height), ui.mine_count(), ui.color()); + + loop { + if ui.update() { + board = Board::new((ui.width, ui.height), ui.mine_count(), ui.color()); + } else { + input::get_input(&mut board, &mut ui); + }; + + view::render(&board, &atlas); + next_frame().await; + } +} diff --git a/src/texture.png b/src/texture.png new file mode 100644 index 0000000..cc35a7f Binary files /dev/null and b/src/texture.png differ diff --git a/src/ui.rs b/src/ui.rs new file mode 100644 index 0000000..8338f23 --- /dev/null +++ b/src/ui.rs @@ -0,0 +1,90 @@ +use macroquad::{color::hsl_to_rgb, prelude::*, ui::{ hash, root_ui, widgets }}; + +const SPACING: f32 = 30.; + +pub struct Ui { + pub showing: bool, + pub width: usize, + pub height: usize, + pub mine_percent: usize, + pub hue: f32, +} + +impl Ui { + pub fn new() -> Self { + Ui { + showing: false, + width: 20, + height: 15, + mine_percent: 20, + hue: 175., + } + } + + pub fn color(&self) -> Color { + hsl_to_rgb(self.hue / 255., 90. / 255., 110. / 255.) + } + + pub fn mine_count(&self) -> usize { + self.width * self.height * self.mine_percent / 100 + } + + pub fn update(&mut self) -> bool { + if !self.showing { + return false; + }; + + let mut updated = false; + widgets::Window::new(hash!(), vec2(10., 10.), vec2(200., 165.)) + .label("Options") + .titlebar(true) + .ui(&mut *root_ui(), |ui| { + ui.label(Vec2::new(10., SPACING * 0.), &format!("Width: {}", self.width)); + if ui.button(Vec2::new(130., SPACING * 0. + 5.), " + ") { + self.width = clamp(self.width + 1, 4, 100); + }; + if ui.button(Vec2::new(160., SPACING * 0. + 5.), " - ") { + self.width = clamp(self.width - 1, 4, 100); + }; + + ui.label(Vec2::new(10., SPACING * 1.), &format!("Height: {}", self.height)); + if ui.button(Vec2::new(130., SPACING * 1. + 5.), " + ") { + self.height = clamp(self.height + 1, 4, 100); + }; + if ui.button(Vec2::new(160., SPACING * 1. + 5.), " - ") { + self.height = clamp(self.height - 1, 4, 100); + }; + + ui.label(Vec2::new(10., SPACING * 2.), &format!("Mine%: {}", self.mine_percent)); + if ui.button(Vec2::new(130., SPACING * 2. + 5.), " + ") { + self.mine_percent = clamp(self.mine_percent + 1, 0, 50); + }; + if ui.button(Vec2::new(160., SPACING * 2. + 5.), " - ") { + self.mine_percent = clamp(self.mine_percent - 1, 0, 50); + }; + + widgets::Group::new(hash!(), Vec2::new(180., SPACING)) + .position(Vec2::new(10., SPACING * 3.)) + .ui(ui, |ui| { + ui.slider(hash!(), "Hue", 0.0..255., &mut self.hue); + + if ui.button(Vec2::new(120., 5.), " + ") { + self.hue = clamp(self.hue + 1., 0., 255.); + }; + + if ui.button(Vec2::new(150., 5.), " - ") { + self.hue = clamp(self.hue - 1., 0., 255.); + }; + }); + + if ui.button(Vec2::new(5., SPACING * 4. + 5.), "Restart") { + self.showing = false; + updated = true; + }; + + ui.label(Vec2::new(65., SPACING * 4. + 5.), "Space to continue"); + }); + + updated + } +} diff --git a/src/view.rs b/src/view.rs new file mode 100644 index 0000000..9dd6909 --- /dev/null +++ b/src/view.rs @@ -0,0 +1,164 @@ +use crate::board::{Board, CellState, GameState}; +use std::time::Instant; +use macroquad::prelude::*; + +pub fn render(board: &Board, atlas: &Texture2D) { + let (board_width, board_height) = board.grid.size(); + + let square = if screen_width() / board_width as f32 > screen_height() / board_height as f32 { + screen_height() / board_height as f32 + } else { + screen_width() / board_width as f32 + }; + + clear_background(color_u8!(20, 20, 20, 255)); + + for x in 0..board_width { + for y in 0..board_height { + let cell = board.grid[y][x]; + + if cell.revealed { + if (x + y % 2) % 2 != 0 { + draw_rectangle( + square * x as f32, + square * y as f32, + square, + square, + color_u8!(30, 30, 30, 255) + ); + } + } else { + draw_texture_ex( + *atlas, + square * x as f32, + square * y as f32, + board.color, + DrawTextureParams { + dest_size: Some(vec2(square, square)), + source: Some(Rect::new(8. * 10., 0., 8., 8.)), + ..Default::default() + }, + ); + } + + if cell.flagged { + draw_texture_ex( + *atlas, + square * x as f32, + square * y as f32, + WHITE, + DrawTextureParams { + dest_size: Some(vec2(square, square)), + source: Some(Rect::new(8. * 9., 0., 8., 8.)), + ..Default::default() + }, + ); + } + + draw_texture_ex( + *atlas, + square * x as f32, + square * y as f32, + WHITE, + DrawTextureParams { + dest_size: Some(vec2(square, square)), + source: Some(Rect::new( + match cell.state { + CellState::Mine => { + if board.state == GameState::Fail { + 8. * 8. + } else { + continue; + } + } + CellState::Number(number) => match number { + 0 => continue, + _ => { + if cell.revealed { + (number - 1) as f32 * 8. + } else { + continue; + } + } + }, + }, + 0., + 8., + 8., + )), + ..Default::default() + }, + ); + } + } + + if board.grid[board.hovering].revealed && is_mouse_button_down(MouseButton::Right) { + match board.grid[board.hovering].state { + CellState::Number(number) => { + if number != 0 { + let (x, y) = board.hovering; + + draw_rectangle( + square * (x as i32 - 1) as f32, + square * (y as i32 - 1) as f32, + square * 3., + square * 3., + color_u8!(255, 0, 0, 30), + ); + }; + }, + _ => (), + }; + }; + + if board.state == GameState::Fail { + draw_rectangle( + 0., + 0., + screen_width(), + screen_height(), + color_u8!(255, 128, 128, 64), + ); + } + + if board.state == GameState::Win { + draw_rectangle( + 0., + 0., + screen_width(), + screen_height(), + color_u8!(128, 255, 128, 64), + ); + } + + + let text = &format!( + "{}", + (Instant::now() - board.start_time).as_secs(), + ); + draw_text_ex( + text, + square, + square * 2., + TextParams { + color: color_u8!(0, 255, 0, 64), + font_size: (square * 3.) as u16, + ..Default::default() + } + ); + + let text = &format!( + "{}", + board.mine_count as isize - board.flag_count as isize + ); + draw_text_ex( + text, + (square * board_width as f32) - square * 2. - square * text.len() as f32, + square * 2., + TextParams { + color: color_u8!(255, 0, 0, 64), + font_size: (square * 3.) as u16, + ..Default::default() + } + ); +}