~jpl8/piet_interpreter

91fc2a26d0b2955aa4ebd3afa3ebb35d2e9d9bf1 — jpl 2 years ago dac2df8
add whitespace, fix roll
9 files changed, 500 insertions(+), 343 deletions(-)

M src/TODO.md
M src/color.rs
M src/interpreter/mod.rs
A src/interpreter/rules.rs
M src/lib.rs
M src/main.rs
M src/piet_img.rs
D src/rules.rs
M src/translator.rs
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);

    }
}