ms_toollib 1.5.16

Algorithms for Minesweeper
Documentation
use std::cell::Cell;
use std::cmp;
use std::fmt;

pub struct Tile {
    pub x: usize,
    pub y: usize,
    pub index: usize,
    pub is_covered: Cell<bool>,
    pub value: Cell<u8>,
    pub is_flagged: Cell<bool>,
    pub found_bomb: Cell<bool>,
    pub is_bomb: Cell<Option<bool>>,
    pub exploded: Cell<bool>,
    pub is_safe: Cell<bool>,
    pub is_next_move: Cell<bool>,
    pub is_start: Cell<bool>,
    pub on_edge: Cell<bool>,
    pub hint: Cell<bool>,
    pub probability: Cell<f64>,
    pub hint_text: Cell<String>,
    pub has_hint: Cell<bool>,
}

impl Clone for Tile {
    fn clone(&self) -> Self {
        Tile {
            x: self.x,
            y: self.y,
            index: self.index,
            is_covered: Cell::new(self.is_covered.get()),
            value: Cell::new(self.value.get()),
            is_flagged: Cell::new(self.is_flagged.get()),
            found_bomb: Cell::new(self.found_bomb.get()),
            is_bomb: Cell::new(self.is_bomb.get()),
            exploded: Cell::new(self.exploded.get()),
            is_safe: Cell::new(self.is_safe.get()),
            is_next_move: Cell::new(self.is_next_move.get()),
            is_start: Cell::new(self.is_start.get()),
            on_edge: Cell::new(self.on_edge.get()),
            hint: Cell::new(self.hint.get()),
            probability: Cell::new(self.probability.get()),
            hint_text: Cell::new(self.hint_text.take()),
            has_hint: Cell::new(self.has_hint.get()),
        }
    }
}

impl Tile {
    pub fn new(x: usize, y: usize, index: usize) -> Self {
        Tile {
            x,
            y,
            index,
            is_covered: Cell::new(true),
            value: Cell::new(0),
            is_flagged: Cell::new(false),
            found_bomb: Cell::new(false),
            is_bomb: Cell::new(None),
            exploded: Cell::new(false),
            is_safe: Cell::new(false),
            is_next_move: Cell::new(false),
            is_start: Cell::new(false),
            on_edge: Cell::new(false),
            hint: Cell::new(false),
            probability: Cell::new(-1.0),
            hint_text: Cell::new(String::new()),
            has_hint: Cell::new(false),
        }
    }

    pub fn is_adjacent(&self, other: &Tile) -> bool {
        let dx = if self.x > other.x { self.x - other.x } else { other.x - self.x };
        let dy = if self.y > other.y { self.y - other.y } else { other.y - self.y };
        dx < 2 && dy < 2 && !(dx == 0 && dy == 0)
    }

    pub fn is_equal(&self, other: &Tile) -> bool {
        self.x == other.x && self.y == other.y
    }

    pub fn as_text(&self) -> String {
        format!("({},{})", self.x, self.y)
    }

    pub fn set_probability(&self, prob: f64, progress: Option<f64>, safety2: Option<f64>) {
        self.probability.set(prob);
        self.has_hint.set(true);

        let text = if (prob - 1.0).abs() < 1e-12 {
            "Safe".to_string()
        } else if prob.abs() < 1e-12 {
            "Mine".to_string()
        } else if progress.is_none() {
            format!("\n{:.2}% safe", prob * 100.0)
        } else {
            format!(
                "\n{:.2}% safe\n{:.2}% second safe\n{:.2}% progress",
                prob * 100.0,
                safety2.unwrap_or(0.0) * 100.0,
                progress.unwrap() * 100.0
            )
        };
        self.hint_text.set(text);
    }

    pub fn is_covered(&self) -> bool {
        self.is_covered.get()
    }

    pub fn set_covered(&self, covered: bool) {
        self.is_covered.set(covered);
    }

    pub fn set_value(&self, value: u8) {
        self.value.set(value);
        self.is_covered.set(false);
    }

    pub fn set_value_only(&self, value: u8) {
        if self.is_flagged.get() {
            eprintln!("{} Assigning value {} to a flagged tile!", self.as_text(), value);
        }
        self.value.set(value);
    }

    pub fn get_value(&self) -> u8 {
        self.value.get()
    }

    pub fn set_found_bomb(&self) {
        self.found_bomb.set(true);
    }

    pub fn unset_found_bomb(&self) {
        self.found_bomb.set(false);
    }

    pub fn is_solver_found_bomb(&self) -> bool {
        self.found_bomb.get()
    }

    pub fn set_bomb(&self, bomb: bool) {
        self.is_bomb.set(Some(bomb));
    }

    pub fn as_bomb(&self) -> Option<bool> {
        self.is_bomb.get()
    }
}

impl cmp::PartialEq for Tile {
    fn eq(&self, other: &Self) -> bool {
        self.x == other.x && self.y == other.y
    }
}

impl fmt::Display for Tile {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({},{})", self.x, self.y)
    }
}