From 02098f0d579259545584e246f64ed5e41be9537b Mon Sep 17 00:00:00 2001
From: stale <stale@masba.net>
Date: Mon, 11 Jul 2022 12:06:17 -0300
Subject: implement reveal on lose

---
 assets/index.html  |  1 +
 src/main.rs        |  8 ++++++--
 src/minesweeper.rs | 26 +++++++++++++++-----------
 3 files changed, 22 insertions(+), 13 deletions(-)

diff --git a/assets/index.html b/assets/index.html
index 7961bde..614ccd0 100644
--- a/assets/index.html
+++ b/assets/index.html
@@ -27,6 +27,7 @@
         <label>public, ie. shown in the lobby <input name="public" type="checkbox" checked></label><br>
         <label>safe first move (if possible) <input name="allsafe1move" type="checkbox" checked></label><br>
         <label>revealed borders <input name="rborders" type="checkbox"></label><br>
+        <label>reveal on lose <input name="revealonlose" type="checkbox" checked></label><br>
         <label>player limit <input name="limit" type="number" value="32"></label><br>
         <button id="createbtn">create</button>
       </fieldset>
diff --git a/src/main.rs b/src/main.rs
index ce1cd45..7a85e63 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -309,7 +309,7 @@ async fn empty_rooms(rooms: &RoomMap) -> Vec<RoomId> {
 }
 
 fn room_from_form(uid: RoomId, rinfo: &HashMap<String,String>, conf: &Conf) -> Result<(types::Room, bool), Rejection> {
-    if let (Some(w),Some(h),Some(num),Some(denom),public,asfm,rborders,Some(limit)) = (
+    if let (Some(w),Some(h),Some(num),Some(denom),public,asfm,rborders,revealol,Some(limit)) = (
         rinfo.get("bwidth").and_then(|w| w.parse::<NonZeroUsize>().ok()),
         rinfo.get("bheight").and_then(|h| h.parse::<NonZeroUsize>().ok()),
         rinfo.get("mineratio-n").and_then(|n| n.parse::<usize>().ok()),
@@ -317,12 +317,16 @@ fn room_from_form(uid: RoomId, rinfo: &HashMap<String,String>, conf: &Conf) -> R
         rinfo.get("public").map(|s| s == "on").unwrap_or(false),
         rinfo.get("allsafe1move").map(|s| s == "on").unwrap_or(false),
         rinfo.get("rborders").map(|s| s == "on").unwrap_or(false),
+        rinfo.get("revealonlose").map(|s| s == "on").unwrap_or(false),
         rinfo.get("limit").and_then(|l| l.parse::<NonZeroUsize>().ok()),
         ) {
         if w.get()*h.get() > conf.limits.board_area {
             return Err(warp::reject::custom(BoardTooBig))
         }
-        let board_conf = minesweeper::BoardConf { w, h, mine_ratio: (num,denom), always_safe_first_move: asfm, revealed_borders: rborders };
+        let board_conf = minesweeper::BoardConf {
+            w, h, mine_ratio: (num,denom),
+            always_safe_first_move: asfm, revealed_borders: rborders, reveal_on_lose: revealol
+        };
         let name = {
             let n = rinfo.get("rname").unwrap().to_owned();
             if n.is_empty() { uid.to_string() } else { n }
diff --git a/src/minesweeper.rs b/src/minesweeper.rs
index 9b6ac0c..ae4fe18 100644
--- a/src/minesweeper.rs
+++ b/src/minesweeper.rs
@@ -39,6 +39,7 @@ pub struct BoardConf {
     pub mine_ratio: (usize,NonZeroUsize),
     pub always_safe_first_move: bool,
     pub revealed_borders: bool,
+    pub reveal_on_lose: bool,
 }
 
 impl std::fmt::Display for BoardConf {
@@ -110,6 +111,10 @@ impl Game {
             }
         } else if self.phase != Phase::Die && self.board.hidden_tiles == self.board.mine_count {
             self.phase = Phase::Win;
+        } else if self.phase == Phase::Die && self.board_conf.reveal_on_lose {
+            for tile in self.board.data.iter_mut().filter(|x| is_mine(**x)) {
+                *tile = unhide(*tile);
+            }
         }
         self
     }
@@ -207,11 +212,12 @@ impl Board {
         let mut queue = vec![pos];
         while let Some(pos) = queue.pop() {
             let off = self.pos_to_off_unchecked(pos);
-            let mut c = self.data[off];
-            if c & HIDDEN_BIT > 0 {
-                c = self.unhide_offset(off);
-                if is_mine(c) { return true; }
-                if c > 0 { continue; }
+            let c = &mut self.data[off];
+            if *c & HIDDEN_BIT > 0 {
+                *c = unhide(*c);
+                self.hidden_tiles -= 1;
+                if is_mine(*c) { return true; }
+                if *c > 0 { continue; }
                 if let Some(mut adj) = self.neighs(pos) {
                     queue.append(&mut adj);
                 }
@@ -248,11 +254,6 @@ impl Board {
             }
         } else { false }
     }
-    pub fn unhide_offset(&mut self, off: usize) -> u8 {
-        self.data[off] &= !(HIDDEN_BIT | FLAGGED_BIT);
-        self.hidden_tiles -= 1;
-        self.data[off]
-    }
     pub fn reveal(mut self, pos: (usize,usize)) -> MoveResult {
         let lost = self.reveal_in_place(pos);
         MoveResult(self, lost)
@@ -330,7 +331,10 @@ fn pos_u2i(pos: (usize, usize)) -> Option<(isize, isize)> {
     { Some((x,y)) } else { None }
 }
 pub fn is_mine(v: u8) -> bool {
-    (v & !(FLAGGED_BIT | CORRECT_BIT)) == TILE_NUMBITS
+    (v & TILE_NUMBITS) == TILE_NUMBITS
+}
+pub fn unhide(tile: u8) -> u8 {
+    tile & !(HIDDEN_BIT | FLAGGED_BIT)
 }
 
 
-- 
cgit v1.2.3