#[cfg(test)]
use enum_iterator::Sequence;
use num_enum::TryFromPrimitive;
#[cfg_attr(test, derive(Sequence))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, TryFromPrimitive)]
#[repr(u32)]
pub enum TokenCode {
Start = 61,
Blocked = 31,
MoveBackwards = 47,
MoveForwards = 55,
Shoot = 59,
TurnLeft = 79,
TurnRight = 87,
Repeat = 91,
While = 155,
Value1 = 93,
Value2 = 103,
Value3 = 107,
Value4 = 109,
Value5 = 115,
Value6 = 117,
Value7 = 121,
Value8 = 143,
ValueInfinite = 151,
IsBlocked = 157,
IsPathClear = 167,
Undefined = 0,
}
impl TokenCode {
pub fn value(&self) -> u32 {
*self as u32
}
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Token {
pub code: TokenCode,
pub diameter: f64,
pub orientation: f64,
pub x: f64,
pub y: f64,
}
impl Token {
pub fn new(code: TokenCode, diameter: f64, orientation: f64, x: f64, y: f64) -> Self {
Self {
code,
diameter,
orientation,
x,
y,
}
}
pub fn is_flow(&self) -> bool {
matches!(
self.code,
TokenCode::Blocked
| TokenCode::MoveBackwards
| TokenCode::MoveForwards
| TokenCode::Shoot
| TokenCode::TurnLeft
| TokenCode::TurnRight
| TokenCode::Repeat
| TokenCode::While
)
}
pub fn is_command(&self) -> bool {
matches!(
self.code,
TokenCode::Shoot
| TokenCode::TurnLeft
| TokenCode::TurnRight
| TokenCode::MoveForwards
| TokenCode::MoveBackwards
)
}
pub fn is_value(&self) -> bool {
matches!(
self.code,
TokenCode::Value1
| TokenCode::Value2
| TokenCode::Value3
| TokenCode::Value4
| TokenCode::Value5
| TokenCode::Value6
| TokenCode::Value7
| TokenCode::Value8
| TokenCode::ValueInfinite
)
}
pub fn is_condition(&self) -> bool {
matches!(self.code, TokenCode::IsBlocked | TokenCode::IsPathClear)
}
pub fn ratio(&self, diameter: f64) -> f64 {
self.diameter / diameter
}
}
#[cfg(test)]
mod tests {
use super::*;
use enum_iterator::all;
use topcodes::TopCode;
#[test]
fn tokencode_enum_values_are_valid_topcodes() {
let tokens = all::<TokenCode>().collect::<Vec<_>>();
for token in tokens {
assert!(TopCode::checksum(token.value()) || token.value() == 0);
}
}
}