use crate::db::{self};
use rand::seq::IteratorRandom;
use std::cell::RefCell;
pub enum State {
Menu,
Playing,
Lost,
Won,
}
pub trait Move {
fn move_all_down(&mut self);
fn move_all_up(&mut self);
fn move_all_left(&mut self);
fn move_all_right(&mut self);
}
#[derive(Debug)]
pub struct Board {
pub size: [[u32; 4]; 4],
pub db: RefCell<db::Score>,
}
impl Board {
pub fn new() -> Self {
Self {
size: [[0; 4]; 4],
db: RefCell::new(db::Score::new().unwrap()),
}
}
#[inline(always)]
pub fn clear(&mut self) {
self.size
.iter_mut()
.flat_map(|r| r.iter_mut())
.for_each(|x| *x = 0);
}
pub fn init_board(&mut self) {
self.clear();
let mut rng = rand::rng();
let empty_positions: Vec<(usize, usize)> = (0..4)
.flat_map(|row| (0..4).map(move |col| (row, col)))
.collect();
for &(row, col) in empty_positions.iter().choose_multiple(&mut rng, 2).iter() {
self.size[*row][*col] = 2;
}
}
pub fn spawn_one_random(&mut self) {
let mut rng = rand::rng();
let mut empty_cells = Vec::new();
for row in 0..4 {
for col in 0..4 {
if self.size[row][col] == 0 {
empty_cells.push((row, col));
}
}
}
if let Some((row, col)) = empty_cells.into_iter().choose(&mut rng) {
let value = if rand::random::<f32>() < 0.9 { 2 } else { 4 };
self.size[row][col] = value;
}
}
#[inline(always)]
pub fn won(&self) -> bool {
self.size.iter().flatten().any(|&x| x == 2048)
}
pub fn lost(&self) -> bool {
let n = self.size.len();
if self.size.iter().flatten().any(|&x| x == 0) {
return false;
}
for i in 0..n {
for j in 0..n {
let current = self.size[i][j];
if j + 1 < n && self.size[i][j + 1] == current {
return false;
}
if i + 1 < n && self.size[i + 1][j] == current {
return false;
}
}
}
true
}
#[inline(always)]
pub fn calculate_score(&self) -> u32 {
let val: u32 = self.size.iter().flatten().sum();
if val > self.db.borrow().get_score().unwrap() {
self.db.borrow_mut().update_score(val).unwrap()
}
val
}
}
impl Move for Board {
fn move_all_down(&mut self) {
for i in 0..self.size.len() {
let mut merged = [false; 4];
let mut stack: Vec<(u32, usize)> = Vec::new();
let mut j = 0;
while j < self.size[0].len() {
stack.push((self.size[j][i], j));
j += 1;
}
while let Some(value) = stack.pop() {
let mut index = value.1;
while index + 1 < j {
let val: u32 = self.size[index][i];
match self.size[index + 1][i] {
0 => {
self.size[index + 1][i] = val;
self.size[index][i] = 0;
index += 1;
}
other if other == val && !merged[index + 1] => {
self.size[index + 1][i] += other;
self.size[index][i] = 0;
merged[index + 1] = true;
break;
}
_ => break,
}
}
}
}
}
fn move_all_up(&mut self) {
for i in 0..self.size.len() {
let mut merged = [false; 4];
let mut stack: Vec<(u32, usize)> = Vec::new();
let mut j = self.size[0].len() - 1;
while j > 0 {
stack.push((self.size[j][i], j));
j -= 1;
}
while let Some(value) = stack.pop() {
let mut index = value.1;
while index > 0 {
let val: u32 = self.size[index][i];
match self.size[index - 1][i] {
0 => {
self.size[index - 1][i] = val;
self.size[index][i] = 0;
index -= 1;
}
other if other == val && !merged[index - 1] => {
self.size[index - 1][i] += other;
self.size[index][i] = 0;
merged[index - 1] = true;
break;
}
_ => break,
}
}
}
}
}
fn move_all_right(&mut self) {
for i in 0..self.size.len() {
let mut merged = [false; 4];
let mut stack: Vec<(u32, usize)> = Vec::new();
let mut j = 0;
while j < self.size[0].len() {
stack.push((self.size[i][j], j));
j += 1;
}
while let Some(value) = stack.pop() {
let mut index = value.1;
while index + 1 < j {
let val = self.size[i][index];
match self.size[i][index + 1] {
0 => {
self.size[i][index + 1] = val;
self.size[i][index] = 0;
index += 1;
}
other if other == val && !merged[index + 1] => {
self.size[i][index + 1] += other;
self.size[i][index] = 0;
merged[index + 1] = true;
break;
}
_ => break,
}
}
}
}
}
fn move_all_left(&mut self) {
for i in 0..self.size.len() {
let mut merged = [false; 4];
let mut stack: Vec<(u32, usize)> = Vec::new();
let mut j = self.size[0].len() - 1;
while j > 0 {
stack.push((self.size[i][j], j));
j -= 1;
}
while let Some(value) = stack.pop() {
let mut index = value.1;
while index > 0 {
let val = self.size[i][index];
match self.size[i][index - 1] {
0 => {
self.size[i][index - 1] = val;
self.size[i][index] = 0;
index -= 1;
}
other if other == val && !merged[index - 1] => {
self.size[i][index - 1] += other;
self.size[i][index] = 0;
merged[index - 1] = true;
break;
}
_ => break,
}
}
}
}
}
}