use crate::utils::{
c, cal_table_minenum_recursion, chunk_matrixes, combine, find_a_border_cell, laymine,
laymine_op, refresh_board, refresh_matrixs, refresh_matrixses, unsolvable_structure,
};
#[cfg(any(feature = "py", feature = "rs"))]
use crate::utils::{cal_bbbv_exp, legalize_board};
use crate::videos::{GameBoardState, MinesweeperBoard};
use crate::big_number::BigNumber;
#[cfg(feature = "js")]
use crate::utils::JsShuffle;
#[cfg(any(feature = "py", feature = "rs"))]
use crate::obr::ImageBoard;
use itertools::Itertools;
#[cfg(any(feature = "py", feature = "rs"))]
use rand::seq::SliceRandom;
#[cfg(any(feature = "py", feature = "rs"))]
use rand::thread_rng;
use std::cmp::{max, min};
#[cfg(any(feature = "py", feature = "rs"))]
use std::sync::mpsc;
#[cfg(any(feature = "py", feature = "rs"))]
use std::sync::{Arc, Mutex};
#[cfg(any(feature = "py", feature = "rs"))]
use std::thread;
#[cfg(any(feature = "py", feature = "rs"))]
use tract_ndarray::Array;
#[cfg(any(feature = "py", feature = "rs"))]
use tract_onnx::prelude::*;
use crate::ENUM_LIMIT;
pub fn solve_minus(
a_mats: &mut Vec<Vec<Vec<i32>>>,
xs: &mut Vec<Vec<(usize, usize)>>,
bs: &mut Vec<Vec<i32>>,
board_of_game: &mut Vec<Vec<i32>>,
) -> Result<(Vec<(usize, usize)>, Vec<(usize, usize)>), usize> {
let block_num = bs.len();
let mut not_mine = vec![];
let mut is_mine = vec![];
let mut remove_blocks_id = vec![];
for b in (0..block_num).rev() {
let mut not_mine_rel = vec![];
let mut is_mine_rel = vec![];
let matrix_column = xs[b].len();
let matrix_row = bs[b].len();
if matrix_row <= 1 {
continue; }
for i in 1..matrix_row {
for j in 0..i {
let mut adval1 = vec![];
let mut advaln1 = vec![];
let mut flag_adj = false;
for k in 0..matrix_column {
if a_mats[b][i][k] >= 1 && a_mats[b][j][k] >= 1 {
flag_adj = true;
continue;
}
if a_mats[b][i][k] - a_mats[b][j][k] == 1 {
adval1.push(k)
} else if a_mats[b][i][k] - a_mats[b][j][k] == -1 {
advaln1.push(k)
}
}
if flag_adj {
let bdval = bs[b][i] - bs[b][j];
if adval1.len() as i32 == bdval {
is_mine_rel.append(&mut adval1);
not_mine_rel.append(&mut advaln1);
} else if advaln1.len() as i32 == -bdval {
is_mine_rel.append(&mut advaln1);
not_mine_rel.append(&mut adval1);
}
}
}
}
is_mine_rel.sort();
is_mine_rel.dedup();
not_mine_rel.sort();
not_mine_rel.dedup();
for i in ¬_mine_rel {
not_mine.push(xs[b][*i]);
board_of_game[xs[b][*i].0][xs[b][*i].1] = 12;
}
for i in &is_mine_rel {
is_mine.push(xs[b][*i]);
board_of_game[xs[b][*i].0][xs[b][*i].1] = 11;
for j in 0..a_mats[b].len() {
bs[b][j] -= a_mats[b][j][*i];
}
}
let mut del_id = not_mine_rel;
del_id.append(&mut is_mine_rel);
del_id.sort_by(|a, b| b.cmp(a));
del_id.dedup();
for i in del_id {
xs[b].remove(i);
for jj in 0..a_mats[b].len() {
a_mats[b][jj].remove(i);
}
}
if xs[b].is_empty() {
remove_blocks_id.push(b);
}
}
for b in remove_blocks_id {
a_mats.remove(b);
bs.remove(b);
xs.remove(b);
}
let (mut not, mut is) = solve_direct(a_mats, xs, bs, board_of_game)?; not_mine.append(&mut not);
is_mine.append(&mut is);
chunk_matrixes(a_mats, xs, bs);
Ok((not_mine, is_mine))
}
pub fn solve_direct(
a_mats: &mut Vec<Vec<Vec<i32>>>,
xs: &mut Vec<Vec<(usize, usize)>>,
bs: &mut Vec<Vec<i32>>,
board_of_game: &mut Vec<Vec<i32>>,
) -> Result<(Vec<(usize, usize)>, Vec<(usize, usize)>), usize> {
let mut is_mine = vec![];
let mut not_mine = vec![];
let block_num = bs.len();
for b in (0..block_num).rev() {
let mut matrix_column = xs[b].len();
let mut matrix_row = bs[b].len();
for i in (0..matrix_row).rev() {
if a_mats[b][i].iter().sum::<i32>() == bs[b][i] {
for k in (0..matrix_column).rev() {
if a_mats[b][i][k] >= 1 {
is_mine.push((xs[b][k].0, xs[b][k].1));
board_of_game[xs[b][k].0][xs[b][k].1] = 11;
xs[b].remove(k);
for t in 0..matrix_row {
bs[b][t] -= a_mats[b][t][k];
a_mats[b][t].remove(k);
}
matrix_column -= 1;
}
}
a_mats[b].remove(i);
bs[b].remove(i);
matrix_row -= 1;
}
}
for i in (0..matrix_row).rev() {
if bs[b][i] == 0 {
for k in (0..matrix_column).rev() {
if a_mats[b][i][k] >= 1 {
not_mine.push(xs[b][k]);
board_of_game[xs[b][k].0][xs[b][k].1] = 12;
xs[b].remove(k);
for t in 0..matrix_row {
a_mats[b][t].remove(k);
}
matrix_column -= 1;
}
}
a_mats[b].remove(i);
bs[b].remove(i);
matrix_row -= 1;
}
}
if bs[b].is_empty() {
a_mats.remove(b);
bs.remove(b);
xs.remove(b);
}
}
let ans = bs.iter().find(|&b| match b.iter().find(|&&x| x < 0) {
Some(_) => return true,
None => return false,
});
match ans {
Some(_) => return Err(6),
None => {}
}
chunk_matrixes(a_mats, xs, bs);
Ok((not_mine, is_mine))
}
pub fn cal_probability(
board_of_game: &Vec<Vec<i32>>,
minenum: f64,
) -> Result<(Vec<((usize, usize), f64)>, f64, [usize; 3], usize), usize> {
let mut exceed_len = 0;
let mut p = vec![];
let mut table_cell_minenum_s: Vec<Vec<Vec<usize>>> = vec![];
let mut comb_relp_s = vec![]; let mut table_minenum_s: Vec<[Vec<usize>; 2]> = vec![];
let (mut matrix_a_s, mut matrix_x_s, mut matrix_b_s, mut inside_cell, is_minenum) =
refresh_matrixs(&board_of_game);
for i in (0..matrix_a_s.len()).rev() {
let matrix_x_s_len = matrix_x_s[i].len();
if matrix_x_s_len > exceed_len {
exceed_len = matrix_x_s_len;
}
if matrix_x_s_len > ENUM_LIMIT {
matrix_a_s.remove(i);
matrix_x_s.remove(i);
matrix_b_s.remove(i);
inside_cell += matrix_x_s_len;
}
}
let block_num = matrix_a_s.len();
let mut matrix_a_squeeze_s: Vec<Vec<Vec<i32>>> = vec![];
let mut matrixx_squeeze_s: Vec<Vec<(usize, usize)>> = vec![];
for i in 0..block_num {
let (matrix_a_squeeze, matrixx_squeeze, combination_relationship) =
combine(&matrix_a_s[i], &matrix_x_s[i]);
comb_relp_s.push(combination_relationship);
matrix_a_squeeze_s.push(matrix_a_squeeze);
matrixx_squeeze_s.push(matrixx_squeeze);
}
for i in 0..block_num {
let (table_minenum_i, table_cell_minenum_i) = cal_table_minenum_recursion(
&matrix_a_squeeze_s[i],
&matrixx_squeeze_s[i],
&matrix_b_s[i],
&comb_relp_s[i],
)?;
table_cell_minenum_s.push(table_cell_minenum_i);
table_minenum_s.push(table_minenum_i);
} let mut min_minenum = 0;
let mut max_minenum = 0;
for i in 0..block_num {
min_minenum += table_minenum_s[i][0].iter().min().unwrap();
max_minenum += table_minenum_s[i][0].iter().max().unwrap();
}
let minenum = if minenum < 1.0 {
let mn = ((board_of_game.len() * board_of_game[0].len()) as f64 * minenum) as usize;
min(max(mn - is_minenum, min_minenum), max_minenum + inside_cell)
} else {
let mm = (minenum as usize).overflowing_sub(is_minenum);
match mm.1 {
false => mm.0,
true => return Err(17),
}
};
max_minenum = min(max_minenum, minenum);
if max_minenum < min_minenum {
return Err(3); }
let unknow_minenum: Vec<usize> =
(minenum - max_minenum..min(minenum - min_minenum, inside_cell) + 1).collect();
let mut unknow_mine_s_num = vec![];
for i in &unknow_minenum {
unknow_mine_s_num.push(c(inside_cell, *i));
}
table_minenum_s.push([unknow_minenum.clone(), vec![]]);
let mut mine_in_each_block = (0..block_num + 1)
.map(|i| 0..table_minenum_s[i][0].len())
.multi_cartesian_product()
.collect::<Vec<_>>();
for i in (0..mine_in_each_block.len()).rev() {
let mut total_num = 0;
for j in 0..block_num + 1 {
total_num += table_minenum_s[j][0][mine_in_each_block[i][j]];
}
if total_num != minenum {
mine_in_each_block.remove(i);
}
}
let mut table_minenum_other: Vec<Vec<BigNumber>> = vec![];
for i in 0..block_num + 1 {
table_minenum_other.push(vec![
BigNumber { a: 0.0, b: 0 };
table_minenum_s[i][0].len()
]);
} for s in mine_in_each_block {
for i in 0..block_num {
let mut s_num = BigNumber { a: 1.0, b: 0 };
let mut s_mn = minenum; for j in 0..block_num {
if i != j {
s_num *= table_minenum_s[j][1][s[j]] as f64;
}
s_mn -= table_minenum_s[j][0][s[j]];
}
let ps = unknow_minenum.iter().position(|x| *x == s_mn).unwrap();
s_num *= &unknow_mine_s_num[ps];
table_minenum_other[i][s[i]] += &s_num;
}
let mut s_num = BigNumber { a: 1.0, b: 0 };
let mut s_mn = minenum; for j in 0..block_num {
s_num *= table_minenum_s[j][1][s[j]] as f64;
s_mn -= table_minenum_s[j][0][s[j]];
}
let ps = unknow_minenum.iter().position(|x| *x == s_mn).unwrap();
table_minenum_other[block_num][ps] += &s_num;
}
let mut tt = BigNumber { a: 0.0, b: 0 };
for i in 0..unknow_mine_s_num.len() {
let mut t = table_minenum_other[block_num][i].clone();
t *= &unknow_mine_s_num[i];
tt += &t;
}
for i in 0..block_num {
for cells_id in 0..comb_relp_s[i].len() {
let cells_len = comb_relp_s[i][cells_id].len();
for cell_id in 0..cells_len {
let mut s_cell = BigNumber { a: 0.0, b: 0 };
for s in 0..table_minenum_other[i].len() {
let mut o = table_minenum_other[i][s].clone();
o *= table_cell_minenum_s[i][s][cells_id] as f64;
s_cell += &o;
}
let p_cell = (&s_cell / &tt).into();
let id = comb_relp_s[i][cells_id][cell_id];
p.push((matrix_x_s[i][id], p_cell));
}
}
}
let mut u_s = BigNumber { a: 0.0, b: 0 };
for i in 0..unknow_minenum.len() {
let mut u = table_minenum_other[block_num][i].clone();
u *= &unknow_mine_s_num[i];
u *= unknow_minenum[i] as f64;
u_s += &u;
}
let temp: f64 = (&u_s / &tt).into();
let p_unknow: f64 = temp / (inside_cell as f64);
Ok((
p,
p_unknow,
[
min_minenum + is_minenum,
minenum + is_minenum,
max_minenum + is_minenum + inside_cell,
],
exceed_len,
))
}
pub fn cal_probability_onboard(
board_of_game: &Vec<Vec<i32>>,
minenum: f64,
) -> Result<(Vec<Vec<f64>>, [usize; 3]), usize> {
let mut p = vec![vec![-1.0; board_of_game[0].len()]; board_of_game.len()];
let pp = cal_probability(&board_of_game, minenum)?;
for i in pp.0 {
p[i.0 .0][i.0 .1] = i.1;
}
for r in 0..board_of_game.len() {
for c in 0..board_of_game[0].len() {
if board_of_game[r][c] == 11 {
p[r][c] = 1.0;
} else if board_of_game[r][c] == 10 && p[r][c] < -0.5 {
p[r][c] = pp.1;
} else if board_of_game[r][c] == 12 {
p[r][c] = 0.0;
} else if p[r][c] < -0.5 {
p[r][c] = 0.0;
}
}
}
Ok((p, pp.2))
}
pub fn cal_probability_cells_is_op(
board_of_game: &Vec<Vec<i32>>,
minenum: usize,
cells: &Vec<(usize, usize)>,
) -> Vec<f64> {
let mut poss = vec![1.0; cells.len()];
let row = board_of_game.len();
let column = board_of_game[0].len();
for (cell_id, &(x, y)) in cells.iter().enumerate() {
let mut board_of_game_modified = board_of_game.clone();
'outer: for m in max(1, x) - 1..min(row, x + 2) {
for n in max(1, y) - 1..min(column, y + 2) {
if (board_of_game[m][n] < 10 && m == x && n == y) || board_of_game[m][n] == 11 {
poss[cell_id] = 0.0;
break 'outer;
} else if board_of_game[m][n] == 12 || board_of_game[m][n] < 10 {
continue;
} else {
let p;
match cal_probability_onboard(&board_of_game_modified, minenum as f64) {
Ok((ppp, _)) => p = ppp,
Err(_) => {
poss[cell_id] = 0.0;
break 'outer;
}
};
poss[cell_id] *= 1.0 - p[m][n];
board_of_game_modified[m][n] = 12;
}
}
}
}
poss
}
pub fn cal_probability_cells_not_mine(
game_board: &Vec<Vec<i32>>,
minenum: f64,
cells: &Vec<(usize, usize)>,
) -> f64 {
let mut poss = 0.0;
let mut game_board_modified = game_board.clone();
for &(x, y) in cells.iter() {
if game_board[x][y] < 10 || game_board[x][y] == 12 {
continue;
} else if game_board[x][y] == 11 {
return 0.0;
} else {
let (board_poss, _) = cal_probability_onboard(&game_board_modified, minenum).unwrap();
poss *= 1.0 - board_poss[x][y];
game_board_modified[x][y] = 12;
}
}
poss
}
pub fn solve_enumerate(
a_mats: &Vec<Vec<Vec<i32>>>,
xs: &Vec<Vec<(usize, usize)>>,
bs: &Vec<Vec<i32>>,
) -> (Vec<(usize, usize)>, Vec<(usize, usize)>) {
if bs.is_empty() {
return (vec![], vec![]);
}
let mut not_mine = vec![];
let mut is_mine = vec![];
let block_num = xs.len();
let mut comb_relp_s = vec![];
let mut matrix_a_squeeze_s: Vec<Vec<Vec<i32>>> = vec![];
let mut matrixx_squeeze_s: Vec<Vec<(usize, usize)>> = vec![];
for i in 0..block_num {
if xs[i].len() > ENUM_LIMIT {
return (not_mine, is_mine);
}
let (matrix_a_squeeze, matrixx_squeeze, combination_relationship) =
combine(&a_mats[i], &xs[i]);
comb_relp_s.push(combination_relationship);
matrix_a_squeeze_s.push(matrix_a_squeeze);
matrixx_squeeze_s.push(matrixx_squeeze);
}
for i in 0..block_num {
let (table_minenum_i, table_cell_minenum_i) = cal_table_minenum_recursion(
&matrix_a_squeeze_s[i],
&matrixx_squeeze_s[i],
&bs[i],
&comb_relp_s[i],
)
.unwrap();
for jj in 0..table_cell_minenum_i[0].len() {
let mut s_num = 0; for ii in 0..table_cell_minenum_i.len() {
s_num += table_cell_minenum_i[ii][jj];
}
if s_num == 0 {
for kk in &comb_relp_s[i][jj] {
not_mine.push(xs[i][*kk]);
}
} else if s_num == table_minenum_i[1].iter().sum::<usize>() * comb_relp_s[i][jj].len() {
for kk in &comb_relp_s[i][jj] {
is_mine.push(xs[i][*kk]);
}
}
}
}
(not_mine, is_mine)
}
fn is_victory(game_board: &Vec<Vec<i32>>, board: &Vec<Vec<i32>>) -> bool {
let row = game_board.len();
let col = game_board[0].len();
for i in 0..row {
for j in 0..col {
if game_board[i][j] == 10 && board[i][j] != -1 {
return false;
}
}
}
return true;
}
pub struct IsVictory {
row: usize,
column: usize,
pointer_x: usize,
pointer_y: usize,
}
impl IsVictory {
pub fn new(row: usize, column: usize) -> IsVictory {
IsVictory {
row,
column,
pointer_x: 0,
pointer_y: 0,
}
}
fn is_victory(&mut self, game_board: &Vec<Vec<i32>>, board: &Vec<Vec<i32>>) -> bool {
for j in self.pointer_y..self.column {
if game_board[self.pointer_x][j] < 10 {
if game_board[self.pointer_x][j] != board[self.pointer_x][j] {
return false; }
}
if game_board[self.pointer_x][j] >= 10 && board[self.pointer_x][j] != -1 {
self.pointer_y = j;
return false;
}
}
for i in self.pointer_x + 1..self.row {
for j in 0..self.column {
if game_board[i][j] < 10 {
if game_board[i][j] != board[i][j] {
return false; }
}
if game_board[i][j] >= 10 && board[i][j] != -1 {
self.pointer_x = i;
self.pointer_y = j;
return false;
}
}
}
true
}
}
pub fn is_solvable(board: &Vec<Vec<i32>>, x0: usize, y0: usize) -> bool {
if board[x0][y0] == -1 {
return false;
}
if unsolvable_structure(&board) {
return false;
}
let row = board.len();
let column = board[0].len();
let mut game_board = vec![vec![10; column]; row];
refresh_board(board, &mut game_board, vec![(x0, y0)]);
let mut judge = IsVictory::new(row, column);
if judge.is_victory(&game_board, &board) {
return true; }
loop {
let (mut a_mats, mut xs, mut bs, _, _) = refresh_matrixs(&game_board);
let ans = solve_direct(&mut a_mats, &mut xs, &mut bs, &mut game_board).unwrap();
let not_mine;
if ans.0.is_empty() && ans.1.is_empty() {
let ans = solve_minus(&mut a_mats, &mut xs, &mut bs, &mut game_board).unwrap();
if ans.0.is_empty() && ans.1.is_empty() {
let ans = solve_enumerate(&a_mats, &xs, &bs);
if ans.0.is_empty() && ans.1.is_empty() {
return false;
} else {
not_mine = ans.0
}
if !ans.1.is_empty() {
for (o, p) in ans.1 {
game_board[o][p] = 11;
}
}
} else {
not_mine = ans.0
}
} else {
not_mine = ans.0
}
refresh_board(board, &mut game_board, not_mine);
if judge.is_victory(&game_board, &board) {
return true;
}
}
}
pub fn try_solve(board: &Vec<Vec<i32>>, x0: usize, y0: usize) -> (Vec<Vec<i32>>, usize) {
let row = board.len();
let column = board[0].len();
let mut game_board = vec![vec![10; column]; row];
if board[x0][y0] == -1 {
game_board[x0][y0] = 15;
return (game_board, 0);
}
let mut minesweeper_board = MinesweeperBoard::<Vec<Vec<i32>>>::new(board.clone());
let _ = minesweeper_board.step("lc", (x0, y0));
let _ = minesweeper_board.step("lr", (x0, y0));
if is_victory(&game_board, &board) {
return (minesweeper_board.game_board, 1); }
loop {
let (mut a_mats, mut xs, mut bs, _, _) = refresh_matrixs(&minesweeper_board.game_board);
let ans = solve_direct(
&mut a_mats,
&mut xs,
&mut bs,
&mut minesweeper_board.game_board,
)
.unwrap();
let not_mine;
if ans.0.is_empty() && ans.1.is_empty() {
let ans = solve_minus(
&mut a_mats,
&mut xs,
&mut bs,
&mut minesweeper_board.game_board,
)
.unwrap();
if ans.0.is_empty() && ans.1.is_empty() {
let ans = solve_enumerate(&a_mats, &xs, &bs);
if ans.0.is_empty() && ans.1.is_empty() {
return (minesweeper_board.game_board, minesweeper_board.bbbv_solved);
} else {
not_mine = ans.0
}
if !ans.1.is_empty() {
for (o, p) in ans.1 {
minesweeper_board.game_board[o][p] = 11;
}
}
} else {
not_mine = ans.0
}
} else {
not_mine = ans.0
}
let mut operation = vec![];
for n in not_mine {
operation.push(("lc".to_string(), n));
operation.push(("lr".to_string(), n));
}
let _ = minesweeper_board.step_flow(&operation);
if minesweeper_board.game_board_state == GameBoardState::Win {
return (minesweeper_board.game_board, minesweeper_board.bbbv_solved);
}
}
}
#[cfg(any(feature = "py", feature = "rs"))]
pub fn laymine_solvable_thread(
row: usize,
column: usize,
minenum: usize,
x0: usize,
y0: usize,
mut max_times: usize,
) -> (Vec<Vec<i32>>, bool) {
let mut game_board = vec![vec![0; column]; row];
let mut handles = vec![];
let flag_exit = Arc::new(Mutex::new(0));
let (tx, rx) = mpsc::channel(); for ii in (1..=8).rev() {
let tx_ = mpsc::Sender::clone(&tx);
let max_time = max_times / ii;
max_times -= max_time;
let flag_exit = Arc::clone(&flag_exit);
let handle = thread::spawn(move || {
let mut counter = 0;
let mut board = vec![vec![0; column]; row];
while counter < max_time {
{
let f = flag_exit.lock().unwrap();
if *f == 1 {
break;
}
} let board_ = laymine_op(row, column, minenum, x0, y0);
counter += 1;
if is_solvable(&board_, x0, y0) {
for i in 0..row {
for j in 0..column {
board[i][j] = board_[i][j];
}
}
let mut f = flag_exit.lock().unwrap();
*f = 1;
tx_.send((board, true)).unwrap();
break;
}
}
let board_ = laymine_op(row, column, minenum, x0, y0);
tx_.send((board_, false)).unwrap();
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let received = rx.recv().unwrap(); for i in 0..row {
for j in 0..column {
game_board[i][j] = received.0[i][j];
}
}
(game_board, received.1)
}
pub fn laymine_solvable(
row: usize,
column: usize,
minenum: usize,
x0: usize,
y0: usize,
max_times: usize,
) -> (Vec<Vec<i32>>, bool) {
let mut times = 0;
let mut board;
while times < max_times {
board = laymine_op(row, column, minenum, x0, y0);
times += 1;
if is_solvable(&board, x0, y0) {
return (board, true);
}
}
board = laymine_op(row, column, minenum, x0, y0);
(board, false)
}
pub fn laymine_solvable_adjust(
row: usize,
column: usize,
minenum: usize,
x0: usize,
y0: usize,
) -> (Vec<Vec<i32>>, bool) {
let mut board;
let mut area_op = 9;
if x0 == 0 || y0 == 0 || x0 == row - 1 || y0 == column - 1 {
if x0 == 0 && y0 == 0
|| x0 == 0 && y0 == column - 1
|| x0 == row - 1 && y0 == 0
|| x0 == row - 1 && y0 == column - 1
{
area_op = 4;
} else {
area_op = 6;
}
}
if row * column - area_op < minenum {
let t = laymine(row, column, minenum, x0, y0);
if row * column - minenum == 1 {
return (t, true);
} else {
return (t, false);
}
}
if row * column == area_op + minenum {
return (laymine_op(row, column, minenum, x0, y0), true);
}
board = vec![vec![-10; column]; row];
let mut board_of_game = vec![vec![10; column]; row];
board_of_game[x0][y0] = 0;
let remain_minenum = minenum;
let remain_not_minenum = row * column - area_op - minenum;
let mut cells_plan_to_click = vec![];
for j in max(1, x0) - 1..min(row, x0 + 2) {
for k in max(1, y0) - 1..min(column, y0 + 2) {
board[j][k] = 0;
board_of_game[j][k] = 0;
if j != x0 || k != y0 {
cells_plan_to_click.push((j, k));
}
}
}
let (mut b, flag) = adjust_step(
&board,
&board_of_game,
remain_minenum,
remain_not_minenum,
remain_not_minenum,
0,
);
if !flag || b.is_empty() {
return (laymine_op(row, column, minenum, x0, y0), false);
}
for i in 0..row {
for j in 0..column {
if b[i][j] == -10 {
b[i][j] = -1;
}
}
}
for i in 0..row {
for j in 0..column {
if b[i][j] == -1 {
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if b[m][n] >= 0 {
b[m][n] += 1;
}
}
}
}
}
}
(b, flag)
}
fn adjust_step(
board: &Vec<Vec<i32>>, board_of_game: &Vec<Vec<i32>>, remain_minenum: usize, remain_not_minenum: usize, remain_not_open: usize, depth: usize,
) -> (Vec<Vec<i32>>, bool) {
let mut board_clone = board.clone(); let mut game_board_clone = board_of_game.clone();
let (a_matses, xses, bses) = refresh_matrixses(&game_board_clone);
if a_matses.is_empty() {
return (vec![], false);
}
if remain_not_minenum == 0 {
let row = board.len();
let column = board[0].len();
let mut delta_remain_minenum = 0;
let mut delta_remain_not_minenum = 0;
let mut delta_remain_not_open = 0;
let mut board_mod = vec![];
for &(x, y) in xses.iter().flatten().flatten() {
for m in max(1, x) - 1..min(row, x + 2) {
for n in max(1, y) - 1..min(column, y + 2) {
if board_clone[m][n] == -1 && game_board_clone[m][n] != 10 {
board_clone[m][n] = -10;
board_mod.push((m, n));
delta_remain_minenum += 1;
game_board_clone[m][n] = 10;
}
if board_clone[m][n] == 0 && game_board_clone[m][n] != 10 {
board_clone[m][n] = -10;
board_mod.push((m, n));
delta_remain_not_minenum += 1;
delta_remain_not_open += 1;
game_board_clone[m][n] = 10;
}
}
}
}
for &(x, y) in xses.iter().flatten().flatten() {
if board_clone[x][y] == -1 {
board_clone[x][y] = -10;
delta_remain_minenum += 1;
}
if board_clone[x][y] == 0 {
board_clone[x][y] = -10;
delta_remain_not_minenum += 1;
}
}
return adjust_step(
&board_clone,
&game_board_clone,
remain_minenum + delta_remain_minenum,
remain_not_minenum + delta_remain_not_minenum,
remain_not_open + delta_remain_not_open,
depth + 1,
);
}
let mut front_xs_0: Vec<(usize, usize)> =
xses.clone().into_iter().flatten().flatten().collect();
front_xs_0.retain(|x| board_clone[x.0][x.1] == -10);
if front_xs_0.is_empty() {
return (vec![], false);
}
let xs_cell_num = front_xs_0.len();
let mut minenum_except = (xs_cell_num as f64 * remain_minenum as f64
/ (remain_not_minenum + remain_minenum) as f64) as usize;
let minenum_exp = (xs_cell_num as f64 * 0.25) as usize;
if minenum_except > minenum_exp {
minenum_except = minenum_exp;
}
let minenum_max = if xs_cell_num > remain_minenum {
remain_minenum
} else {
xs_cell_num
};
let minenum_min = if xs_cell_num < remain_not_minenum {
0
} else {
xs_cell_num - remain_not_minenum
};
let delta: [isize; 15] = [0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5, -6, 6, -7, 7];
let mut first_loop_flag = true;
for minenum in delta.iter().filter_map(|m| {
let a = m + minenum_except as isize;
if a < 0 {
return None;
}
let a = a as usize;
if a >= minenum_min && a <= minenum_max {
Some(a)
} else {
None
}
}) {
let loop_time = if first_loop_flag { 5 } else { 1 };
for _ in 0..loop_time {
adjust_the_area_on_board(&mut board_clone, &front_xs_0, minenum);
let mut not_mine = vec![];
let mut is_mine = vec![];
for (i, mut b_s) in bses.clone().into_iter().enumerate() {
let a_s = a_matses.get(i).unwrap();
let x_s = xses.get(i).unwrap();
for bb in 0..b_s.len() {
for ss in 0..b_s[bb].len() {
b_s[bb][ss] = 0;
for aa in 0..a_s[bb][0].len() {
if a_s[bb][ss][aa] == 1 {
if board_clone[x_s[bb][aa].0][x_s[bb][aa].1] == -1
&& game_board_clone[x_s[bb][aa].0][x_s[bb][aa].1] != 11
{
b_s[bb][ss] += 1;
}
}
}
}
}
let (mut _not_mine, mut _is_mine) = get_all_not_and_is_mine_on_board(
&mut a_s.clone(),
&mut x_s.clone(),
&mut b_s.clone(),
&mut game_board_clone.clone(),
);
not_mine.append(&mut _not_mine);
is_mine.append(&mut _is_mine);
}
if not_mine.len() > 0 {
not_mine.iter().for_each(|x| game_board_clone[x.0][x.1] = 1);
is_mine.iter().for_each(|x| game_board_clone[x.0][x.1] = 11);
if remain_not_open <= not_mine.len() {
board_clone.iter_mut().for_each(|x| {
x.iter_mut().for_each(|i| {
if *i == -10 {
*i = -1;
}
})
});
return (board_clone, true);
}
let a = adjust_step(
&board_clone,
&game_board_clone,
remain_minenum - minenum,
remain_not_minenum + minenum - xs_cell_num,
remain_not_open - not_mine.len(),
depth + 1,
);
if a.1 {
if !a.0.is_empty() {
return (a.0, true);
}
} else {
board_clone = board.clone();
game_board_clone = board_of_game.clone();
continue;
}
}
}
first_loop_flag = false;
}
return (vec![], false);
}
fn adjust_the_area_on_board(
board: &mut Vec<Vec<i32>>,
area_current_adjust: &Vec<(usize, usize)>,
minenum: usize,
) {
let cell_num = area_current_adjust.len();
let mut b = vec![0; cell_num - minenum];
b.append(&mut vec![-1; minenum]);
#[cfg(any(feature = "py", feature = "rs"))]
let mut rng = thread_rng();
#[cfg(any(feature = "py", feature = "rs"))]
b.shuffle(&mut rng);
#[cfg(feature = "js")]
b.shuffle_();
let mut id = 0;
for &(x, y) in area_current_adjust {
board[x][y] = b[id];
id += 1;
}
}
#[cfg(any(feature = "py", feature = "rs"))]
pub fn sample_bbbvs_exp(x0: usize, y0: usize, n: usize) -> [usize; 382] {
let n0 = n / 16;
let mut threads = vec![];
for _i in 0..16 {
let join_item = thread::spawn(move || -> [usize; 382] { laymine_study_exp(x0, y0, n0) });
threads.push(join_item);
}
let mut aa = [0; 382];
for i in threads.into_iter().map(|c| c.join().unwrap()) {
for ii in 0..382 {
aa[ii] += i[ii];
}
}
aa
}
#[cfg(any(feature = "py", feature = "rs"))]
fn laymine_study_exp(x0: usize, y0: usize, n: usize) -> [usize; 382] {
let mut rng = thread_rng();
let pointer = x0 + y0 * 16;
let mut bv_record = [0; 382];
for _id in 0..n {
let mut board1_dim = [0; 479];
for i in 380..479 {
board1_dim[i] = -1;
}
board1_dim.shuffle(&mut rng);
let mut board1_dim_2 = [0; 480];
for i in 0..pointer {
board1_dim_2[i] = board1_dim[i];
}
board1_dim_2[pointer] = 0;
for i in pointer..479 {
board1_dim_2[i + 1] = board1_dim[i];
}
let mut board: Vec<Vec<i32>> = vec![vec![0; 30]; 16];
for i in 0..480 {
if board1_dim_2[i] < 0 {
let x = i % 16;
let y = i / 16;
board[x][y] = -1;
for j in max(1, x) - 1..min(16, x + 2) {
for k in max(1, y) - 1..min(30, y + 2) {
if board[j][k] >= 0 {
board[j][k] += 1;
}
}
}
}
}
bv_record[cal_bbbv_exp(&board)] += 1;
}
bv_record
}
#[cfg(any(feature = "py", feature = "rs"))]
fn obr_cell(
cell_image: &Vec<f32>,
model: &tract_onnx::prelude::SimplePlan<
tract_onnx::prelude::TypedFact,
std::boxed::Box<dyn tract_onnx::prelude::TypedOp>,
tract_onnx::prelude::Graph<
tract_onnx::prelude::TypedFact,
std::boxed::Box<dyn tract_onnx::prelude::TypedOp>,
>,
>,
) -> TractResult<i32> {
let image: Tensor = Array::from_shape_vec((1, 3, 16, 16), (*cell_image).clone())
.unwrap()
.into();
let result = model.run(tvec!(image.into()))?;
let best = result[0]
.to_array_view::<f32>()?
.iter()
.cloned()
.zip(1..)
.max_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
match best.unwrap().1 {
1 => Ok(0),
2 => Ok(1),
3 => Ok(2),
4 => Ok(3),
5 => Ok(4),
6 => Ok(5),
7 => Ok(6),
8 => Ok(7),
9 => Ok(8),
10 => Ok(10),
_ => Ok(11),
}
}
#[cfg(any(feature = "py", feature = "rs"))]
pub fn obr_board(
data_vec: Vec<usize>,
height: usize,
width: usize,
) -> Result<Vec<Vec<i32>>, String> {
if height <= 24 || width <= 24 {
return Err("one input size of the board is smaller than 3".to_string());
}
let mut image_board = ImageBoard::new(data_vec, height, width);
image_board.get_pos_pixel();
if image_board.r <= 3 || image_board.c <= 3 {
return Err("one size of the board seems to be smaller than 3".to_string());
}
let mut board = vec![vec![0i32; image_board.c]; image_board.r];
let model = (tract_onnx::onnx()
.model_for_path("params.onnx")
.unwrap()
.with_input_fact(
0,
InferenceFact::dt_shape(f32::datum_type(), tvec!(1, 3, 16, 16)),
)
.unwrap()
.into_optimized()
.unwrap()
.into_runnable())
.unwrap();
for i in 0..image_board.r {
for j in 0..image_board.c {
let cell = obr_cell(&image_board.extra_save_cell(i, j, 16), &model).unwrap();
board[i][j] = cell;
}
}
legalize_board(&mut board);
Ok(board)
}
pub fn mark_board(game_board: &mut Vec<Vec<i32>>, remark: bool) -> Result<(usize, usize), usize> {
if remark {
for row in game_board.iter_mut() {
for num in row.iter_mut() {
if *num == 11 || *num == 12 {
*num = 10;
}
}
}
}
let (mut a_mats, mut xs, mut bs, _, _) = refresh_matrixs(&game_board);
let mut not_mine_num = 0;
let mut is_mine_num = 0;
let (not, is) = solve_direct(&mut a_mats, &mut xs, &mut bs, game_board)?;
not_mine_num += not.len();
is_mine_num += is.len();
let (not, is) = solve_minus(&mut a_mats, &mut xs, &mut bs, game_board)?;
not_mine_num += not.len();
is_mine_num += is.len();
Ok((not_mine_num, is_mine_num))
}
pub fn get_all_not_and_is_mine_on_board(
a_mats: &mut Vec<Vec<Vec<i32>>>,
xs: &mut Vec<Vec<(usize, usize)>>,
bs: &mut Vec<Vec<i32>>,
board_of_game: &mut Vec<Vec<i32>>,
) -> (Vec<(usize, usize)>, Vec<(usize, usize)>) {
let mut ans = solve_direct(a_mats, xs, bs, board_of_game).unwrap();
let mut is_mine = vec![];
let mut not_mine = vec![];
not_mine.append(&mut ans.0);
is_mine.append(&mut ans.1);
let mut ans = solve_minus(a_mats, xs, bs, board_of_game).unwrap();
not_mine.append(&mut ans.0);
is_mine.append(&mut ans.1);
let mut ans = solve_enumerate(a_mats, xs, bs);
not_mine.append(&mut ans.0);
is_mine.append(&mut ans.1);
(not_mine, is_mine)
}
pub fn is_guess_while_needless(board_of_game: &mut Vec<Vec<i32>>, xy: &(usize, usize)) -> i32 {
board_of_game.iter_mut().for_each(|x| {
x.iter_mut().for_each(|xx| {
if *xx > 10 {
*xx = 10
}
})
});
if board_of_game[xy.0][xy.1] < 10 {
return 5;
}
let mut flag_need;
let (mut a_matses, mut xses, mut bses) = refresh_matrixses(&board_of_game);
if let (Some(xy), flag_border) = find_a_border_cell(board_of_game, xy) {
let t = xses
.iter()
.position(|r| r.iter().any(|x| x.contains(&xy)))
.unwrap();
let a_mats = &mut a_matses[t];
let xs = &mut xses[t];
let bs = &mut bses[t];
let (n, _) = solve_direct(a_mats, xs, bs, board_of_game).unwrap();
if !flag_border && !n.is_empty() {
return 3;
}
flag_need = n.is_empty();
match board_of_game[xy.0][xy.1] {
12 => return 1,
11 => return 4,
_ => {
let (n, _) = solve_minus(a_mats, xs, bs, board_of_game).unwrap();
if !flag_border && !n.is_empty() {
return 3;
}
flag_need = flag_need && n.is_empty();
match board_of_game[xy.0][xy.1] {
12 => return 1,
11 => return 4,
_ => {
let (n, i) = solve_enumerate(a_mats, xs, bs);
if !flag_border && !n.is_empty() {
return 3;
}
flag_need = flag_need && n.is_empty();
if n.contains(&xy) {
return 1;
} else if i.contains(&xy) {
return 4;
} else if flag_need {
return 2;
} else {
return 3;
}
}
}
}
}
} else {
return 2; }
}
pub fn is_able_to_solve(board_of_game: &mut Vec<Vec<i32>>, xy: &(usize, usize)) -> bool {
board_of_game.iter_mut().for_each(|x| {
x.iter_mut().for_each(|xx| {
if *xx > 10 {
*xx = 10
}
})
});
let (mut a_mats, mut xs, mut bs, _, _) = refresh_matrixs(&board_of_game);
let _ = solve_direct(&mut a_mats, &mut xs, &mut bs, board_of_game);
if board_of_game[xy.0][xy.1] == 11 || board_of_game[xy.0][xy.1] == 12 {
return true;
}
let _ = solve_minus(&mut a_mats, &mut xs, &mut bs, board_of_game);
if board_of_game[xy.0][xy.1] == 11 || board_of_game[xy.0][xy.1] == 12 {
return true;
}
let (n, i) = solve_enumerate(&a_mats, &xs, &bs);
if i.contains(xy) || n.contains(xy) {
return true;
}
false
}