use std::collections::HashMap;
use std::fmt;
use std::fmt::Write;
use std::ops::Shl;
use crate::Stone;
pub trait Board {
fn size(&self) -> (usize, usize);
fn new(height: usize, width: usize) -> Self;
fn get(&self, row: usize, col: usize) -> Stone;
fn set(&mut self, row: usize, col: usize, val: Stone);
}
#[derive(Debug, Copy, Clone)]
pub struct BoardDisplay<'a, T: Board> {
board: &'a T,
}
impl<'a, T: Board> From<&'a T> for BoardDisplay<'a, T> {
fn from(board: &'a T) -> Self {
Self {
board,
}
}
}
impl<T: Board> fmt::Display for BoardDisplay<'_, T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let size = self.board.size();
for i in 0..size.0 - 1 {
for j in 0..size.1 {
f.write_char(self.board.get(i, j).into())?;
}
f.write_char('\n')?;
}
for j in 0..size.1 {
f.write_char(self.board.get(size.0 - 1, j).into())?;
}
Ok(())
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct VecBoard {
vec: Vec<Stone>,
width: usize,
}
impl VecBoard {
pub fn from_vec(vec: Vec<Stone>, width: usize) -> Self {
if vec.len() % width != 0 {
panic!("Square number = {} is not a multiple of width = {}", vec.len(), width);
}
Self {
vec,
width,
}
}
}
impl Board for VecBoard {
fn size(&self) -> (usize, usize) {
(self.vec.len() / self.width, self.width)
}
fn new(height: usize, width: usize) -> Self {
Self {
vec: vec![Stone::None; height * width],
width,
}
}
fn get(&self, row: usize, col: usize) -> Stone {
self.vec[row * self.width + col]
}
fn set(&mut self, row: usize, col: usize, val: Stone) {
self.vec[row * self.width + col] = val;
}
}
#[derive(Debug, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
pub struct BinBoard {
vec: Vec<u8>,
width: usize,
}
impl BinBoard {
pub fn from_iter<T: Iterator<Item=Stone>>(iter: &mut T, width: usize) -> Self {
let mut vec = Vec::new();
let mut i = 4usize;
let mut len = 0usize;
for stone in iter {
if i > 3 {
vec.push(0);
i = 0;
}
*vec.last_mut().unwrap() |= u8::shl(stone.into(), i * 2);
i += 1;
len += 1;
}
if len % width != 0 {
panic!("Square number = {} is not a multiple of width = {}", vec.len(), width);
}
while i < 4 {
*vec.last_mut().unwrap() |= 3 << i * 2;
i += 1;
}
Self {
vec,
width,
}
}
}
impl Board for BinBoard {
fn size(&self) -> (usize, usize) {
let mut nulls = 0usize;
while (self.vec.last().unwrap() >> (3 - nulls) * 2) & 3 == 3 {
nulls += 1;
}
((self.vec.len() * 4 - nulls) / self.width, self.width)
}
fn new(height: usize, width: usize) -> Self {
let mut vec = vec![Stone::None.into(); (height * width + 3) / 4];
if height * width % 4 != 0 {
*vec.last_mut().unwrap() = 0xffu8;
for i in 0..height * width % 4 {
*vec.last_mut().unwrap() ^= 3 << (i * 2);
}
}
Self {
vec,
width,
}
}
fn get(&self, row: usize, col: usize) -> Stone {
let i = row * self.width + col;
((self.vec[i / 4] >> i % 4 * 2) & 3).into()
}
fn set(&mut self, row: usize, col: usize, val: Stone) {
let i = row * self.width + col;
assert_ne!((self.vec[i / 4] >> i % 4 * 2) & 3, 3);
self.vec[i / 4] &= u8::MAX ^ 3 << i % 4 * 2;
self.vec[i / 4] |= u8::shl(val.into(), i % 4 * 2);
}
}
impl<T: Board> From<&T> for BinBoard {
fn from(board: &T) -> Self {
let (height, width) = board.size();
let mut this = BinBoard::new(height, width);
let mut i = 0;
for x in 0..height {
for y in 0..width {
this.vec[i / 4] |= u8::shl(board.get(x, y).into(), i % 4 * 2);
i += 1;
}
}
this
}
}
#[derive(Debug, Clone)]
pub struct EditedBoard<'a, B: Board> {
board: &'a B,
map: HashMap<(usize, usize), Stone>,
}
impl<'a, B: Board> EditedBoard<'a, B> {
pub fn new(board: &'a B, row: usize, col: usize, val: Stone) -> Self {
if row >= board.size().0 || col >= board.size().1 {
panic!("Square {}, {} is out of bounds", row, col);
}
Self {
board,
map: HashMap::from([((row, col), val)]),
}
}
}
impl<'a, B: Board> From<&'a B> for EditedBoard<'a, B> {
fn from(board: &'a B) -> Self {
Self {
board,
map: HashMap::new(),
}
}
}
impl<B: Board> Board for EditedBoard<'_, B> {
fn size(&self) -> (usize, usize) {
self.board.size()
}
fn new(_height: usize, _width: usize) -> Self {
unimplemented!()
}
fn get(&self, row: usize, col: usize) -> Stone {
match self.map.get(&(row, col)) {
None => self.board.get(row, col),
Some(x) => *x,
}
}
fn set(&mut self, row: usize, col: usize, val: Stone) {
if row >= self.size().0 || col >= self.size().1 {
panic!("Square {}, {} is out of bounds", row, col);
}
self.map.insert((row, col), val);
}
}