use std::collections::HashMap; use raylib::{ color::Color, drawing::{RaylibDraw, RaylibDrawHandle}, ffi::Rectangle, math::Vector2, texture::Texture2D, }; use super::board::Pos; pub type MarbleValue = u32; #[derive(Debug, Default, Clone, Copy)] pub enum Tile { #[default] Blank, Block, Comment(u8), Marble { value: MarbleValue, dir: Direction, }, Digit(u8), Mirror(MirrorType), Arrow(Direction), Powerable(PTile, bool), } #[derive(Debug, Clone, Copy)] pub enum PTile { Trigger, Wire(WireType), Gate(GateType), Math(MathOp), Bag, Flipper, Input, Output, } #[derive(Debug, Clone, Copy)] pub enum MirrorType { Forward, Back, } #[derive(Debug, Clone, Copy)] pub enum MathOp { Add, Sub, Mul, Div, Rem, } #[derive(Debug, Clone, Copy)] pub enum GateType { LessThan, GreaterThan, Equal, NotEqual, } #[derive(Debug, Clone, Copy)] pub enum WireType { Vertical, Horizontal, Cross, } #[derive(Debug, Clone, Copy, PartialEq)] pub enum Direction { Up, Down, Left, Right, } impl Tile { pub fn is_blank(&self) -> bool { matches!(self, Tile::Blank) } pub fn read_value(&self) -> MarbleValue { if let Tile::Marble { value, dir: _ } = self { *value } else { 0 } } pub fn draw( &self, d: &mut RaylibDrawHandle, textures: &HashMap, x: i32, y: i32, size: i32, ) { let tex_name = match self { Tile::Blank => "", Tile::Block => "", Tile::Comment(_) => "", Tile::Marble { value, dir } => "todo!()", Tile::Digit(_) => "", Tile::Mirror(_) => "", Tile::Arrow(dir) => match dir { Direction::Up => "up", Direction::Down => "down", Direction::Left => "left", Direction::Right => "right", }, Tile::Powerable(tile, state) => { let t = match tile { PTile::Trigger => "trigger", PTile::Wire(wire) => match wire { WireType::Vertical => "wire_vertical", WireType::Horizontal => "wire_horizontal", WireType::Cross => "wire_cross", }, PTile::Gate(gate) => match gate { GateType::LessThan => "lt", GateType::GreaterThan => "gt", GateType::Equal => "eq", GateType::NotEqual => "neq", }, PTile::Math(math_op) => match math_op { MathOp::Add => "add", MathOp::Sub => "sub", MathOp::Mul => "mul", MathOp::Div => "div", MathOp::Rem => "rem", }, PTile::Bag => "bag", PTile::Flipper => "flipper", PTile::Input => "input", PTile::Output => "output", }; &format!("{t}_{}", if *state { "on" } else { "off" }) } }; let tex_name = format!("{tex_name}.png"); if let Some(texture) = textures.get(&tex_name) { d.draw_texture_ex( texture, Vector2::new((x - size / 2) as f32, (y - size / 2) as f32), 0.0, 2.0, Color::WHITE, ); return; } match self { Tile::Blank => (), Tile::Block => d.draw_rectangle(x - size / 2, y - size / 2, size, size, Color::DIMGRAY), Tile::Comment(c) => { 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::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 + 2, y - size / 2 + 2, 20, Color::MAGENTA, ); } Tile::Digit(n) => { d.draw_text(&String::from(*n as char), x - 10, y - 10, 20, Color::ORANGE) } Tile::Mirror(mirror) => { let height = size as f32 * 1.25; let width = (size / 4) as f32; let rec = Rectangle { x: x as f32, y: y as f32, width, height, }; let rot = match mirror { MirrorType::Forward => 45.0, MirrorType::Back => -45.0, }; d.draw_rectangle_pro(rec, Vector2::new(width, height) * 0.5, rot, Color::CYAN); } _ => d.draw_rectangle(x - size / 2, y - size / 2, size, size, Color::YELLOW), } } } 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 } } impl WireType { pub fn directions(self) -> &'static [Direction] { match self { WireType::Vertical => &[Direction::Up, Direction::Down], WireType::Horizontal => &[Direction::Left, Direction::Right], WireType::Cross => &Direction::ALL, } } } 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, }, } } }