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};
use std::vec;
#[cfg(feature = "js")]
use getrandom::getrandom;
use crate::safe_board;
use crate::safe_board::BoardSize;
use crate::ENUM_LIMIT;
use crate:: big_number::BigNumber;
pub fn cal_op<T>(board_raw: &T) -> usize
where
T: std::ops::Index<usize> + safe_board::BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
let row = board_raw.get_row();
let column = board_raw.get_column();
let mut board = vec![vec![0; column]; row];
for i in 0..row {
for j in 0..column {
board[i][j] = board_raw[i][j];
}
}
let mut op = 0;
for i in 0..row {
for j in 0..column {
if board[i][j] == 0 {
infect_board(&mut board, i, j);
op += 1;
}
}
}
op
}
fn infect_board(board: &mut Vec<Vec<i32>>, x: usize, y: usize) {
let row = board.len();
let column = board[0].len();
board[x][y] = 1;
for i in max(1, x) - 1..min(row, x + 2) {
for j in max(1, y) - 1..min(column, y + 2) {
if board[i][j] == 0 {
infect_board(board, i, j);
}
}
}
}
pub fn cal_isl<T>(raw_board: &T) -> usize
where
T: std::ops::Index<usize> + safe_board::BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
let row = raw_board.get_row();
let column = raw_board.get_column();
let mut board = vec![vec![1; column]; row];
for i in 0..row {
for j in 0..column {
if raw_board[i][j] <= 0 {
continue;
}
let mut flag = true;
'outer: for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if raw_board[m][n] == 0 {
flag = false;
break 'outer;
}
}
}
if flag {
board[i][j] = 0;
}
}
}
cal_op(&board)
}
pub fn cal_cell_nums<T>(raw_board: &T) -> [usize; 9]
where
T: std::ops::Index<usize> + BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
let row = raw_board.get_row();
let column = raw_board.get_column();
let mut ans = [0; 9];
for i in 0..row {
for j in 0..column {
if raw_board[i][j] < 0 {
continue;
}
ans[raw_board[i][j] as usize] += 1;
}
}
ans
}
pub fn refresh_matrix(
game_board: &Vec<Vec<i32>>,
) -> (Vec<Vec<i32>>, Vec<(usize, usize)>, Vec<i32>) {
let row = game_board.len();
let column = game_board[0].len();
let mut matrix_a: Vec<Vec<i32>> = Vec::new();
let mut matrixx: Vec<(usize, usize)> = Vec::new();
let mut matrixb: Vec<i32> = Vec::new();
let mut matrix_a_row_num = 0;
let mut matrix_a_column_num = 0;
for i in 0..row {
for j in 0..column {
if game_board[i][j] > 0 && game_board[i][j] < 10 {
let mut flag: bool = false;
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if game_board[m][n] == 10 {
flag = true;
}
}
}
if flag {
matrix_a.push(vec![0; matrix_a_column_num]);
matrixb.push(game_board[i][j]);
matrix_a_row_num += 1;
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if game_board[m][n] == 11 {
matrixb[matrix_a_row_num - 1] -= 1
} else if game_board[m][n] == 10 {
let mut flag_exit: bool = false;
for id_matrixx in 0..matrix_a_column_num {
if matrixx[id_matrixx].0 == m && matrixx[id_matrixx].1 == n {
flag_exit = true;
matrix_a[matrix_a_row_num - 1][id_matrixx] = 1;
}
}
if !flag_exit {
for ii in 0..matrix_a_row_num {
matrix_a[ii].push(0)
}
matrixx.push((m, n));
matrix_a_column_num += 1;
matrix_a[matrix_a_row_num - 1][matrix_a_column_num - 1] = 1;
}
}
}
}
}
}
}
}
(matrix_a, matrixx, matrixb)
}
pub fn refresh_matrixs(
board_of_game: &Vec<Vec<i32>>,
) -> (
Vec<Vec<Vec<i32>>>,
Vec<Vec<(usize, usize)>>,
Vec<Vec<i32>>,
usize,
usize,
) {
let row = board_of_game.len();
let column = board_of_game[0].len();
let mut inside_cell = 0;
let mut is_minenum = 0;
let mut matrix_as = vec![];
let mut matrix_xs = vec![];
let mut matrix_bs = vec![];
let mut all_cell: Vec<(usize, usize)> = vec![]; for i in 0..row {
for j in 0..column {
if board_of_game[i][j] >= 0 && board_of_game[i][j] < 10 {
'outer: for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if board_of_game[m][n] == 10 {
all_cell.push((i, j));
break 'outer;
}
}
}
} else if board_of_game[i][j] == 10 {
let mut flag = true;
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if board_of_game[m][n] < 10 {
flag = false;
}
}
}
if flag {
inside_cell += 1;
}
} else if board_of_game[i][j] == 11 {
is_minenum += 1;
}
}
}
let mut p = 0; while !all_cell.is_empty() {
matrix_xs.push(vec![]);
matrix_bs.push(vec![]);
let x_0 = all_cell[0].0;
let y_0 = all_cell[0].1;
let mut num_cells = vec![]; let mut temp_cells = vec![]; let mut flag_num = 0;
for m in max(1, x_0) - 1..min(row, x_0 + 2) {
for n in max(1, y_0) - 1..min(column, y_0 + 2) {
if board_of_game[m][n] == 10 {
matrix_xs[p].push((m, n));
}
if board_of_game[m][n] == 11 {
flag_num += 1;
}
}
}
matrix_bs[p].push(board_of_game[x_0][y_0] - flag_num);
num_cells.push((x_0, y_0));
temp_cells.push((x_0, y_0));
while !temp_cells.is_empty() {
let x_e = temp_cells[0].0;
let y_e = temp_cells[0].1;
temp_cells.remove(0);
for t in (1..all_cell.len()).rev() {
let x_t = all_cell[t].0;
let y_t = all_cell[t].1;
if x_t >= x_e + 3 || x_e >= x_t + 3 || y_t >= y_e + 3 || y_e >= y_t + 3 {
continue;
}
let mut flag_be_neighbor = false;
for m in max(1, max(x_t, x_e)) - 1..min(row, min(x_t + 2, x_e + 2)) {
for n in max(1, max(y_t, y_e)) - 1..min(column, min(y_t + 2, y_e + 2)) {
if board_of_game[m][n] == 10 {
flag_be_neighbor = true;
break;
}
}
} if flag_be_neighbor {
let mut flag_num = 0;
for m in max(1, x_t) - 1..min(row, x_t + 2) {
for n in max(1, y_t) - 1..min(column, y_t + 2) {
if board_of_game[m][n] == 10 {
if !matrix_xs[p].contains(&(m, n)) {
matrix_xs[p].push((m, n));
}
}
if board_of_game[m][n] == 11 {
flag_num += 1;
}
}
}
matrix_bs[p].push(board_of_game[x_t][y_t] - flag_num);
num_cells.push((x_t, y_t));
temp_cells.push(all_cell[t]);
all_cell.remove(t);
}
}
}
matrix_as.push(vec![vec![0; matrix_xs[p].len()]; matrix_bs[p].len()]);
for i in 0..num_cells.len() {
for j in 0..matrix_xs[p].len() {
if num_cells[i].0 <= matrix_xs[p][j].0 + 1
&& matrix_xs[p][j].0 <= num_cells[i].0 + 1
&& num_cells[i].1 <= matrix_xs[p][j].1 + 1
&& matrix_xs[p][j].1 <= num_cells[i].1 + 1
{
matrix_as[p][i][j] = 1;
}
}
}
all_cell.remove(0);
p += 1;
}
(matrix_as, matrix_xs, matrix_bs, inside_cell, is_minenum)
}
pub fn refresh_matrixses(
board_of_game: &Vec<Vec<i32>>,
) -> (
Vec<Vec<Vec<Vec<i32>>>>,
Vec<Vec<Vec<(usize, usize)>>>,
Vec<Vec<Vec<i32>>>,
) {
let row = board_of_game.len();
let column = board_of_game[0].len();
let mut a_matses = vec![];
let mut xses = vec![];
let mut bses = vec![];
let (mut a_mats, mut xs, mut bs, _, _) = refresh_matrixs(board_of_game);
if a_mats.len() == 1 {
return (vec![a_mats], vec![xs], vec![bs]);
}
let mut adjacency_matrix = vec![vec![false; a_mats.len()]; a_mats.len()];
let mut board_mark = board_of_game.clone();
let mut cell_10 = vec![];
for i in 0..row {
for j in 0..column {
if board_mark[i][j] == 10 {
board_mark[i][j] = 21;
let mut flag_c = false;
let mut buffer = vec![];
buffer.push((i, j));
while !buffer.is_empty() {
let (t_i, t_j) = buffer.pop().unwrap();
let mut flag_is_side = false;
for m in max(1, t_i) - 1..min(row, t_i + 2) {
for n in max(1, t_j) - 1..min(column, t_j + 2) {
if board_mark[m][n] == 10 {
board_mark[m][n] = 21;
buffer.push((m, n));
} else if board_mark[m][n] < 10 {
flag_is_side = true;
}
}
}
if flag_is_side {
if !flag_c {
cell_10.push(vec![]);
flag_c = true;
}
cell_10.last_mut().unwrap().push((t_i, t_j));
}
}
} else {
continue;
}
}
}
if cell_10.len() == 1 {
return (vec![a_mats], vec![xs], vec![bs]);
}
for mut block in cell_10 {
let mut seed_id = -1;
while !block.is_empty() {
let seed = block.pop().unwrap();
let t = xs.iter().position(|r| r.contains(&seed)).unwrap();
if seed_id >= 0 {
adjacency_matrix[seed_id as usize][t] = true;
adjacency_matrix[t][seed_id as usize] = true;
}
seed_id = t as i32;
block.retain(|x| !xs[seed_id as usize].contains(x))
}
} for i in 0..a_mats.len() {
if a_mats[i].is_empty() {
continue;
}
a_matses.push(vec![]);
xses.push(vec![]);
bses.push(vec![]);
let mut buffer = vec![i];
while !buffer.is_empty() {
let t = buffer.pop().unwrap();
a_matses.last_mut().unwrap().push(vec![]);
a_matses
.last_mut()
.unwrap()
.last_mut()
.unwrap()
.append(&mut a_mats[t]);
xses.last_mut().unwrap().push(vec![]);
xses.last_mut()
.unwrap()
.last_mut()
.unwrap()
.append(&mut xs[t]);
bses.last_mut().unwrap().push(vec![]);
bses.last_mut()
.unwrap()
.last_mut()
.unwrap()
.append(&mut bs[t]);
for idj in t..a_mats.len() {
if adjacency_matrix[t][idj] {
buffer.push(idj);
}
}
}
}
(a_matses, xses, bses)
}
#[cfg(feature = "js")]
pub fn get_random_int(limit: usize) -> usize {
if limit == 0 {
return 0;
}
let mut a = [0, 0, 0, 0];
let mut t;
loop {
getrandom(&mut a).unwrap();
t = (a[0] as usize) << 24 ^ (a[1] as usize) << 16 ^ (a[2] as usize) << 8 ^ (a[3] as usize);
if t < (0b11111111_11111111_11111111_11111111 / limit * limit) {
break;
}
}
t % limit
}
#[cfg(feature = "js")]
pub trait JsShuffle {
fn shuffle_(&mut self);
}
#[cfg(feature = "js")]
impl JsShuffle for Vec<i32> {
fn shuffle_(&mut self) {
let l = self.len();
for i in 1..l {
let id = get_random_int(i + 1);
let t = self[i];
self[i] = self[id];
self[id] = t;
}
}
}
pub fn get_board_1d(area: usize, minenum: usize) -> Vec<i32> {
let mut board_1d: Vec<i32> = vec![];
board_1d.reserve(area);
board_1d = vec![0; area - minenum];
board_1d.append(&mut vec![-1; minenum]);
#[cfg(any(feature = "py", feature = "rs"))]
let mut rng = thread_rng();
#[cfg(any(feature = "py", feature = "rs"))]
board_1d.shuffle(&mut rng);
#[cfg(feature = "js")]
board_1d.shuffle_();
board_1d
}
pub fn trans_board_1d_2d_op(
board_1d: &Vec<i32>,
row: usize,
column: usize,
x0: usize,
y0: usize,
) -> Vec<Vec<i32>> {
let mut board = vec![vec![0; column]; row];
let mut i = 0;
for x in 0..row {
for y in 0..column {
if x <= x0 + 1 && x0 <= x + 1 && y <= y0 + 1 && y0 <= y + 1 {
continue;
}
if board_1d[i] < 0 {
board[x][y] = -1;
for j in max(1, x) - 1..min(row, x + 2) {
for k in max(1, y) - 1..min(column, y + 2) {
if board[j][k] >= 0 {
board[j][k] += 1
}
}
}
}
i += 1;
}
}
board
}
pub fn laymine(row: usize, column: usize, minenum: usize, x0: usize, y0: usize) -> Vec<Vec<i32>> {
let board1_dim = get_board_1d(row * column - 1, minenum);
let mut board1_dim_2: Vec<i32> = vec![];
board1_dim_2.reserve(row * column);
let pointer = x0 + y0 * row;
for i in 0..pointer {
board1_dim_2.push(board1_dim[i]);
}
board1_dim_2.push(0);
for i in pointer..(row * column - 1) {
board1_dim_2.push(board1_dim[i]);
}
let mut board: Vec<Vec<i32>> = vec![vec![0; column]; row];
for i in 0..(row * column) {
if board1_dim_2[i] < 0 {
let x = i % row;
let y = i / row;
board[x][y] = -1;
for j in max(1, x) - 1..min(row, x + 2) {
for k in max(1, y) - 1..min(column, y + 2) {
if board[j][k] >= 0 {
board[j][k] += 1;
}
}
}
}
}
board
}
pub fn laymine_op(
row: usize,
column: usize,
minenum: usize,
x0: usize,
y0: usize,
) -> Vec<Vec<i32>> {
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;
}
}
let area = row * column - area_op;
let board_1d = get_board_1d(area, minenum);
trans_board_1d_2d_op(&board_1d, row, column, x0, y0)
}
pub fn cal_bbbv_on_island<T>(board: &T) -> usize
where
T: std::ops::Index<usize> + safe_board::BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
let row = board.get_row();
let column = board.get_column();
let mut num_bbbv_on_island = 0;
for i in 0..row {
for j in 0..column {
if board[i][j] > 0 {
let mut flag: bool = true;
for x in max(1, i) - 1..min(row, i + 2) {
for y in max(1, j) - 1..min(column, j + 2) {
if board[x][y] == 0 {
flag = false;
}
}
}
if flag {
num_bbbv_on_island += 1;
}
}
}
}
num_bbbv_on_island
}
pub fn cal_bbbv<T>(board: &T) -> usize
where
T: std::ops::Index<usize> + safe_board::BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
cal_bbbv_on_island(board) + cal_op(board)
}
pub fn refresh_board<T>(
board: &T,
board_of_game: &mut Vec<Vec<i32>>,
mut clicked_poses: Vec<(usize, usize)>,
) where
T: std::ops::Index<usize> + safe_board::BoardSize,
T::Output: std::ops::Index<usize, Output = i32>,
{
let row = board.get_row();
let column = board.get_column();
let mut loss_flag = false;
while let Some(top) = clicked_poses.pop() {
let (i, j) = top;
if board[i][j] > 0 {
board_of_game[i][j] = board[i][j];
} else if board[i][j] == 0 {
board_of_game[i][j] = 0;
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if (i != m || j != n)
&& (board_of_game[m][n] == 10 || board_of_game[m][n] == 12)
{
clicked_poses.push((m, n));
}
}
}
} else {
board_of_game[i][j] = 15; loss_flag = true;
}
}
if loss_flag {
for i in 0..row {
for j in 0..column {
if board_of_game[i][j] == 11 && board[i][j] != -1 {
board_of_game[i][j] = 14; }
}
}
}
}
pub fn c(n: usize, k: usize) -> BigNumber {
if k > n {
return BigNumber { a: 0.0, b: 0 };
}
if k > n - k {
return c(n, n - k);
}
let mut result = BigNumber { a: 1.0, b: 0 };
for i in 0..k {
result = &result * ((n - i) as f64 / (i + 1) as f64);
}
result
}
pub fn c_query<T, U>(n: T, k: U) -> usize
where
T: Into<usize>,
U: Into<usize>,
{
let a = [
[1, 0, 0, 0, 0, 0, 0, 0, 0],
[1, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 2, 1, 0, 0, 0, 0, 0, 0],
[1, 3, 3, 1, 0, 0, 0, 0, 0],
[1, 4, 6, 4, 1, 0, 0, 0, 0],
[1, 5, 10, 10, 5, 1, 0, 0, 0],
[1, 6, 15, 20, 15, 6, 1, 0, 0],
[1, 7, 21, 35, 35, 21, 7, 1, 0],
[1, 8, 28, 56, 70, 56, 28, 8, 1],
];
a[n.into()][k.into()]
}
pub fn combine(
matrix_a: &Vec<Vec<i32>>,
matrixx: &Vec<(usize, usize)>,
) -> (Vec<Vec<i32>>, Vec<(usize, usize)>, Vec<Vec<usize>>) {
let mut matrix_a_squeeze = matrix_a.clone();
let mut matrixx_squeeze = matrixx.clone();
let cells_num = matrixx_squeeze.len();
let mut pair_cells = vec![];
let mut del_cells = vec![]; for i in 0..cells_num {
pair_cells.push(vec![i]);
for j in i + 1..cells_num {
if !matrix_a_squeeze.iter().any(|x| x[i] != x[j]) {
pair_cells[i].push(j);
del_cells.push(j);
}
}
}
del_cells.sort_by(|a, b| b.cmp(&a));
del_cells.dedup();
for i in del_cells {
for r in 0..matrix_a_squeeze.len() {
matrix_a_squeeze[r].remove(i);
}
matrixx_squeeze.remove(i);
pair_cells.remove(i);
}
let cell_squeeze_num = pair_cells.len();
for i in 0..cell_squeeze_num {
let k = pair_cells[i].len() as i32;
for r in 0..matrix_a_squeeze.len() {
matrix_a_squeeze[r][i] *= k;
}
}
(matrix_a_squeeze, matrixx_squeeze, pair_cells)
}
pub fn cal_all_solution(matrix_a: &Vec<Vec<i32>>, matrixb: &Vec<i32>) -> Vec<Vec<u8>> {
let column = matrix_a[0].len();
let row = matrix_a.len();
let mut enum_comb_table: Vec<Vec<u8>> = vec![vec![0; column]];
let mut not_enum_cell: Vec<bool> = vec![true; column]; let mut enum_cell_table: Vec<Vec<usize>> = vec![];
for row in 0..row {
let mut new_enum_cell = vec![]; let mut enum_cell = vec![]; let mut new_enum_max = vec![];
for j in 0..column {
if matrix_a[row][j] > 0 {
enum_cell.push(j);
if not_enum_cell[j] {
not_enum_cell[j] = false;
new_enum_cell.push(j);
new_enum_max.push(matrix_a[row][j]);
}
}
}
let mut new_enum_table = (0..new_enum_cell.len())
.map(|i| 0..new_enum_max[i] + 1)
.multi_cartesian_product()
.collect::<Vec<_>>();
new_enum_table.retain(|x| x.iter().sum::<i32>() <= matrixb[row]);
if new_enum_table.is_empty() {
enum_comb_table.retain(|item| {
enum_cell
.iter()
.fold(0, |sum: u8, i: &usize| sum + item[*i])
== matrixb[row] as u8
});
} else {
let mut flag_1 = true; let enum_comb_table_len = enum_comb_table.len();
for item in new_enum_table {
if flag_1 {
for m in 0..new_enum_cell.len() {
for n in 0..enum_comb_table_len {
enum_comb_table[n][new_enum_cell[m]] = item[m] as u8;
}
}
flag_1 = false;
} else {
for n in 0..enum_comb_table_len {
let mut one_row_in_new_table = enum_comb_table[n].clone();
for m in 0..new_enum_cell.len() {
one_row_in_new_table[new_enum_cell[m]] = item[m] as u8;
}
enum_comb_table.push(one_row_in_new_table);
}
}
} let mut equations = vec![];
for kk in &enum_cell {
for rr in 0..row {
if matrix_a[rr][*kk] > 0 {
equations.push(rr);
}
}
}
equations.dedup();
for equ in equations {
enum_comb_table.retain(|item| {
enum_cell_table[equ]
.iter()
.fold(0, |sum: u8, i: &usize| sum + item[*i])
== matrixb[equ] as u8
});
}
enum_comb_table.retain(|item| {
enum_cell
.iter()
.fold(0, |sum: u8, i: &usize| sum + item[*i])
== matrixb[row] as u8
}); }
enum_cell_table.push(enum_cell);
}
enum_comb_table
}
fn cal_cell_and_equation_map(matrix_a: &Vec<Vec<i32>>) -> (Vec<Vec<usize>>, Vec<Vec<usize>>) {
let cells_num = matrix_a[0].len();
let equations_num = matrix_a.len();
let mut cell_to_equation_map = vec![vec![]; cells_num];
let mut equation_to_cell_map = vec![vec![]; equations_num];
for i in 0..equations_num {
for j in 0..cells_num {
if matrix_a[i][j] >= 1 {
equation_to_cell_map[i].push(j);
cell_to_equation_map[j].push(i);
}
}
}
(cell_to_equation_map, equation_to_cell_map)
}
fn cal_table_minenum_recursion_step(
idx: usize,
current_amount: usize,
table_minenum: &mut [Vec<usize>; 2],
table_cell_minenum: &mut Vec<Vec<usize>>,
matrix_a_squeeze: &Vec<Vec<i32>>,
matrix_b: &Vec<i32>,
matrix_b_remain: &mut Vec<i32>,
combination_relationship: &Vec<Vec<usize>>,
cell_to_equation_map: &Vec<Vec<usize>>,
equation_to_cell_map: &Vec<Vec<usize>>,
mine_vec: &mut Vec<usize>,
) -> Result<bool, usize> {
let cells_num = matrix_a_squeeze[0].len();
if idx >= cells_num {
let total_mines_num: usize = mine_vec.iter().sum();
if total_mines_num >= table_minenum[1].len() {
return Err(5);
}
table_minenum[1][total_mines_num] += current_amount;
for (idn, n) in mine_vec.iter().enumerate() {
table_cell_minenum[total_mines_num][idn] +=
current_amount * n / combination_relationship[idn].len();
}
return Ok(true);
}
let mut upper_limit = combination_relationship[idx].len();
let mut lower_limit = 0usize;
for cell_i in &cell_to_equation_map[idx] {
if matrix_a_squeeze[*cell_i][idx] == 0 {
continue;
}
let upper_limit_i = min(
matrix_b_remain[*cell_i],
combination_relationship[idx].len() as i32,
);
let mut lower_limit_i = matrix_b_remain[*cell_i];
for j in &equation_to_cell_map[*cell_i] {
if j > &idx {
lower_limit_i -= combination_relationship[*j].len() as i32;
}
}
if upper_limit_i < upper_limit as i32 {
upper_limit = upper_limit_i as usize;
}
if lower_limit_i > lower_limit as i32 {
lower_limit = lower_limit_i as usize;
}
}
for u in lower_limit..upper_limit + 1 {
mine_vec[idx] = u;
if u > 0 {
for tt in &cell_to_equation_map[idx] {
matrix_b_remain[*tt] -= u as i32;
}
}
let _ = cal_table_minenum_recursion_step(
idx + 1,
current_amount * c_query(combination_relationship[idx].len(), u),
table_minenum,
table_cell_minenum,
&matrix_a_squeeze,
&matrix_b,
matrix_b_remain,
&combination_relationship,
&cell_to_equation_map,
&equation_to_cell_map,
mine_vec,
)?;
for tt in &cell_to_equation_map[idx] {
matrix_b_remain[*tt] += u as i32;
}
mine_vec[idx] = 0;
}
Ok(false)
}
pub fn cal_table_minenum_recursion(
matrix_a_squeeze: &Vec<Vec<i32>>,
matrixx_squeeze: &Vec<(usize, usize)>,
matrix_b: &Vec<i32>,
combination_relationship: &Vec<Vec<usize>>,
) -> Result<([Vec<usize>; 2], Vec<Vec<usize>>), usize> {
let cells_num = matrixx_squeeze.len();
if cells_num > ENUM_LIMIT {
return Err(cells_num);
}
let cells_num_total = combination_relationship
.iter()
.fold(0, |item, x| item + x.len());
let mut flag_legal_board = true;
let mut table_minenum: [Vec<usize>; 2] = [
(0..cells_num_total + 1).collect::<Vec<usize>>(),
vec![0; cells_num_total + 1],
];
let (cell_to_equation_map, equation_to_cell_map) = cal_cell_and_equation_map(&matrix_a_squeeze);
let mut table_cell_minenum: Vec<Vec<usize>> = vec![vec![0; cells_num]; cells_num_total + 1];
cal_table_minenum_recursion_step(
0,
1,
&mut table_minenum,
&mut table_cell_minenum,
&matrix_a_squeeze,
&matrix_b,
&mut matrix_b.clone(),
&combination_relationship,
&cell_to_equation_map,
&equation_to_cell_map,
&mut (vec![0; cells_num]),
)?;
while table_minenum[1][0] == 0 {
table_minenum[0].remove(0);
table_minenum[1].remove(0);
table_cell_minenum.remove(0);
if table_cell_minenum.is_empty() {
flag_legal_board = false;
break;
}
}
if flag_legal_board {
while table_minenum[1][table_cell_minenum.len() - 1] == 0 {
table_minenum[0].pop();
table_minenum[1].pop();
table_cell_minenum.pop();
}
}
if flag_legal_board {
Ok((table_minenum, table_cell_minenum))
} else {
return Err(1);
}
}
pub fn unsolvable_structure(board_check: &Vec<Vec<i32>>) -> bool {
let row = board_check.len();
let column = board_check[0].len();
let mut board = vec![vec![0; column]; row];
for i in 0..row {
for j in 0..column {
if board_check[i][j] == -1 {
board[i][j] = -1;
}
}
}
for i in 0..row - 2 {
if i < row - 3 {
if board[i][0] == -1
&& board[i][1] == -1
&& board[i + 3][0] == -1
&& board[i + 3][1] == -1
&& board[i + 1][0] + board[i + 2][0] == -1
|| board[i][column - 1] == -1
&& board[i][column - 2] == -1
&& board[i + 3][column - 1] == -1
&& board[i + 3][column - 2] == -1
&& board[i + 1][column - 1] + board[i + 2][column - 1] == -1
{
return true;
}
}
if board[i][2] == -1
&& board[i + 1][2] == -1
&& board[i + 2][2] == -1
&& board[i + 1][0] + board[i + 1][1] == -1
|| board[i][column - 3] == -1
&& board[i + 1][column - 3] == -1
&& board[i + 2][column - 3] == -1
&& board[i + 1][column - 1] + board[i + 1][column - 2] == -1
|| board[i][0] == -1
&& board[i][1] == -1
&& board[i + 1][1] == -1
&& board[i + 2][1] == -1
&& board[i + 2][0] == -1
&& board[i + 1][0] == 0
|| board[i][column - 1] == -1
&& board[i][column - 2] == -1
&& board[i + 1][column - 2] == -1
&& board[i + 2][column - 2] == -1
&& board[i + 2][column - 1] == -1
&& board[i + 1][column - 1] == 0
{
return true;
}
if i < row - 3 {
if board[i][2] == -1
&& board[i + 3][2] == -1
&& board[i + 1][0] + board[i + 1][1] == -1
&& board[i + 1][1] + board[i + 2][1] == -1
&& board[i + 2][1] + board[i + 2][0] == -1
|| board[i][column - 3] == -1
&& board[i + 3][column - 3] == -1
&& board[i + 1][column - 1] + board[i + 1][column - 2] == -1
&& board[i + 1][column - 2] + board[i + 2][column - 2] == -1
&& board[i + 2][column - 2] + board[i + 2][column - 1] == -1
{
return true;
}
}
}
for j in 0..column - 2 {
if j < column - 3 {
if board[0][j] == -1
&& board[1][j] == -1
&& board[0][j + 3] == -1
&& board[1][j + 3] == -1
&& board[0][j + 1] + board[0][j + 2] == -1
|| board[row - 1][j] == -1
&& board[row - 2][j] == -1
&& board[row - 1][j + 3] == -1
&& board[row - 2][j + 3] == -1
&& board[row - 1][j + 1] + board[row - 1][j + 2] == -1
{
return true;
}
}
if board[2][j] == -1
&& board[2][j + 1] == -1
&& board[2][j + 2] == -1
&& board[0][j + 1] + board[1][j + 1] == -1
|| board[row - 3][j] == -1
&& board[row - 3][j + 1] == -1
&& board[row - 3][j + 2] == -1
&& board[row - 1][j + 1] + board[row - 2][j + 1] == -1
|| board[0][j] == -1
&& board[1][j] == -1
&& board[1][j + 1] == -1
&& board[1][j + 2] == -1
&& board[0][j + 2] == -1
&& board[0][j + 1] == 0
|| board[row - 1][j] == -1
&& board[row - 2][j] == -1
&& board[row - 2][j + 1] == -1
&& board[row - 2][j + 2] == -1
&& board[row - 1][j + 2] == -1
&& board[row - 1][j + 1] == 0
{
return true;
}
if j < column - 3 {
if board[2][j] == -1
&& board[2][j + 3] == -1
&& board[0][j + 1] + board[1][j + 1] == -1
&& board[1][j + 1] + board[1][j + 2] == -1
&& board[1][j + 2] + board[0][j + 2] == -1
|| board[row - 3][j] == -1
&& board[row - 3][j + 3] == -1
&& board[row - 1][j + 1] + board[row - 2][j + 1] == -1
&& board[row - 2][j + 1] + board[row - 2][j + 2] == -1
&& board[row - 2][j + 2] + board[row - 1][j + 2] == -1
{
return true;
}
}
}
if board[0][2] == -1 && board[1][2] == -1 && board[0][0] + board[0][1] == -1
|| board[2][0] == -1 && board[2][1] == -1 && board[0][0] + board[1][0] == -1
|| board[0][column - 3] == -1
&& board[1][column - 3] == -1
&& board[0][column - 1] + board[0][column - 2] == -1
|| board[2][column - 1] == -1
&& board[2][column - 2] == -1
&& board[0][column - 1] + board[1][column - 1] == -1
|| board[row - 1][2] == -1
&& board[row - 2][2] == -1
&& board[row - 1][0] + board[row - 1][1] == -1
|| board[row - 3][0] == -1
&& board[row - 3][1] == -1
&& board[row - 1][0] + board[row - 2][0] == -1
|| board[row - 1][column - 3] == -1
&& board[row - 2][column - 3] == -1
&& board[row - 1][column - 1] + board[row - 1][column - 2] == -1
|| board[row - 3][column - 1] == -1
&& board[row - 3][column - 2] == -1
&& board[row - 1][column - 1] + board[row - 2][column - 1] == -1
|| board[0][1] + board[1][1] + board[1][0] == -3 && board[0][0] == 0
|| board[0][column - 2] + board[1][column - 2] + board[1][column - 1] == -3
&& board[0][column - 1] == 0
|| board[row - 1][column - 2] + board[row - 2][column - 2] + board[row - 2][column - 1]
== -3
&& board[row - 1][column - 1] == 0
|| board[row - 1][1] + board[row - 2][1] + board[row - 2][0] == -3 && board[row - 1][0] == 0
|| board[2][2] == -1 && board[0][1] + board[1][1] == -1 && board[1][0] + board[1][1] == -1
|| board[row - 3][2] == -1
&& board[row - 1][1] + board[row - 2][1] == -1
&& board[row - 2][0] + board[row - 2][1] == -1
|| board[row - 3][column - 3] == -1
&& board[row - 1][column - 2] + board[row - 2][column - 2] == -1
&& board[row - 2][column - 1] + board[row - 2][column - 2] == -1
|| board[2][column - 3] == -1
&& board[0][column - 2] + board[1][column - 2] == -1
&& board[1][column - 1] + board[1][column - 2] == -1
{
return true;
}
for i in 0..row - 2 {
for j in 0..column - 2 {
if j < column - 3 {
if board[i][j] == -1
&& board[i + 1][j] == -1
&& board[i + 2][j] == -1
&& board[i][j + 3] == -1
&& board[i + 1][j + 3] == -1
&& board[i + 2][j + 3] == -1
&& board[i + 1][j + 1] + board[i + 1][j + 2] == -1
{
return true;
}
}
if i < row - 3 {
if board[i][j] == -1
&& board[i][j + 1] == -1
&& board[i][j + 2] == -1
&& board[i + 3][j] == -1
&& board[i + 3][j + 1] == -1
&& board[i + 3][j + 2] == -1
&& board[i + 1][j + 1] + board[i + 2][j + 1] == -1
{
return true;
}
}
if board[i][j] == -1
&& board[i + 1][j] == -1
&& board[i + 2][j] == -1
&& board[i][j + 1] == -1
&& board[i + 2][j + 1] == -1
&& board[i][j + 2] == -1
&& board[i + 1][j + 2] == -1
&& board[i + 2][j + 2] == -1
&& board[i + 1][j + 1] == 0
{
return true;
}
if j < column - 3 && i < row - 3 {
if board[i][j] == -1
&& board[i + 3][j] == -1
&& board[i][j + 3] == -1
&& board[i + 3][j + 3] == -1
&& board[i + 1][j + 1] + board[i + 2][j + 1] == -1
&& board[i + 1][j + 1] + board[i + 1][j + 2] == -1
&& board[i + 2][j + 1] + board[i + 2][j + 2] == -1
{
return true;
}
}
}
}
false
}
#[cfg(any(feature = "py", feature = "rs"))]
pub fn cal_bbbv_exp(board_in: &Vec<Vec<i32>>) -> usize {
let mut board = board_in.clone();
let mut op_id = 0;
let mut op_list = [false; 200];
let mut bv = 0;
for x in 0..16 {
for y in 0..30 {
if board[x][y] > 0 {
board[x][y] = 1000000;
bv += 1;
} else if board[x][y] == 0 {
let mut min_op_id = 1000;
let mut flag_op = false; if x >= 1 {
for j in max(1, y) - 1..min(30, y + 2) {
if board[x - 1][j] > 999999 {
board[x - 1][j] = 1;
bv -= 1;
} else if board_in[x - 1][j] == 0 {
if board[x - 1][j] < min_op_id {
if flag_op {
op_list[min_op_id as usize] = false;
} else {
flag_op = true;
}
min_op_id = board[x - 1][j];
}
}
}
}
if y >= 1 {
if board[x][y - 1] > 999999 {
board[x][y - 1] = 1;
bv -= 1;
} else if board_in[x][y - 1] == 0 {
if board[x][y - 1] < min_op_id {
if flag_op {
op_list[min_op_id as usize] = false;
} else {
flag_op = true;
}
}
}
}
if !flag_op {
op_id += 1;
op_list[op_id as usize] = true;
}
}
}
}
for x in (0..16).rev() {
for y in (0..30).rev() {
if board[x][y] == 0 {
if x <= 14 {
for j in max(1, y) - 1..min(30, y + 2) {
if board[x + 1][j] > 999999 {
board[x + 1][j] = 1;
bv -= 1;
} else if board_in[x + 1][j] == 0 {
if board[x + 1][j] < board[x][y] {
op_list[board[x][y] as usize] = false;
board[x][y] = board[x + 1][j];
}
}
}
}
if y <= 28 {
if board[x][y + 1] > 999999 {
board[x][y + 1] = 1;
bv -= 1;
} else if board_in[x][y + 1] == 0 {
if board[x][y + 1] < board[x][y] {
op_list[board[x][y] as usize] = false;
board[x][y] = board[x][y + 1];
}
}
}
}
}
}
for i in 0..op_id + 1 {
if op_list[i] {
bv += 1;
}
}
bv
}
#[cfg(any(feature = "py", feature = "rs"))]
pub fn legalize_board(board: &mut Vec<Vec<i32>>) {
let row = board.len();
let column = board[0].len();
for x in 0..row {
for y in 0..column {
if board[x][y] <= -1 || board[x][y] >= 13 || board[x][y] == 9 {
board[x][y] = 10;
} else if board[x][y] >= 1 && board[x][y] <= 8 {
let mut minenum_limit = 0;
for i in max(1, x) - 1..min(row, x + 2) {
for j in max(1, y) - 1..min(column, y + 2) {
if board[i][j] == 10 || board[i][j] == 11 {
minenum_limit += 1;
}
}
}
board[x][y] = min(board[x][y], minenum_limit);
}
}
}
}
pub fn chunk_matrixes(
matrix_as: &mut Vec<Vec<Vec<i32>>>,
matrix_xs: &mut Vec<Vec<(usize, usize)>>,
matrix_bs: &mut Vec<Vec<i32>>,
) {
let block_num = matrix_bs.len();
let mut aas = vec![];
let mut xxs = vec![];
let mut bbs = vec![];
for _ in 0..block_num {
let aa = matrix_as.pop().unwrap();
let xx = matrix_xs.pop().unwrap();
let bb = matrix_bs.pop().unwrap();
let (mut a_, mut x_, mut b_) = chunk_matrix(aa, xx, bb);
aas.append(&mut a_);
xxs.append(&mut x_);
bbs.append(&mut b_);
}
*matrix_as = aas;
*matrix_xs = xxs;
*matrix_bs = bbs;
}
pub fn chunk_matrix(
mut matrix_a: Vec<Vec<i32>>,
mut matrix_x: Vec<(usize, usize)>,
mut matrix_b: Vec<i32>,
) -> (Vec<Vec<Vec<i32>>>, Vec<Vec<(usize, usize)>>, Vec<Vec<i32>>) {
let mut block_id = 0;
let mut matrix_as = vec![];
let mut matrix_xs = vec![];
let mut matrix_bs = vec![];
loop {
let row_num = matrix_a.len();
let column_num = matrix_a[0].len();
let mut current_rows_bool = vec![false; row_num];
let mut current_columns_bool = vec![false; column_num];
current_columns_bool[0] = true;
let mut column_buffer = vec![0];
loop {
let mut row_buffer = vec![];
if column_buffer.is_empty() {
break;
}
for i in &column_buffer {
for idr in 0..matrix_a.len() {
if matrix_a[idr][*i] >= 1 && !current_rows_bool[idr] {
row_buffer.push(idr);
current_rows_bool[idr] = true;
}
}
}
column_buffer.clear();
if row_buffer.is_empty() {
break;
}
for i in row_buffer {
for (idc, &c) in matrix_a[i].iter().enumerate() {
if c >= 1 && !current_columns_bool[idc] {
column_buffer.push(idc);
current_columns_bool[idc] = true;
}
}
}
}
let mut current_rows = vec![];
let mut current_columns = vec![];
for (idx, &x) in current_columns_bool.iter().enumerate() {
if x {
current_columns.push(idx)
}
}
for (idx, &x) in current_rows_bool.iter().enumerate() {
if x {
current_rows.push(idx)
}
}
current_rows.sort_by(|a, b| b.cmp(a));
current_rows.dedup();
current_columns.sort_by(|a, b| b.cmp(a));
current_columns.dedup();
matrix_as.push(vec![vec![0; current_columns.len()]; current_rows.len()]);
matrix_bs.push(vec![0; current_rows.len()]);
matrix_xs.push(vec![(0, 0); current_columns.len()]);
for (idx, x) in current_rows.iter().enumerate() {
for (idy, y) in current_columns.iter().enumerate() {
matrix_as[block_id][idx][idy] = matrix_a[*x][*y];
}
}
for (idx, x) in current_rows.iter().enumerate() {
matrix_bs[block_id][idx] = matrix_b[*x];
}
for (idy, y) in current_columns.iter().enumerate() {
matrix_xs[block_id][idy] = matrix_x[*y];
}
for i in current_rows {
matrix_a.remove(i);
matrix_b.remove(i);
}
for j in current_columns {
for k in 0..matrix_a.len() {
matrix_a[k].remove(j);
}
matrix_x.remove(j);
}
if matrix_b.is_empty() {
break;
}
block_id += 1;
}
(matrix_as, matrix_xs, matrix_bs)
}
#[test]
fn chunk_matrix_works() {
let a = vec![
vec![1, 1, 0, 0],
vec![0, 0, 1, 1],
vec![0, 1, 0, 0],
vec![0, 0, 0, 1],
];
let x = vec![(1, 2), (3, 4), (5, 6), (7, 8)];
let b = vec![1, 2, 3, 4];
let (_aa, xx, _bb) = chunk_matrix(a, x, b);
println!("{:?}", xx);
}
pub fn find_a_border_cell(
board_of_game: &Vec<Vec<i32>>,
xy: &(usize, usize),
) -> (Option<(usize, usize)>, bool) {
let row = board_of_game.len();
let column = board_of_game[0].len();
for m in max(1, xy.0) - 1..min(row, xy.0 + 2) {
for n in max(1, xy.1) - 1..min(column, xy.1 + 2) {
if board_of_game[m][n] < 10 {
return (Some(*xy), true);
}
}
}
let mut board_of_game_clone = board_of_game.clone();
board_of_game_clone[xy.0][xy.1] = 100;
let mut buffer = vec![(xy.0, xy.1)];
while let Some(top) = buffer.pop() {
let (i, j) = top;
for m in max(1, i) - 1..min(row, i + 2) {
for n in max(1, j) - 1..min(column, j + 2) {
if (i != m || j != n) && board_of_game_clone[m][n] == 10 {
for mm in max(1, m) - 1..min(row, m + 2) {
for nn in max(1, n) - 1..min(column, n + 2) {
if board_of_game_clone[mm][nn] < 10 {
return (Some((m, n)), false);
}
}
}
buffer.push((m, n));
board_of_game_clone[m][n] = 100;
}
}
}
}
(None, false)
}
pub fn is_good_chording(board_of_game: &Vec<Vec<i32>>, pos: (usize, usize)) -> bool {
let row = board_of_game.len();
let column = board_of_game[0].len();
let mid_num = surround_cell_num(board_of_game, pos);
if pos.0 > 0 {
if mid_num < surround_cell_num(board_of_game, (pos.0 - 1, pos.1)) {
return false;
}
}
if pos.1 > 0 {
if mid_num < surround_cell_num(board_of_game, (pos.0, pos.1 - 1)) {
return false;
}
}
if pos.0 + 1 < row {
if mid_num < surround_cell_num(board_of_game, (pos.0 + 1, pos.1)) {
return false;
}
}
if pos.1 < column + 1 {
if mid_num < surround_cell_num(board_of_game, (pos.0, pos.1 + 1)) {
return false;
}
}
return mid_num > 0;
}
fn surround_cell_num(board_of_game: &Vec<Vec<i32>>, pos: (usize, usize)) -> i8 {
let row = board_of_game.len();
let column = board_of_game[0].len();
if board_of_game[pos.0][pos.1] > 8 || board_of_game[pos.0][pos.1] < 1 {
return -1;
}
let mut flag_num = 0;
let mut num = 0;
for m in max(1, pos.0) - 1..min(row, pos.0 + 2) {
for n in max(1, pos.1) - 1..min(column, pos.1 + 2) {
if board_of_game[m][n] == 10 {
num += 1;
} else if board_of_game[m][n] == 11 {
flag_num += 1;
}
}
}
if board_of_game[pos.0][pos.1] as i8 == flag_num {
return num;
} else {
return -1;
}
}
pub fn cal_board_numbers(board: &mut Vec<Vec<i32>>) {
let height = board.len();
let width = board[0].len();
for x in 0..height {
for y in 0..width {
if board[x][y] == -1 {
for j in max(1, x) - 1..min(height, x + 2) {
for k in max(1, y) - 1..min(width, y + 2) {
if board[j][k] >= 0 {
board[j][k] += 1;
}
}
}
}
}
}
}