~jpl8/piet_interpreter

d2cbee3ecd24a7926d65088c3e07fbeb17af8e13 — jpl 2 years ago fab1cd5
Add stdout lock instead of just print!'ing.
2 files changed, 182 insertions(+), 169 deletions(-)

M src/interpreter/mod.rs
M src/interpreter/rules.rs
M src/interpreter/mod.rs => src/interpreter/mod.rs +169 -166
@@ 16,117 16,121 @@ pub struct Interpreter {

#[allow(dead_code)]
impl Interpreter {

    pub fn new<P>(path: P) -> io::Result<Self>
    where P: AsRef<Path>
    where
        P: AsRef<Path>,
    {
        let img = translator::to_piet_img(path)?;
        Ok(Interpreter::from_img(img))
    }

    pub fn with_codel_size<P>(path: P, codel_size: u32) -> io::Result<Self>
    where P: AsRef<Path>
    where
        P: AsRef<Path>,
    {
        let img = translator::with_codel_size(path, codel_size)?;
        Ok(Interpreter::from_img(img))
    }

    pub fn from_img(img: PietImage) -> Self { 
    pub fn from_img(img: PietImage) -> Self {
        Self {
            img, 
            img,
            head: Head::default(),
            stack: vec!(),
            stack: vec![],
            debug: false,
        }
    }

    pub fn head(&self) -> &Head { &self.head }
    pub fn head_as_mut(&mut self) -> &mut Head { &mut self.head }
    
    pub fn debug(&self) -> bool { self.debug }
    pub fn set_debug(&mut self, debug: bool) { self.debug = debug }
    pub fn head(&self) -> &Head {
        &self.head
    }
    pub fn head_as_mut(&mut self) -> &mut Head {
        &mut self.head
    }

    pub fn debug(&self) -> bool {
        self.debug
    }
    pub fn set_debug(&mut self, debug: bool) {
        self.debug = debug
    }

    pub fn img(&self) -> &PietImage { &self.img }
    pub fn stack(&self) -> &Vec<isize> { &self.stack }
    pub fn stack_as_mut(&mut self) -> &mut Vec<isize> { &mut self.stack }
    pub fn img(&self) -> &PietImage {
        &self.img
    }
    pub fn stack(&self) -> &Vec<isize> {
        &self.stack
    }
    pub fn stack_as_mut(&mut self) -> &mut Vec<isize> {
        &mut self.stack
    }

    pub fn exec(&mut self) -> io::Result<()> {

       loop {
        let mut stdout_handle = std::io::stdout().lock();
        loop {
            let curr = self.head.pos();
            //eprintln!("{:?}", curr);
            if let Some(next) = self.move_next() {

                let curr_codel = self.img().get(curr.0, curr.1);
                let next_codel = self.img().get(next.0, next.1);
                rules::do_op(self, &curr_codel, &next_codel)?;

                rules::do_op(self, &curr_codel, &next_codel, &mut stdout_handle)?;
            } else {
                return Ok(());
            }

            else { return Ok(()) }

       }

        }
    }


   fn move_next(&mut self) -> Option<(u32, u32)> {
    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 tries == 8 {
                return None;
            }

            if self.img.get(curr_codel.0, curr_codel.1).color() == Color::White {
                    return self.move_through_whitespace(curr_codel);
                return self.move_through_whitespace(curr_codel);
            }

            if let Some(next) = self.get_head_next(codel_on_edge.0, codel_on_edge.1) {

                self.head.pos = next;
                return Some(next); 

            }
            else {
                return Some(next);
            } else {
                if cc_switches == 1 {
                    cc_switches = 0;
                    self.head.direction_pointer = self.head.direction_pointer.clockwise();
                }
                else { 
                } else {
                    cc_switches += 1;
                    self.head.codel_chooser = self.head.codel_chooser.toggle(); 
                    self.head.codel_chooser = self.head.codel_chooser.toggle();
                }
                tries += 1;
            }

        }
    }

    fn move_through_whitespace(&mut self, start: (u32, u32)) -> Option<(u32, u32)> {
        let (width, height) = self.img.dimensions();
        let mut curr = start;
        let mut states = vec!();
        let mut states = vec![];
        loop {
            //eprintln!("in: {:?}", curr);

            let on_top_edge    = curr.1 == 0;
            let on_top_edge = curr.1 == 0;
            let on_bottom_edge = curr.1 == height - 1;
            let on_left_edge   = curr.0 == 0;
            let on_right_edge  = curr.0 == width - 1;


            let on_left_edge = curr.0 == 0;
            let on_right_edge = curr.0 == width - 1;

            if states.contains(&(curr, self.head.direction_pointer)) {
                return None;
            }

            let (x,y) = curr;
            let (x, y) = curr;
            if self.img.get(x, y).color() != Color::White {
                self.head_as_mut().pos = curr;
                return Some(curr);


@@ 136,174 140,173 @@ impl Interpreter {

            match self.head.direction_pointer {
                Direction::Up => {
                    if on_top_edge || self.img.get(x, y-1).color() == Color::Black { 
                    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(); 
                    }
                    else {
                        curr = (x, y-1);
                        self.head.codel_chooser = self.head.codel_chooser.toggle();
                    } else {
                        curr = (x, y - 1);
                    }
                }
                Direction::Right => {
                    if on_right_edge || self.img.get(x+1, y).color() == Color::Black{
                    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 { 
                        curr = (x+1, y);
                        self.head.codel_chooser = self.head.codel_chooser.toggle();
                    } else {
                        curr = (x + 1, y);
                    }
                }
                Direction::Down => {
                    if on_bottom_edge || self.img.get(x, y+1).color() == Color::Black {
                    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(); 

                    }
                    else { 
                        curr = (x, y+1);
                        self.head.codel_chooser = self.head.codel_chooser.toggle();
                    } else {
                        curr = (x, y + 1);
                    }
                }
                Direction::Left => {
                    if on_left_edge || self.img.get(x-1, y).color() == Color::Black { 
                    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(); 

                    }
                    else { 
                        curr = (x-1, y);
                        self.head.codel_chooser = self.head.codel_chooser.toggle();
                    } else {
                        curr = (x - 1, y);
                    }
                }
            }
        }
    }

   

    fn get_head_next(&self, x: u32, y: u32) -> Option<(u32, u32)> {
        let (width, height) = self.img.dimensions();

        let on_top_edge    = y == 0;
        let on_top_edge = y == 0;
        let on_bottom_edge = y == height - 1;
        let on_left_edge   = x == 0;
        let on_right_edge  = x == width - 1;
        let on_left_edge = x == 0;
        let on_right_edge = x == width - 1;

        match self.head.direction_pointer {
            Direction::Up => {
                if on_top_edge || self.img.get(x, y-1).color() == Color::Black { None }
                else { Some((x, y-1)) }
                if on_top_edge || self.img.get(x, y - 1).color() == Color::Black {
                    None
                } else {
                    Some((x, y - 1))
                }
            }
            Direction::Right => {
                if on_right_edge || self.img.get(x+1, y).color() == Color::Black{ None }
                else { Some((x+1, y)) }
                if on_right_edge || self.img.get(x + 1, y).color() == Color::Black {
                    None
                } else {
                    Some((x + 1, y))
                }
            }
            Direction::Down => {
                if on_bottom_edge || self.img.get(x, y+1).color() == Color::Black { None }
                else { Some((x, y+1)) }
                if on_bottom_edge || self.img.get(x, y + 1).color() == Color::Black {
                    None
                } else {
                    Some((x, y + 1))
                }
            }
            Direction::Left => {
                if on_left_edge || self.img.get(x-1, y).color() == Color::Black { None }
                else { Some((x-1, y)) }
                if on_left_edge || self.img.get(x - 1, y).color() == Color::Black {
                    None
                } else {
                    Some((x - 1, y))
                }
            }
        }
    }

    
    #[allow(dead_code)]
    fn reset(&mut self) {
            self.img.reset_block_sizes();
            self.img.update_block_sizes();
        
            self.head.set_pos( (0,0) );
            self.stack = vec!(); 
    
    }
        self.img.reset_block_sizes();
        self.img.update_block_sizes();

    pub fn get_utf8_char(buffer: &str) -> &[u8] { 
        self.head.set_pos((0, 0));
        self.stack = vec![];
    }

    pub fn get_utf8_char(buffer: &str) -> &[u8] {
        let bytes = buffer.as_bytes();
        let num_bytes = bytes[0].leading_ones() as usize;

        if num_bytes == 0 { &bytes[..1] }
        else { &bytes[..num_bytes] }
        if num_bytes == 0 {
            &bytes[..1]
        } else {
            &bytes[..num_bytes]
        }
    }

    pub 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!();
        let mut code_point: Vec<&str> = vec![];
        let byte_strs: Vec<String> = bytes.iter().map(|byte| format!("{:b}", byte)).collect();
        let header_str = &byte_strs[0];
       
        // Ascii
        if byte_strs.len() == 1 { return bytes[0] as isize }

        // Ascii
        if byte_strs.len() == 1 {
            return bytes[0] as isize;
        }

        // Non-Ascii UTF-8

        code_point.push(&header_str[num_bytes+1..]);
        code_point.push(&header_str[num_bytes + 1..]);

        for i in 1..num_bytes {
            code_point.push(&byte_strs[i][2..]);
        }

        
        let mut code_point_num: isize = 0;
        let mut multiplier = 1;

        for bit in code_point.join("").chars().rev() {
            code_point_num += (bit.to_digit(2).unwrap() as isize) * multiplier;
            multiplier *= 2;

        }

        code_point_num

    }



}




#[allow(dead_code)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Direction {
    Up, Down, Left, Right
    Up,
    Down,
    Left,
    Right,
}

impl Direction {
    pub fn clockwise(&self) -> Self {
        match self {
            Direction::Up    => Direction::Right,
            Direction::Up => Direction::Right,
            Direction::Right => Direction::Down,
            Direction::Down  => Direction::Left,
            Direction::Left  => Direction::Up,
            Direction::Down => Direction::Left,
            Direction::Left => Direction::Up,
        }
    }

    pub fn anticlockwise(&self) -> Self {
        match self {
            Direction::Up    => Direction::Left,
            Direction::Up => Direction::Left,
            Direction::Right => Direction::Up,
            Direction::Down  => Direction::Right,
            Direction::Left  => Direction::Down,
            Direction::Down => Direction::Right,
            Direction::Left => Direction::Down,
        }
    }

}

#[allow(dead_code)]
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum CcDirection {
    Left, Right
    Left,
    Right,
}

impl CcDirection {
    pub fn toggle(&self) -> Self {
        match self {
            CcDirection::Left  => CcDirection::Right,
            CcDirection::Left => CcDirection::Right,
            CcDirection::Right => CcDirection::Left,
        }
    }


@@ 319,7 322,6 @@ pub struct Head {

#[allow(dead_code)]
impl Head {

    pub fn new(pos: (u32, u32), direction_pointer: Direction, codel_chooser: CcDirection) -> Self {
        Self {
            pos,


@@ 330,14 332,18 @@ impl Head {

    pub fn default() -> Self {
        Self {
            pos: (0,0),
            pos: (0, 0),
            direction_pointer: Direction::Right,
            codel_chooser: CcDirection::Left,
        }
    }

    pub fn direction_pointer(&self) -> &Direction { &self.direction_pointer }
    pub fn codel_chooser(&self) -> &CcDirection { &self.codel_chooser }
    pub fn direction_pointer(&self) -> &Direction {
        &self.direction_pointer
    }
    pub fn codel_chooser(&self) -> &CcDirection {
        &self.codel_chooser
    }

    pub fn set_direction(&mut self, dir: Direction) {
        self.direction_pointer = dir;


@@ 347,67 353,64 @@ impl Head {
        self.codel_chooser = cc;
    }

    pub fn pos(&self) -> (u32, u32) {  self.pos  }

    pub fn set_pos(&mut self, pos: (u32, u32)) { self.pos = pos }

    pub fn pos(&self) -> (u32, u32) {
        self.pos
    }

    pub fn set_pos(&mut self, pos: (u32, u32)) {
        self.pos = pos
    }

    fn get_furthest_edge(&self, block: &Vec<(u32, u32)>) -> Vec<(u32, u32)> {
    
        let mut max_x: u32 = block[0].0;
        let mut min_x: u32 = block[0].0;
        let mut max_y: u32 = block[0].1;
        let mut min_y: u32 = block[0].1;
    

        for &(x, y) in block.iter() {
            if max_x < x { max_x = x; }
            if min_x > x { min_x = x; }
            if max_y < y { max_y = y; }
            if min_y > y { min_y = y; }
            if max_x < x {
                max_x = x;
            }
            if min_x > x {
                min_x = x;
            }
            if max_y < y {
                max_y = y;
            }
            if min_y > y {
                min_y = y;
            }
        }
    
        let right_edge  = block.iter().filter(|(x, _)| *x == max_x).cloned().collect();
        let left_edge   = block.iter().filter(|(x, _)| *x == min_x).cloned().collect();

        let right_edge = block.iter().filter(|(x, _)| *x == max_x).cloned().collect();
        let left_edge = block.iter().filter(|(x, _)| *x == min_x).cloned().collect();
        let bottom_edge = block.iter().filter(|(_, y)| *y == max_y).cloned().collect();
        let top_edge    = block.iter().filter(|(_, y)| *y == min_y).cloned().collect();
    
        let top_edge = block.iter().filter(|(_, y)| *y == min_y).cloned().collect();

        match self.direction_pointer {
            Direction::Right => { right_edge  },
            Direction::Left  => { left_edge   },
            Direction::Down  => { bottom_edge },
            Direction::Up    => { top_edge    },
    
            Direction::Right => right_edge,
            Direction::Left => left_edge,
            Direction::Down => bottom_edge,
            Direction::Up => top_edge,
        }
    
    
    }
    fn get_furthest_codel_on_edge(&self, edge: &Vec<(u32, u32)>) -> (u32, u32) {
    
    
        let uppermost = *edge.iter().min_by_key(|(_,y)| y ).unwrap();
        let lowermost = *edge.iter().max_by_key(|(_,y)| y ).unwrap();
        let rightmost = *edge.iter().max_by_key(|(x,_)| x ).unwrap();
        let leftmost  = *edge.iter().min_by_key(|(x,_)| x ).unwrap();
    
    
        let uppermost = *edge.iter().min_by_key(|(_, y)| y).unwrap();
        let lowermost = *edge.iter().max_by_key(|(_, y)| y).unwrap();
        let rightmost = *edge.iter().max_by_key(|(x, _)| x).unwrap();
        let leftmost = *edge.iter().min_by_key(|(x, _)| x).unwrap();

        match (self.direction_pointer, self.codel_chooser) {
    
            (Direction::Right, CcDirection::Left)  => { uppermost },
            (Direction::Right, CcDirection::Right) => { lowermost },
            (Direction::Down,  CcDirection::Left)  => { rightmost },
            (Direction::Down,  CcDirection::Right) => { leftmost },
            (Direction::Left,  CcDirection::Left)  => { lowermost },
            (Direction::Left,  CcDirection::Right) => { uppermost },
            (Direction::Up,    CcDirection::Left)  => { leftmost },
            (Direction::Up,    CcDirection::Right) => { rightmost },
    
            (Direction::Right, CcDirection::Left) => uppermost,
            (Direction::Right, CcDirection::Right) => lowermost,
            (Direction::Down, CcDirection::Left) => rightmost,
            (Direction::Down, CcDirection::Right) => leftmost,
            (Direction::Left, CcDirection::Left) => lowermost,
            (Direction::Left, CcDirection::Right) => uppermost,
            (Direction::Up, CcDirection::Left) => leftmost,
            (Direction::Up, CcDirection::Right) => rightmost,
        }

}



    }
}

#[cfg(test)]

M src/interpreter/rules.rs => src/interpreter/rules.rs +13 -3
@@ 53,7 53,12 @@ pub fn get_op(curr: &Codel, next: &Codel) -> Option<Op> {
    }
}

pub fn do_op(interpreter: &mut Interpreter, curr: &Codel, next: &Codel) -> io::Result<()> {
pub fn do_op(
    interpreter: &mut Interpreter,
    curr: &Codel,
    next: &Codel,
    handle: &mut std::io::StdoutLock,
) -> io::Result<()> {
    if let Some(op) = get_op(curr, next) {
        match op {
            Op::Push => {


@@ 376,7 381,12 @@ pub fn do_op(interpreter: &mut Interpreter, curr: &Codel, next: &Codel) -> io::R
                    if interpreter.debug() {
                        eprintln!("Executed: OutNum({})", val);
                    }
                    print!("{}", val);
                    let bytes = if cfg!(target_endian = "big") {
                        val.to_be_bytes()
                    } else {
                        val.to_le_bytes()
                    };
                    handle.write_all(&bytes)?;
                }
                Ok(())
            }


@@ 387,7 397,7 @@ pub fn do_op(interpreter: &mut Interpreter, curr: &Codel, next: &Codel) -> io::R
                        if interpreter.debug() {
                            eprintln!("Executed: OutChar({} = {})", val, c);
                        }
                        print!("{}", c);
                        handle.write_all(c.to_string().as_bytes())?;
                    }
                }
                Ok(())