marble-machinations/src/marble_engine/tile.rs

519 lines
12 KiB
Rust

use crate::marble_engine::Pos;
pub type MarbleValue = u32;
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Tile {
Open(OpenTile, Claim),
Block,
Marble { value: MarbleValue, dir: Direction },
Mirror(MirrorType),
Arrow(Direction),
Button(bool),
Wire(WireType, bool),
Powerable(PTile, bool),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Claim {
Free,
ClaimedIndirect,
BlockedIndirect,
Claimed,
Blocked,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum OpenTile {
Blank,
Digit(u8),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PTile {
Comparator(Comparison),
Math(MathOp),
Silo,
Flipper,
IO,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MirrorType {
Forward,
Back,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum MathOp {
Add,
Sub,
Mul,
Div,
Rem,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Comparison {
LessThan,
GreaterThan,
Equal,
NotEqual,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum WireType {
Vertical,
Horizontal,
Cross,
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum Direction {
Up,
Down,
Left,
Right,
}
impl Tile {
pub const BLANK: Self = Tile::Open(OpenTile::Blank, Claim::Free);
pub const fn from_char(c: char) -> Tile {
match c {
'o' => Tile::Marble {
value: 0,
dir: Direction::Down,
},
'*' => Tile::Button(false),
'-' => Tile::Wire(WireType::Horizontal, false),
'|' => Tile::Wire(WireType::Vertical, false),
'+' => Tile::Wire(WireType::Cross, false),
'/' => Tile::Mirror(MirrorType::Forward),
'\\' => Tile::Mirror(MirrorType::Back),
'^' => Tile::Arrow(Direction::Up),
'v' => Tile::Arrow(Direction::Down),
'<' => Tile::Arrow(Direction::Left),
'>' => Tile::Arrow(Direction::Right),
'=' => Tile::Powerable(PTile::Comparator(Comparison::Equal), false),
'!' => Tile::Powerable(PTile::Comparator(Comparison::NotEqual), false),
'L' => Tile::Powerable(PTile::Comparator(Comparison::LessThan), false),
'G' => Tile::Powerable(PTile::Comparator(Comparison::GreaterThan), false),
'I' | 'P' => Tile::Powerable(PTile::IO, false),
'F' => Tile::Powerable(PTile::Flipper, false),
'A' => Tile::Powerable(PTile::Math(MathOp::Add), false),
'S' => Tile::Powerable(PTile::Math(MathOp::Sub), false),
'M' => Tile::Powerable(PTile::Math(MathOp::Mul), false),
'D' => Tile::Powerable(PTile::Math(MathOp::Div), false),
'R' => Tile::Powerable(PTile::Math(MathOp::Rem), false),
'B' => Tile::Powerable(PTile::Silo, false),
d @ '0'..='9' => Tile::Open(OpenTile::Digit(d as u8 - b'0'), Claim::Free),
'#' => Tile::Block,
_ => Tile::Open(OpenTile::Blank, Claim::Free),
}
}
pub fn to_char(self) -> char {
match self {
Tile::Open(OpenTile::Blank, _) => ' ',
Tile::Block => '#',
Tile::Marble { value: _, dir: _ } => 'o',
Tile::Open(OpenTile::Digit(n), _) => (b'0' + n) as char,
Tile::Mirror(dir) => match dir {
MirrorType::Forward => '/',
MirrorType::Back => '\\',
},
Tile::Arrow(dir) => match dir {
Direction::Up => '^',
Direction::Down => 'v',
Direction::Left => '<',
Direction::Right => '>',
},
Tile::Button(_) => '*',
Tile::Wire(wire, _) => match wire {
WireType::Vertical => '|',
WireType::Horizontal => '-',
WireType::Cross => '+',
},
Tile::Powerable(tile, _) => match tile {
PTile::Comparator(comp) => match comp {
Comparison::LessThan => 'L',
Comparison::GreaterThan => 'G',
Comparison::Equal => '=',
Comparison::NotEqual => '!',
},
PTile::Math(math) => match math {
MathOp::Add => 'A',
MathOp::Sub => 'S',
MathOp::Mul => 'M',
MathOp::Div => 'D',
MathOp::Rem => 'R',
},
PTile::Silo => 'B',
PTile::Flipper => 'F',
PTile::IO => 'I',
},
}
}
pub fn is_blank(self) -> bool {
matches!(self, Tile::Open(OpenTile::Blank, _))
}
pub fn read_value(self) -> MarbleValue {
match self {
Tile::Marble { value, dir: _ } => value,
Tile::Open(OpenTile::Digit(d), _) => d as MarbleValue,
_ => 0,
}
}
pub fn texture(self) -> &'static str {
match self {
Tile::Open(OpenTile::Blank, _) => "",
Tile::Block => "block",
Tile::Marble { value: _, dir: _ } => "marble",
Tile::Open(OpenTile::Digit(n), _) => match n {
0 => "tile_digit_0",
1 => "tile_digit_1",
2 => "tile_digit_2",
3 => "tile_digit_3",
4 => "tile_digit_4",
5 => "tile_digit_5",
6 => "tile_digit_6",
7 => "tile_digit_7",
8 => "tile_digit_8",
9 => "tile_digit_9",
_ => unreachable!(),
},
Tile::Mirror(mirror) => mirror.texture_name(),
Tile::Arrow(dir) => dir.arrow_tile_texture_name(),
Tile::Button(state) => {
if state {
return "button_on";
}
"button_off"
}
Tile::Wire(wire, state) => {
if state {
return wire.texture_name_on();
}
wire.texture_name_off()
}
Tile::Powerable(tile, state) => {
if state {
return match tile {
PTile::Comparator(comp) => comp.texture_name_on(),
PTile::Math(math_op) => math_op.texture_name_on(),
PTile::Silo => "silo_on",
PTile::Flipper => "flipper_on",
PTile::IO => "io_tile_on",
};
}
match tile {
PTile::Comparator(comp) => comp.texture_name_off(),
PTile::Math(math_op) => math_op.texture_name_off(),
PTile::Silo => "silo_off",
PTile::Flipper => "flipper_off",
PTile::IO => "io_tile_off",
}
}
}
}
}
impl Direction {
pub const ALL: [Direction; 4] = [
Direction::Up,
Direction::Down,
Direction::Left,
Direction::Right,
];
pub fn opposite(self) -> Direction {
match self {
Direction::Up => Direction::Down,
Direction::Down => Direction::Up,
Direction::Left => Direction::Right,
Direction::Right => Direction::Left,
}
}
pub fn right(self) -> Direction {
match self {
Direction::Up => Direction::Right,
Direction::Down => Direction::Left,
Direction::Left => Direction::Up,
Direction::Right => Direction::Down,
}
}
pub fn left(self) -> Direction {
self.right().opposite()
}
pub fn step(self, mut pos: Pos) -> Pos {
match self {
Direction::Up => pos.y -= 1,
Direction::Down => pos.y += 1,
Direction::Left => pos.x -= 1,
Direction::Right => pos.x += 1,
}
pos
}
pub const fn arrow_tile_texture_name(self) -> &'static str {
match self {
Direction::Up => "arrow_up",
Direction::Down => "arrow_down",
Direction::Left => "arrow_left",
Direction::Right => "arrow_right",
}
}
pub const fn arrow_tile_human_name(self) -> &'static str {
match self {
Direction::Up => "Up Arrow",
Direction::Down => "Down Arrow",
Direction::Left => "Left Arrow",
Direction::Right => "Right Arrow",
}
}
pub const fn arrow_texture_name(self) -> &'static str {
match self {
Direction::Up => "direction_up",
Direction::Down => "direction_down",
Direction::Left => "direction_left",
Direction::Right => "direction_right",
}
}
}
impl WireType {
pub fn has_output(self, dir: Direction) -> bool {
match self {
WireType::Vertical => matches!(dir, Direction::Up | Direction::Down),
WireType::Horizontal => matches!(dir, Direction::Right | Direction::Left),
WireType::Cross => true,
}
}
pub fn directions(self) -> &'static [Direction] {
match self {
WireType::Vertical => &[Direction::Up, Direction::Down],
WireType::Horizontal => &[Direction::Left, Direction::Right],
WireType::Cross => &Direction::ALL,
}
}
pub fn next(&mut self) {
*self = match self {
WireType::Vertical => WireType::Horizontal,
WireType::Horizontal => WireType::Cross,
WireType::Cross => WireType::Vertical,
}
}
pub fn prev(&mut self) {
*self = match self {
WireType::Vertical => WireType::Cross,
WireType::Horizontal => WireType::Vertical,
WireType::Cross => WireType::Horizontal,
}
}
pub const fn texture_name_on(self) -> &'static str {
match self {
WireType::Vertical => "wire_vertical_on",
WireType::Horizontal => "wire_horizontal_on",
WireType::Cross => "wire_cross_on",
}
}
pub const fn texture_name_off(self) -> &'static str {
match self {
WireType::Vertical => "wire_vertical_off",
WireType::Horizontal => "wire_horizontal_off",
WireType::Cross => "wire_cross_off",
}
}
pub const fn human_name(self) -> &'static str {
match self {
WireType::Vertical => "Vertical Wire",
WireType::Horizontal => "Horizontal Wire",
WireType::Cross => "Wire Cross",
}
}
}
impl MirrorType {
pub fn new_dir(self, dir: Direction) -> Direction {
match self {
MirrorType::Forward => match dir {
Direction::Up => Direction::Right,
Direction::Down => Direction::Left,
Direction::Left => Direction::Down,
Direction::Right => Direction::Up,
},
MirrorType::Back => match dir {
Direction::Up => Direction::Left,
Direction::Down => Direction::Right,
Direction::Left => Direction::Up,
Direction::Right => Direction::Down,
},
}
}
pub fn flip(&mut self) {
*self = match self {
MirrorType::Forward => MirrorType::Back,
MirrorType::Back => MirrorType::Forward,
}
}
pub const fn texture_name(self) -> &'static str {
match self {
MirrorType::Forward => "mirror_forward",
MirrorType::Back => "mirror_back",
}
}
pub const fn human_name(self) -> &'static str {
match self {
MirrorType::Forward => "Mirror A",
MirrorType::Back => "Mirror B",
}
}
}
impl MathOp {
pub const fn human_name(self) -> &'static str {
match self {
MathOp::Add => "Math: Add",
MathOp::Sub => "Math: Subtract",
MathOp::Mul => "Math: Multiply",
MathOp::Div => "Math: Divide",
MathOp::Rem => "Math: Remainder",
}
}
pub const fn texture_name_on(self) -> &'static str {
match self {
MathOp::Add => "add_on",
MathOp::Sub => "sub_on",
MathOp::Mul => "mul_on",
MathOp::Div => "div_on",
MathOp::Rem => "rem_on",
}
}
pub const fn texture_name_off(self) -> &'static str {
match self {
MathOp::Add => "add_off",
MathOp::Sub => "sub_off",
MathOp::Mul => "mul_off",
MathOp::Div => "div_off",
MathOp::Rem => "rem_off",
}
}
pub fn next(&mut self) {
*self = match self {
MathOp::Add => MathOp::Sub,
MathOp::Sub => MathOp::Mul,
MathOp::Mul => MathOp::Div,
MathOp::Div => MathOp::Rem,
MathOp::Rem => MathOp::Add,
}
}
pub fn prev(&mut self) {
*self = match self {
MathOp::Add => MathOp::Rem,
MathOp::Sub => MathOp::Add,
MathOp::Mul => MathOp::Sub,
MathOp::Div => MathOp::Mul,
MathOp::Rem => MathOp::Div,
}
}
}
impl Comparison {
pub const fn human_name(self) -> &'static str {
match self {
Comparison::LessThan => "Comparator: Less than",
Comparison::GreaterThan => "Comparator: Greater than",
Comparison::Equal => "Comparator: Equal",
Comparison::NotEqual => "Comparator: Not Equal",
}
}
pub const fn texture_name_on(self) -> &'static str {
match self {
Comparison::LessThan => "lt_on",
Comparison::GreaterThan => "gt_on",
Comparison::Equal => "eq_on",
Comparison::NotEqual => "neq_on",
}
}
pub const fn texture_name_off(self) -> &'static str {
match self {
Comparison::LessThan => "lt_off",
Comparison::GreaterThan => "gt_off",
Comparison::Equal => "eq_off",
Comparison::NotEqual => "neq_off",
}
}
pub fn next(&mut self) {
*self = match self {
Comparison::LessThan => Comparison::GreaterThan,
Comparison::GreaterThan => Comparison::Equal,
Comparison::Equal => Comparison::NotEqual,
Comparison::NotEqual => Comparison::LessThan,
}
}
pub fn prev(&mut self) {
*self = match self {
Comparison::LessThan => Comparison::NotEqual,
Comparison::GreaterThan => Comparison::LessThan,
Comparison::Equal => Comparison::GreaterThan,
Comparison::NotEqual => Comparison::Equal,
}
}
}
impl Claim {
#[must_use]
/// returns `was_free`
pub fn claim(&mut self) -> bool {
let mut was_free = false;
*self = match self {
Claim::Free => {
was_free = true;
Claim::Claimed
}
Claim::ClaimedIndirect | Claim::BlockedIndirect => Claim::Claimed,
Claim::Claimed | Claim::Blocked => Claim::Blocked,
};
was_free
}
#[must_use]
/// returns `was_free`
pub fn claim_indirect(&mut self) -> bool {
let mut was_free = false;
*self = match self {
Claim::Free => {
was_free = true;
Claim::ClaimedIndirect
}
Claim::ClaimedIndirect => Claim::BlockedIndirect,
_ => *self,
};
was_free
}
}