diff --git a/src/main.rs b/src/main.rs index f8634fb..ae41baa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,10 +6,10 @@ use raylib::prelude::*; mod marble_engine; fn main() { - let (mut rl, thread) = raylib::init().resizable().title("Hello, World").build(); + let (mut rl, thread) = raylib::init().resizable().title("good window title").build(); rl.set_target_fps(60); - let board = parse(&read_to_string("boards/flow.mbl").unwrap()); + let board = parse(&read_to_string("boards/adder.mbl").unwrap()); let mut pos_offset = Vector2::zero(); let mut machine = marble_engine::Machine::new(board, "Vec::new()".bytes().collect()); @@ -28,7 +28,6 @@ fn main() { d.clear_background(Color::new(64, 64, 64, 255)); machine.draw(&mut d, pos_offset); - d.draw_text("Hello, world!", 12, 12, 20, Color::WHITE); d.draw_fps(2, 2); } diff --git a/src/marble_engine.rs b/src/marble_engine.rs index ceb9f87..c8b043d 100644 --- a/src/marble_engine.rs +++ b/src/marble_engine.rs @@ -67,7 +67,7 @@ impl Machine { for y in 0..self.board.height() { for x in 0..self.board.width() { match self.board.get_mut((x, y).into()) { - Tile::Wire(_, state) => *state = false, + Tile::Powerable(_, state) => *state = false, Tile::Trigger(state) => *state = false, _ => (), } @@ -103,7 +103,7 @@ impl Machine { self.marbles[i] = next_pos; new_tile = Some(Tile::Blank); } - Tile::Bag => { + Tile::Powerable(PTile::Bag, _) => { to_remove.push(i); new_tile = Some(Tile::Blank); } @@ -190,107 +190,102 @@ impl Machine { } let tile = self.board.get_mut(pos); let front_pos = dir.step(pos); - match tile { - Tile::Wire(wiretype, state) => { - if *state { - return; - } - *state = true; - let dirs = wiretype.directions(); - for d in dirs { - self.propagate_power(*d, d.step(pos)); - } + if let Tile::Powerable(tile, state) = tile { + if *state { + return; } - Tile::Print => { - let sample = self.board.get_or_blank(front_pos); - if let Tile::Marble { value, dir: _ } = sample { - self.output.push(value as u8); + *state = true; + match tile { + PTile::Wire(wiretype) => { + let dirs = wiretype.directions(); + for d in dirs { + self.propagate_power(*d, d.step(pos)); + } } - } - Tile::Bag => { - if let Some(Tile::Blank) = self.board.get(front_pos) { - *self.board.get_mut(front_pos) = Tile::Marble { value: 0, dir }; - self.marbles.push(front_pos); + PTile::Output => { + let sample = self.board.get_or_blank(front_pos); + if let Tile::Marble { value, dir: _ } = sample { + self.output.push(value as u8); + } } - } - Tile::Input => { - if self.input_index < self.input.len() - && self.board.get_or_blank(front_pos).is_blank() - { - let value = self.input[self.input_index] as MarbleValue; - *self.board.get_mut(front_pos) = Tile::Marble { value, dir }; - self.marbles.push(front_pos); - self.input_index += 1; + PTile::Bag => { + if let Some(Tile::Blank) = self.board.get(front_pos) { + *self.board.get_mut(front_pos) = Tile::Marble { value: 0, dir }; + self.marbles.push(front_pos); + } } - } - Tile::Math(op) => { - let op = *op; - let pos_a = dir.left().step(pos); - let pos_b = dir.right().step(pos); - let val_a = self.board.get_or_blank(pos_a).read_value(); - let val_b = self.board.get_or_blank(pos_b).read_value(); - if (!self.board.get_or_blank(pos_a).is_blank() - || !self.board.get_or_blank(pos_b).is_blank()) - && self.board.get_or_blank(front_pos).is_blank() - { - let result = match op { - MathOp::Add => val_a.wrapping_add(val_b), - MathOp::Sub => val_a.wrapping_sub(val_b), - MathOp::Mul => val_a.wrapping_mul(val_b), - MathOp::Div => val_a.checked_div(val_b).unwrap_or_default(), - MathOp::Rem => val_a.checked_rem(val_b).unwrap_or_default(), + PTile::Input => { + if self.input_index < self.input.len() + && self.board.get_or_blank(front_pos).is_blank() + { + let value = self.input[self.input_index] as MarbleValue; + *self.board.get_mut(front_pos) = Tile::Marble { value, dir }; + self.marbles.push(front_pos); + self.input_index += 1; + } + } + PTile::Math(op) => { + let op = *op; + let pos_a = dir.left().step(pos); + let pos_b = dir.right().step(pos); + let val_a = self.board.get_or_blank(pos_a).read_value(); + let val_b = self.board.get_or_blank(pos_b).read_value(); + if (!self.board.get_or_blank(pos_a).is_blank() + || !self.board.get_or_blank(pos_b).is_blank()) + && self.board.get_or_blank(front_pos).is_blank() + { + let result = match op { + MathOp::Add => val_a.wrapping_add(val_b), + MathOp::Sub => val_a.wrapping_sub(val_b), + MathOp::Mul => val_a.wrapping_mul(val_b), + MathOp::Div => val_a.checked_div(val_b).unwrap_or_default(), + MathOp::Rem => val_a.checked_rem(val_b).unwrap_or_default(), + }; + // println!("{op:?} a:{val_a} b:{val_b}"); + *self.board.get_mut(front_pos) = Tile::Marble { value: result, dir }; + self.marbles.push(front_pos); + } + } + PTile::Flipper => { + let m = self.board.get_mut(front_pos); + match m { + Tile::Powerable(PTile::Wire(wire_type), _) => { + *wire_type = match *wire_type { + WireType::Vertical => WireType::Horizontal, + WireType::Horizontal => WireType::Vertical, + WireType::Cross => WireType::Cross, + }; + } + Tile::Mirror(mirror) => { + *mirror = match *mirror { + MirrorType::Forward => MirrorType::Back, + MirrorType::Back => MirrorType::Forward, + }; + } + Tile::Arrow(dir) => { + *dir = dir.opposite(); + } + _ => (), }; - // println!("{op:?} a:{val_a} b:{val_b}"); - *self.board.get_mut(front_pos) = Tile::Marble { value: result, dir }; - self.marbles.push(front_pos); } - } - Tile::Flip => { - let m = self.board.get_mut(front_pos); - match m { - Tile::Wire(wire_type, _) => { - *wire_type = match *wire_type { - WireType::Vertical => WireType::Horizontal, - WireType::Horizontal => WireType::Vertical, - WireType::Cross => WireType::Cross, - }; - } - Tile::Mirror(mirror) => { - *mirror = match *mirror { - MirrorType::Forward => MirrorType::Back, - MirrorType::Back => MirrorType::Forward, - }; - } - Tile::Arrow(dir) => { - *dir = dir.opposite(); - } - _ => (), - }; - } - Tile::Gate(gate) => { - let gate = *gate; - let pos_a = dir.left().step(pos); - let pos_b = dir.right().step(pos); - let val_a = self.board.get_or_blank(pos_a).read_value(); - let val_b = self.board.get_or_blank(pos_b).read_value(); + PTile::Gate(gate) => { + let gate = *gate; + let pos_a = dir.left().step(pos); + let pos_b = dir.right().step(pos); + let val_a = self.board.get_or_blank(pos_a).read_value(); + let val_b = self.board.get_or_blank(pos_b).read_value(); - let result = match gate { - GateType::LessThan => val_a < val_b, - GateType::GreaterThan => val_a > val_b, - GateType::Equal => val_a == val_b, - GateType::NotEqual => val_a != val_b, - }; - if result { - self.propagate_power(dir, dir.step(pos)); + let result = match gate { + GateType::LessThan => val_a < val_b, + GateType::GreaterThan => val_a > val_b, + GateType::Equal => val_a == val_b, + GateType::NotEqual => val_a != val_b, + }; + if result { + self.propagate_power(dir, dir.step(pos)); + } } } - Tile::Marble { value: _, dir: _ } - | Tile::Trigger(_) - | Tile::Digit(_) - | Tile::Mirror(_) - | Tile::Arrow(_) - | Tile::Comment(_) - | Tile::Blank => (), } } } @@ -322,30 +317,30 @@ pub fn parse(source: &str) -> Board { dir: Direction::Down, }, '*' => Tile::Trigger(false), - '-' => Tile::Wire(WireType::Horizontal, false), - '|' => Tile::Wire(WireType::Vertical, false), - '+' => Tile::Wire(WireType::Cross, false), + '-' => Tile::Powerable(PTile::Wire(WireType::Horizontal), false), + '|' => Tile::Powerable(PTile::Wire(WireType::Vertical), false), + '+' => Tile::Powerable(PTile::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::Gate(GateType::Equal), - '!' => Tile::Gate(GateType::NotEqual), - 'L' => Tile::Gate(GateType::LessThan), - 'G' => Tile::Gate(GateType::GreaterThan), - 'P' => Tile::Print, - 'I' => Tile::Input, - 'F' => Tile::Flip, - 'A' => Tile::Math(MathOp::Add), - 'S' => Tile::Math(MathOp::Sub), - 'M' => Tile::Math(MathOp::Mul), - 'D' => Tile::Math(MathOp::Div), - 'R' => Tile::Math(MathOp::Rem), - 'B' => Tile::Bag, + '=' => Tile::Powerable(PTile::Gate(GateType::Equal), false), + '!' => Tile::Powerable(PTile::Gate(GateType::NotEqual), false), + 'L' => Tile::Powerable(PTile::Gate(GateType::LessThan), false), + 'G' => Tile::Powerable(PTile::Gate(GateType::GreaterThan), false), + 'P' => Tile::Powerable(PTile::Output, false), + 'I' => Tile::Powerable(PTile::Input, 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::Bag, false), d @ '0'..='9' => Tile::Digit(d as u8), - '#' => Tile::Comment(b'#'), + '#' => Tile::Block, ' ' => Tile::Blank, '(' => { in_comment = true; diff --git a/src/marble_engine/tile.rs b/src/marble_engine/tile.rs index 9928361..7f24a40 100644 --- a/src/marble_engine/tile.rs +++ b/src/marble_engine/tile.rs @@ -13,22 +13,28 @@ pub type MarbleValue = u32; pub enum Tile { #[default] Blank, + Block, Comment(u8), - Bag, Marble { value: MarbleValue, dir: Direction, }, Trigger(bool), Digit(u8), - Wire(WireType, bool), - Gate(GateType), - Print, - Input, - Flip, - Math(MathOp), Mirror(MirrorType), Arrow(Direction), + Powerable(PTile, bool), +} + +#[derive(Debug, Clone, Copy)] +pub enum PTile { + Wire(WireType), + Gate(GateType), + Math(MathOp), + Bag, + Flipper, + Input, + Output, } #[derive(Debug, Clone, Copy)] @@ -89,16 +95,17 @@ impl Tile { let right = x + size / 2 - 1; match self { Tile::Blank => (), + Tile::Block => d.draw_rectangle(x - size / 2, y - size / 2, size, size, Color::DIMGRAY), Tile::Comment(c) => { - d.draw_text(&format!("{}", *c as char), x - 10, y - 10, 20, Color::RED) + d.draw_rectangle(x-size/2, y-size/2, size, size, Color::DIMGRAY); + d.draw_text(&format!("{}", *c as char), x - 10, y - 10, 20, Color::WHITE); } - Tile::Bag => d.draw_circle_lines(x, y, size as f32 * 0.4, Color::CYAN), Tile::Marble { value, dir } => { d.draw_circle(x, y, size as f32 * 0.35, Color::new(15, 15, 15, 255)); d.draw_text( &format!("{value}"), - x - size / 2, - y - size / 2, + x - size / 2 + 2, + y - size / 2 + 2, 20, Color::MAGENTA, ); @@ -110,24 +117,6 @@ impl Tile { Tile::Digit(n) => { d.draw_text(&String::from(*n as char), x - 10, y - 10, 20, Color::ORANGE) } - Tile::Wire(wire, state) => { - let color = if *state { Color::RED } else { Color::WHITE }; - let vertical = !matches!(wire, WireType::Horizontal); - let horizontal = !matches!(wire, WireType::Vertical); - if vertical { - // d.draw_line(x, up, x, down, color); - d.draw_rectangle(x - size / 8, y - size / 2, size / 4, size, color) - } - if horizontal { - // d.draw_line(left, y, right, y, color); - d.draw_rectangle(x - size / 2, y - size / 8, size, size / 4, color) - } - } - // Tile::Gate(_) => todo!(), - // Tile::Print => todo!(), - // Tile::Input => todo!(), - // Tile::Flip => todo!(), - // Tile::Math(_) => todo!(), Tile::Mirror(mirror) => { let height = size as f32 * 1.25; let width = (size / 4) as f32; @@ -156,7 +145,32 @@ impl Tile { }; d.draw_triangle(v1, v2, v3, Color::CYAN); } - _ => d.draw_rectangle(x - size / 2, y - size / 2, size, size, Color::YELLOW), + Tile::Powerable(tile, state) => { + let color = if *state { Color::RED } else { Color::LIGHTGRAY }; + match tile { + PTile::Bag => { + d.draw_circle(x, y, size as f32 * 0.4, color); + d.draw_circle(x, y, size as f32 * 0.2, Color::GRAY); + } + PTile::Wire(wire) => { + let vertical = !matches!(wire, WireType::Horizontal); + let horizontal = !matches!(wire, WireType::Vertical); + if vertical { + d.draw_rectangle(x - size / 8, y - size / 2, size / 4, size, color) + } + if horizontal { + d.draw_rectangle(x - size / 2, y - size / 8, size, size / 4, color) + } + } + // PTile::Gate(_) => todo!(), + // PTile::Math(_) => todo!(), + // PTile::Print => todo!(), + // PTile::Input => todo!(), + // PTile::Flip => todo!(), + _ => d.draw_rectangle(x - size / 2, y - size / 2, size, size, color), + } + } + } } }