]> git.seodisparate.com - EN605.607.81.SP22_ASDM_Project/commitdiff
Fix rand not compilable for wasm, impl game logic
authorStephen Seo <seo.disparate@gmail.com>
Wed, 9 Mar 2022 07:22:01 +0000 (16:22 +0900)
committerStephen Seo <seo.disparate@gmail.com>
Wed, 9 Mar 2022 07:26:14 +0000 (16:26 +0900)
"rand" crate was not compilable for wasm-unknown-unknown target, so an
alternative "oorandom" crate was substituted in.

Basic game win/draw detection logic added.

front_end/Cargo.lock
front_end/Cargo.toml
front_end/src/ai.rs
front_end/src/game_logic.rs [new file with mode: 0644]
front_end/src/main.rs
front_end/src/random_helper.rs [new file with mode: 0644]

index 4a61525f0ebc3b2d9e7c454ba84fd62f8ea1659e..e89084f4fb6f186a27189b7059e8b50796b87596 100644 (file)
@@ -41,23 +41,12 @@ name = "four_line_dropper_frontend"
 version = "0.1.0"
 dependencies = [
  "log",
- "rand",
+ "oorandom",
  "wasm-logger",
  "web-sys",
  "yew",
 ]
 
-[[package]]
-name = "getrandom"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
 [[package]]
 name = "gloo"
 version = "0.4.2"
@@ -201,12 +190,6 @@ version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
-[[package]]
-name = "libc"
-version = "0.2.119"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4"
-
 [[package]]
 name = "log"
 version = "0.4.14"
@@ -217,10 +200,10 @@ dependencies = [
 ]
 
 [[package]]
-name = "ppv-lite86"
-version = "0.2.16"
+name = "oorandom"
+version = "11.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872"
+checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
 name = "proc-macro-error"
@@ -264,36 +247,6 @@ dependencies = [
  "proc-macro2",
 ]
 
-[[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7"
-dependencies = [
- "getrandom",
-]
-
 [[package]]
 name = "ryu"
 version = "1.0.9"
@@ -386,12 +339,6 @@ version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 
-[[package]]
-name = "wasi"
-version = "0.10.2+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
-
 [[package]]
 name = "wasm-bindgen"
 version = "0.2.79"
index a089c9a0421987a5277f4a9acc93e58ca26de855..f27b53957cec7a67012f6006297b1ad5202f7486 100644 (file)
@@ -10,4 +10,4 @@ yew = "0.19"
 log = "0.4.6"
 wasm-logger = "0.2.0"
 web-sys = { version = "0.3.56", features = ["Window", "Document", "Element"] }
-rand = "0.8.5"
+oorandom = "11.1.3"
index 7718217912e49d281abd2bc630a5d7435e547f74..05476e8cd0b7acc00e740d3e1c4e64f6b67a3415 100644 (file)
@@ -1,10 +1,9 @@
 use std::collections::BTreeMap;
 
 use crate::constants::{AI_EASY_MAX_CHOICES, AI_NORMAL_MAX_CHOICES, COLS, ROWS};
+use crate::random_helper::get_seeded_random;
 use crate::state::{BoardState, BoardType, Turn};
 
-use rand::{thread_rng, Rng};
-
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
 pub enum AIDifficulty {
     Easy,
@@ -63,6 +62,8 @@ pub fn get_ai_choice(
     player: Turn,
     board: &BoardType,
 ) -> Result<SlotChoice, String> {
+    let mut rng = get_seeded_random()?;
+
     let mut utilities = Vec::with_capacity(COLS as usize);
     for i in 0..(COLS as usize) {
         let slot = i.into();
@@ -82,11 +83,11 @@ pub fn get_ai_choice(
     let mut utilities: Vec<(usize, f64)> = utilities.into_iter().enumerate().collect();
     if utilities.len() > 1 {
         for i in 1..utilities.len() {
-            utilities.swap(i, thread_rng().gen_range(0..=i));
+            utilities.swap(i, rng.rand_range(0..((i + 1) as u32)) as usize);
         }
     }
 
-    let pick_some_of_choices = |amount: usize| -> Result<SlotChoice, String> {
+    let mut pick_some_of_choices = |amount: usize| -> Result<SlotChoice, String> {
         let mut maximums: BTreeMap<i64, usize> = BTreeMap::new();
         for (idx, utility) in &utilities {
             // f64 cannot be used as Key since it doesn't implement Ord.
@@ -94,7 +95,7 @@ pub fn get_ai_choice(
             // order.
             let mut utility_value = (utility * 10000.0) as i64;
             while maximums.contains_key(&utility_value) {
-                utility_value += thread_rng().gen_range(-3..=3);
+                utility_value += rng.rand_range(0..7) as i64 - 3;
             }
             maximums.insert(utility_value, *idx);
         }
@@ -108,7 +109,7 @@ pub fn get_ai_choice(
 
         // don't use random if only 1 item is to be picked
         let random_number: usize = if mod_amount > 1 {
-            thread_rng().gen::<usize>() % mod_amount
+            rng.rand_u32() as usize % mod_amount
         } else {
             0
         };
diff --git a/front_end/src/game_logic.rs b/front_end/src/game_logic.rs
new file mode 100644 (file)
index 0000000..98ab872
--- /dev/null
@@ -0,0 +1,132 @@
+use crate::constants::{COLS, ROWS};
+use crate::state::{BoardState, BoardType};
+
+/// Returns a BoardState if win/draw, None if game is still going
+pub fn check_win_draw(board: &BoardType) -> Option<BoardState> {
+    let mut has_empty_slot = false;
+    for slot in board {
+        match slot.get() {
+            BoardState::Empty => {
+                has_empty_slot = true;
+                break;
+            }
+            BoardState::Cyan | BoardState::Magenta => (),
+        }
+    }
+
+    if has_empty_slot {
+        return None;
+    }
+
+    let check_result = |state| -> Option<BoardState> {
+        match state {
+            BoardState::Empty => None,
+            BoardState::Cyan => Some(BoardState::Cyan),
+            BoardState::Magenta => Some(BoardState::Magenta),
+        }
+    };
+
+    // check horizontals
+    for y in 0..(ROWS as usize) {
+        for x in 0..((COLS - 3) as usize) {
+            let result = check_result(has_right_horizontal_at_idx(x + y * (COLS as usize), board));
+            if result.is_some() {
+                return result;
+            }
+        }
+    }
+
+    // check verticals
+    for y in 0..((ROWS - 3) as usize) {
+        for x in 0..(COLS as usize) {
+            let result = check_result(has_down_vertical_at_idx(x + y * (COLS as usize), board));
+            if result.is_some() {
+                return result;
+            }
+        }
+    }
+
+    // check up diagonals
+    for y in 3..(ROWS as usize) {
+        for x in 0..((COLS - 3) as usize) {
+            let result = check_result(has_right_up_diagonal_at_idx(x + y * (COLS as usize), board));
+            if result.is_some() {
+                return result;
+            }
+        }
+    }
+
+    // check down diagonals
+    for y in 0..((ROWS - 3) as usize) {
+        for x in 0..((COLS - 3) as usize) {
+            let result = check_result(has_right_down_diagonal_at_idx(
+                x + y * (COLS as usize),
+                board,
+            ));
+            if result.is_some() {
+                return result;
+            }
+        }
+    }
+
+    None
+}
+
+fn has_right_horizontal_at_idx(idx: usize, board: &BoardType) -> BoardState {
+    let state_at_idx = board[idx].get();
+    if idx % (COLS as usize) < (COLS as usize) - 3 {
+        for x in 0..=3 {
+            if board[idx + x].get() != state_at_idx {
+                break;
+            } else if x == 3 {
+                return state_at_idx;
+            }
+        }
+    }
+
+    BoardState::Empty
+}
+
+fn has_down_vertical_at_idx(idx: usize, board: &BoardType) -> BoardState {
+    let state_at_idx = board[idx].get();
+    if idx / (COLS as usize) < (ROWS as usize) - 3 {
+        for y in 0..=3 {
+            if board[idx + y * (COLS as usize)].get() != state_at_idx {
+                break;
+            } else if y == 3 {
+                return state_at_idx;
+            }
+        }
+    }
+
+    BoardState::Empty
+}
+
+fn has_right_up_diagonal_at_idx(idx: usize, board: &BoardType) -> BoardState {
+    let state_at_idx = board[idx].get();
+    if idx % (COLS as usize) < (COLS as usize) - 3 && idx / (COLS as usize) > 2 {
+        for i in 0..=3 {
+            if board[idx + i - i * (COLS as usize)].get() != state_at_idx {
+                break;
+            } else if i == 3 {
+                return state_at_idx;
+            }
+        }
+    }
+
+    BoardState::Empty
+}
+
+fn has_right_down_diagonal_at_idx(idx: usize, board: &BoardType) -> BoardState {
+    let state_at_idx = board[idx].get();
+    if idx % (COLS as usize) < (COLS as usize) - 3 && idx / (COLS as usize) < (ROWS as usize) - 3 {
+        for i in 0..=3 {
+            if board[idx + i + i * (COLS as usize)].get() != state_at_idx {
+                break;
+            } else if i == 3 {
+                return state_at_idx;
+            }
+        }
+    }
+    BoardState::Empty
+}
index 947ed491af4445eab71001ab0aa9623db825023b..eeca10f2a360b0c5e4435b4b19169a222a32f09b 100644 (file)
@@ -1,5 +1,7 @@
 mod ai;
 mod constants;
+mod game_logic;
+mod random_helper;
 mod state;
 mod yew_components;
 
diff --git a/front_end/src/random_helper.rs b/front_end/src/random_helper.rs
new file mode 100644 (file)
index 0000000..17bde78
--- /dev/null
@@ -0,0 +1,12 @@
+use oorandom::Rand32;
+
+use std::time::{SystemTime, UNIX_EPOCH};
+
+pub fn get_seeded_random() -> Result<Rand32, String> {
+    let now = SystemTime::now();
+    let duration = now
+        .duration_since(UNIX_EPOCH)
+        .map_err(|e| format!("{}", e))?;
+
+    Ok(Rand32::new(duration.as_secs()))
+}