├── imgs └── demo.png ├── docs ├── pkg │ ├── minesweeper_bg.wasm │ ├── package.json │ ├── README.md │ ├── minesweeper_bg.d.ts │ ├── minesweeper_bg.wasm.d.ts │ ├── LICENSE │ ├── minesweeper.d.ts │ └── minesweeper.js ├── index.html └── style.css ├── .gitignore ├── lib_minesweeper ├── Cargo.toml └── src │ ├── main.rs │ └── lib.rs ├── README.md ├── LICENSE ├── Cargo.toml ├── index.html ├── style.css ├── src └── lib.rs └── Cargo.lock /imgs/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgpaiva/minesweeper/HEAD/imgs/demo.png -------------------------------------------------------------------------------- /docs/pkg/minesweeper_bg.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jgpaiva/minesweeper/HEAD/docs/pkg/minesweeper_bg.wasm -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | -------------------------------------------------------------------------------- /lib_minesweeper/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "lib_minesweeper" 3 | version = "0.1.0" 4 | authors = ["João Paiva "] 5 | edition = "2018" 6 | 7 | [lib] 8 | crate-type = ["cdylib", "rlib"] 9 | 10 | [dependencies] 11 | colored = "1.9.3" 12 | serde = "1" 13 | serde_derive = "1" 14 | 15 | [dependencies.rand] 16 | version = "0.8.5" 17 | features = ["log"] 18 | 19 | [dev-dependencies] 20 | pretty_assertions = "0.6.1" -------------------------------------------------------------------------------- /docs/pkg/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "minesweeper", 3 | "collaborators": [ 4 | "João Paiva " 5 | ], 6 | "description": "This is an attempt at building a minesweeper solver. Right now it is just a complete console and WASM implementation of the game and has no solver. It features a really simplistic robot solver that can only work for the most obvious cases.", 7 | "version": "0.1.0", 8 | "license": "MIT", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/jgpaiva/minesweeper" 12 | }, 13 | "files": [ 14 | "minesweeper_bg.wasm", 15 | "minesweeper.js", 16 | "minesweeper.d.ts" 17 | ], 18 | "module": "minesweeper.js", 19 | "types": "minesweeper.d.ts", 20 | "sideEffects": false 21 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Minesweeper in the browser 2 | 3 | This project is a minesweeper built with [rust](https://www.rust-lang.org/), [wasm](https://webassembly.org/) and [yew](https://yew.rs/). It started with the goal of becoming a complete solver for minesweeper in the CLI, but ended up becoming a complete game + basic solver library with a browser and a CLI frontend. 4 | 5 | ## Demo 6 | 7 | You can play the WASM version online [here](https://jgpaiva.github.io/minesweeper/). 8 | 9 | ## How to run localy 10 | 11 | After installing rust and cargo, run `wasm-pack build --dev --target web`. After 12 | this, start a server on the local folder (e.g. `python3 -m http.server`) and 13 | check it out on your favourite browser. 14 | 15 | ## Example output 16 | 17 | ![demo output](imgs/demo.png) 18 | -------------------------------------------------------------------------------- /docs/pkg/README.md: -------------------------------------------------------------------------------- 1 | # Minesweeper in the browser 2 | 3 | This project is a minesweeper built with [rust](https://www.rust-lang.org/), [wasm](https://webassembly.org/) and [yew](https://yew.rs/). It started with the goal of becoming a complete solver for minesweeper in the CLI, but ended up becoming a complete game + basic solver library with a browser and a CLI frontend. 4 | 5 | ## Demo 6 | 7 | You can play the WASM version online [here](https://jgpaiva.github.io/minesweeper/). 8 | 9 | ## How to run localy 10 | 11 | After installing rust and cargo, run `wasm-pack build --dev --target web`. After 12 | this, start a server on the local folder (e.g. `python3 -m http.server`) and 13 | check it out on your favourite browser. 14 | 15 | ## Example output 16 | 17 | ![demo output](imgs/demo.png) 18 | -------------------------------------------------------------------------------- /docs/pkg/minesweeper_bg.d.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | export const memory: WebAssembly.Memory; 4 | export function main(): void; 5 | export function __wbindgen_malloc(a: number): number; 6 | export function __wbindgen_realloc(a: number, b: number, c: number): number; 7 | export const __wbindgen_export_2: WebAssembly.Table; 8 | export function _dyn_core__ops__function__Fn__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hfcfa9ebc4f2b0fab(a: number, b: number, c: number): void; 9 | export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h16b698ce6b3f17d0(a: number, b: number): void; 10 | export function __wbindgen_free(a: number, b: number): void; 11 | export function __wbindgen_exn_store(a: number): void; 12 | export function __wbindgen_start(): void; 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 João Paiva 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/pkg/minesweeper_bg.wasm.d.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | export const memory: WebAssembly.Memory; 4 | export function main(): void; 5 | export function __wbindgen_malloc(a: number): number; 6 | export function __wbindgen_realloc(a: number, b: number, c: number): number; 7 | export const __wbindgen_export_2: WebAssembly.Table; 8 | export function _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5ed4b4b85ddfbb0a(a: number, b: number): void; 9 | export function _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb55b0760ea278817(a: number, b: number, c: number): void; 10 | export function _dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb7f91896e3086b5b(a: number, b: number, c: number): void; 11 | export function __wbindgen_free(a: number, b: number): void; 12 | export function __wbindgen_exn_store(a: number): void; 13 | export function __wbindgen_start(): void; 14 | -------------------------------------------------------------------------------- /docs/pkg/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 João Paiva 2 | 3 | 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: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/pkg/minesweeper.d.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable */ 2 | /* eslint-disable */ 3 | /** 4 | */ 5 | export function main(): void; 6 | 7 | export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; 8 | 9 | export interface InitOutput { 10 | readonly memory: WebAssembly.Memory; 11 | readonly main: () => void; 12 | readonly __wbindgen_malloc: (a: number) => number; 13 | readonly __wbindgen_realloc: (a: number, b: number, c: number) => number; 14 | readonly __wbindgen_export_2: WebAssembly.Table; 15 | readonly _dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5ed4b4b85ddfbb0a: (a: number, b: number) => void; 16 | readonly _dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb55b0760ea278817: (a: number, b: number, c: number) => void; 17 | readonly _dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb7f91896e3086b5b: (a: number, b: number, c: number) => void; 18 | readonly __wbindgen_free: (a: number, b: number) => void; 19 | readonly __wbindgen_exn_store: (a: number) => void; 20 | readonly __wbindgen_start: () => void; 21 | } 22 | 23 | export type SyncInitInput = BufferSource | WebAssembly.Module; 24 | /** 25 | * Instantiates the given `module`, which can either be bytes or 26 | * a precompiled `WebAssembly.Module`. 27 | * 28 | * @param {SyncInitInput} module 29 | * 30 | * @returns {InitOutput} 31 | */ 32 | export function initSync(module: SyncInitInput): InitOutput; 33 | 34 | /** 35 | * If `module_or_path` is {RequestInfo} or {URL}, makes a request and 36 | * for everything else, calls `WebAssembly.instantiate` directly. 37 | * 38 | * @param {InitInput | Promise} module_or_path 39 | * 40 | * @returns {Promise} 41 | */ 42 | export default function init (module_or_path?: InitInput | Promise): Promise; 43 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "minesweeper" 3 | version = "0.1.0" 4 | authors = ["João Paiva "] 5 | edition = "2018" 6 | description="This is an attempt at building a minesweeper solver. Right now it is just a complete console and WASM implementation of the game and has no solver. It features a really simplistic robot solver that can only work for the most obvious cases." 7 | repository="https://github.com/jgpaiva/minesweeper" 8 | license="MIT" 9 | 10 | [lib] 11 | crate-type = ["cdylib", "rlib"] 12 | 13 | [workspace] 14 | members = [ 15 | "lib_minesweeper" 16 | ] 17 | 18 | [dependencies.lib_minesweeper] 19 | path = "lib_minesweeper" 20 | 21 | [dependencies] 22 | strum = "0.24" 23 | strum_macros = "0.24" 24 | serde = "1" 25 | serde_derive = "1" 26 | 27 | lazy_static = "1.4.0" 28 | wasm-bindgen = "0.2.60" 29 | log = "0.4.8" 30 | 31 | js-sys = "0.3.32" 32 | gloo = "0.3.0" 33 | gloo-timers = "0.2" 34 | 35 | # The `console_error_panic_hook` crate provides better debugging of panics by 36 | # logging them with `console.error`. This is great for development, but requires 37 | # all the `std::fmt` and `std::panicking` infrastructure, so isn't great for 38 | # code size when deploying. 39 | console_error_panic_hook = { version = "0.1.1", optional = true } 40 | 41 | [dependencies.yew] 42 | version = "0.20" 43 | features = ["csr"] 44 | 45 | [dependencies.rand] 46 | version = "0.8.5" 47 | features = ["log"] 48 | 49 | [dependencies.getrandom] 50 | version = "0.2.8" 51 | features = ["js"] 52 | 53 | [dependencies.web-sys] 54 | version = "0.3.4" 55 | features = [ 56 | "Document", 57 | "Element", 58 | "Node", 59 | "Window", 60 | 'Attr', 61 | 'CssStyleDeclaration', 62 | 'HtmlElement', 63 | 'HtmlDivElement', 64 | 'HtmlLiElement', 65 | 'HtmlUListElement', 66 | 'SvgElement', 67 | 'SvgRectElement', 68 | 'SvgTitleElement', 69 | 'SvgDescElement', 70 | 'console', 71 | 'EventTarget', 72 | 'MouseEvent', 73 | ] 74 | 75 | [features] 76 | default = ["console_error_panic_hook"] 77 | 78 | [dev-dependencies] 79 | pretty_assertions = "1.3.0" 80 | wasm-bindgen-test = "0.2" 81 | 82 | [profile.release] 83 | # Tell `rustc` to optimize for small code size. 84 | opt-level = 3 -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 54 | 55 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 55 | 56 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | .flex-container { 2 | display: flex; 3 | flex-flow: row wrap; 4 | padding: 3%; 5 | justify-content: center; 6 | } 7 | 8 | .break { 9 | width: 100%; 10 | flex-basis: 100%; 11 | } 12 | 13 | .item:before { 14 | content: ""; 15 | display: block; 16 | padding-top: 100%; 17 | } 18 | 19 | .item { 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | font-size: 40px; 24 | } 25 | 26 | .mines-1 { 27 | color: #5296a5; 28 | } 29 | 30 | .mines-2 { 31 | color: #50723c; 32 | } 33 | 34 | .mines-3 { 35 | color: #d81159; 36 | } 37 | 38 | .mines-4 { 39 | color: #ffbc42; 40 | } 41 | 42 | .mines-5 { 43 | color: #218380; 44 | } 45 | 46 | .mines-6 { 47 | color: #685369; 48 | } 49 | 50 | .mines-7 { 51 | color: #8f2d56; 52 | } 53 | 54 | .mines-8 { 55 | color: #423e28 56 | } 57 | 58 | .clickable2 { 59 | box-shadow: inset 0px 2px 0px 0px #ffffff; 60 | background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); 61 | border-radius: 10px; 62 | cursor: pointer; 63 | color: #666666; 64 | font-weight: bold; 65 | text-decoration: none; 66 | } 67 | 68 | .clickable2:active { 69 | position: relative; 70 | top: 2px; 71 | box-shadow: inset 0px 0px 0px 0px #ffffff; 72 | } 73 | 74 | .not-clickable2 { 75 | box-shadow: inset 0px 2px 0px 0px #ffffff; 76 | border-radius: 10px; 77 | cursor: pointer; 78 | color: #666666; 79 | font-weight: bold; 80 | text-decoration: none; 81 | background: linear-gradient(to bottom, #f9f9f9 5%, #f9f9f9 100%); 82 | } 83 | 84 | .clickable { 85 | box-shadow: inset 0px 2px 0px 0px #ffffff; 86 | background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); 87 | background-color: #f9f9f9; 88 | border-radius: 10px; 89 | border: 2px solid #dcdcdc; 90 | cursor: pointer; 91 | color: #666666; 92 | font-weight: bold; 93 | text-decoration: none; 94 | height: 2em; 95 | width: 2em; 96 | margin-left: 1em; 97 | margin-right: 1em; 98 | } 99 | 100 | .not-clickable { 101 | box-shadow: inset 0px 2px 0px 0px #ffffff; 102 | border-radius: 10px; 103 | cursor: pointer; 104 | color: #666666; 105 | font-weight: bold; 106 | text-decoration: none; 107 | background: linear-gradient(to bottom, #f9f9f9 5%, #f9f9f9 100%); 108 | height: 2em; 109 | width: 2em; 110 | margin-left: 1em; 111 | margin-right: 1em; 112 | } 113 | 114 | .clickable:active { 115 | position: relative; 116 | top: 2px; 117 | box-shadow: inset 0px 0px 0px 0px #ffffff; 118 | background-color: #beebf6; 119 | } 120 | 121 | .clickable2.active { 122 | background-color: #beebf6; 123 | } 124 | 125 | .ongoing { 126 | background-color: #ffffff; 127 | } 128 | 129 | .won { 130 | background-color: #057F74; 131 | } 132 | 133 | .failed { 134 | background-color: #f4796b; 135 | } 136 | 137 | body { 138 | margin: 0; 139 | font-family: 'Roboto', sans-serif; 140 | } -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | .flex-container { 2 | display: flex; 3 | flex-flow: row wrap; 4 | padding: 3%; 5 | justify-content: center; 6 | } 7 | 8 | .break { 9 | width: 100%; 10 | flex-basis: 100%; 11 | } 12 | 13 | .item:before { 14 | content: ""; 15 | display: block; 16 | padding-top: 100%; 17 | } 18 | 19 | .item { 20 | display: flex; 21 | justify-content: center; 22 | align-items: center; 23 | font-size: 40px; 24 | } 25 | 26 | .mines-1 { 27 | color: #5296a5; 28 | } 29 | 30 | .mines-2 { 31 | color: #50723c; 32 | } 33 | 34 | .mines-3 { 35 | color: #d81159; 36 | } 37 | 38 | .mines-4 { 39 | color: #ffbc42; 40 | } 41 | 42 | .mines-5 { 43 | color: #218380; 44 | } 45 | 46 | .mines-6 { 47 | color: #685369; 48 | } 49 | 50 | .mines-7 { 51 | color: #8f2d56; 52 | } 53 | 54 | .mines-8 { 55 | color: #423e28 56 | } 57 | 58 | .clickable2 { 59 | box-shadow: inset 0px 2px 0px 0px #ffffff; 60 | background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); 61 | border-radius: 10px; 62 | cursor: pointer; 63 | color: #666666; 64 | font-weight: bold; 65 | text-decoration: none; 66 | } 67 | 68 | .clickable2:active { 69 | position: relative; 70 | top: 2px; 71 | box-shadow: inset 0px 0px 0px 0px #ffffff; 72 | } 73 | 74 | .not-clickable2 { 75 | box-shadow: inset 0px 2px 0px 0px #ffffff; 76 | border-radius: 10px; 77 | cursor: pointer; 78 | color: #666666; 79 | font-weight: bold; 80 | text-decoration: none; 81 | background: linear-gradient(to bottom, #f9f9f9 5%, #f9f9f9 100%); 82 | } 83 | 84 | .clickable { 85 | box-shadow: inset 0px 2px 0px 0px #ffffff; 86 | background: linear-gradient(to bottom, #f9f9f9 5%, #e9e9e9 100%); 87 | background-color: #f9f9f9; 88 | border-radius: 10px; 89 | border: 2px solid #dcdcdc; 90 | cursor: pointer; 91 | color: #666666; 92 | font-weight: bold; 93 | text-decoration: none; 94 | height: 2em; 95 | width: 2em; 96 | margin-left: 1em; 97 | margin-right: 1em; 98 | } 99 | 100 | .not-clickable { 101 | box-shadow: inset 0px 2px 0px 0px #ffffff; 102 | border-radius: 10px; 103 | cursor: pointer; 104 | color: #666666; 105 | font-weight: bold; 106 | text-decoration: none; 107 | background: linear-gradient(to bottom, #f9f9f9 5%, #f9f9f9 100%); 108 | height: 2em; 109 | width: 2em; 110 | margin-left: 1em; 111 | margin-right: 1em; 112 | } 113 | 114 | .clickable:active { 115 | position: relative; 116 | top: 2px; 117 | box-shadow: inset 0px 0px 0px 0px #ffffff; 118 | background-color: #beebf6; 119 | } 120 | 121 | .clickable2.active { 122 | background-color: #beebf6; 123 | } 124 | 125 | .ongoing { 126 | background-color: #ffffff; 127 | } 128 | 129 | .won { 130 | background-color: #057F74; 131 | } 132 | 133 | .failed { 134 | background-color: #f4796b; 135 | } 136 | 137 | body { 138 | margin: 0; 139 | font-family: 'Roboto', sans-serif; 140 | } -------------------------------------------------------------------------------- /lib_minesweeper/src/main.rs: -------------------------------------------------------------------------------- 1 | use colored::Colorize; 2 | use rand::Rng; 3 | use std::io; 4 | 5 | use lib_minesweeper::create_board; 6 | use lib_minesweeper::numbers_on_board; 7 | use lib_minesweeper::Board; 8 | use lib_minesweeper::BoardState; 9 | use lib_minesweeper::MapElement::Mine; 10 | use lib_minesweeper::MapElement::Number; 11 | use lib_minesweeper::MapElementCellState::Closed; 12 | use lib_minesweeper::MapElementCellState::Flagged; 13 | use lib_minesweeper::MapElementCellState::Open; 14 | use lib_minesweeper::Point; 15 | 16 | fn main() { 17 | let width = 8; 18 | let height = 8; 19 | let mines = 10; 20 | 21 | let board = create_board(width, height, mines, |x, y| { 22 | rand::thread_rng().gen_range(x..y) 23 | }); 24 | 25 | let mut board = numbers_on_board(board); 26 | 27 | loop { 28 | colorized_print_map(&board); 29 | if matches!(board.state, BoardState::Failed | BoardState::Won) { 30 | return; 31 | } 32 | 33 | println!("Please input operation (open or flag), column and row.Examples:\no35 to open column 3, row 5\nf13 to flag column 1, row 3"); 34 | let mut line = String::new(); 35 | io::stdin() 36 | .read_line(&mut line) 37 | .expect("failed to read line"); 38 | let op = process_line(line, &board); 39 | match op { 40 | Some(Operation::Open { point }) => { 41 | board = board.cascade_open_item(&point).unwrap_or(board) 42 | } 43 | Some(Operation::Flag { point }) => board = board.flag_item(&point), 44 | _ => continue, 45 | } 46 | } 47 | } 48 | 49 | #[derive(Debug, PartialEq, Eq)] 50 | pub enum Operation { 51 | Open { point: Point }, 52 | Flag { point: Point }, 53 | } 54 | 55 | fn process_line(line: String, board: &Board) -> Option { 56 | let bytes = line.as_bytes(); 57 | match bytes { 58 | [op, x, y, b'\n'] => { 59 | let x = coord_reverse_mapping(*x); 60 | let y = coord_reverse_mapping(*y); 61 | let p = Point { x, y }; 62 | if matches!(board.at(&p), Some(_)) { 63 | match op { 64 | b'o' => Some(Operation::Open { point: p }), 65 | b'f' => Some(Operation::Flag { point: p }), 66 | _ => None, 67 | } 68 | } else { 69 | None 70 | } 71 | } 72 | _ => None, 73 | } 74 | } 75 | 76 | fn coord_reverse_mapping(c: u8) -> i32 { 77 | let mut mapping = vec![]; 78 | mapping.extend(b'0'..=b'9'); 79 | mapping.extend(b'a'..=b'z'); 80 | 81 | mapping 82 | .iter() 83 | .enumerate() 84 | .map(|(i, c)| (i as i32, c)) 85 | .find(|(_, &x)| c == x) 86 | .map(|(i, _)| i) 87 | .unwrap_or(-1) 88 | } 89 | 90 | fn print_board_state(board: &Board) { 91 | print!("Board is currently "); 92 | match board.state { 93 | BoardState::Won => print!("{}", "🎉🎉 WON! 🎉🎉".green()), 94 | BoardState::Playing => print!("{}", "in play".green()), 95 | BoardState::Failed => print!("{}", "☠️ FAILED ☠️".red()), 96 | _ => unreachable!(), 97 | } 98 | println!(); 99 | } 100 | 101 | fn colorized_print_map(board: &Board) { 102 | print_board_state(board); 103 | let mut mapping = vec![]; 104 | mapping.extend((b'0'..=b'9').map(char::from)); 105 | mapping.extend((b'a'..=b'z').map(char::from)); 106 | print!(" "); 107 | for item in mapping.iter().take(board.width) { 108 | print!("{} ", item); 109 | } 110 | println!(); 111 | let is_done = matches!(board.state, BoardState::Failed | BoardState::Won); 112 | for y in 0..board.height { 113 | print!("{} ", mapping[y]); 114 | for x in 0..board.width { 115 | let x = x as i32; 116 | let y = y as i32; 117 | let c = match board.at(&Point { x, y }) { 118 | Some(Mine { state }) => match (state, is_done) { 119 | (_, true) | (Open, _) => " ".on_red(), 120 | (Flagged, _) => " ".on_bright_green(), 121 | (Closed, _) => " ".on_yellow(), 122 | }, 123 | Some(Number { state, count: 0 }) => match (state, is_done) { 124 | (_, true) | (Open, _) => " ".on_bright_white(), 125 | (Flagged, _) => " ".on_bright_green(), 126 | (Closed, _) => " ".on_yellow(), 127 | }, 128 | Some(Number { state, count }) => match (state, is_done) { 129 | (_, true) | (Open, _) => format!("{}", count).black().on_bright_cyan(), 130 | (Flagged, _) => " ".on_bright_green(), 131 | (Closed, _) => " ".on_yellow(), 132 | }, 133 | _ => unreachable!(), 134 | }; 135 | print!("{} ", c); 136 | } 137 | print!("{}", mapping[y]); 138 | println!(); 139 | } 140 | 141 | print!(" "); 142 | for item in mapping.iter().take(board.width) { 143 | print!("{} ", item); 144 | } 145 | println!(); 146 | } 147 | 148 | #[cfg(test)] 149 | mod tests { 150 | use super::*; 151 | use lib_minesweeper::*; 152 | use pretty_assertions::assert_eq; 153 | 154 | // TODO: I'm a dummy and couldn't figure out how to import this function and the next one from lib.rs 155 | fn make_map(map: Vec>) -> Vec> { 156 | map.iter() 157 | .map(|row| { 158 | row.iter() 159 | .map(|(open, count)| match count { 160 | -1 => Mine { 161 | state: if *open { Open } else { Closed }, 162 | }, 163 | count => Number { 164 | state: if *open { Open } else { Closed }, 165 | count: *count, 166 | }, 167 | }) 168 | .collect() 169 | }) 170 | .collect() 171 | } 172 | 173 | pub fn five_by_two_board() -> Board { 174 | Board::new(make_map(vec![ 175 | vec![(false, -1), (false, 0), (false, 0), (false, 0), (false, 0)], 176 | vec![(false, 0), (false, -1), (false, 0), (false, 0), (false, 0)], 177 | ])) 178 | } 179 | 180 | #[test] 181 | fn test_process_line() { 182 | let o = process_line(String::from("o01\n"), &tests::five_by_two_board()); 183 | assert_eq!( 184 | o, 185 | Some(Operation::Open { 186 | point: Point { x: 0, y: 1 } 187 | }) 188 | ); 189 | } 190 | 191 | #[test] 192 | fn test_process_line_out_of_bounds_argument() { 193 | let o = process_line(String::from("o34\n"), &tests::five_by_two_board()); 194 | assert_eq!(o, None); 195 | } 196 | 197 | #[test] 198 | fn test_process_line_bad_arguments() { 199 | let o = process_line(String::from("o\n"), &tests::five_by_two_board()); 200 | assert_eq!(o, None); 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![recursion_limit = "512"] 2 | 3 | use lib_minesweeper::create_board; 4 | use lib_minesweeper::numbers_on_board; 5 | use lib_minesweeper::Board; 6 | use lib_minesweeper::BoardState; 7 | use lib_minesweeper::BoardState::Failed; 8 | use lib_minesweeper::BoardState::NotReady; 9 | use lib_minesweeper::BoardState::Playing; 10 | use lib_minesweeper::BoardState::Ready; 11 | use lib_minesweeper::BoardState::Won; 12 | use lib_minesweeper::MapElement; 13 | use lib_minesweeper::MapElement::Mine; 14 | use lib_minesweeper::MapElement::Number; 15 | use lib_minesweeper::MapElementCellState::Closed; 16 | use lib_minesweeper::MapElementCellState::Flagged; 17 | use lib_minesweeper::MapElementCellState::Open; 18 | use lib_minesweeper::Point; 19 | 20 | use wasm_bindgen::prelude::*; 21 | 22 | use serde_derive::{Deserialize, Serialize}; 23 | //use yew::format::Json; 24 | use yew::prelude::*; 25 | 26 | use js_sys::Date; 27 | 28 | //use yew::services::storage::{Area, StorageService}; 29 | 30 | fn small_board() -> Board { 31 | use rand::Rng; 32 | let width = 10; 33 | let height = 10; 34 | let mines = 10; 35 | 36 | let board = create_board(width, height, mines, |x, y| { 37 | rand::thread_rng().gen_range(x..y) 38 | }); 39 | 40 | numbers_on_board(board) 41 | } 42 | 43 | fn medium_board() -> Board { 44 | use rand::Rng; 45 | let width = 16; 46 | let height = 16; 47 | let mines = 40; 48 | 49 | let board = create_board(width, height, mines, |x, y| { 50 | rand::thread_rng().gen_range(x..y) 51 | }); 52 | 53 | numbers_on_board(board) 54 | } 55 | 56 | fn large_board() -> Board { 57 | use rand::Rng; 58 | let width = 16; 59 | let height = 30; 60 | let mines = 99; 61 | 62 | let board = create_board(width, height, mines, |x, y| { 63 | rand::thread_rng().gen_range(x..y) 64 | }); 65 | 66 | numbers_on_board(board) 67 | } 68 | 69 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 70 | enum Mode { 71 | Flagging, 72 | Digging, 73 | } 74 | 75 | #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] 76 | enum Difficulty { 77 | Easy, 78 | Medium, 79 | Hard, 80 | } 81 | struct Model { 82 | //storage: StorageService, 83 | state: State, 84 | } 85 | 86 | enum Msg { 87 | ToggleDifficulty, 88 | ToggleMode, 89 | UpdateBoard { point: Point }, 90 | RunRobot, 91 | } 92 | 93 | #[derive(Serialize, Deserialize, Clone)] 94 | pub struct State { 95 | difficulty: Difficulty, 96 | mode: Mode, 97 | board: Board, 98 | } 99 | 100 | //const KEY: &'static str = "jgpaiva.minesweeper.self"; 101 | 102 | impl Component for Model { 103 | type Message = Msg; 104 | type Properties = (); 105 | fn create(_: &Context) -> Self { 106 | //let storage = StorageService::new(Area::Local).expect("storage was disabled by the user"); 107 | // let difficulty = { 108 | // if let Json(Ok(restored_model)) = storage.restore(KEY) { 109 | // restored_model 110 | // } else { 111 | // 112 | // } 113 | // }; 114 | let state = State { 115 | difficulty: Difficulty::Easy, 116 | mode: Mode::Digging, 117 | board: small_board(), 118 | }; 119 | Self { 120 | //storage, 121 | state, 122 | } 123 | } 124 | 125 | fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { 126 | match msg { 127 | Msg::ToggleDifficulty => self.toggle_difficulty(), 128 | Msg::ToggleMode => self.toggle_mode(), 129 | Msg::UpdateBoard { point } => self.update_board(point), 130 | Msg::RunRobot => self.run_robot(), 131 | } 132 | true 133 | } 134 | 135 | fn view(&self, ctx: &Context) -> Html { 136 | html! { 137 |
138 |
139 |
143 | { self.render_difficulty() } 144 |
145 |
149 | { self.render_mode() } 150 |
151 |
155 | { self.render_robot()} 156 |
157 | TimeKeeperOp::Stopped, 160 | Failed => TimeKeeperOp::Stopped, 161 | Playing => TimeKeeperOp::Counting, 162 | Ready => TimeKeeperOp::Reset, 163 | NotReady => unreachable!(), 164 | }}/> 165 |
166 |
167 |
168 | { 169 | (0..self.state.board.height) 170 | .flat_map(|y| { 171 | (0..self.state.board.width+1).map(move |x| { 172 | if x == self.state.board.width{ 173 | self.render_break() 174 | } else { 175 | let board = &self.state.board; 176 | html!{ 177 | 184 | } 185 | } 186 | }) 187 | }).collect::() 188 | } 189 |
190 |
191 |
192 | } 193 | } 194 | } 195 | 196 | impl Model { 197 | fn toggle_difficulty(&mut self) { 198 | let (new_board, new_difficulty) = match ( 199 | self.state.board.state.clone(), 200 | self.state.difficulty.clone(), 201 | ) { 202 | (Ready, Difficulty::Easy) => (medium_board(), Difficulty::Medium), 203 | (Ready, Difficulty::Medium) => (large_board(), Difficulty::Hard), 204 | (Ready, Difficulty::Hard) => (small_board(), Difficulty::Easy), 205 | (_, Difficulty::Easy) => (small_board(), Difficulty::Easy), 206 | (_, Difficulty::Medium) => (medium_board(), Difficulty::Medium), 207 | (_, Difficulty::Hard) => (large_board(), Difficulty::Hard), 208 | }; 209 | self.state = State { 210 | difficulty: new_difficulty, 211 | board: new_board, 212 | ..self.state.clone() 213 | } 214 | } 215 | fn toggle_mode(&mut self) { 216 | if matches!(self.state.board.state, Won | Failed) { 217 | return; 218 | } 219 | self.state = match self.state.mode { 220 | Mode::Digging => State { 221 | mode: Mode::Flagging, 222 | ..self.state.clone() 223 | }, 224 | Mode::Flagging => State { 225 | mode: Mode::Digging, 226 | ..self.state.clone() 227 | }, 228 | } 229 | } 230 | 231 | fn render_main_container_class(&self) -> String { 232 | match self.state.board.state { 233 | Ready | Playing => "ongoing", 234 | Won => "won", 235 | Failed => "failed", 236 | NotReady => unreachable!(), 237 | } 238 | .into() 239 | } 240 | 241 | fn render_difficulty(&self) -> Html { 242 | html! { 243 | match self.state.difficulty { 244 | Difficulty::Easy => "😀", 245 | Difficulty::Medium => "🤨", 246 | Difficulty::Hard => "🧐", 247 | } 248 | } 249 | } 250 | 251 | fn render_mode_class(&self) -> String { 252 | match &self.state.board.state { 253 | Won | Failed => "item".into(), 254 | _ => "clickable item".into(), 255 | } 256 | } 257 | 258 | fn render_mode(&self) -> String { 259 | match (&self.state.board.state, self.state.mode.clone()) { 260 | (Ready, Mode::Flagging) | (Playing, Mode::Flagging) => "🚩", 261 | (Ready, Mode::Digging) | (Playing, Mode::Digging) => "⛏️", 262 | (Won, _) => "🏆", 263 | (Failed, _) => "☠️", 264 | _ => unreachable!(), 265 | } 266 | .into() 267 | } 268 | 269 | fn render_robot(&self) -> &str { 270 | if matches!(&self.state.board.state, Ready | Playing) { 271 | "🤖" 272 | } else { 273 | "" 274 | } 275 | } 276 | 277 | fn render_break(&self) -> Html { 278 | html! { 279 |
280 |
281 | } 282 | } 283 | 284 | fn update_board(&mut self, p: Point) { 285 | match self.state.mode { 286 | Mode::Digging => { 287 | let new_board = self.state.board.cascade_open_item(&p); 288 | if let Some(b) = new_board { 289 | self.state.board = b 290 | } 291 | } 292 | Mode::Flagging => { 293 | self.state.board = self.state.board.flag_item(&p); 294 | } 295 | } 296 | } 297 | 298 | fn run_robot(&mut self) { 299 | if matches!(self.state.board.state, Won | Failed) { 300 | return; 301 | } 302 | let board = &self.state.board; 303 | for x in 0..board.width { 304 | for y in 0..board.height { 305 | let p = Point::new(x, y); 306 | if let Some(board) = Self::run_robot_on_point(board, p) { 307 | self.state.board = board; 308 | return; 309 | } 310 | } 311 | } 312 | } 313 | 314 | fn run_robot_on_point(board: &Board, p: Point) -> Option { 315 | let el = board.at(&p).unwrap(); 316 | let Number { 317 | state: Open, 318 | count: mine_count, 319 | } = el else { 320 | return None 321 | }; 322 | if *mine_count == 0 { 323 | return None; 324 | } 325 | let surrounding_points = board.surrounding_points(&p); 326 | let surrounding_els: Vec<_> = surrounding_points 327 | .iter() 328 | .map(|p| (p, board.at(p).unwrap().clone())) 329 | .filter(|(_p, el)| { 330 | !matches!( 331 | el, 332 | Number { 333 | state: Open, 334 | count: 0 335 | } 336 | ) 337 | }) 338 | .collect(); 339 | let mut unopened = surrounding_els 340 | .iter() 341 | .filter(|(_p, el)| !matches!(el, Number { state: Open, .. })); 342 | let flagged_count = surrounding_els 343 | .iter() 344 | .filter(|(_p, el)| { 345 | matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 346 | }) 347 | .count(); 348 | let unopened_count = unopened.clone().count(); 349 | if *mine_count == unopened_count as i32 && flagged_count < unopened_count { 350 | let (p, _el) = unopened 351 | .find(|(_p, el)| { 352 | !matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 353 | }) 354 | .unwrap(); 355 | return Some(board.flag_item(p)); 356 | } 357 | if *mine_count == flagged_count as i32 && unopened_count - flagged_count > 0 { 358 | let (p, _el) = unopened 359 | .find(|(_p, el)| { 360 | !matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 361 | }) 362 | .unwrap(); 363 | return board.cascade_open_item(p); 364 | } 365 | None 366 | } 367 | } 368 | 369 | #[derive(Copy, Clone, Properties, PartialEq)] 370 | struct TimeKeeperProps { 371 | op: TimeKeeperOp, 372 | } 373 | 374 | #[derive(Copy, Clone, PartialEq)] 375 | enum TimeKeeperOp { 376 | Reset, 377 | Counting, 378 | Stopped, 379 | } 380 | 381 | struct TimeKeeperState { 382 | started_at: Option, 383 | stopped_at: Option, 384 | _handle: gloo_timers::callback::Interval, 385 | } 386 | 387 | struct TimeKeeper { 388 | state: TimeKeeperState, 389 | } 390 | 391 | enum TimeKeeperMsg { 392 | Tick, 393 | } 394 | 395 | impl Component for TimeKeeper { 396 | type Message = TimeKeeperMsg; 397 | type Properties = TimeKeeperProps; 398 | fn create(ctx: &Context) -> Self { 399 | let link = ctx.link().clone(); 400 | let _handle = gloo_timers::callback::Interval::new(100, move || { 401 | link.send_message(TimeKeeperMsg::Tick) 402 | }); 403 | 404 | let state = TimeKeeperState { 405 | started_at: None, 406 | stopped_at: None, 407 | _handle, 408 | }; 409 | Self { state } 410 | } 411 | 412 | fn changed(&mut self, ctx: &Context, old_props: &Self::Properties) -> bool { 413 | let props = ctx.props(); 414 | match (old_props.op, props.op) { 415 | (TimeKeeperOp::Counting, TimeKeeperOp::Reset) 416 | | (TimeKeeperOp::Stopped, TimeKeeperOp::Reset) => { 417 | self.state.started_at = None; 418 | self.state.stopped_at = None; 419 | true 420 | } 421 | (TimeKeeperOp::Reset, TimeKeeperOp::Reset) => false, 422 | (TimeKeeperOp::Stopped, TimeKeeperOp::Counting) 423 | | (TimeKeeperOp::Reset, TimeKeeperOp::Counting) => { 424 | self.state.started_at = Some(Date::new_0()); 425 | true 426 | } 427 | (TimeKeeperOp::Counting, TimeKeeperOp::Counting) => true, 428 | (TimeKeeperOp::Counting, TimeKeeperOp::Stopped) => { 429 | self.state.stopped_at = Some(Date::new_0()); 430 | true 431 | } 432 | (TimeKeeperOp::Reset, TimeKeeperOp::Stopped) => { 433 | self.state.started_at = Some(Date::new_0()); 434 | self.state.stopped_at = Some(Date::new_0()); 435 | true 436 | } 437 | (TimeKeeperOp::Stopped, TimeKeeperOp::Stopped) => false, 438 | } 439 | } 440 | 441 | fn view(&self, _ctx: &Context) -> Html { 442 | html! { 443 |
444 |

{ self.render_timer() }

445 |
446 | } 447 | } 448 | 449 | fn update(&mut self, _ctx: &Context, msg: Self::Message) -> bool { 450 | match msg { 451 | TimeKeeperMsg::Tick => {} 452 | } 453 | true 454 | } 455 | } 456 | 457 | impl TimeKeeper { 458 | fn render_timer(&self) -> String { 459 | match (&self.state.started_at, &self.state.stopped_at) { 460 | (Some(started_at), None) => { 461 | let now = Date::new_0(); 462 | format!( 463 | "{}", 464 | ((now.get_time() - started_at.get_time()) / 1000_f64) 465 | .round() 466 | .min(999_f64) // make sure we don't run out of space 467 | ) 468 | } 469 | (Some(started_at), Some(stopped_at)) => format!( 470 | "{}", 471 | ((stopped_at.get_time() - started_at.get_time()) / 1000_f64) 472 | .round() 473 | .min(999_f64) // make sure we don't run out of space 474 | ), 475 | (None, None) => String::from("0"), 476 | _ => unreachable!(), 477 | } 478 | } 479 | } 480 | 481 | #[derive(Clone, Properties, PartialEq)] 482 | struct BoardItemProps { 483 | x: usize, 484 | y: usize, 485 | board_state: BoardState, 486 | board_width: usize, 487 | element: MapElement, 488 | update_signal: Callback, 489 | } 490 | 491 | struct BoardItem {} 492 | 493 | impl Component for BoardItem { 494 | type Message = Msg; 495 | type Properties = BoardItemProps; 496 | fn create(_ctx: &Context) -> Self { 497 | Self {} 498 | } 499 | 500 | fn changed(&mut self, ctx: &Context, old_props: &Self::Properties) -> bool { 501 | let props = ctx.props(); 502 | !(old_props.x == props.x 503 | && old_props.y == props.y 504 | && old_props.board_state == props.board_state 505 | && old_props.board_width == props.board_width 506 | && old_props.element == props.element) 507 | } 508 | 509 | fn update(&mut self, ctx: &Context, msg: Self::Message) -> bool { 510 | match msg { 511 | Msg::UpdateBoard { point } => { 512 | ctx.props().update_signal.emit(Msg::UpdateBoard { point }) 513 | } 514 | _ => unreachable!(), 515 | } 516 | true 517 | } 518 | 519 | fn view(&self, ctx: &Context) -> Html { 520 | let props = ctx.props(); 521 | let x = props.x; 522 | let y = props.y; 523 | html! { 524 |
{ 531 | String::from("item clickable2") 532 | }, 533 | (Playing, Number {state: Open, count}) 534 | | (Won,Number {count, ..}) 535 | | (Failed,Number {count, ..}) => { 536 | format!("item not-clickable2 mines-{}", count) 537 | }, 538 | _ => String::from("item not-clickable2") 539 | }} 540 | style={self.get_item_style(ctx.props().board_width)} 541 | onclick={ctx.link().callback(move |_| {Msg::UpdateBoard {point:Point::new(x,y)}})} > 542 |
{ 543 | match (&props.board_state, &props.element) { 544 | (Ready, Number { state: Flagged, .. }) 545 | | (Ready, Mine { state: Flagged, .. }) 546 | | (Playing, Number { state: Flagged, .. }) 547 | | (Playing, Mine { state: Flagged, .. }) => { 548 | String::from("🚩") 549 | } 550 | (Ready, Number { state: Closed, .. }) 551 | | (Ready, Mine { state: Closed, .. }) 552 | | (Playing, Number { state: Closed, .. }) 553 | | (Playing, Mine { state: Closed, .. }) => { 554 | String::from("❓") 555 | } 556 | (_, Number { count:0, .. }) => String::from(""), 557 | (_, Number { count, .. }) => format!("{}",count), 558 | (Failed, Mine { .. }) => String::from("💣"), 559 | (Won, Mine { .. }) => String::from("🚩"), 560 | _ => unreachable!(), 561 | } 562 | } 563 |
564 |
565 | } 566 | } 567 | } 568 | 569 | impl BoardItem { 570 | fn get_item_style(&self, board_width: usize) -> String { 571 | let square_size: f64 = 100.0 / (board_width as f64); 572 | let margin: f64 = 0.05 * square_size; 573 | let width = format!("{:.2}", square_size - 2.0 * margin); 574 | 575 | format!("width: {}%; margin: {}%", width, margin) 576 | } 577 | } 578 | 579 | #[wasm_bindgen(start)] 580 | pub fn main() -> Result<(), JsValue> { 581 | yew::Renderer::::default().render(); 582 | 583 | gloo::console::log!("App initialized"); 584 | Ok(()) 585 | } 586 | -------------------------------------------------------------------------------- /lib_minesweeper/src/lib.rs: -------------------------------------------------------------------------------- 1 | use serde_derive::{Deserialize, Serialize}; 2 | 3 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] 4 | pub enum MapElement { 5 | Mine { 6 | state: MapElementCellState, 7 | }, 8 | Number { 9 | state: MapElementCellState, 10 | count: i32, 11 | }, 12 | } 13 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] 14 | pub enum MapElementCellState { 15 | Closed, 16 | Open, 17 | Flagged, 18 | } 19 | 20 | use MapElement::Mine; 21 | use MapElement::Number; 22 | use MapElementCellState::Closed; 23 | use MapElementCellState::Flagged; 24 | use MapElementCellState::Open; 25 | 26 | #[derive(Debug, PartialEq, Eq, PartialOrd, Serialize, Deserialize)] 27 | pub struct Point { 28 | pub x: i32, 29 | pub y: i32, 30 | } 31 | 32 | impl Point { 33 | pub fn new(x: usize, y: usize) -> Point { 34 | let x = x as i32; 35 | let y = y as i32; 36 | Point { x, y } 37 | } 38 | } 39 | 40 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] 41 | pub enum BoardState { 42 | NotReady, 43 | Ready, 44 | Playing, 45 | Won, 46 | Failed, 47 | } 48 | 49 | #[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] 50 | pub struct Board { 51 | map: Vec>, 52 | missing_points: i32, 53 | pub width: usize, 54 | pub height: usize, 55 | pub mines: usize, 56 | pub state: BoardState, 57 | } 58 | 59 | impl Board { 60 | pub fn new(map: Vec>) -> Board { 61 | let mines = map 62 | .iter() 63 | .flat_map(|x| x.iter()) 64 | .filter(|x| matches!(x, Mine { .. })) 65 | .count(); 66 | let width = map.first().unwrap().len(); 67 | let height = map.len(); 68 | Board { 69 | width, 70 | height, 71 | mines, 72 | missing_points: (width as i32) * (height as i32) - (mines as i32), 73 | state: BoardState::NotReady, 74 | map, 75 | } 76 | } 77 | 78 | pub fn at(&self, p: &Point) -> Option<&MapElement> { 79 | let width = self.width as i32; 80 | let height = self.height as i32; 81 | if p.x < 0 || p.x >= width || p.y < 0 || p.y >= height { 82 | None 83 | } else { 84 | let x = p.x as usize; 85 | let y = p.y as usize; 86 | Some(&self.map[y][x]) 87 | } 88 | } 89 | 90 | fn replace(&self, p: &Point, el: MapElement) -> Board { 91 | let was_closed = matches!(self.at(p), Some(Number { state: Closed, .. })); 92 | let map = (0..self.height) 93 | .map(|y| { 94 | (0..self.width) 95 | .map(|x| { 96 | if Point::new(x, y) == *p { 97 | el.clone() 98 | } else { 99 | self.at(&Point::new(x, y)).unwrap().clone() 100 | } 101 | }) 102 | .collect() 103 | }) 104 | .collect(); 105 | let missing_points = if was_closed { 106 | self.missing_points - 1 107 | } else { 108 | self.missing_points 109 | }; 110 | Board { 111 | width: self.width, 112 | height: self.height, 113 | mines: self.mines, 114 | missing_points, 115 | map, 116 | state: match (missing_points, &self.state) { 117 | (0, _) => BoardState::Won, 118 | (_, BoardState::Ready) => BoardState::Playing, 119 | _ => self.state.clone(), 120 | }, 121 | } 122 | } 123 | 124 | pub fn flag_item(&self, p: &Point) -> Board { 125 | match self.at(p) { 126 | Some(Mine { state }) => self.replace( 127 | p, 128 | Mine { 129 | state: match *state { 130 | Closed => Flagged, 131 | Flagged => Closed, 132 | Open => Open, 133 | }, 134 | }, 135 | ), 136 | Some(Number { state, count }) => self.replace( 137 | p, 138 | Number { 139 | state: match *state { 140 | Closed => Flagged, 141 | Flagged => Closed, 142 | Open => Open, 143 | }, 144 | count: *count, 145 | }, 146 | ), 147 | None => unreachable!(), 148 | } 149 | } 150 | 151 | pub fn cascade_open_item(&self, p: &Point) -> Option { 152 | match self.at(p).unwrap() { 153 | Number { state: Open, .. } 154 | | Mine { state: Flagged, .. } 155 | | Number { state: Flagged, .. } => None, 156 | Number { 157 | state: Closed, 158 | count, 159 | } => { 160 | let board = self.replace( 161 | p, 162 | Number { 163 | state: Open, 164 | count: *count, 165 | }, 166 | ); 167 | if *count == 0 { 168 | Some( 169 | board 170 | .surrounding_points(p) 171 | .iter() 172 | .fold(board, |b: Board, p| b.cascade_open_item(p).unwrap_or(b)), 173 | ) 174 | } else { 175 | Some(board) 176 | } 177 | } 178 | Mine { state: Open } | Mine { state: Closed } => Some(Board { 179 | map: self.map.clone(), 180 | width: self.width, 181 | height: self.height, 182 | mines: self.mines, 183 | missing_points: self.missing_points, 184 | state: BoardState::Failed, 185 | }), 186 | } 187 | } 188 | 189 | pub fn surrounding_points(&self, p: &Point) -> Vec { 190 | [p.x - 1, p.x, p.x + 1] 191 | .iter() 192 | .flat_map(|&x| { 193 | [p.y - 1, p.y, p.y + 1] 194 | .iter() 195 | .map(|&y| Point { x, y }) 196 | .filter(|&Point { x, y }| p.x != x || p.y != y) 197 | .filter(|p| self.at(p).is_some()) 198 | .collect::>() 199 | }) 200 | .collect() 201 | } 202 | 203 | pub fn run_robot_on_point(&self, p: Point) -> Option { 204 | let el = self.at(&p).unwrap(); 205 | let Number { 206 | state: Open, 207 | count: mine_count, 208 | } = el else { 209 | return None 210 | }; 211 | if *mine_count == 0 { 212 | return None; 213 | } 214 | let surrounding_points = self.surrounding_points(&p); 215 | let surrounding_els: Vec<_> = surrounding_points 216 | .iter() 217 | .map(|p| (p, self.at(p).unwrap().clone())) 218 | .filter(|(_p, el)| { 219 | !matches!( 220 | el, 221 | Number { 222 | state: Open, 223 | count: 0 224 | } 225 | ) 226 | }) 227 | .collect(); 228 | let mut unopened = surrounding_els 229 | .iter() 230 | .filter(|(_p, el)| !matches!(el, Number { state: Open, .. })); 231 | let flagged_count = surrounding_els 232 | .iter() 233 | .filter(|(_p, el)| { 234 | matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 235 | }) 236 | .count(); 237 | let unopened_count = unopened.clone().count(); 238 | if *mine_count == unopened_count as i32 && flagged_count < unopened_count { 239 | let (p, _el) = unopened 240 | .find(|(_p, el)| { 241 | !matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 242 | }) 243 | .unwrap(); 244 | return Some(self.flag_item(p)); 245 | } 246 | if *mine_count == flagged_count as i32 && unopened_count - flagged_count > 0 { 247 | let (p, _el) = unopened 248 | .find(|(_p, el)| { 249 | !matches!(el, Mine { state: Flagged } | Number { state: Flagged, .. }) 250 | }) 251 | .unwrap(); 252 | return self.cascade_open_item(p); 253 | } 254 | None 255 | } 256 | } 257 | 258 | pub fn create_board( 259 | width: usize, 260 | height: usize, 261 | mines: usize, 262 | mut rand: impl FnMut(usize, usize) -> usize, 263 | ) -> Board { 264 | let mut points: Vec = Vec::with_capacity(mines); 265 | for _ in 0..mines { 266 | loop { 267 | let x = rand(0, width); 268 | let y = rand(0, height); 269 | let p = Point::new(x, y); 270 | if points.contains(&p) { 271 | continue; 272 | } 273 | points.push(p); 274 | break; 275 | } 276 | } 277 | 278 | let map = (0..height) 279 | .map(|y| { 280 | (0..width) 281 | .map(|x| { 282 | if points.contains(&Point::new(x, y)) { 283 | Mine { state: Closed } 284 | } else { 285 | Number { 286 | state: Closed, 287 | count: 0, 288 | } 289 | } 290 | }) 291 | .collect() 292 | }) 293 | .collect(); 294 | Board::new(map) 295 | } 296 | 297 | pub fn numbers_on_board(board: Board) -> Board { 298 | let map = (0..board.height) 299 | .map(|y| { 300 | (0..board.width) 301 | .map(|x| { 302 | let point = Point::new(x, y); 303 | match board.at(&point).unwrap() { 304 | Mine { state } => Mine { 305 | state: state.clone(), 306 | }, 307 | Number { count: 0, state } => { 308 | let count = board 309 | .surrounding_points(&point) 310 | .iter() 311 | .filter(|p| matches!(board.at(p), Some(Mine { .. }))) 312 | .count() as i32; 313 | Number { 314 | state: state.clone(), 315 | count, 316 | } 317 | } 318 | _ => unreachable!(), 319 | } 320 | }) 321 | .collect() 322 | }) 323 | .collect(); 324 | Board { 325 | map, 326 | state: BoardState::Ready, 327 | ..board 328 | } 329 | } 330 | 331 | #[cfg(test)] 332 | pub mod tests { 333 | use super::*; 334 | use pretty_assertions::assert_eq; 335 | 336 | macro_rules! board_matches { 337 | ($value: expr, $expected: literal) => { 338 | let s = board_to_string(&$value); 339 | for (i, (line_value, line_expected)) in s.lines().zip($expected.lines()).enumerate() { 340 | let line_expected = line_expected.trim(); 341 | assert_eq!(line_value, line_expected, "boards didn't match on line {i}"); 342 | } 343 | }; 344 | } 345 | 346 | macro_rules! map { 347 | ($bombs: literal, $state: literal) => { 348 | make_map($bombs, $state) 349 | }; 350 | } 351 | 352 | impl From<&u8> for MapElementCellState { 353 | fn from(state: &u8) -> Self { 354 | match state { 355 | b'O' => Open, 356 | b'C' => Closed, 357 | b'F' => Flagged, 358 | _ => unreachable!(), 359 | } 360 | } 361 | } 362 | 363 | fn count_from_bytes(c: u8) -> i32 { 364 | (c as i32) - (b'0' as i32) 365 | } 366 | 367 | fn make_map(map: &str, state: &str) -> Vec> { 368 | map.lines() 369 | .zip(state.lines()) 370 | .map(|(map_row, state_row)| { 371 | let map_row = map_row.trim(); 372 | let state_row = state_row.trim(); 373 | map_row 374 | .as_bytes() 375 | .iter() 376 | .zip(state_row.as_bytes()) 377 | .map(|(row_el, state_el)| match row_el { 378 | b'X' => Mine { 379 | state: state_el.into(), 380 | }, 381 | _ => Number { 382 | state: state_el.into(), 383 | count: count_from_bytes(*row_el), 384 | }, 385 | }) 386 | .collect() 387 | }) 388 | .collect() 389 | } 390 | 391 | #[test] 392 | fn test_make_map() { 393 | let map = map!( 394 | "00 395 | 22 396 | XX", 397 | "OC 398 | FC 399 | CF" 400 | ); 401 | let expected_map = vec![ 402 | vec![ 403 | Number { 404 | count: 0, 405 | state: Open, 406 | }, 407 | Number { 408 | count: 0, 409 | state: Closed, 410 | }, 411 | ], 412 | vec![ 413 | Number { 414 | count: 2, 415 | state: Flagged, 416 | }, 417 | Number { 418 | count: 2, 419 | state: Closed, 420 | }, 421 | ], 422 | vec![Mine { state: Closed }, Mine { state: Flagged }], 423 | ]; 424 | 425 | assert_eq!(map, expected_map); 426 | } 427 | 428 | pub fn five_by_four_board() -> Board { 429 | Board::new(map!( 430 | "X0000 431 | 0X000 432 | 00X00 433 | 000X0", 434 | "CCCCC 435 | CCCCC 436 | CCCCC 437 | CCCCC" 438 | )) 439 | } 440 | 441 | pub fn five_by_two_board() -> Board { 442 | Board::new(map!( 443 | "X0000 444 | 0X000", 445 | "CCCCC 446 | CCCCC" 447 | )) 448 | } 449 | 450 | #[test] 451 | fn test_create_board() { 452 | let width = 5; 453 | let height = 4; 454 | let mines = 4; 455 | let mut v = vec![3, 3, 2, 2, 1, 1, 0, 0]; 456 | let rand = move |_start: usize, _end: usize| -> usize { v.pop().unwrap() }; 457 | let board = create_board(width, height, mines, rand); 458 | let expected_map = five_by_four_board().map; 459 | assert_eq!(board.map, expected_map); 460 | assert_eq!(board.state, BoardState::NotReady); 461 | } 462 | 463 | #[test] 464 | fn test_create_board_without_repeated_mines() { 465 | let width = 5; 466 | let height = 4; 467 | let mines = 4; 468 | let mut v = vec![3, 3, 2, 2, 0, 0, 1, 1, 0, 0]; 469 | let rand = move |_start: usize, _end: usize| -> usize { v.pop().unwrap() }; 470 | let board = create_board(width, height, mines, rand); 471 | let expected_map = five_by_four_board().map; 472 | assert_eq!(board.map, expected_map); 473 | assert_eq!(board.state, BoardState::NotReady); 474 | } 475 | 476 | #[test] 477 | fn test_numbers_on_board() { 478 | let board = numbers_on_board(five_by_four_board()); 479 | let expected_map = map!( 480 | "X2100 481 | 2X210 482 | 12X21 483 | 012X1", 484 | "CCCCC 485 | CCCCC 486 | CCCCC 487 | CCCCC" 488 | ); 489 | assert_eq!(board.map, expected_map); 490 | assert_eq!(board.state, BoardState::Ready); 491 | } 492 | 493 | #[test] 494 | fn test_surrounding_points() { 495 | assert_eq!( 496 | five_by_two_board().surrounding_points(&Point { x: 1, y: 0 }), 497 | vec![ 498 | Point { x: 0, y: 0 }, 499 | Point { x: 0, y: 1 }, 500 | Point { x: 1, y: 1 }, 501 | Point { x: 2, y: 0 }, 502 | Point { x: 2, y: 1 }, 503 | ] 504 | ); 505 | } 506 | 507 | #[test] 508 | fn test_cascade_open_item() { 509 | let board = numbers_on_board(five_by_two_board()); 510 | let board = board.cascade_open_item(&Point::new(3, 1)).unwrap(); 511 | let expected_map = map!( 512 | "X2100 513 | 2X100", 514 | "CCOOO 515 | CCOOO" 516 | ); 517 | assert_eq!(board.map, expected_map); 518 | assert_eq!(board.state, BoardState::Playing); 519 | } 520 | 521 | #[test] 522 | fn test_win_board() { 523 | let board = numbers_on_board(five_by_two_board()); 524 | let board = board.cascade_open_item(&Point::new(3, 1)).unwrap(); 525 | let board = board.cascade_open_item(&Point::new(0, 1)).unwrap(); 526 | let board = board.cascade_open_item(&Point::new(1, 0)).unwrap(); 527 | let expected_map = map!( 528 | "X2100 529 | 2X100", 530 | "COOOO 531 | OCOOO" 532 | ); 533 | assert_eq!(board.map, expected_map); 534 | assert_eq!(board.state, BoardState::Won); 535 | } 536 | 537 | #[test] 538 | fn test_flag() { 539 | let board = numbers_on_board(five_by_two_board()); 540 | let board = board.flag_item(&Point::new(3, 1)); 541 | let expected_map = map!( 542 | "X2100 543 | 2X100", 544 | "CCCCC 545 | CCCFC" 546 | ); 547 | assert_eq!(board.map, expected_map); 548 | assert_eq!(board.state, BoardState::Playing); 549 | } 550 | 551 | #[test] 552 | fn test_flagging_again_unflags() { 553 | let board = numbers_on_board(five_by_two_board()); 554 | let board = board.flag_item(&Point::new(3, 1)); 555 | let board = board.flag_item(&Point::new(3, 1)); 556 | let expected_map = map!( 557 | "X2100 558 | 2X100", 559 | "CCCCC 560 | CCCCC" 561 | ); 562 | assert_eq!(board.map, expected_map); 563 | assert_eq!(board.state, BoardState::Playing); 564 | } 565 | 566 | #[test] 567 | fn test_flagging_open_does_noting() { 568 | let board = numbers_on_board(five_by_two_board()); 569 | let board = board.cascade_open_item(&Point::new(2, 0)).unwrap(); 570 | let board = board.flag_item(&Point::new(2, 0)); 571 | let expected_map = map!( 572 | "X2100 573 | 2X100", 574 | "CCOCC 575 | CCCCC" 576 | ); 577 | assert_eq!(board.map, expected_map); 578 | assert_eq!(board.state, BoardState::Playing); 579 | } 580 | 581 | fn board_to_string(board: &Board) -> String { 582 | let mut ret = String::default(); 583 | for y in 0..board.height { 584 | for x in 0..board.width { 585 | let p = Point::new(x, y); 586 | let el = board.at(&p).unwrap(); 587 | let v = match el { 588 | Mine { 589 | state: MapElementCellState::Flagged, 590 | } 591 | | Number { 592 | state: MapElementCellState::Flagged, 593 | .. 594 | } => "F".to_string(), 595 | Number { 596 | state: MapElementCellState::Closed, 597 | .. 598 | } 599 | | Mine { 600 | state: MapElementCellState::Closed, 601 | } => "•".to_string(), 602 | Number { 603 | state: MapElementCellState::Open, 604 | count: 0, 605 | } => "_".to_string(), 606 | Number { 607 | state: MapElementCellState::Open, 608 | count, 609 | } => count.to_string(), 610 | _ => unreachable!(), 611 | }; 612 | ret.push_str(&v); 613 | } 614 | ret.push('\n'); 615 | } 616 | ret 617 | } 618 | 619 | #[test] 620 | fn test_run_robot_on_point() { 621 | let board = numbers_on_board(five_by_two_board()); 622 | let res = board.run_robot_on_point(Point::new(4, 0)); 623 | assert!(res.is_none()); 624 | 625 | let board = board.flag_item(&Point::new(1, 1)); 626 | let board = board.cascade_open_item(&Point::new(2, 0)).unwrap(); 627 | board_matches!( 628 | board, 629 | "••1•• 630 | •F•••" 631 | ); 632 | let board = board.run_robot_on_point(Point::new(2, 0)).unwrap(); 633 | board_matches!( 634 | board, 635 | "•21•• 636 | •F•••" 637 | ); 638 | let board = board.run_robot_on_point(Point::new(2, 0)).unwrap(); 639 | board_matches!( 640 | board, 641 | "•21•• 642 | •F1••" 643 | ); 644 | let board = board.run_robot_on_point(Point::new(2, 0)).unwrap(); 645 | board_matches!( 646 | board, 647 | "•21__ 648 | •F1__" 649 | ); 650 | let res = board.run_robot_on_point(Point::new(2, 0)); 651 | assert!(res.is_none()); 652 | } 653 | 654 | #[ignore] // currently working on this test 655 | #[test] 656 | fn test_advanced_run_robot_on_point() { 657 | let board = numbers_on_board(Board::new(map!( 658 | "X0X 659 | 000 660 | 000", 661 | "COC 662 | COO 663 | CCC" 664 | ))); 665 | board_matches!( 666 | board, 667 | "•2• 668 | •21 669 | •••" 670 | ); 671 | let board = board.run_robot_on_point(Point::new(4, 0)).unwrap(); 672 | board_matches!( 673 | board, 674 | "•2F 675 | •21 676 | •••" 677 | ); 678 | } 679 | } 680 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "ansi_term" 7 | version = "0.11.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" 10 | dependencies = [ 11 | "winapi", 12 | ] 13 | 14 | [[package]] 15 | name = "anymap2" 16 | version = "0.13.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "d301b3b94cb4b2f23d7917810addbbaff90738e0ca2be692bd027e70d7e0330c" 19 | 20 | [[package]] 21 | name = "atty" 22 | version = "0.2.14" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" 25 | dependencies = [ 26 | "hermit-abi", 27 | "libc", 28 | "winapi", 29 | ] 30 | 31 | [[package]] 32 | name = "autocfg" 33 | version = "1.1.0" 34 | source = "registry+https://github.com/rust-lang/crates.io-index" 35 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" 36 | 37 | [[package]] 38 | name = "bincode" 39 | version = "1.3.3" 40 | source = "registry+https://github.com/rust-lang/crates.io-index" 41 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 42 | dependencies = [ 43 | "serde", 44 | ] 45 | 46 | [[package]] 47 | name = "boolinator" 48 | version = "2.4.0" 49 | source = "registry+https://github.com/rust-lang/crates.io-index" 50 | checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9" 51 | 52 | [[package]] 53 | name = "bumpalo" 54 | version = "3.2.1" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | checksum = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" 57 | 58 | [[package]] 59 | name = "cfg-if" 60 | version = "0.1.10" 61 | source = "registry+https://github.com/rust-lang/crates.io-index" 62 | checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 63 | 64 | [[package]] 65 | name = "cfg-if" 66 | version = "1.0.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 69 | 70 | [[package]] 71 | name = "colored" 72 | version = "1.9.3" 73 | source = "registry+https://github.com/rust-lang/crates.io-index" 74 | checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" 75 | dependencies = [ 76 | "atty", 77 | "lazy_static", 78 | "winapi", 79 | ] 80 | 81 | [[package]] 82 | name = "console_error_panic_hook" 83 | version = "0.1.6" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" 86 | dependencies = [ 87 | "cfg-if 0.1.10", 88 | "wasm-bindgen", 89 | ] 90 | 91 | [[package]] 92 | name = "ctor" 93 | version = "0.1.13" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "47c5e5ac752e18207b12e16b10631ae5f7f68f8805f335f9b817ead83d9ffce1" 96 | dependencies = [ 97 | "quote 1.0.3", 98 | "syn", 99 | ] 100 | 101 | [[package]] 102 | name = "diff" 103 | version = "0.1.13" 104 | source = "registry+https://github.com/rust-lang/crates.io-index" 105 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" 106 | 107 | [[package]] 108 | name = "difference" 109 | version = "2.0.0" 110 | source = "registry+https://github.com/rust-lang/crates.io-index" 111 | checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 112 | 113 | [[package]] 114 | name = "fnv" 115 | version = "1.0.7" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 118 | 119 | [[package]] 120 | name = "form_urlencoded" 121 | version = "1.1.0" 122 | source = "registry+https://github.com/rust-lang/crates.io-index" 123 | checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" 124 | dependencies = [ 125 | "percent-encoding", 126 | ] 127 | 128 | [[package]] 129 | name = "futures" 130 | version = "0.1.29" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" 133 | 134 | [[package]] 135 | name = "futures" 136 | version = "0.3.25" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" 139 | dependencies = [ 140 | "futures-channel", 141 | "futures-core", 142 | "futures-io", 143 | "futures-sink", 144 | "futures-task", 145 | "futures-util", 146 | ] 147 | 148 | [[package]] 149 | name = "futures-channel" 150 | version = "0.3.25" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" 153 | dependencies = [ 154 | "futures-core", 155 | "futures-sink", 156 | ] 157 | 158 | [[package]] 159 | name = "futures-core" 160 | version = "0.3.25" 161 | source = "registry+https://github.com/rust-lang/crates.io-index" 162 | checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" 163 | 164 | [[package]] 165 | name = "futures-io" 166 | version = "0.3.25" 167 | source = "registry+https://github.com/rust-lang/crates.io-index" 168 | checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" 169 | 170 | [[package]] 171 | name = "futures-macro" 172 | version = "0.3.25" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" 175 | dependencies = [ 176 | "proc-macro2 1.0.47", 177 | "quote 1.0.3", 178 | "syn", 179 | ] 180 | 181 | [[package]] 182 | name = "futures-sink" 183 | version = "0.3.25" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" 186 | 187 | [[package]] 188 | name = "futures-task" 189 | version = "0.3.25" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" 192 | 193 | [[package]] 194 | name = "futures-util" 195 | version = "0.3.25" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" 198 | dependencies = [ 199 | "futures-channel", 200 | "futures-core", 201 | "futures-io", 202 | "futures-macro", 203 | "futures-sink", 204 | "futures-task", 205 | "memchr", 206 | "pin-project-lite", 207 | "pin-utils", 208 | "slab", 209 | ] 210 | 211 | [[package]] 212 | name = "getrandom" 213 | version = "0.2.8" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" 216 | dependencies = [ 217 | "cfg-if 1.0.0", 218 | "js-sys", 219 | "libc", 220 | "wasi", 221 | "wasm-bindgen", 222 | ] 223 | 224 | [[package]] 225 | name = "gloo" 226 | version = "0.3.0" 227 | source = "registry+https://github.com/rust-lang/crates.io-index" 228 | checksum = "0b31ec63066de893f3be98da84af50441ea35819bd7be95373802dea56293952" 229 | dependencies = [ 230 | "gloo-console 0.1.0", 231 | "gloo-dialogs", 232 | "gloo-events", 233 | "gloo-file 0.1.0", 234 | "gloo-render", 235 | "gloo-storage 0.1.0", 236 | "gloo-timers", 237 | ] 238 | 239 | [[package]] 240 | name = "gloo" 241 | version = "0.8.0" 242 | source = "registry+https://github.com/rust-lang/crates.io-index" 243 | checksum = "3a4bef6b277b3ab073253d4bca60761240cf8d6998f4bd142211957b69a61b20" 244 | dependencies = [ 245 | "gloo-console 0.2.3", 246 | "gloo-dialogs", 247 | "gloo-events", 248 | "gloo-file 0.2.3", 249 | "gloo-history", 250 | "gloo-net", 251 | "gloo-render", 252 | "gloo-storage 0.2.2", 253 | "gloo-timers", 254 | "gloo-utils", 255 | "gloo-worker", 256 | ] 257 | 258 | [[package]] 259 | name = "gloo-console" 260 | version = "0.1.0" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "770942b86a2ab86330201eeafc5fe526fb203e54dbc6ef82a36453cebcb90e4c" 263 | dependencies = [ 264 | "js-sys", 265 | "serde", 266 | "wasm-bindgen", 267 | "web-sys", 268 | ] 269 | 270 | [[package]] 271 | name = "gloo-console" 272 | version = "0.2.3" 273 | source = "registry+https://github.com/rust-lang/crates.io-index" 274 | checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" 275 | dependencies = [ 276 | "gloo-utils", 277 | "js-sys", 278 | "serde", 279 | "wasm-bindgen", 280 | "web-sys", 281 | ] 282 | 283 | [[package]] 284 | name = "gloo-dialogs" 285 | version = "0.1.1" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "67062364ac72d27f08445a46cab428188e2e224ec9e37efdba48ae8c289002e6" 288 | dependencies = [ 289 | "wasm-bindgen", 290 | "web-sys", 291 | ] 292 | 293 | [[package]] 294 | name = "gloo-events" 295 | version = "0.1.1" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "088514ec8ef284891c762c88a66b639b3a730134714692ee31829765c5bc814f" 298 | dependencies = [ 299 | "wasm-bindgen", 300 | "web-sys", 301 | ] 302 | 303 | [[package]] 304 | name = "gloo-file" 305 | version = "0.1.0" 306 | source = "registry+https://github.com/rust-lang/crates.io-index" 307 | checksum = "8f9fecfe46b5dc3cc46f58e98ba580cc714f2c93860796d002eb3527a465ef49" 308 | dependencies = [ 309 | "gloo-events", 310 | "js-sys", 311 | "wasm-bindgen", 312 | "web-sys", 313 | ] 314 | 315 | [[package]] 316 | name = "gloo-file" 317 | version = "0.2.3" 318 | source = "registry+https://github.com/rust-lang/crates.io-index" 319 | checksum = "a8d5564e570a38b43d78bdc063374a0c3098c4f0d64005b12f9bbe87e869b6d7" 320 | dependencies = [ 321 | "gloo-events", 322 | "js-sys", 323 | "wasm-bindgen", 324 | "web-sys", 325 | ] 326 | 327 | [[package]] 328 | name = "gloo-history" 329 | version = "0.1.0" 330 | source = "registry+https://github.com/rust-lang/crates.io-index" 331 | checksum = "f81af52c0d31e86242eecefe1ed4d066deb79cfb80f9f7da0847fac417396bfe" 332 | dependencies = [ 333 | "gloo-events", 334 | "gloo-utils", 335 | "serde", 336 | "serde-wasm-bindgen", 337 | "serde_urlencoded", 338 | "thiserror", 339 | "wasm-bindgen", 340 | "web-sys", 341 | ] 342 | 343 | [[package]] 344 | name = "gloo-net" 345 | version = "0.2.4" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | checksum = "ec897194fb9ac576c708f63d35604bc58f2a262b8cec0fabfed26f3991255f21" 348 | dependencies = [ 349 | "futures-channel", 350 | "futures-core", 351 | "futures-sink", 352 | "gloo-utils", 353 | "js-sys", 354 | "pin-project", 355 | "serde", 356 | "serde_json", 357 | "thiserror", 358 | "wasm-bindgen", 359 | "wasm-bindgen-futures 0.4.10", 360 | "web-sys", 361 | ] 362 | 363 | [[package]] 364 | name = "gloo-render" 365 | version = "0.1.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "2fd9306aef67cfd4449823aadcd14e3958e0800aa2183955a309112a84ec7764" 368 | dependencies = [ 369 | "wasm-bindgen", 370 | "web-sys", 371 | ] 372 | 373 | [[package]] 374 | name = "gloo-storage" 375 | version = "0.1.0" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "8c6cbd4f8664a9eec3d1f65de3e88d5898ef331db56efceae30fae4883ed311b" 378 | dependencies = [ 379 | "js-sys", 380 | "serde", 381 | "serde_json", 382 | "thiserror", 383 | "wasm-bindgen", 384 | "web-sys", 385 | ] 386 | 387 | [[package]] 388 | name = "gloo-storage" 389 | version = "0.2.2" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" 392 | dependencies = [ 393 | "gloo-utils", 394 | "js-sys", 395 | "serde", 396 | "serde_json", 397 | "thiserror", 398 | "wasm-bindgen", 399 | "web-sys", 400 | ] 401 | 402 | [[package]] 403 | name = "gloo-timers" 404 | version = "0.2.1" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" 407 | dependencies = [ 408 | "js-sys", 409 | "wasm-bindgen", 410 | "web-sys", 411 | ] 412 | 413 | [[package]] 414 | name = "gloo-utils" 415 | version = "0.1.5" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "40913a05c8297adca04392f707b1e73b12ba7b8eab7244a4961580b1fd34063c" 418 | dependencies = [ 419 | "js-sys", 420 | "serde", 421 | "serde_json", 422 | "wasm-bindgen", 423 | "web-sys", 424 | ] 425 | 426 | [[package]] 427 | name = "gloo-worker" 428 | version = "0.2.1" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "13471584da78061a28306d1359dd0178d8d6fc1c7c80e5e35d27260346e0516a" 431 | dependencies = [ 432 | "anymap2", 433 | "bincode", 434 | "gloo-console 0.2.3", 435 | "gloo-utils", 436 | "js-sys", 437 | "serde", 438 | "wasm-bindgen", 439 | "wasm-bindgen-futures 0.4.10", 440 | "web-sys", 441 | ] 442 | 443 | [[package]] 444 | name = "hashbrown" 445 | version = "0.12.3" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 448 | 449 | [[package]] 450 | name = "heck" 451 | version = "0.4.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" 454 | 455 | [[package]] 456 | name = "hermit-abi" 457 | version = "0.1.10" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" 460 | dependencies = [ 461 | "libc", 462 | ] 463 | 464 | [[package]] 465 | name = "implicit-clone" 466 | version = "0.3.2" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "a937e630d3907d421944abd8edb5288936f1fde83aaaf1a8c6c89bb4222f0677" 469 | dependencies = [ 470 | "indexmap", 471 | ] 472 | 473 | [[package]] 474 | name = "indexmap" 475 | version = "1.9.2" 476 | source = "registry+https://github.com/rust-lang/crates.io-index" 477 | checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" 478 | dependencies = [ 479 | "autocfg", 480 | "hashbrown", 481 | ] 482 | 483 | [[package]] 484 | name = "itoa" 485 | version = "0.4.5" 486 | source = "registry+https://github.com/rust-lang/crates.io-index" 487 | checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" 488 | 489 | [[package]] 490 | name = "itoa" 491 | version = "1.0.4" 492 | source = "registry+https://github.com/rust-lang/crates.io-index" 493 | checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" 494 | 495 | [[package]] 496 | name = "js-sys" 497 | version = "0.3.60" 498 | source = "registry+https://github.com/rust-lang/crates.io-index" 499 | checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" 500 | dependencies = [ 501 | "wasm-bindgen", 502 | ] 503 | 504 | [[package]] 505 | name = "lazy_static" 506 | version = "1.4.0" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 509 | 510 | [[package]] 511 | name = "lib_minesweeper" 512 | version = "0.1.0" 513 | dependencies = [ 514 | "colored", 515 | "pretty_assertions 0.6.1", 516 | "rand", 517 | "serde", 518 | "serde_derive", 519 | ] 520 | 521 | [[package]] 522 | name = "libc" 523 | version = "0.2.137" 524 | source = "registry+https://github.com/rust-lang/crates.io-index" 525 | checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" 526 | 527 | [[package]] 528 | name = "log" 529 | version = "0.4.8" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 532 | dependencies = [ 533 | "cfg-if 0.1.10", 534 | ] 535 | 536 | [[package]] 537 | name = "memchr" 538 | version = "2.5.0" 539 | source = "registry+https://github.com/rust-lang/crates.io-index" 540 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" 541 | 542 | [[package]] 543 | name = "minesweeper" 544 | version = "0.1.0" 545 | dependencies = [ 546 | "console_error_panic_hook", 547 | "getrandom", 548 | "gloo 0.3.0", 549 | "gloo-timers", 550 | "js-sys", 551 | "lazy_static", 552 | "lib_minesweeper", 553 | "log", 554 | "pretty_assertions 1.3.0", 555 | "rand", 556 | "serde", 557 | "serde_derive", 558 | "strum", 559 | "strum_macros", 560 | "wasm-bindgen", 561 | "wasm-bindgen-test", 562 | "web-sys", 563 | "yew", 564 | ] 565 | 566 | [[package]] 567 | name = "num_cpus" 568 | version = "1.14.0" 569 | source = "registry+https://github.com/rust-lang/crates.io-index" 570 | checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" 571 | dependencies = [ 572 | "hermit-abi", 573 | "libc", 574 | ] 575 | 576 | [[package]] 577 | name = "once_cell" 578 | version = "1.16.0" 579 | source = "registry+https://github.com/rust-lang/crates.io-index" 580 | checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" 581 | 582 | [[package]] 583 | name = "output_vt100" 584 | version = "0.1.2" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" 587 | dependencies = [ 588 | "winapi", 589 | ] 590 | 591 | [[package]] 592 | name = "percent-encoding" 593 | version = "2.2.0" 594 | source = "registry+https://github.com/rust-lang/crates.io-index" 595 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" 596 | 597 | [[package]] 598 | name = "pin-project" 599 | version = "1.0.12" 600 | source = "registry+https://github.com/rust-lang/crates.io-index" 601 | checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" 602 | dependencies = [ 603 | "pin-project-internal", 604 | ] 605 | 606 | [[package]] 607 | name = "pin-project-internal" 608 | version = "1.0.12" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" 611 | dependencies = [ 612 | "proc-macro2 1.0.47", 613 | "quote 1.0.3", 614 | "syn", 615 | ] 616 | 617 | [[package]] 618 | name = "pin-project-lite" 619 | version = "0.2.9" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" 622 | 623 | [[package]] 624 | name = "pin-utils" 625 | version = "0.1.0" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 628 | 629 | [[package]] 630 | name = "pinned" 631 | version = "0.1.0" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" 634 | dependencies = [ 635 | "futures 0.3.25", 636 | "rustversion", 637 | "thiserror", 638 | ] 639 | 640 | [[package]] 641 | name = "ppv-lite86" 642 | version = "0.2.17" 643 | source = "registry+https://github.com/rust-lang/crates.io-index" 644 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" 645 | 646 | [[package]] 647 | name = "pretty_assertions" 648 | version = "0.6.1" 649 | source = "registry+https://github.com/rust-lang/crates.io-index" 650 | checksum = "3f81e1644e1b54f5a68959a29aa86cde704219254669da328ecfdf6a1f09d427" 651 | dependencies = [ 652 | "ansi_term", 653 | "ctor", 654 | "difference", 655 | "output_vt100", 656 | ] 657 | 658 | [[package]] 659 | name = "pretty_assertions" 660 | version = "1.3.0" 661 | source = "registry+https://github.com/rust-lang/crates.io-index" 662 | checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" 663 | dependencies = [ 664 | "ctor", 665 | "diff", 666 | "output_vt100", 667 | "yansi", 668 | ] 669 | 670 | [[package]] 671 | name = "prettyplease" 672 | version = "0.1.21" 673 | source = "registry+https://github.com/rust-lang/crates.io-index" 674 | checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" 675 | dependencies = [ 676 | "proc-macro2 1.0.47", 677 | "syn", 678 | ] 679 | 680 | [[package]] 681 | name = "proc-macro-error" 682 | version = "1.0.4" 683 | source = "registry+https://github.com/rust-lang/crates.io-index" 684 | checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" 685 | dependencies = [ 686 | "proc-macro-error-attr", 687 | "proc-macro2 1.0.47", 688 | "quote 1.0.3", 689 | "syn", 690 | "version_check", 691 | ] 692 | 693 | [[package]] 694 | name = "proc-macro-error-attr" 695 | version = "1.0.4" 696 | source = "registry+https://github.com/rust-lang/crates.io-index" 697 | checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" 698 | dependencies = [ 699 | "proc-macro2 1.0.47", 700 | "quote 1.0.3", 701 | "version_check", 702 | ] 703 | 704 | [[package]] 705 | name = "proc-macro2" 706 | version = "0.4.30" 707 | source = "registry+https://github.com/rust-lang/crates.io-index" 708 | checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 709 | dependencies = [ 710 | "unicode-xid", 711 | ] 712 | 713 | [[package]] 714 | name = "proc-macro2" 715 | version = "1.0.47" 716 | source = "registry+https://github.com/rust-lang/crates.io-index" 717 | checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" 718 | dependencies = [ 719 | "unicode-ident", 720 | ] 721 | 722 | [[package]] 723 | name = "prokio" 724 | version = "0.1.0" 725 | source = "registry+https://github.com/rust-lang/crates.io-index" 726 | checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" 727 | dependencies = [ 728 | "futures 0.3.25", 729 | "gloo 0.8.0", 730 | "num_cpus", 731 | "once_cell", 732 | "pin-project", 733 | "pinned", 734 | "tokio", 735 | "tokio-stream", 736 | "wasm-bindgen-futures 0.4.10", 737 | ] 738 | 739 | [[package]] 740 | name = "quote" 741 | version = "0.6.13" 742 | source = "registry+https://github.com/rust-lang/crates.io-index" 743 | checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 744 | dependencies = [ 745 | "proc-macro2 0.4.30", 746 | ] 747 | 748 | [[package]] 749 | name = "quote" 750 | version = "1.0.3" 751 | source = "registry+https://github.com/rust-lang/crates.io-index" 752 | checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" 753 | dependencies = [ 754 | "proc-macro2 1.0.47", 755 | ] 756 | 757 | [[package]] 758 | name = "rand" 759 | version = "0.8.5" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 762 | dependencies = [ 763 | "libc", 764 | "log", 765 | "rand_chacha", 766 | "rand_core", 767 | ] 768 | 769 | [[package]] 770 | name = "rand_chacha" 771 | version = "0.3.1" 772 | source = "registry+https://github.com/rust-lang/crates.io-index" 773 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 774 | dependencies = [ 775 | "ppv-lite86", 776 | "rand_core", 777 | ] 778 | 779 | [[package]] 780 | name = "rand_core" 781 | version = "0.6.4" 782 | source = "registry+https://github.com/rust-lang/crates.io-index" 783 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 784 | dependencies = [ 785 | "getrandom", 786 | ] 787 | 788 | [[package]] 789 | name = "rustversion" 790 | version = "1.0.9" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8" 793 | 794 | [[package]] 795 | name = "ryu" 796 | version = "1.0.3" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" 799 | 800 | [[package]] 801 | name = "scoped-tls" 802 | version = "1.0.0" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" 805 | 806 | [[package]] 807 | name = "serde" 808 | version = "1.0.106" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" 811 | dependencies = [ 812 | "serde_derive", 813 | ] 814 | 815 | [[package]] 816 | name = "serde-wasm-bindgen" 817 | version = "0.3.1" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "618365e8e586c22123d692b72a7d791d5ee697817b65a218cdf12a98870af0f7" 820 | dependencies = [ 821 | "fnv", 822 | "js-sys", 823 | "serde", 824 | "wasm-bindgen", 825 | ] 826 | 827 | [[package]] 828 | name = "serde_derive" 829 | version = "1.0.106" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" 832 | dependencies = [ 833 | "proc-macro2 1.0.47", 834 | "quote 1.0.3", 835 | "syn", 836 | ] 837 | 838 | [[package]] 839 | name = "serde_json" 840 | version = "1.0.51" 841 | source = "registry+https://github.com/rust-lang/crates.io-index" 842 | checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" 843 | dependencies = [ 844 | "itoa 0.4.5", 845 | "ryu", 846 | "serde", 847 | ] 848 | 849 | [[package]] 850 | name = "serde_urlencoded" 851 | version = "0.7.1" 852 | source = "registry+https://github.com/rust-lang/crates.io-index" 853 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 854 | dependencies = [ 855 | "form_urlencoded", 856 | "itoa 1.0.4", 857 | "ryu", 858 | "serde", 859 | ] 860 | 861 | [[package]] 862 | name = "slab" 863 | version = "0.4.2" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 866 | 867 | [[package]] 868 | name = "strum" 869 | version = "0.24.1" 870 | source = "registry+https://github.com/rust-lang/crates.io-index" 871 | checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" 872 | 873 | [[package]] 874 | name = "strum_macros" 875 | version = "0.24.3" 876 | source = "registry+https://github.com/rust-lang/crates.io-index" 877 | checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" 878 | dependencies = [ 879 | "heck", 880 | "proc-macro2 1.0.47", 881 | "quote 1.0.3", 882 | "rustversion", 883 | "syn", 884 | ] 885 | 886 | [[package]] 887 | name = "syn" 888 | version = "1.0.103" 889 | source = "registry+https://github.com/rust-lang/crates.io-index" 890 | checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" 891 | dependencies = [ 892 | "proc-macro2 1.0.47", 893 | "quote 1.0.3", 894 | "unicode-ident", 895 | ] 896 | 897 | [[package]] 898 | name = "thiserror" 899 | version = "1.0.37" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" 902 | dependencies = [ 903 | "thiserror-impl", 904 | ] 905 | 906 | [[package]] 907 | name = "thiserror-impl" 908 | version = "1.0.37" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" 911 | dependencies = [ 912 | "proc-macro2 1.0.47", 913 | "quote 1.0.3", 914 | "syn", 915 | ] 916 | 917 | [[package]] 918 | name = "tokio" 919 | version = "1.22.0" 920 | source = "registry+https://github.com/rust-lang/crates.io-index" 921 | checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" 922 | dependencies = [ 923 | "autocfg", 924 | "pin-project-lite", 925 | ] 926 | 927 | [[package]] 928 | name = "tokio-stream" 929 | version = "0.1.11" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" 932 | dependencies = [ 933 | "futures-core", 934 | "pin-project-lite", 935 | "tokio", 936 | ] 937 | 938 | [[package]] 939 | name = "tracing" 940 | version = "0.1.37" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" 943 | dependencies = [ 944 | "cfg-if 1.0.0", 945 | "pin-project-lite", 946 | "tracing-attributes", 947 | "tracing-core", 948 | ] 949 | 950 | [[package]] 951 | name = "tracing-attributes" 952 | version = "0.1.23" 953 | source = "registry+https://github.com/rust-lang/crates.io-index" 954 | checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" 955 | dependencies = [ 956 | "proc-macro2 1.0.47", 957 | "quote 1.0.3", 958 | "syn", 959 | ] 960 | 961 | [[package]] 962 | name = "tracing-core" 963 | version = "0.1.30" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" 966 | dependencies = [ 967 | "once_cell", 968 | ] 969 | 970 | [[package]] 971 | name = "unicode-ident" 972 | version = "1.0.5" 973 | source = "registry+https://github.com/rust-lang/crates.io-index" 974 | checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" 975 | 976 | [[package]] 977 | name = "unicode-xid" 978 | version = "0.1.0" 979 | source = "registry+https://github.com/rust-lang/crates.io-index" 980 | checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" 981 | 982 | [[package]] 983 | name = "version_check" 984 | version = "0.9.4" 985 | source = "registry+https://github.com/rust-lang/crates.io-index" 986 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" 987 | 988 | [[package]] 989 | name = "wasi" 990 | version = "0.11.0+wasi-snapshot-preview1" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 993 | 994 | [[package]] 995 | name = "wasm-bindgen" 996 | version = "0.2.83" 997 | source = "registry+https://github.com/rust-lang/crates.io-index" 998 | checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" 999 | dependencies = [ 1000 | "cfg-if 1.0.0", 1001 | "serde", 1002 | "serde_json", 1003 | "wasm-bindgen-macro", 1004 | ] 1005 | 1006 | [[package]] 1007 | name = "wasm-bindgen-backend" 1008 | version = "0.2.83" 1009 | source = "registry+https://github.com/rust-lang/crates.io-index" 1010 | checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" 1011 | dependencies = [ 1012 | "bumpalo", 1013 | "log", 1014 | "once_cell", 1015 | "proc-macro2 1.0.47", 1016 | "quote 1.0.3", 1017 | "syn", 1018 | "wasm-bindgen-shared", 1019 | ] 1020 | 1021 | [[package]] 1022 | name = "wasm-bindgen-futures" 1023 | version = "0.3.27" 1024 | source = "registry+https://github.com/rust-lang/crates.io-index" 1025 | checksum = "83420b37346c311b9ed822af41ec2e82839bfe99867ec6c54e2da43b7538771c" 1026 | dependencies = [ 1027 | "cfg-if 0.1.10", 1028 | "futures 0.1.29", 1029 | "js-sys", 1030 | "wasm-bindgen", 1031 | "web-sys", 1032 | ] 1033 | 1034 | [[package]] 1035 | name = "wasm-bindgen-futures" 1036 | version = "0.4.10" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "7add542ea1ac7fdaa9dc25e031a6af33b7d63376292bd24140c637d00d1c312a" 1039 | dependencies = [ 1040 | "cfg-if 0.1.10", 1041 | "js-sys", 1042 | "wasm-bindgen", 1043 | "web-sys", 1044 | ] 1045 | 1046 | [[package]] 1047 | name = "wasm-bindgen-macro" 1048 | version = "0.2.83" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" 1051 | dependencies = [ 1052 | "quote 1.0.3", 1053 | "wasm-bindgen-macro-support", 1054 | ] 1055 | 1056 | [[package]] 1057 | name = "wasm-bindgen-macro-support" 1058 | version = "0.2.83" 1059 | source = "registry+https://github.com/rust-lang/crates.io-index" 1060 | checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" 1061 | dependencies = [ 1062 | "proc-macro2 1.0.47", 1063 | "quote 1.0.3", 1064 | "syn", 1065 | "wasm-bindgen-backend", 1066 | "wasm-bindgen-shared", 1067 | ] 1068 | 1069 | [[package]] 1070 | name = "wasm-bindgen-shared" 1071 | version = "0.2.83" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" 1074 | 1075 | [[package]] 1076 | name = "wasm-bindgen-test" 1077 | version = "0.2.50" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "a2d9693b63a742d481c7f80587e057920e568317b2806988c59cd71618bc26c1" 1080 | dependencies = [ 1081 | "console_error_panic_hook", 1082 | "futures 0.1.29", 1083 | "js-sys", 1084 | "scoped-tls", 1085 | "wasm-bindgen", 1086 | "wasm-bindgen-futures 0.3.27", 1087 | "wasm-bindgen-test-macro", 1088 | ] 1089 | 1090 | [[package]] 1091 | name = "wasm-bindgen-test-macro" 1092 | version = "0.2.50" 1093 | source = "registry+https://github.com/rust-lang/crates.io-index" 1094 | checksum = "0789dac148a8840bbcf9efe13905463b733fa96543bfbf263790535c11af7ba5" 1095 | dependencies = [ 1096 | "proc-macro2 0.4.30", 1097 | "quote 0.6.13", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "web-sys" 1102 | version = "0.3.60" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" 1105 | dependencies = [ 1106 | "js-sys", 1107 | "wasm-bindgen", 1108 | ] 1109 | 1110 | [[package]] 1111 | name = "winapi" 1112 | version = "0.3.8" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 1115 | dependencies = [ 1116 | "winapi-i686-pc-windows-gnu", 1117 | "winapi-x86_64-pc-windows-gnu", 1118 | ] 1119 | 1120 | [[package]] 1121 | name = "winapi-i686-pc-windows-gnu" 1122 | version = "0.4.0" 1123 | source = "registry+https://github.com/rust-lang/crates.io-index" 1124 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 1125 | 1126 | [[package]] 1127 | name = "winapi-x86_64-pc-windows-gnu" 1128 | version = "0.4.0" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1131 | 1132 | [[package]] 1133 | name = "yansi" 1134 | version = "0.5.1" 1135 | source = "registry+https://github.com/rust-lang/crates.io-index" 1136 | checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" 1137 | 1138 | [[package]] 1139 | name = "yew" 1140 | version = "0.20.0" 1141 | source = "registry+https://github.com/rust-lang/crates.io-index" 1142 | checksum = "5dbecfe44343b70cc2932c3eb445425969ae21754a8ab3a0966981c1cf7af1cc" 1143 | dependencies = [ 1144 | "console_error_panic_hook", 1145 | "futures 0.3.25", 1146 | "gloo 0.8.0", 1147 | "implicit-clone", 1148 | "indexmap", 1149 | "js-sys", 1150 | "prokio", 1151 | "rustversion", 1152 | "serde", 1153 | "slab", 1154 | "thiserror", 1155 | "tokio", 1156 | "tracing", 1157 | "wasm-bindgen", 1158 | "wasm-bindgen-futures 0.4.10", 1159 | "web-sys", 1160 | "yew-macro", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "yew-macro" 1165 | version = "0.20.0" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "b64c253c1d401f1ea868ca9988db63958cfa15a69f739101f338d6f05eea8301" 1168 | dependencies = [ 1169 | "boolinator", 1170 | "once_cell", 1171 | "prettyplease", 1172 | "proc-macro-error", 1173 | "proc-macro2 1.0.47", 1174 | "quote 1.0.3", 1175 | "syn", 1176 | ] 1177 | -------------------------------------------------------------------------------- /docs/pkg/minesweeper.js: -------------------------------------------------------------------------------- 1 | 2 | let wasm; 3 | 4 | const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); 5 | 6 | cachedTextDecoder.decode(); 7 | 8 | let cachedUint8Memory0 = new Uint8Array(); 9 | 10 | function getUint8Memory0() { 11 | if (cachedUint8Memory0.byteLength === 0) { 12 | cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); 13 | } 14 | return cachedUint8Memory0; 15 | } 16 | 17 | function getStringFromWasm0(ptr, len) { 18 | return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); 19 | } 20 | 21 | const heap = new Array(32).fill(undefined); 22 | 23 | heap.push(undefined, null, true, false); 24 | 25 | let heap_next = heap.length; 26 | 27 | function addHeapObject(obj) { 28 | if (heap_next === heap.length) heap.push(heap.length + 1); 29 | const idx = heap_next; 30 | heap_next = heap[idx]; 31 | 32 | if (typeof(heap_next) !== 'number') throw new Error('corrupt heap'); 33 | 34 | heap[idx] = obj; 35 | return idx; 36 | } 37 | 38 | function getObject(idx) { return heap[idx]; } 39 | 40 | function _assertBoolean(n) { 41 | if (typeof(n) !== 'boolean') { 42 | throw new Error('expected a boolean argument'); 43 | } 44 | } 45 | 46 | function dropObject(idx) { 47 | if (idx < 36) return; 48 | heap[idx] = heap_next; 49 | heap_next = idx; 50 | } 51 | 52 | function takeObject(idx) { 53 | const ret = getObject(idx); 54 | dropObject(idx); 55 | return ret; 56 | } 57 | 58 | function debugString(val) { 59 | // primitive types 60 | const type = typeof val; 61 | if (type == 'number' || type == 'boolean' || val == null) { 62 | return `${val}`; 63 | } 64 | if (type == 'string') { 65 | return `"${val}"`; 66 | } 67 | if (type == 'symbol') { 68 | const description = val.description; 69 | if (description == null) { 70 | return 'Symbol'; 71 | } else { 72 | return `Symbol(${description})`; 73 | } 74 | } 75 | if (type == 'function') { 76 | const name = val.name; 77 | if (typeof name == 'string' && name.length > 0) { 78 | return `Function(${name})`; 79 | } else { 80 | return 'Function'; 81 | } 82 | } 83 | // objects 84 | if (Array.isArray(val)) { 85 | const length = val.length; 86 | let debug = '['; 87 | if (length > 0) { 88 | debug += debugString(val[0]); 89 | } 90 | for(let i = 1; i < length; i++) { 91 | debug += ', ' + debugString(val[i]); 92 | } 93 | debug += ']'; 94 | return debug; 95 | } 96 | // Test for built-in 97 | const builtInMatches = /\[object ([^\]]+)\]/.exec(toString.call(val)); 98 | let className; 99 | if (builtInMatches.length > 1) { 100 | className = builtInMatches[1]; 101 | } else { 102 | // Failed to match the standard '[object ClassName]' 103 | return toString.call(val); 104 | } 105 | if (className == 'Object') { 106 | // we're a user defined class or Object 107 | // JSON.stringify avoids problems with cycles, and is generally much 108 | // easier than looping through ownProperties of `val`. 109 | try { 110 | return 'Object(' + JSON.stringify(val) + ')'; 111 | } catch (_) { 112 | return 'Object'; 113 | } 114 | } 115 | // errors 116 | if (val instanceof Error) { 117 | return `${val.name}: ${val.message}\n${val.stack}`; 118 | } 119 | // TODO we could test for more things here, like `Set`s and `Map`s. 120 | return className; 121 | } 122 | 123 | let WASM_VECTOR_LEN = 0; 124 | 125 | const cachedTextEncoder = new TextEncoder('utf-8'); 126 | 127 | const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' 128 | ? function (arg, view) { 129 | return cachedTextEncoder.encodeInto(arg, view); 130 | } 131 | : function (arg, view) { 132 | const buf = cachedTextEncoder.encode(arg); 133 | view.set(buf); 134 | return { 135 | read: arg.length, 136 | written: buf.length 137 | }; 138 | }); 139 | 140 | function passStringToWasm0(arg, malloc, realloc) { 141 | 142 | if (typeof(arg) !== 'string') throw new Error('expected a string argument'); 143 | 144 | if (realloc === undefined) { 145 | const buf = cachedTextEncoder.encode(arg); 146 | const ptr = malloc(buf.length); 147 | getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); 148 | WASM_VECTOR_LEN = buf.length; 149 | return ptr; 150 | } 151 | 152 | let len = arg.length; 153 | let ptr = malloc(len); 154 | 155 | const mem = getUint8Memory0(); 156 | 157 | let offset = 0; 158 | 159 | for (; offset < len; offset++) { 160 | const code = arg.charCodeAt(offset); 161 | if (code > 0x7F) break; 162 | mem[ptr + offset] = code; 163 | } 164 | 165 | if (offset !== len) { 166 | if (offset !== 0) { 167 | arg = arg.slice(offset); 168 | } 169 | ptr = realloc(ptr, len, len = offset + arg.length * 3); 170 | const view = getUint8Memory0().subarray(ptr + offset, ptr + len); 171 | const ret = encodeString(arg, view); 172 | if (ret.read !== arg.length) throw new Error('failed to pass whole string'); 173 | offset += ret.written; 174 | } 175 | 176 | WASM_VECTOR_LEN = offset; 177 | return ptr; 178 | } 179 | 180 | let cachedInt32Memory0 = new Int32Array(); 181 | 182 | function getInt32Memory0() { 183 | if (cachedInt32Memory0.byteLength === 0) { 184 | cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); 185 | } 186 | return cachedInt32Memory0; 187 | } 188 | 189 | function makeMutClosure(arg0, arg1, dtor, f) { 190 | const state = { a: arg0, b: arg1, cnt: 1, dtor }; 191 | const real = (...args) => { 192 | // First up with a closure we increment the internal reference 193 | // count. This ensures that the Rust closure environment won't 194 | // be deallocated while we're invoking it. 195 | state.cnt++; 196 | const a = state.a; 197 | state.a = 0; 198 | try { 199 | return f(a, state.b, ...args); 200 | } finally { 201 | if (--state.cnt === 0) { 202 | wasm.__wbindgen_export_2.get(state.dtor)(a, state.b); 203 | 204 | } else { 205 | state.a = a; 206 | } 207 | } 208 | }; 209 | real.original = state; 210 | 211 | return real; 212 | } 213 | 214 | function logError(f, args) { 215 | try { 216 | return f.apply(this, args); 217 | } catch (e) { 218 | let error = (function () { 219 | try { 220 | return e instanceof Error ? `${e.message}\n\nStack:\n${e.stack}` : e.toString(); 221 | } catch(_) { 222 | return ""; 223 | } 224 | }()); 225 | console.error("wasm-bindgen: imported JS function that was not marked as `catch` threw an error:", error); 226 | throw e; 227 | } 228 | } 229 | 230 | function _assertNum(n) { 231 | if (typeof(n) !== 'number') throw new Error('expected a number argument'); 232 | } 233 | function __wbg_adapter_26(arg0, arg1) { 234 | _assertNum(arg0); 235 | _assertNum(arg1); 236 | wasm._dyn_core__ops__function__FnMut_____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__h5ed4b4b85ddfbb0a(arg0, arg1); 237 | } 238 | 239 | function __wbg_adapter_29(arg0, arg1, arg2) { 240 | _assertNum(arg0); 241 | _assertNum(arg1); 242 | wasm._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb55b0760ea278817(arg0, arg1, addHeapObject(arg2)); 243 | } 244 | 245 | let stack_pointer = 32; 246 | 247 | function addBorrowedObject(obj) { 248 | if (stack_pointer == 1) throw new Error('out of js stack'); 249 | heap[--stack_pointer] = obj; 250 | return stack_pointer; 251 | } 252 | function __wbg_adapter_32(arg0, arg1, arg2) { 253 | try { 254 | _assertNum(arg0); 255 | _assertNum(arg1); 256 | wasm._dyn_core__ops__function__FnMut___A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__invoke__hb7f91896e3086b5b(arg0, arg1, addBorrowedObject(arg2)); 257 | } finally { 258 | heap[stack_pointer++] = undefined; 259 | } 260 | } 261 | 262 | /** 263 | */ 264 | export function main() { 265 | wasm.main(); 266 | } 267 | 268 | let cachedUint32Memory0 = new Uint32Array(); 269 | 270 | function getUint32Memory0() { 271 | if (cachedUint32Memory0.byteLength === 0) { 272 | cachedUint32Memory0 = new Uint32Array(wasm.memory.buffer); 273 | } 274 | return cachedUint32Memory0; 275 | } 276 | 277 | function getArrayJsValueFromWasm0(ptr, len) { 278 | const mem = getUint32Memory0(); 279 | const slice = mem.subarray(ptr / 4, ptr / 4 + len); 280 | const result = []; 281 | for (let i = 0; i < slice.length; i++) { 282 | result.push(takeObject(slice[i])); 283 | } 284 | return result; 285 | } 286 | 287 | function handleError(f, args) { 288 | try { 289 | return f.apply(this, args); 290 | } catch (e) { 291 | wasm.__wbindgen_exn_store(addHeapObject(e)); 292 | } 293 | } 294 | 295 | function getArrayU8FromWasm0(ptr, len) { 296 | return getUint8Memory0().subarray(ptr / 1, ptr / 1 + len); 297 | } 298 | 299 | function isLikeNone(x) { 300 | return x === undefined || x === null; 301 | } 302 | 303 | async function load(module, imports) { 304 | if (typeof Response === 'function' && module instanceof Response) { 305 | if (typeof WebAssembly.instantiateStreaming === 'function') { 306 | try { 307 | return await WebAssembly.instantiateStreaming(module, imports); 308 | 309 | } catch (e) { 310 | if (module.headers.get('Content-Type') != 'application/wasm') { 311 | console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); 312 | 313 | } else { 314 | throw e; 315 | } 316 | } 317 | } 318 | 319 | const bytes = await module.arrayBuffer(); 320 | return await WebAssembly.instantiate(bytes, imports); 321 | 322 | } else { 323 | const instance = await WebAssembly.instantiate(module, imports); 324 | 325 | if (instance instanceof WebAssembly.Instance) { 326 | return { instance, module }; 327 | 328 | } else { 329 | return instance; 330 | } 331 | } 332 | } 333 | 334 | function getImports() { 335 | const imports = {}; 336 | imports.wbg = {}; 337 | imports.wbg.__wbindgen_string_new = function(arg0, arg1) { 338 | const ret = getStringFromWasm0(arg0, arg1); 339 | return addHeapObject(ret); 340 | }; 341 | imports.wbg.__wbg_log_88553661525565c0 = function() { return logError(function (arg0, arg1) { 342 | var v0 = getArrayJsValueFromWasm0(arg0, arg1).slice(); 343 | wasm.__wbindgen_free(arg0, arg1 * 4); 344 | console.log(...v0); 345 | }, arguments) }; 346 | imports.wbg.__wbindgen_is_object = function(arg0) { 347 | const val = getObject(arg0); 348 | const ret = typeof(val) === 'object' && val !== null; 349 | _assertBoolean(ret); 350 | return ret; 351 | }; 352 | imports.wbg.__wbindgen_is_string = function(arg0) { 353 | const ret = typeof(getObject(arg0)) === 'string'; 354 | _assertBoolean(ret); 355 | return ret; 356 | }; 357 | imports.wbg.__wbg_crypto_e1d53a1d73fb10b8 = function() { return logError(function (arg0) { 358 | const ret = getObject(arg0).crypto; 359 | return addHeapObject(ret); 360 | }, arguments) }; 361 | imports.wbg.__wbg_msCrypto_6e7d3e1f92610cbb = function() { return logError(function (arg0) { 362 | const ret = getObject(arg0).msCrypto; 363 | return addHeapObject(ret); 364 | }, arguments) }; 365 | imports.wbg.__wbg_getRandomValues_805f1c3d65988a5a = function() { return handleError(function (arg0, arg1) { 366 | getObject(arg0).getRandomValues(getObject(arg1)); 367 | }, arguments) }; 368 | imports.wbg.__wbg_randomFillSync_6894564c2c334c42 = function() { return handleError(function (arg0, arg1, arg2) { 369 | getObject(arg0).randomFillSync(getArrayU8FromWasm0(arg1, arg2)); 370 | }, arguments) }; 371 | imports.wbg.__wbg_require_78a3dcfbdba9cbce = function() { return handleError(function () { 372 | const ret = module.require; 373 | return addHeapObject(ret); 374 | }, arguments) }; 375 | imports.wbg.__wbg_process_038c26bf42b093f8 = function() { return logError(function (arg0) { 376 | const ret = getObject(arg0).process; 377 | return addHeapObject(ret); 378 | }, arguments) }; 379 | imports.wbg.__wbg_versions_ab37218d2f0b24a8 = function() { return logError(function (arg0) { 380 | const ret = getObject(arg0).versions; 381 | return addHeapObject(ret); 382 | }, arguments) }; 383 | imports.wbg.__wbg_node_080f4b19d15bc1fe = function() { return logError(function (arg0) { 384 | const ret = getObject(arg0).node; 385 | return addHeapObject(ret); 386 | }, arguments) }; 387 | imports.wbg.__wbindgen_object_clone_ref = function(arg0) { 388 | const ret = getObject(arg0); 389 | return addHeapObject(ret); 390 | }; 391 | imports.wbg.__wbg_listenerid_12315eee21527820 = function() { return logError(function (arg0, arg1) { 392 | const ret = getObject(arg1).__yew_listener_id; 393 | if (!isLikeNone(ret)) { 394 | _assertNum(ret); 395 | } 396 | getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; 397 | getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); 398 | }, arguments) }; 399 | imports.wbg.__wbg_setlistenerid_3183aae8fa5840fb = function() { return logError(function (arg0, arg1) { 400 | getObject(arg0).__yew_listener_id = arg1 >>> 0; 401 | }, arguments) }; 402 | imports.wbg.__wbg_subtreeid_e348577f7ef777e3 = function() { return logError(function (arg0, arg1) { 403 | const ret = getObject(arg1).__yew_subtree_id; 404 | if (!isLikeNone(ret)) { 405 | _assertNum(ret); 406 | } 407 | getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; 408 | getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); 409 | }, arguments) }; 410 | imports.wbg.__wbg_setsubtreeid_d32e6327eef1f7fc = function() { return logError(function (arg0, arg1) { 411 | getObject(arg0).__yew_subtree_id = arg1 >>> 0; 412 | }, arguments) }; 413 | imports.wbg.__wbg_cachekey_b61393159c57fd7b = function() { return logError(function (arg0, arg1) { 414 | const ret = getObject(arg1).__yew_subtree_cache_key; 415 | if (!isLikeNone(ret)) { 416 | _assertNum(ret); 417 | } 418 | getInt32Memory0()[arg0 / 4 + 1] = isLikeNone(ret) ? 0 : ret; 419 | getInt32Memory0()[arg0 / 4 + 0] = !isLikeNone(ret); 420 | }, arguments) }; 421 | imports.wbg.__wbg_setcachekey_80183b7cfc421143 = function() { return logError(function (arg0, arg1) { 422 | getObject(arg0).__yew_subtree_cache_key = arg1 >>> 0; 423 | }, arguments) }; 424 | imports.wbg.__wbindgen_object_drop_ref = function(arg0) { 425 | takeObject(arg0); 426 | }; 427 | imports.wbg.__wbg_error_f7214ae7db04600c = function() { return logError(function (arg0, arg1) { 428 | try { 429 | console.error(getStringFromWasm0(arg0, arg1)); 430 | } finally { 431 | wasm.__wbindgen_free(arg0, arg1); 432 | } 433 | }, arguments) }; 434 | imports.wbg.__wbg_new_a99726b0abef495b = function() { return logError(function () { 435 | const ret = new Error(); 436 | return addHeapObject(ret); 437 | }, arguments) }; 438 | imports.wbg.__wbg_stack_4931b18709aff089 = function() { return logError(function (arg0, arg1) { 439 | const ret = getObject(arg1).stack; 440 | const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 441 | const len0 = WASM_VECTOR_LEN; 442 | getInt32Memory0()[arg0 / 4 + 1] = len0; 443 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 444 | }, arguments) }; 445 | imports.wbg.__wbindgen_is_undefined = function(arg0) { 446 | const ret = getObject(arg0) === undefined; 447 | _assertBoolean(ret); 448 | return ret; 449 | }; 450 | imports.wbg.__wbg_Window_fb1ff292e1d47c10 = function() { return logError(function (arg0) { 451 | const ret = getObject(arg0).Window; 452 | return addHeapObject(ret); 453 | }, arguments) }; 454 | imports.wbg.__wbg_WorkerGlobalScope_32b0cdb58df54a5e = function() { return logError(function (arg0) { 455 | const ret = getObject(arg0).WorkerGlobalScope; 456 | return addHeapObject(ret); 457 | }, arguments) }; 458 | imports.wbg.__wbindgen_cb_drop = function(arg0) { 459 | const obj = takeObject(arg0).original; 460 | if (obj.cnt-- == 1) { 461 | obj.a = 0; 462 | return true; 463 | } 464 | const ret = false; 465 | _assertBoolean(ret); 466 | return ret; 467 | }; 468 | imports.wbg.__wbg_error_71d6845bf00a930f = function() { return logError(function (arg0, arg1) { 469 | var v0 = getArrayJsValueFromWasm0(arg0, arg1).slice(); 470 | wasm.__wbindgen_free(arg0, arg1 * 4); 471 | console.error(...v0); 472 | }, arguments) }; 473 | imports.wbg.__wbg_instanceof_Window_acc97ff9f5d2c7b4 = function() { return logError(function (arg0) { 474 | let result; 475 | try { 476 | result = getObject(arg0) instanceof Window; 477 | } catch { 478 | result = false; 479 | } 480 | const ret = result; 481 | _assertBoolean(ret); 482 | return ret; 483 | }, arguments) }; 484 | imports.wbg.__wbg_document_3ead31dbcad65886 = function() { return logError(function (arg0) { 485 | const ret = getObject(arg0).document; 486 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 487 | }, arguments) }; 488 | imports.wbg.__wbg_clearInterval_9d8e1ff2b921f41f = function() { return logError(function (arg0, arg1) { 489 | getObject(arg0).clearInterval(arg1); 490 | }, arguments) }; 491 | imports.wbg.__wbg_setInterval_b6f2e23785929613 = function() { return handleError(function (arg0, arg1, arg2) { 492 | const ret = getObject(arg0).setInterval(getObject(arg1), arg2); 493 | _assertNum(ret); 494 | return ret; 495 | }, arguments) }; 496 | imports.wbg.__wbg_body_3cb4b4042b9a632b = function() { return logError(function (arg0) { 497 | const ret = getObject(arg0).body; 498 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 499 | }, arguments) }; 500 | imports.wbg.__wbg_createElement_976dbb84fe1661b5 = function() { return handleError(function (arg0, arg1, arg2) { 501 | const ret = getObject(arg0).createElement(getStringFromWasm0(arg1, arg2)); 502 | return addHeapObject(ret); 503 | }, arguments) }; 504 | imports.wbg.__wbg_createElementNS_1561aca8ee3693c0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { 505 | const ret = getObject(arg0).createElementNS(arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); 506 | return addHeapObject(ret); 507 | }, arguments) }; 508 | imports.wbg.__wbg_createTextNode_300f845fab76642f = function() { return logError(function (arg0, arg1, arg2) { 509 | const ret = getObject(arg0).createTextNode(getStringFromWasm0(arg1, arg2)); 510 | return addHeapObject(ret); 511 | }, arguments) }; 512 | imports.wbg.__wbg_parentNode_e397bbbe28be7b28 = function() { return logError(function (arg0) { 513 | const ret = getObject(arg0).parentNode; 514 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 515 | }, arguments) }; 516 | imports.wbg.__wbg_parentElement_0cffb3ceb0f107bd = function() { return logError(function (arg0) { 517 | const ret = getObject(arg0).parentElement; 518 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 519 | }, arguments) }; 520 | imports.wbg.__wbg_lastChild_a2f5ed739809bb31 = function() { return logError(function (arg0) { 521 | const ret = getObject(arg0).lastChild; 522 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 523 | }, arguments) }; 524 | imports.wbg.__wbg_nextSibling_62338ec2a05607b4 = function() { return logError(function (arg0) { 525 | const ret = getObject(arg0).nextSibling; 526 | return isLikeNone(ret) ? 0 : addHeapObject(ret); 527 | }, arguments) }; 528 | imports.wbg.__wbg_setnodeValue_4077cafeefd0725e = function() { return logError(function (arg0, arg1, arg2) { 529 | getObject(arg0).nodeValue = arg1 === 0 ? undefined : getStringFromWasm0(arg1, arg2); 530 | }, arguments) }; 531 | imports.wbg.__wbg_textContent_77bd294928962f93 = function() { return logError(function (arg0, arg1) { 532 | const ret = getObject(arg1).textContent; 533 | var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 534 | var len0 = WASM_VECTOR_LEN; 535 | getInt32Memory0()[arg0 / 4 + 1] = len0; 536 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 537 | }, arguments) }; 538 | imports.wbg.__wbg_appendChild_e513ef0e5098dfdd = function() { return handleError(function (arg0, arg1) { 539 | const ret = getObject(arg0).appendChild(getObject(arg1)); 540 | return addHeapObject(ret); 541 | }, arguments) }; 542 | imports.wbg.__wbg_insertBefore_9f2d2defb9471006 = function() { return handleError(function (arg0, arg1, arg2) { 543 | const ret = getObject(arg0).insertBefore(getObject(arg1), getObject(arg2)); 544 | return addHeapObject(ret); 545 | }, arguments) }; 546 | imports.wbg.__wbg_removeChild_6751e9ca5d9aaf00 = function() { return handleError(function (arg0, arg1) { 547 | const ret = getObject(arg0).removeChild(getObject(arg1)); 548 | return addHeapObject(ret); 549 | }, arguments) }; 550 | imports.wbg.__wbg_instanceof_ShadowRoot_76b32ccdae10a710 = function() { return logError(function (arg0) { 551 | let result; 552 | try { 553 | result = getObject(arg0) instanceof ShadowRoot; 554 | } catch { 555 | result = false; 556 | } 557 | const ret = result; 558 | _assertBoolean(ret); 559 | return ret; 560 | }, arguments) }; 561 | imports.wbg.__wbg_host_57eec05a2624bc1b = function() { return logError(function (arg0) { 562 | const ret = getObject(arg0).host; 563 | return addHeapObject(ret); 564 | }, arguments) }; 565 | imports.wbg.__wbg_value_ccb32485ee1b3928 = function() { return logError(function (arg0, arg1) { 566 | const ret = getObject(arg1).value; 567 | const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 568 | const len0 = WASM_VECTOR_LEN; 569 | getInt32Memory0()[arg0 / 4 + 1] = len0; 570 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 571 | }, arguments) }; 572 | imports.wbg.__wbg_setvalue_df64bc6794c098f2 = function() { return logError(function (arg0, arg1, arg2) { 573 | getObject(arg0).value = getStringFromWasm0(arg1, arg2); 574 | }, arguments) }; 575 | imports.wbg.__wbg_instanceof_Element_33bd126d58f2021b = function() { return logError(function (arg0) { 576 | let result; 577 | try { 578 | result = getObject(arg0) instanceof Element; 579 | } catch { 580 | result = false; 581 | } 582 | const ret = result; 583 | _assertBoolean(ret); 584 | return ret; 585 | }, arguments) }; 586 | imports.wbg.__wbg_namespaceURI_e19c7be2c60e5b5c = function() { return logError(function (arg0, arg1) { 587 | const ret = getObject(arg1).namespaceURI; 588 | var ptr0 = isLikeNone(ret) ? 0 : passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 589 | var len0 = WASM_VECTOR_LEN; 590 | getInt32Memory0()[arg0 / 4 + 1] = len0; 591 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 592 | }, arguments) }; 593 | imports.wbg.__wbg_setinnerHTML_32081d8a164e6dc4 = function() { return logError(function (arg0, arg1, arg2) { 594 | getObject(arg0).innerHTML = getStringFromWasm0(arg1, arg2); 595 | }, arguments) }; 596 | imports.wbg.__wbg_outerHTML_bf662bdff92e5910 = function() { return logError(function (arg0, arg1) { 597 | const ret = getObject(arg1).outerHTML; 598 | const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 599 | const len0 = WASM_VECTOR_LEN; 600 | getInt32Memory0()[arg0 / 4 + 1] = len0; 601 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 602 | }, arguments) }; 603 | imports.wbg.__wbg_children_67776b4810f38b6a = function() { return logError(function (arg0) { 604 | const ret = getObject(arg0).children; 605 | return addHeapObject(ret); 606 | }, arguments) }; 607 | imports.wbg.__wbg_removeAttribute_beaed7727852af78 = function() { return handleError(function (arg0, arg1, arg2) { 608 | getObject(arg0).removeAttribute(getStringFromWasm0(arg1, arg2)); 609 | }, arguments) }; 610 | imports.wbg.__wbg_setAttribute_d8436c14a59ab1af = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { 611 | getObject(arg0).setAttribute(getStringFromWasm0(arg1, arg2), getStringFromWasm0(arg3, arg4)); 612 | }, arguments) }; 613 | imports.wbg.__wbg_bubbles_03eed164b4feeaf1 = function() { return logError(function (arg0) { 614 | const ret = getObject(arg0).bubbles; 615 | _assertBoolean(ret); 616 | return ret; 617 | }, arguments) }; 618 | imports.wbg.__wbg_cancelBubble_8c0bdf21c08f1717 = function() { return logError(function (arg0) { 619 | const ret = getObject(arg0).cancelBubble; 620 | _assertBoolean(ret); 621 | return ret; 622 | }, arguments) }; 623 | imports.wbg.__wbg_composedPath_160ed014dc4d787f = function() { return logError(function (arg0) { 624 | const ret = getObject(arg0).composedPath(); 625 | return addHeapObject(ret); 626 | }, arguments) }; 627 | imports.wbg.__wbg_setchecked_f1e1f3e62cdca8e7 = function() { return logError(function (arg0, arg1) { 628 | getObject(arg0).checked = arg1 !== 0; 629 | }, arguments) }; 630 | imports.wbg.__wbg_value_b2a620d34c663701 = function() { return logError(function (arg0, arg1) { 631 | const ret = getObject(arg1).value; 632 | const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 633 | const len0 = WASM_VECTOR_LEN; 634 | getInt32Memory0()[arg0 / 4 + 1] = len0; 635 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 636 | }, arguments) }; 637 | imports.wbg.__wbg_setvalue_e5b519cca37d82a7 = function() { return logError(function (arg0, arg1, arg2) { 638 | getObject(arg0).value = getStringFromWasm0(arg1, arg2); 639 | }, arguments) }; 640 | imports.wbg.__wbg_addEventListener_1fc744729ac6dc27 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { 641 | getObject(arg0).addEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), getObject(arg4)); 642 | }, arguments) }; 643 | imports.wbg.__wbg_removeEventListener_b10f1a66647f3aa0 = function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) { 644 | getObject(arg0).removeEventListener(getStringFromWasm0(arg1, arg2), getObject(arg3), arg4 !== 0); 645 | }, arguments) }; 646 | imports.wbg.__wbg_clearInterval_4fa7ec3e56ed4164 = function() { return logError(function (arg0, arg1) { 647 | getObject(arg0).clearInterval(arg1); 648 | }, arguments) }; 649 | imports.wbg.__wbg_setInterval_09ab17480e4543ba = function() { return handleError(function (arg0, arg1, arg2) { 650 | const ret = getObject(arg0).setInterval(getObject(arg1), arg2); 651 | _assertNum(ret); 652 | return ret; 653 | }, arguments) }; 654 | imports.wbg.__wbg_get_57245cc7d7c7619d = function() { return logError(function (arg0, arg1) { 655 | const ret = getObject(arg0)[arg1 >>> 0]; 656 | return addHeapObject(ret); 657 | }, arguments) }; 658 | imports.wbg.__wbg_from_7ce3cb27cb258569 = function() { return logError(function (arg0) { 659 | const ret = Array.from(getObject(arg0)); 660 | return addHeapObject(ret); 661 | }, arguments) }; 662 | imports.wbg.__wbg_length_6e3bbe7c8bd4dbd8 = function() { return logError(function (arg0) { 663 | const ret = getObject(arg0).length; 664 | _assertNum(ret); 665 | return ret; 666 | }, arguments) }; 667 | imports.wbg.__wbg_newnoargs_b5b063fc6c2f0376 = function() { return logError(function (arg0, arg1) { 668 | const ret = new Function(getStringFromWasm0(arg0, arg1)); 669 | return addHeapObject(ret); 670 | }, arguments) }; 671 | imports.wbg.__wbg_call_97ae9d8645dc388b = function() { return handleError(function (arg0, arg1) { 672 | const ret = getObject(arg0).call(getObject(arg1)); 673 | return addHeapObject(ret); 674 | }, arguments) }; 675 | imports.wbg.__wbg_call_168da88779e35f61 = function() { return handleError(function (arg0, arg1, arg2) { 676 | const ret = getObject(arg0).call(getObject(arg1), getObject(arg2)); 677 | return addHeapObject(ret); 678 | }, arguments) }; 679 | imports.wbg.__wbg_getTime_cb82adb2556ed13e = function() { return logError(function (arg0) { 680 | const ret = getObject(arg0).getTime(); 681 | return ret; 682 | }, arguments) }; 683 | imports.wbg.__wbg_new0_a57059d72c5b7aee = function() { return logError(function () { 684 | const ret = new Date(); 685 | return addHeapObject(ret); 686 | }, arguments) }; 687 | imports.wbg.__wbg_is_40a66842732708e7 = function() { return logError(function (arg0, arg1) { 688 | const ret = Object.is(getObject(arg0), getObject(arg1)); 689 | _assertBoolean(ret); 690 | return ret; 691 | }, arguments) }; 692 | imports.wbg.__wbg_new_0b9bfdd97583284e = function() { return logError(function () { 693 | const ret = new Object(); 694 | return addHeapObject(ret); 695 | }, arguments) }; 696 | imports.wbg.__wbg_resolve_99fe17964f31ffc0 = function() { return logError(function (arg0) { 697 | const ret = Promise.resolve(getObject(arg0)); 698 | return addHeapObject(ret); 699 | }, arguments) }; 700 | imports.wbg.__wbg_then_11f7a54d67b4bfad = function() { return logError(function (arg0, arg1) { 701 | const ret = getObject(arg0).then(getObject(arg1)); 702 | return addHeapObject(ret); 703 | }, arguments) }; 704 | imports.wbg.__wbg_globalThis_7f206bda628d5286 = function() { return handleError(function () { 705 | const ret = globalThis.globalThis; 706 | return addHeapObject(ret); 707 | }, arguments) }; 708 | imports.wbg.__wbg_self_6d479506f72c6a71 = function() { return handleError(function () { 709 | const ret = self.self; 710 | return addHeapObject(ret); 711 | }, arguments) }; 712 | imports.wbg.__wbg_window_f2557cc78490aceb = function() { return handleError(function () { 713 | const ret = window.window; 714 | return addHeapObject(ret); 715 | }, arguments) }; 716 | imports.wbg.__wbg_global_ba75c50d1cf384f4 = function() { return handleError(function () { 717 | const ret = global.global; 718 | return addHeapObject(ret); 719 | }, arguments) }; 720 | imports.wbg.__wbg_new_8c3f0052272a457a = function() { return logError(function (arg0) { 721 | const ret = new Uint8Array(getObject(arg0)); 722 | return addHeapObject(ret); 723 | }, arguments) }; 724 | imports.wbg.__wbg_newwithlength_f5933855e4f48a19 = function() { return logError(function (arg0) { 725 | const ret = new Uint8Array(arg0 >>> 0); 726 | return addHeapObject(ret); 727 | }, arguments) }; 728 | imports.wbg.__wbg_subarray_58ad4efbb5bcb886 = function() { return logError(function (arg0, arg1, arg2) { 729 | const ret = getObject(arg0).subarray(arg1 >>> 0, arg2 >>> 0); 730 | return addHeapObject(ret); 731 | }, arguments) }; 732 | imports.wbg.__wbg_length_9e1ae1900cb0fbd5 = function() { return logError(function (arg0) { 733 | const ret = getObject(arg0).length; 734 | _assertNum(ret); 735 | return ret; 736 | }, arguments) }; 737 | imports.wbg.__wbg_set_83db9690f9353e79 = function() { return logError(function (arg0, arg1, arg2) { 738 | getObject(arg0).set(getObject(arg1), arg2 >>> 0); 739 | }, arguments) }; 740 | imports.wbg.__wbindgen_is_function = function(arg0) { 741 | const ret = typeof(getObject(arg0)) === 'function'; 742 | _assertBoolean(ret); 743 | return ret; 744 | }; 745 | imports.wbg.__wbg_buffer_3f3d764d4747d564 = function() { return logError(function (arg0) { 746 | const ret = getObject(arg0).buffer; 747 | return addHeapObject(ret); 748 | }, arguments) }; 749 | imports.wbg.__wbg_set_bf3f89b92d5a34bf = function() { return handleError(function (arg0, arg1, arg2) { 750 | const ret = Reflect.set(getObject(arg0), getObject(arg1), getObject(arg2)); 751 | _assertBoolean(ret); 752 | return ret; 753 | }, arguments) }; 754 | imports.wbg.__wbindgen_debug_string = function(arg0, arg1) { 755 | const ret = debugString(getObject(arg1)); 756 | const ptr0 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); 757 | const len0 = WASM_VECTOR_LEN; 758 | getInt32Memory0()[arg0 / 4 + 1] = len0; 759 | getInt32Memory0()[arg0 / 4 + 0] = ptr0; 760 | }; 761 | imports.wbg.__wbindgen_throw = function(arg0, arg1) { 762 | throw new Error(getStringFromWasm0(arg0, arg1)); 763 | }; 764 | imports.wbg.__wbindgen_rethrow = function(arg0) { 765 | throw takeObject(arg0); 766 | }; 767 | imports.wbg.__wbindgen_memory = function() { 768 | const ret = wasm.memory; 769 | return addHeapObject(ret); 770 | }; 771 | imports.wbg.__wbindgen_closure_wrapper4898 = function() { return logError(function (arg0, arg1, arg2) { 772 | const ret = makeMutClosure(arg0, arg1, 326, __wbg_adapter_26); 773 | return addHeapObject(ret); 774 | }, arguments) }; 775 | imports.wbg.__wbindgen_closure_wrapper5013 = function() { return logError(function (arg0, arg1, arg2) { 776 | const ret = makeMutClosure(arg0, arg1, 331, __wbg_adapter_29); 777 | return addHeapObject(ret); 778 | }, arguments) }; 779 | imports.wbg.__wbindgen_closure_wrapper5109 = function() { return logError(function (arg0, arg1, arg2) { 780 | const ret = makeMutClosure(arg0, arg1, 350, __wbg_adapter_32); 781 | return addHeapObject(ret); 782 | }, arguments) }; 783 | 784 | return imports; 785 | } 786 | 787 | function initMemory(imports, maybe_memory) { 788 | 789 | } 790 | 791 | function finalizeInit(instance, module) { 792 | wasm = instance.exports; 793 | init.__wbindgen_wasm_module = module; 794 | cachedInt32Memory0 = new Int32Array(); 795 | cachedUint32Memory0 = new Uint32Array(); 796 | cachedUint8Memory0 = new Uint8Array(); 797 | 798 | wasm.__wbindgen_start(); 799 | return wasm; 800 | } 801 | 802 | function initSync(module) { 803 | const imports = getImports(); 804 | 805 | initMemory(imports); 806 | 807 | if (!(module instanceof WebAssembly.Module)) { 808 | module = new WebAssembly.Module(module); 809 | } 810 | 811 | const instance = new WebAssembly.Instance(module, imports); 812 | 813 | return finalizeInit(instance, module); 814 | } 815 | 816 | async function init(input) { 817 | if (typeof input === 'undefined') { 818 | input = new URL('minesweeper_bg.wasm', import.meta.url); 819 | } 820 | const imports = getImports(); 821 | 822 | if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { 823 | input = fetch(input); 824 | } 825 | 826 | initMemory(imports); 827 | 828 | const { instance, module } = await load(await input, imports); 829 | 830 | return finalizeInit(instance, module); 831 | } 832 | 833 | export { initSync } 834 | export default init; 835 | --------------------------------------------------------------------------------