|
| 1 | +#![doc = include_str!("./README.md")] |
| 2 | + |
| 3 | +#[cfg(feature = "egui")] |
| 4 | +pub mod gui; |
| 5 | + |
| 6 | +use array2d::Array2D; |
| 7 | +use game_solver::{game::{Game, GameState}, player::PartizanPlayer}; |
| 8 | +use thiserror::Error; |
| 9 | + |
| 10 | +#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)] |
| 11 | +pub enum InnerCellType { |
| 12 | + Wave, |
| 13 | + Cross, |
| 14 | + Circle, |
| 15 | + Square, |
| 16 | + Star |
| 17 | +} |
| 18 | + |
| 19 | +#[derive(Clone, Copy, Hash, Eq, PartialEq, Debug)] |
| 20 | +pub struct CellType(InnerCellType, PartizanPlayer); |
| 21 | + |
| 22 | +#[derive(Clone, Hash, Eq, PartialEq)] |
| 23 | +pub struct Zener { |
| 24 | + /// [0] is the piece on the bottom, [len - 1] is the piece on top. |
| 25 | + board: Array2D<Vec<CellType>>, |
| 26 | + player: PartizanPlayer, |
| 27 | + compulsory: Option<InnerCellType>, |
| 28 | + move_count: usize, |
| 29 | + gutter: Option<CellType>, |
| 30 | +} |
| 31 | + |
| 32 | +const NUM_ROWS: usize = 7; |
| 33 | +const NUM_COLS: usize = 5; |
| 34 | + |
| 35 | +impl Default for Zener { |
| 36 | + fn default() -> Self { |
| 37 | + let mut board = Array2D::filled_with(vec![], NUM_ROWS, NUM_COLS); |
| 38 | + // TODO: make this generic |
| 39 | + board[(0, 0)] = vec![CellType(InnerCellType::Star, PartizanPlayer::Right)]; |
| 40 | + board[(0, 1)] = vec![CellType(InnerCellType::Square, PartizanPlayer::Right)]; |
| 41 | + board[(0, 2)] = vec![CellType(InnerCellType::Wave, PartizanPlayer::Right)]; |
| 42 | + board[(0, 3)] = vec![CellType(InnerCellType::Cross, PartizanPlayer::Right)]; |
| 43 | + board[(0, 4)] = vec![CellType(InnerCellType::Circle, PartizanPlayer::Right)]; |
| 44 | + |
| 45 | + board[(NUM_ROWS - 1, 4)] = vec![CellType(InnerCellType::Star, PartizanPlayer::Right)]; |
| 46 | + board[(NUM_ROWS - 1, 3)] = vec![CellType(InnerCellType::Square, PartizanPlayer::Right)]; |
| 47 | + board[(NUM_ROWS - 1, 2)] = vec![CellType(InnerCellType::Wave, PartizanPlayer::Right)]; |
| 48 | + board[(NUM_ROWS - 1, 1)] = vec![CellType(InnerCellType::Cross, PartizanPlayer::Right)]; |
| 49 | + board[(NUM_ROWS - 1, 0)] = vec![CellType(InnerCellType::Circle, PartizanPlayer::Right)]; |
| 50 | + |
| 51 | + Self { |
| 52 | + board, |
| 53 | + player: PartizanPlayer::Left, |
| 54 | + compulsory: None, |
| 55 | + move_count: 0, |
| 56 | + |
| 57 | + gutter: None |
| 58 | + } |
| 59 | + } |
| 60 | +} |
| 61 | + |
| 62 | +#[derive(Error, Clone, Debug)] |
| 63 | +pub enum ZenerMoveError { |
| 64 | + #[error("can not move at {0:?} since there's no piece!")] |
| 65 | + NoPiece(ZenerPosition) |
| 66 | +} |
| 67 | + |
| 68 | +/// (row, col) |
| 69 | +pub type ZenerPosition = (usize, usize); |
| 70 | + |
| 71 | +#[derive(Clone, Copy)] |
| 72 | +pub struct ZenerMove { |
| 73 | + from: ZenerPosition, |
| 74 | + to: ZenerPosition |
| 75 | +} |
| 76 | + |
| 77 | +impl Game for Zener { |
| 78 | + type Move = ZenerMove; |
| 79 | + type Iter<'a> = std::vec::IntoIter<Self::Move>; |
| 80 | + /// Left is bottom, Right is top |
| 81 | + type Player = PartizanPlayer; |
| 82 | + type MoveError = ZenerMoveError; |
| 83 | + |
| 84 | + fn max_moves(&self) -> Option<usize> { |
| 85 | + // TODO |
| 86 | + None |
| 87 | + } |
| 88 | + |
| 89 | + fn move_count(&self) -> usize { |
| 90 | + self.move_count |
| 91 | + } |
| 92 | + |
| 93 | + fn make_move(&mut self, m: &Self::Move) -> Result<(), Self::MoveError> { |
| 94 | + // get the piece to move |
| 95 | + let from_piece = self.board[m.from] |
| 96 | + .last() |
| 97 | + .ok_or(ZenerMoveError::NoPiece(m.from))?.clone(); |
| 98 | + |
| 99 | + // add it on the 'to' stack. |
| 100 | + self.board[m.to].push(from_piece); |
| 101 | + |
| 102 | + Ok(()) |
| 103 | + } |
| 104 | + |
| 105 | + fn possible_moves(&self) -> Self::Iter<'_> { |
| 106 | + unimplemented!() |
| 107 | + } |
| 108 | + |
| 109 | + fn player(&self) -> Self::Player { |
| 110 | + self.player |
| 111 | + } |
| 112 | + |
| 113 | + fn state(&self) -> GameState<Self::Player> { |
| 114 | + match self.gutter { |
| 115 | + None => GameState::Playable, |
| 116 | + Some(CellType(_, player)) => GameState::Win(player) |
| 117 | + } |
| 118 | + } |
| 119 | +} |
0 commit comments