use crate::bitmap::Bitmap; use crate::bitmap::Pixel; use crate::bitmap::Point; use crate::bitmap::SIZE; use std::cmp::max; struct Bucket { total_r: usize, total_g: usize, total_b: usize, total_a: usize, count_rgb: usize, count_a: usize, } pub struct RnaProcessor { bucket: Bucket, position: Point, mark: Point, dir: Point, bitmaps: Vec, } impl Bucket { fn new() -> Bucket { Bucket { total_r: 0, total_g: 0, total_b: 0, total_a: 0, count_rgb: 0, count_a: 0, } } fn current_pixel(&self) -> Pixel { let (r, g, b) = if self.count_rgb == 0 { (0, 0, 0) } else { ( self.total_r / self.count_rgb, self.total_g / self.count_rgb, self.total_b / self.count_rgb, ) }; let a = if self.count_a == 0 { 255 } else { self.total_a / self.count_a }; return ( (r * a / 255) as u8, (g * a / 255) as u8, (b * a / 255) as u8, a as u8, ); } fn add_rgb(&mut self, r: usize, g: usize, b: usize) { self.total_r += r; self.total_g += g; self.total_b += b; self.count_rgb += 1; } fn add_a(&mut self, a: usize) { self.total_a += a; self.count_a += 1; } fn clear(&mut self) { self.total_r = 0; self.total_g = 0; self.total_b = 0; self.total_a = 0; self.count_rgb = 0; self.count_a = 0; } } impl RnaProcessor { pub fn new() -> RnaProcessor { RnaProcessor { bucket: Bucket::new(), position: (0, 0), mark: (0, 0), dir: (1, 0), bitmaps: vec![Bitmap::new()], } } fn set_pixel(&mut self, p: Point) { if let Some(b) = self.bitmaps.last_mut() { *b.pixel_mut(p) = self.bucket.current_pixel(); } } pub fn process_rna(&mut self, rna: Vec<&str>) { for r in rna { if r == "PIPIIIC" { self.bucket.add_rgb(0, 0, 0); } else if r == "PIPIIIP" { self.bucket.add_rgb(255, 0, 0); } else if r == "PIPIICC" { self.bucket.add_rgb(0, 255, 0); } else if r == "PIPIICF" { self.bucket.add_rgb(255, 255, 0); } else if r == "PIPIICP" { self.bucket.add_rgb(0, 0, 255); } else if r == "PIPIIFC" { self.bucket.add_rgb(255, 0, 255); } else if r == "PIPIIFF" { self.bucket.add_rgb(0, 255, 255); } else if r == "PIPIIPC" { self.bucket.add_rgb(255, 255, 255); } else if r == "PIPIIPF" { self.bucket.add_a(0); } else if r == "PIPIIPP" { self.bucket.add_a(255); } else if r == "PIIPICP" { self.bucket.clear(); } else if r == "PIIIIIP" { let (x, y) = self.position; let (dx, dy) = self.dir; self.position = ((x + dx) % SIZE, (y + dy) % SIZE); } else if r == "PCCCCCP" { let (dx, dy) = self.dir; self.dir = (dy, SIZE - dx); } else if r == "PFFFFFP" { let (dx, dy) = self.dir; self.dir = (SIZE - dy, dx); } else if r == "PCCIFFP" { self.mark = self.position; } else if r == "PFFICCP" { let x0 = self.position.0 as isize; let y0 = self.position.1 as isize; let x1 = self.mark.0 as isize; let y1 = self.mark.1 as isize; let dx = x1 - x0; let dy = y1 - y0; let d = max(dx.abs(), dy.abs()); let c = if dx * dy <= 0 { 1 } else { 0 }; let mut x = x0 * d + (d - c) / 2; let mut y = y0 * d + (d - c) / 2; for _ in 0..d { self.set_pixel(((x / d) as usize, (y / d) as usize)); x += dx; y += dy; } self.set_pixel((x1 as usize, y1 as usize)); } else if r == "PIIPIIP" { if let Some(b) = self.bitmaps.last_mut() { let old = *b.pixel(self.position); let new = self.bucket.current_pixel(); if new == old { continue; } let mut to_fill = Vec::new(); to_fill.push(self.position); while let Some(p) = to_fill.pop() { if *b.pixel(p) == old { *b.pixel_mut(p) = new; let (x, y) = p; if x > 0 { to_fill.push((x - 1, y)); } if x < SIZE - 1 { to_fill.push((x + 1, y)); } if y > 0 { to_fill.push((x, y - 1)); } if y < SIZE - 1 { to_fill.push((x, y + 1)); } } } } } else if r == "PCCPFFP" { if self.bitmaps.len() < 10 { self.bitmaps.push(Bitmap::new()); } } else if r == "PFFPCCP" { if self.bitmaps.len() >= 2 { let bmp0 = self.bitmaps.pop().unwrap(); let mut bmp1 = self.bitmaps.pop().unwrap(); for x in 0..SIZE { for y in 0..SIZE { let (r0, g0, b0, a0) = *bmp0.pixel((x, y)); let (r1, g1, b1, a1) = *bmp1.pixel((x, y)); let r = r0 + ((r1 as usize) * (255 - a0 as usize) / 255) as u8; let g = g0 + ((g1 as usize) * (255 - a0 as usize) / 255) as u8; let b = b0 + ((b1 as usize) * (255 - a0 as usize) / 255) as u8; let a = a0 + ((a1 as usize) * (255 - a0 as usize) / 255) as u8; *bmp1.pixel_mut((x, y)) = (r, g, b, a); } } self.bitmaps.push(bmp1); } } else if r == "PFFICCF" { if self.bitmaps.len() >= 2 { let bmp0 = self.bitmaps.pop().unwrap(); let mut bmp1 = self.bitmaps.pop().unwrap(); for x in 0..SIZE { for y in 0..SIZE { let (_, _, _, a0) = *bmp0.pixel((x, y)); let (r1, g1, b1, a1) = *bmp1.pixel((x, y)); let r = ((r1 as usize) * (a0 as usize) / 255) as u8; let g = ((g1 as usize) * (a0 as usize) / 255) as u8; let b = ((b1 as usize) * (a0 as usize) / 255) as u8; let a = ((a1 as usize) * (a0 as usize) / 255) as u8; *bmp1.pixel_mut((x, y)) = (r, g, b, a); } } self.bitmaps.push(bmp1); } } } } pub fn bitmap(&self) -> Option<&Bitmap> { self.bitmaps.last() } }