You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
207 lines
5.3 KiB
Rust
207 lines
5.3 KiB
Rust
use crate::prelude::*;
|
|
|
|
pub(crate) struct GamePlugin;
|
|
|
|
impl Plugin for GamePlugin {
|
|
fn build(&self, app: &mut App) {
|
|
app.add_event::<GameEvent>()
|
|
.init_resource::<ActiveTile>()
|
|
.add_systems(Startup, setup_board)
|
|
.add_systems(
|
|
PostUpdate,
|
|
(
|
|
debug_hovering
|
|
.run_if(resource_exists::<debug::DebugEnabled>())
|
|
.run_if(resource_changed::<ActiveTile>()),
|
|
debug_board.run_if(resource_exists::<debug::DebugEnabled>()),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Component, Clone)]
|
|
pub(crate) enum Piece {
|
|
Pawn,
|
|
Drone,
|
|
Queen,
|
|
}
|
|
|
|
// manually for the type.
|
|
impl std::fmt::Display for Piece {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
match self {
|
|
Piece::Queen => write!(f, "@"),
|
|
Piece::Drone => write!(f, "^"),
|
|
Piece::Pawn => write!(f, "*"),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub(crate) enum GameError {
|
|
NullMove,
|
|
InvalidMove,
|
|
}
|
|
|
|
#[derive(Debug, Event)]
|
|
pub(crate) enum GameEvent {
|
|
SelectPiece,
|
|
PlacePiece,
|
|
}
|
|
|
|
/// The board is setup like this:
|
|
/// ```text
|
|
/// 0 1 2 3 4 5 6 7
|
|
/// +--+--+--+--+--+--+--+--+
|
|
/// a | | | | I | d| Q| Q|
|
|
/// +--+--+--+--+--+--+--+--+
|
|
/// b |d |p |p | I | p| d| Q|
|
|
/// +--+--+--+--+--+--+--+--+
|
|
/// c |Q |d |p | I | p| p| d|
|
|
/// +--+--+--+--+--+--+--+--+
|
|
/// d |Q |Q |d | I | | | |
|
|
/// +--+--+--+--+--+--+--+--+
|
|
/// ````
|
|
#[derive(Debug, Resource)]
|
|
pub(crate) struct Board {
|
|
inner: Vec<Vec<Option<Piece>>>,
|
|
}
|
|
|
|
#[derive(Debug, Component, PartialEq, Clone)]
|
|
pub(crate) struct BoardIndex {
|
|
pub x: usize,
|
|
pub y: usize,
|
|
}
|
|
|
|
impl Board {
|
|
/// Returns the piece at the given location
|
|
pub(crate) fn at(&self, BoardIndex { x, y }: &BoardIndex) -> Option<Piece> {
|
|
self.inner[*y][*x].clone()
|
|
}
|
|
|
|
/// Returns a list of all pieces on the board with their location
|
|
pub(crate) fn pieces(&self) -> Vec<(BoardIndex, Piece)> {
|
|
self.inner
|
|
.iter()
|
|
.enumerate()
|
|
.flat_map(|(y, nested)| {
|
|
nested.iter().enumerate().filter_map(move |(x, p)| {
|
|
p.as_ref().map(|val| (BoardIndex { x, y }, val.clone()))
|
|
})
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
pub(crate) fn move_piece(
|
|
&mut self,
|
|
from: &BoardIndex,
|
|
to: &BoardIndex,
|
|
) -> Result<(), GameError> {
|
|
if from == to {
|
|
Err(GameError::NullMove)
|
|
} else if self.at(to).is_none() {
|
|
self.at(from).map_or(Err(GameError::NullMove), |from_val| {
|
|
// TODO: We can self.inner.swap(to, from) if board is single vec
|
|
self.inner[to.y][to.x] = Some(from_val);
|
|
self.inner[from.y][from.x] = None;
|
|
Ok(())
|
|
})
|
|
} else {
|
|
Err(GameError::InvalidMove)
|
|
}
|
|
}
|
|
}
|
|
|
|
impl std::fmt::Display for Board {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
self.inner.iter().rev().for_each(|row| {
|
|
let _ = write!(f, "+--+--+--+--+--+--+--+--+\n");
|
|
let _ = write!(f, "|");
|
|
row.iter().for_each(|piece| {
|
|
let _ = match piece {
|
|
Some(p) => write!(f, "{} |", p),
|
|
None => write!(f, " |"),
|
|
};
|
|
});
|
|
let _ = write!(f, "\n");
|
|
});
|
|
let _ = write!(f, "+--+--+--+--+--+--+--+--+");
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Default, Resource)]
|
|
pub(crate) struct ActiveTile {
|
|
pub idx: Option<BoardIndex>,
|
|
}
|
|
|
|
#[derive(Debug, Default, Component)]
|
|
pub(crate) struct Selected;
|
|
|
|
fn setup_board(mut commands: Commands) {
|
|
use Piece::*;
|
|
commands.insert_resource(Board {
|
|
inner: vec![
|
|
vec![
|
|
Some(Queen),
|
|
Some(Queen),
|
|
Some(Drone),
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
],
|
|
vec![
|
|
Some(Queen),
|
|
Some(Drone),
|
|
Some(Pawn),
|
|
None,
|
|
None,
|
|
Some(Pawn),
|
|
Some(Pawn),
|
|
Some(Drone),
|
|
],
|
|
vec![
|
|
Some(Drone),
|
|
Some(Pawn),
|
|
Some(Pawn),
|
|
None,
|
|
None,
|
|
Some(Pawn),
|
|
Some(Drone),
|
|
Some(Queen),
|
|
],
|
|
vec![
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
None,
|
|
Some(Drone),
|
|
Some(Queen),
|
|
Some(Queen),
|
|
],
|
|
],
|
|
});
|
|
}
|
|
|
|
/// TODO: only run_if debug enabled
|
|
fn debug_hovering(
|
|
selected: Res<ActiveTile>,
|
|
board: Res<Board>,
|
|
mut debug_info: ResMut<debug::DebugInfo>,
|
|
) {
|
|
match &selected.idx {
|
|
Some(idx) => debug_info.set(
|
|
"hovering".into(),
|
|
format!("{:?}@({},{})", board.at(&idx), idx.x, idx.y,),
|
|
),
|
|
None => debug_info.set("selected".into(), format!("N/A")),
|
|
};
|
|
}
|
|
|
|
fn debug_board(board: Res<Board>, mut debug_info: ResMut<debug::DebugInfo>) {
|
|
debug_info.set("board".into(), format!("\n{}", *board));
|
|
}
|