M src/TODO.md => src/TODO.md +1 -7
@@ 2,10 2,4 @@
# Change movement through white blocks to match spec
-# Create rules
-Create the rules modules, which represents the rules of the language.
-This entails implementing the operations on the stack when moving
-from one color to another.
-
-The rules module should then be used in the exec function of the
-interpreter
+# Add color guesser
M src/color.rs => src/color.rs +24 -23
@@ 4,33 4,34 @@ pub enum Color {
LightRed, LightYellow, LightGreen, LightCyan, LightBlue, LightMagenta,
Red, Yellow, Green, Cyan, Blue, Magenta, White, Black,
DarkRed, DarkYellow, DarkGreen, DarkCyan, DarkBlue, DarkMagenta,
+ Unknown,
}
impl Color {
- pub fn to_color(color: [u8; 3]) -> Option<Self> {
- if color == [0xFF, 0xC0, 0xC0] { return Some(Color::LightRed); }
- if color == [0xFF, 0xFF, 0xC0] { return Some(Color::LightYellow); }
- if color == [0xC0, 0xFF, 0xC0] { return Some(Color::LightGreen); }
- if color == [0xC0, 0xFF, 0xFF] { return Some(Color::LightCyan); }
- if color == [0xC0, 0xC0, 0xFF] { return Some(Color::LightBlue); }
- if color == [0xFF, 0xC0, 0xFF] { return Some(Color::LightMagenta); }
- if color == [0xFF, 0x00, 0x00] { return Some(Color::Red) }
- if color == [0xFF, 0xFF, 0x00] { return Some(Color::Yellow); }
- if color == [0x00, 0xFF, 0x00] { return Some(Color::Green); }
- if color == [0x00, 0xFF, 0xFF] { return Some(Color::Cyan); }
- if color == [0x00, 0x00, 0xFF] { return Some(Color::Blue); }
- if color == [0xFF, 0x00, 0xFF] { return Some(Color::Magenta); }
- if color == [0xC0, 0x00, 0x00] { return Some(Color::DarkRed); }
- if color == [0xC0, 0xC0, 0x00] { return Some(Color::DarkYellow); }
- if color == [0x00, 0xC0, 0x00] { return Some(Color::DarkGreen); }
- if color == [0x00, 0xC0, 0xC0] { return Some(Color::DarkCyan); }
- if color == [0x00, 0x00, 0xC0] { return Some(Color::DarkBlue); }
- if color == [0xC0, 0x00, 0xC0] { return Some(Color::DarkMagenta); }
- if color == [0xFF, 0xFF, 0xFF] { return Some(Color::White); }
- if color == [0x00, 0x00, 0x00] { return Some(Color::Black); }
-
- None
+ pub fn to_color(color: [u8; 3]) -> Self {
+ if color == [0xFF, 0xC0, 0xC0] { return Color::LightRed; }
+ if color == [0xFF, 0xFF, 0xC0] { return Color::LightYellow; }
+ if color == [0xC0, 0xFF, 0xC0] { return Color::LightGreen; }
+ if color == [0xC0, 0xFF, 0xFF] { return Color::LightCyan; }
+ if color == [0xC0, 0xC0, 0xFF] { return Color::LightBlue; }
+ if color == [0xFF, 0xC0, 0xFF] { return Color::LightMagenta; }
+ if color == [0xFF, 0x00, 0x00] { return Color::Red; }
+ if color == [0xFF, 0xFF, 0x00] { return Color::Yellow; }
+ if color == [0x00, 0xFF, 0x00] { return Color::Green; }
+ if color == [0x00, 0xFF, 0xFF] { return Color::Cyan; }
+ if color == [0x00, 0x00, 0xFF] { return Color::Blue; }
+ if color == [0xFF, 0x00, 0xFF] { return Color::Magenta; }
+ if color == [0xC0, 0x00, 0x00] { return Color::DarkRed; }
+ if color == [0xC0, 0xC0, 0x00] { return Color::DarkYellow; }
+ if color == [0x00, 0xC0, 0x00] { return Color::DarkGreen; }
+ if color == [0x00, 0xC0, 0xC0] { return Color::DarkCyan; }
+ if color == [0x00, 0x00, 0xC0] { return Color::DarkBlue; }
+ if color == [0xC0, 0x00, 0xC0] { return Color::DarkMagenta; }
+ if color == [0xFF, 0xFF, 0xFF] { return Color::White; }
+ if color == [0x00, 0x00, 0x00] { return Color::Black; }
+
+ Color::Unknown
}
M src/interpreter/mod.rs => src/interpreter/mod.rs +82 -244
@@ 1,11 1,11 @@
-use std::io::{self, Error, ErrorKind, Write};
+use std::io;
use std::path::Path;
use crate::color::Color;
-use crate::piet_img::{PietImage, Codel};
+use crate::piet_img::PietImage;
use crate::translator;
-use crate::rules::{self, Op};
+mod rules;
pub struct Interpreter {
img: PietImage,
@@ 35,7 35,7 @@ impl Interpreter {
pub fn head_as_mut(&mut self) -> &mut Head { &mut self.head }
pub fn img(&self) -> &PietImage { &self.img }
pub fn stack(&self) -> &Vec<isize> { &self.stack }
- pub fn mut_stack(&mut self) -> &Vec<isize> { &mut self.stack }
+ pub fn stack_as_mut(&mut self) -> &mut Vec<isize> { &mut self.stack }
pub fn exec(&mut self) -> io::Result<()> {
@@ 45,7 45,7 @@ impl Interpreter {
let curr_codel = self.img().get(curr.0, curr.1);
let next_codel = self.img().get(next.0, next.1);
- self.do_op(&curr_codel, &next_codel)?;
+ rules::do_op(self, &curr_codel, &next_codel)?;
}
@@ 64,9 64,11 @@ impl Interpreter {
let curr_codel = self.img().get(curr.0, curr.1);
let next_codel = self.img().get(next.0, next.1);
+ println!("Stack: {:?}", self.stack);
println!("In: {:?}, Next: {:?}, Op: {:?}", curr, next, rules::get_op(&curr_codel, &next_codel));
+ println!("============");
- self.do_op(&curr_codel, &next_codel)?;
+ rules::do_op(self, &curr_codel, &next_codel)?;
}
@@ 76,273 78,108 @@ impl Interpreter {
}
-
- fn do_op(&mut self, curr: &Codel, next: &Codel) -> io::Result<()> {
-
- // error = Err(Error::new(ErrorKind::InvalidInput, "ERROR"));
-
+ fn move_next(&mut self) -> Option<(u32, u32)> {
+ let curr_codel = self.head.pos;
+ let block = &self.img.get_block(curr_codel.0, curr_codel.1);
- if let Some(op) = rules::get_op(curr, next) {
+ let mut cc_switches = 0;
+ let mut tries = 0;
- match op {
+ loop {
- Op::Push => {
- let block_size = curr.block_size().expect("Block size set to None!") as isize;
- self.stack.push(block_size);
- Ok(())
- }
+ let edge = self.head.get_furthest_edge(&block);
+ let codel_on_edge = self.head.get_furthest_codel_on_edge(&edge);
+ if tries == 8 { return None }
- Op::Pop => {
- self.stack.pop();
- Ok(())
- }
+ if let Some(next) = self.get_head_next(codel_on_edge.0, codel_on_edge.1) {
- Op::Add => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- self.stack.push(a + b);
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
+ if self.img.get(next.0, next.1).color() == Color::White {
+ return self.move_through_whitespace(next);
}
-
- Op::Sub => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- self.stack.push(b - a);
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
-
+ else {
+ self.head.pos = next;
+ return Some(next);
}
-
- Op::Mult => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- self.stack.push(b * a);
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
-
+ }
+ else {
+ if cc_switches == 1 {
+ cc_switches = 0;
+ self.head.direction_pointer = self.head.direction_pointer.clockwise();
}
-
-
- Op::Div => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- if a == 0 {
- return Err(Error::new(ErrorKind::InvalidInput, "Division by zero!"))
- }
- self.stack.push(b / a);
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
-
+ else {
+ cc_switches += 1;
+ self.head.codel_chooser = self.head.codel_chooser.toggle();
}
+ tries += 1;
+ }
- Op::Mod => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- if a == 0 {
- return Err(Error::new(ErrorKind::InvalidInput, "Division by zero!"))
- }
- self.stack.push(b % a + if b%a < 0 { a } else { 0 } );
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
+ }
+ }
- }
+ fn move_through_whitespace(&mut self, start: (u32, u32)) -> Option<(u32, u32)> {
+ let (width, height) = self.img.dimensions();
- Op::Not => {
- if self.stack.pop() == Some(0) { self.stack.push(1) } else { self.stack.push(0) }
- Ok(())
- }
+ let on_top_edge = start.1 == 0;
+ let on_bottom_edge = start.1 == height - 1;
+ let on_left_edge = start.0 == 0;
+ let on_right_edge = start.0 == width - 1;
- Op::Greater => {
- let first_pop = self.stack.pop();
- let second_pop = self.stack.pop();
- if let (Some(a), Some(b)) = (first_pop, second_pop) {
- if b > a { self.stack.push(1) } else { self.stack.push(0) }
- Ok(())
- }
- else {
- Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
- }
-
- }
+ let mut curr = start;
+ let mut states = vec!((curr, self.head.direction_pointer));
+ loop {
- Op::Pointer => {
- if let Some(val) = self.stack.pop() {
- if val < 0 {
- for _ in 0..(-val) {
- let new_dir = self.head().direction_pointer()
- .anticlockwise();
- self.head_as_mut().set_direction(new_dir);
- }
- }
- else {
- for _ in 0..val {
- let new_dir = self.head().direction_pointer()
- .clockwise();
- self.head_as_mut().set_direction(new_dir);
- }
- }
- }
+ if states.contains(&(curr, self.head.direction_pointer)) {
+ return None;
+ }
- Ok(())
+ let (x,y) = curr;
+ if self.img.get(x, y).color() != Color::White {
+ return Some(curr);
+ }
- }
+ states.push((curr, self.head.direction_pointer));
- Op::Switch => {
- if let Some(val) = self.stack.pop() {
- for _ in 0..(val.abs()) {
- let new_dir = self.head().codel_chooser().toggle();
- self.head_as_mut().set_codel_chooser(new_dir);
- }
+ match self.head.direction_pointer {
+ Direction::Up => {
+ if on_top_edge || self.img.get(x, y-1).color() == Color::Black {
+ self.head.direction_pointer = self.head.direction_pointer.clockwise();
+ self.head.codel_chooser = self.head.codel_chooser.toggle();
}
- Ok(())
-
- }
-
- Op::Duplicate => {
- if let Some(val) = self.stack.pop() {
- self.stack.push(val);
- self.stack.push(val);
+ else {
+ curr = (x, y-1);
}
- Ok(())
}
-
- Op::Roll => {
- if self.stack.len() < 3 {
- return Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"));
- }
-
- let first_pop = self.stack.pop().unwrap();
- let second_pop = self.stack.pop().unwrap();
- if second_pop < 0 {
- // depth is negative -> ignore
- return Ok(());
- }
-
- if first_pop < 0 {
- for _ in 0..(first_pop.abs()) {
- let front = self.stack.remove(0);
- self.stack.insert(second_pop as usize, front);
- }
+ Direction::Right => {
+ if on_right_edge || self.img.get(x+1, y).color() == Color::Black{
+ self.head.direction_pointer = self.head.direction_pointer.clockwise();
+ self.head.codel_chooser = self.head.codel_chooser.toggle();
}
else {
- for _ in 0..first_pop {
- let third_pop = self.stack.pop().unwrap();
- self.stack.insert(self.stack.len() - second_pop as usize, third_pop);
- }
+ curr = (x+1, y);
}
- Ok(())
-
}
+ Direction::Down => {
+ if on_bottom_edge || self.img.get(x, y+1).color() == Color::Black {
+ self.head.direction_pointer = self.head.direction_pointer.clockwise();
+ self.head.codel_chooser = self.head.codel_chooser.toggle();
- Op::InNum => {
- let mut input = String::with_capacity(8);
- // Ignore errors (it's what the author recommended)
- if let Err(_) = io::stdin().read_line(&mut input) {
- return Ok(());
}
- input = input.trim().to_string();
- if let Ok(val) = input.parse::<isize>() {
- self.stack.push(val);
+ else {
+ curr = (x, y+1);
}
-
- Ok(())
}
+ Direction::Left => {
+ if on_left_edge || self.img.get(x-1, y).color() == Color::Black {
+ self.head.direction_pointer = self.head.direction_pointer.clockwise();
+ self.head.codel_chooser = self.head.codel_chooser.toggle();
- Op::InChar => {
- let mut input = String::with_capacity(8);
- // Ignore errors (it's what the author recommended)
- if let Err(_) = io::stdin().read_line(&mut input) {
- return Ok(());
}
- input = input.trim().to_string();
-
- let bytes = Self::get_utf8_char(&input);
- let code_point = Self::utf8_to_unicode(&bytes);
-
- self.stack.push(code_point);
-
- Ok(())
- }
-
- Op::OutNum => {
- if let Some(val) = self.stack.pop() {
- print!("{}", val);
- io::stdout().flush().expect("Failed to flush to stdout!");
- }
- Ok(())
- }
-
- Op::OutChar => {
-
- if let Some(val) = self.stack.pop() {
- if let Some(c) = char::from_u32(val as u32) {
- print!("{}", c);
- io::stdout().flush().expect("Failed to flush to stdout!");
- }
+ else {
+ curr = (x-1, y);
}
- Ok(())
- }
-
- }
-
- }
- else { Ok(()) }
-
-
- }
-
- fn move_next(&mut self) -> Option<(u32, u32)> {
- let curr_codel = self.head.pos;
- let block = &self.img.get_block(curr_codel.0, curr_codel.1);
-
- let mut cc_switches = 0;
- let mut tries = 0;
-
- loop {
-
- let edge = self.head.get_furthest_edge(&block);
- let codel_on_edge = self.head.get_furthest_codel_on_edge(&edge);
- if tries == 8 { return None }
-
- if let Some(next) = self.get_head_next(codel_on_edge.0, codel_on_edge.1) {
- self.head.pos = next;
- return Some(next);
-
- }
- else {
- if cc_switches == 1 {
- cc_switches = 0;
- self.head.direction_pointer = self.head.direction_pointer.clockwise();
}
- else {
- cc_switches += 1;
- self.head.codel_chooser = self.head.codel_chooser.toggle();
- }
- tries += 1;
}
-
}
}
@@ 375,6 212,7 @@ impl Interpreter {
}
}
}
+
#[allow(dead_code)]
fn reset(&mut self) {
@@ 386,7 224,7 @@ impl Interpreter {
}
- fn get_utf8_char(buffer: &str) -> &[u8] {
+ pub fn get_utf8_char(buffer: &str) -> &[u8] {
let bytes = buffer.as_bytes();
let num_bytes = bytes[0].leading_ones() as usize;
@@ 395,7 233,7 @@ impl Interpreter {
else { &bytes[..num_bytes] }
}
- fn utf8_to_unicode(bytes: &[u8]) -> isize {
+ pub fn utf8_to_unicode(bytes: &[u8]) -> isize {
let num_bytes = bytes[0].leading_ones() as usize;
let mut code_point: Vec<&str> = vec!();
@@ 441,7 279,7 @@ pub enum Direction {
}
impl Direction {
- fn clockwise(&self) -> Self {
+ pub fn clockwise(&self) -> Self {
match self {
Direction::Up => Direction::Right,
Direction::Right => Direction::Down,
@@ 450,7 288,7 @@ impl Direction {
}
}
- fn anticlockwise(&self) -> Self {
+ pub fn anticlockwise(&self) -> Self {
match self {
Direction::Up => Direction::Left,
Direction::Right => Direction::Up,
@@ 468,7 306,7 @@ pub enum CcDirection {
}
impl CcDirection {
- fn toggle(&self) -> Self {
+ pub fn toggle(&self) -> Self {
match self {
CcDirection::Left => CcDirection::Right,
CcDirection::Right => CcDirection::Left,
A src/interpreter/rules.rs => src/interpreter/rules.rs +296 -0
@@ 0,0 1,296 @@
+use crate::piet_img::Codel;
+use crate::interpreter::Interpreter;
+use std::io::{self, Error, ErrorKind, Write};
+
+#[derive(Debug)]
+pub enum Op {
+ Push,
+ Pop,
+ Add,
+ Sub,
+ Mult,
+ Div,
+ Mod,
+ Not,
+ Greater,
+ Pointer,
+ Switch,
+ Duplicate,
+ Roll,
+ InNum,
+ InChar,
+ OutNum,
+ OutChar,
+}
+
+pub fn get_op(curr: &Codel, next: &Codel) -> Option<Op> {
+
+ if let (Some(hue_diff), Some(light_diff)) = (curr.color().hue_diff(&next.color()), curr.color().light_diff(&next.color())) {
+
+ match (hue_diff, light_diff) {
+ (0, 1) => Some(Op::Push),
+ (0, 2) => Some(Op::Pop),
+ (1, 0) => Some(Op::Add),
+ (1, 1) => Some(Op::Sub),
+ (1, 2) => Some(Op::Mult),
+ (2, 0) => Some(Op::Div),
+ (2, 1) => Some(Op::Mod),
+ (2, 2) => Some(Op::Not),
+ (3, 0) => Some(Op::Greater),
+ (3, 1) => Some(Op::Pointer),
+ (3, 2) => Some(Op::Switch),
+ (4, 0) => Some(Op::Duplicate),
+ (4, 1) => Some(Op::Roll),
+ (4, 2) => Some(Op::InNum),
+ (5, 0) => Some(Op::InChar),
+ (5, 1) => Some(Op::OutNum),
+ (5, 2) => Some(Op::OutChar),
+ _ => None
+
+ }
+ }
+ else { None }
+
+}
+
+pub fn do_op(interpreter: &mut Interpreter, curr: &Codel, next: &Codel) -> io::Result<()> {
+
+ if let Some(op) = get_op(curr, next) {
+
+ match op {
+
+ Op::Push => {
+ let block_size = curr.block_size().expect("Block size set to None!") as isize;
+ interpreter.stack_as_mut().push(block_size);
+ Ok(())
+ }
+
+ Op::Pop => {
+ interpreter.stack_as_mut().pop();
+ Ok(())
+ }
+
+ Op::Add => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ interpreter.stack_as_mut().push(a + b);
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+ }
+
+ Op::Sub => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ interpreter.stack_as_mut().push(b - a);
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+
+ }
+
+
+ Op::Mult => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ interpreter.stack_as_mut().push(b * a);
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+
+ }
+
+
+ Op::Div => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ if a == 0 {
+ return Err(Error::new(ErrorKind::InvalidInput, "Division by zero!"))
+ }
+ interpreter.stack_as_mut().push(b / a);
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+
+ }
+
+ Op::Mod => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ if a == 0 {
+ return Err(Error::new(ErrorKind::InvalidInput, "Division by zero!"))
+ }
+ interpreter.stack_as_mut().push(b % a + if b%a < 0 { a } else { 0 } );
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+
+ }
+
+ Op::Not => {
+ if interpreter.stack().len() == 0 { return Ok(()); }
+ if interpreter.stack_as_mut().pop() == Some(0) { interpreter.stack_as_mut().push(1) } else { interpreter.stack_as_mut().push(0) }
+ Ok(())
+ }
+
+ Op::Greater => {
+ let first_pop = interpreter.stack_as_mut().pop();
+ let second_pop = interpreter.stack_as_mut().pop();
+ if let (Some(a), Some(b)) = (first_pop, second_pop) {
+ if b > a { interpreter.stack_as_mut().push(1) } else { interpreter.stack_as_mut().push(0) }
+ Ok(())
+ }
+ else {
+ Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"))
+ }
+
+ }
+
+ Op::Pointer => {
+ if let Some(val) = interpreter.stack_as_mut().pop() {
+ if val < 0 {
+ for _ in 0..(-val) {
+ let new_dir = interpreter.head().direction_pointer()
+ .anticlockwise();
+ interpreter.head_as_mut().set_direction(new_dir);
+ }
+ }
+ else {
+ for _ in 0..val {
+ let new_dir = interpreter.head().direction_pointer()
+ .clockwise();
+ interpreter.head_as_mut().set_direction(new_dir);
+ }
+ }
+ }
+
+ Ok(())
+
+ }
+
+ Op::Switch => {
+ if let Some(val) = interpreter.stack_as_mut().pop() {
+ for _ in 0..(val.abs()) {
+ let new_dir = interpreter.head().codel_chooser().toggle();
+ interpreter.head_as_mut().set_codel_chooser(new_dir);
+ }
+ }
+ Ok(())
+
+ }
+
+ Op::Duplicate => {
+ if let Some(val) = interpreter.stack_as_mut().pop() {
+ interpreter.stack_as_mut().push(val);
+ interpreter.stack_as_mut().push(val);
+ }
+ Ok(())
+ }
+
+ Op::Roll => {
+ if interpreter.stack_as_mut().len() < 3 {
+ return Err(Error::new(ErrorKind::InvalidInput, "Not enough values on stack!"));
+ }
+
+ let first_pop = interpreter.stack_as_mut().pop().unwrap();
+ let second_pop = interpreter.stack_as_mut().pop().unwrap();
+ if second_pop < 0 {
+ // depth is negative -> ignore
+ return Ok(());
+ }
+
+ if first_pop < 0 {
+ for _ in 0..(first_pop.abs()) {
+ let front = interpreter.stack_as_mut().remove(0);
+ interpreter.stack_as_mut().insert((second_pop) as usize, front);
+ }
+ }
+ else {
+ for _ in 0..first_pop {
+ let len = interpreter.stack().len();
+ let depth = if (len as isize) < second_pop {
+ return Ok(());
+ }
+ else {
+ len - second_pop as usize
+ };
+ let third_pop = interpreter.stack_as_mut().pop().unwrap();
+ interpreter.stack_as_mut().insert(depth, third_pop);
+ }
+ }
+ Ok(())
+
+ }
+
+ Op::InNum => {
+ let mut input = String::with_capacity(8);
+ // Ignore errors (it's what the author recommended)
+ if let Err(_) = io::stdin().read_line(&mut input) {
+ return Ok(());
+ }
+ input = input.trim().to_string();
+ if let Ok(val) = input.parse::<isize>() {
+ interpreter.stack_as_mut().push(val);
+ }
+
+ Ok(())
+ }
+
+ Op::InChar => {
+ let mut input = String::with_capacity(8);
+ // Ignore errors (it's what the author recommended)
+ if let Err(_) = io::stdin().read_line(&mut input) {
+ return Ok(());
+ }
+ input = input.trim().to_string();
+
+ let bytes = Interpreter::get_utf8_char(&input);
+ let code_point = Interpreter::utf8_to_unicode(&bytes);
+
+ interpreter.stack_as_mut().push(code_point);
+
+ Ok(())
+ }
+
+ Op::OutNum => {
+ if let Some(val) = interpreter.stack_as_mut().pop() {
+ print!("{}", val);
+ io::stdout().flush().expect("Failed to flush to stdout!");
+ }
+ Ok(())
+ }
+
+ Op::OutChar => {
+
+ if let Some(val) = interpreter.stack_as_mut().pop() {
+ if let Some(c) = char::from_u32(val as u32) {
+ print!("{}", c);
+ io::stdout().flush().expect("Failed to flush to stdout!");
+ }
+ }
+ Ok(())
+ }
+
+ }
+
+ }
+ else { Ok(()) }
+
+
+}
+
M src/lib.rs => src/lib.rs +0 -1
@@ 2,5 2,4 @@ pub mod color;
pub mod piet_img;
pub mod interpreter;
pub mod translator;
-pub mod rules;
M src/main.rs => src/main.rs +22 -2
@@ 1,8 1,28 @@
use piet::interpreter::{Interpreter};
+use std::env;
+
fn main() {
- let mut interpreter = Interpreter::new("images/Piet_hello_big.png").unwrap();
- interpreter.exec().expect("Execution Failed!");
+
+ let args: Vec<String> = env::args().collect();
+
+ if args.len() < 2 {
+ panic!("No image has been submited!");
+ }
+
+
+ let image = &args[1];
+ let debug = if args.len() >= 3 { &args[2] } else { "" };
+
+ let mut interpreter = Interpreter::new(&image)
+ .expect(format!("Error opening file {}!", image).as_str());
+
+ if debug == "--debug" {
+ interpreter.debug().expect("Execution Failed!");
+ }
+ else {
+ interpreter.exec().expect("Execution Failed!");
+ }
}
M src/piet_img.rs => src/piet_img.rs +5 -6
@@ 17,14 17,12 @@ impl Codel {
}
}
- pub fn from_bytes(bytes: [u8; 3]) -> Option<Self> {
- if let Some(color) = Color::to_color(bytes) {
- Some(Self {
+ pub fn from_bytes(bytes: [u8; 3]) -> Self {
+ let color = Color::to_color(bytes);
+ Self {
color,
block_size: None,
- })
- }
- else { None }
+ }
}
pub fn color(&self) -> Color { self.color }
@@ 67,6 65,7 @@ impl PietImage {
}
pub fn dimensions(&self) -> (u32, u32) { self.dimensions }
+ pub fn codels(&self) -> &Vec<Vec<Codel>> { &self.codels }
pub fn get(&self, x: u32, y: u32) -> Codel {
D src/rules.rs => src/rules.rs +0 -52
@@ 1,52 0,0 @@
-use crate::piet_img::Codel;
-
-#[derive(Debug)]
-pub enum Op {
- Push,
- Pop,
- Add,
- Sub,
- Mult,
- Div,
- Mod,
- Not,
- Greater,
- Pointer,
- Switch,
- Duplicate,
- Roll,
- InNum,
- InChar,
- OutNum,
- OutChar,
-}
-
-pub fn get_op(curr: &Codel, next: &Codel) -> Option<Op> {
-
- if let (Some(hue_diff), Some(light_diff)) = (curr.color().hue_diff(&next.color()), curr.color().light_diff(&next.color())) {
-
- match (hue_diff, light_diff) {
- (0, 1) => Some(Op::Push),
- (0, 2) => Some(Op::Pop),
- (1, 0) => Some(Op::Add),
- (1, 1) => Some(Op::Sub),
- (1, 2) => Some(Op::Mult),
- (2, 0) => Some(Op::Div),
- (2, 1) => Some(Op::Mod),
- (2, 2) => Some(Op::Not),
- (3, 0) => Some(Op::Greater),
- (3, 1) => Some(Op::Pointer),
- (3, 2) => Some(Op::Switch),
- (4, 0) => Some(Op::Duplicate),
- (4, 1) => Some(Op::Roll),
- (4, 2) => Some(Op::InNum),
- (5, 0) => Some(Op::InChar),
- (5, 1) => Some(Op::OutNum),
- (5, 2) => Some(Op::OutChar),
- _ => None
-
- }
- }
- else { None }
-
-}
M src/translator.rs => src/translator.rs +70 -8
@@ 10,8 10,6 @@ pub fn png_to_piet_img<P>(path: P) -> io::Result<PietImage>
where P: AsRef<Path>
{
- let error = Err(Error::new(ErrorKind::InvalidInput, "Failed to convert to PietImage! Some color is not accepted"));
-
let img = ImageReader::open(path).expect("Failed to open given path!")
.decode().expect("Failed to decode!");
@@ 23,16 21,80 @@ where P: AsRef<Path>
codels.push(vec!());
let len = codels.len();
for Rgb(bytes) in row {
- if let Some(codel) = Codel::from_bytes(*bytes) {
- codels[len - 1].push(codel);
- }
- else { return error }
+ let codel = Codel::from_bytes(*bytes);
+ codels[len - 1].push(codel);
+ }
+ }
+
+ let codel_size = codel_size(&codels);
+ let dimensions = (rgb_img.dimensions().0 / codel_size,
+ rgb_img.dimensions().1 / codel_size);
+
+
+ let mut upscaled_codels = vec!();
+ let row_len = codels[0].len();
+ let col_len = codels.len();
+
+ for row in (0..row_len).step_by(codel_size as usize) {
+ upscaled_codels.push(vec!());
+ for col in (0..col_len).step_by(codel_size as usize) {
+ upscaled_codels[row].push(codels[row][col]);
+
+ }
+ }
+
+ return Ok(PietImage::new(dimensions, upscaled_codels));
+ }
+
+ Err(Error::new(ErrorKind::InvalidInput, "Failed to convert to PietImage!"))
+}
+
+pub fn codel_size(codels: &Vec<Vec<Codel>>) -> u32 {
+ let mut min_width = usize::MAX;
+ for row in codels {
+ let mut prev = &row[0];
+ let mut width = 0;
+ for codel in row {
+ if codel.color() == prev.color() { width += 1; }
+ else {
+ if min_width > width { min_width = width; }
+ width = 1;
}
+ prev = codel;
}
+ }
- return Ok(PietImage::new(rgb_img.dimensions(), codels));
+ let mut min_height = usize::MAX;
+
+ let num_columns = codels[0].len();
+ let num_rows = codels.len();
+
+ for col in 0..num_columns {
+ let mut prev = codels[0][col];
+ let mut height = 0;
+ for row in 0..num_rows {
+ if codels[row][col].color() == prev.color() { height += 1; }
+ else {
+ if min_height > height { min_height = height; }
+ height = 1;
+ }
+ prev = codels[row][col];
+ }
}
- error
+ (if min_width < min_height { min_width } else { min_height }) as u32
+
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::color::Color;
+ use super::*;
+ #[test]
+ fn upscale_works() {
+ let img = png_to_piet_img("images/test_upscale.png").expect("Error on new");
+ assert_eq!(codel_size(img.codels()), 4);
+
+ }
}