519 lines
12 KiB
Rust
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
|
|
}
|
|
}
|