ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/
1use crate::bitmap::Bitmap; 2use crate::bitmap::Pixel; 3use crate::bitmap::Point; 4use crate::bitmap::SIZE; 5use std::cmp::max; 6 7struct Bucket { 8 total_r: usize, 9 total_g: usize, 10 total_b: usize, 11 total_a: usize, 12 count_rgb: usize, 13 count_a: usize, 14} 15 16pub struct RnaProcessor { 17 bucket: Bucket, 18 position: Point, 19 mark: Point, 20 dir: Point, 21 bitmaps: Vec<Bitmap>, 22} 23 24impl Bucket { 25 fn new() -> Bucket { 26 Bucket { 27 total_r: 0, 28 total_g: 0, 29 total_b: 0, 30 total_a: 0, 31 count_rgb: 0, 32 count_a: 0, 33 } 34 } 35 36 fn current_pixel(&self) -> Pixel { 37 let (r, g, b) = if self.count_rgb == 0 { 38 (0, 0, 0) 39 } else { 40 ( 41 self.total_r / self.count_rgb, 42 self.total_g / self.count_rgb, 43 self.total_b / self.count_rgb, 44 ) 45 }; 46 let a = if self.count_a == 0 { 47 255 48 } else { 49 self.total_a / self.count_a 50 }; 51 52 return ( 53 (r * a / 255) as u8, 54 (g * a / 255) as u8, 55 (b * a / 255) as u8, 56 a as u8, 57 ); 58 } 59 60 fn add_rgb(&mut self, r: usize, g: usize, b: usize) { 61 self.total_r += r; 62 self.total_g += g; 63 self.total_b += b; 64 self.count_rgb += 1; 65 } 66 67 fn add_a(&mut self, a: usize) { 68 self.total_a += a; 69 self.count_a += 1; 70 } 71 72 fn clear(&mut self) { 73 self.total_r = 0; 74 self.total_g = 0; 75 self.total_b = 0; 76 self.total_a = 0; 77 self.count_rgb = 0; 78 self.count_a = 0; 79 } 80} 81 82impl RnaProcessor { 83 pub fn new() -> RnaProcessor { 84 RnaProcessor { 85 bucket: Bucket::new(), 86 position: (0, 0), 87 mark: (0, 0), 88 dir: (1, 0), 89 bitmaps: vec![Bitmap::new()], 90 } 91 } 92 93 fn set_pixel(&mut self, p: Point) { 94 if let Some(b) = self.bitmaps.last_mut() { 95 *b.pixel_mut(p) = self.bucket.current_pixel(); 96 } 97 } 98 99 pub fn process_rna(&mut self, rna: Vec<&str>) { 100 for r in rna { 101 if r == "PIPIIIC" { 102 self.bucket.add_rgb(0, 0, 0); 103 } else if r == "PIPIIIP" { 104 self.bucket.add_rgb(255, 0, 0); 105 } else if r == "PIPIICC" { 106 self.bucket.add_rgb(0, 255, 0); 107 } else if r == "PIPIICF" { 108 self.bucket.add_rgb(255, 255, 0); 109 } else if r == "PIPIICP" { 110 self.bucket.add_rgb(0, 0, 255); 111 } else if r == "PIPIIFC" { 112 self.bucket.add_rgb(255, 0, 255); 113 } else if r == "PIPIIFF" { 114 self.bucket.add_rgb(0, 255, 255); 115 } else if r == "PIPIIPC" { 116 self.bucket.add_rgb(255, 255, 255); 117 } else if r == "PIPIIPF" { 118 self.bucket.add_a(0); 119 } else if r == "PIPIIPP" { 120 self.bucket.add_a(255); 121 } else if r == "PIIPICP" { 122 self.bucket.clear(); 123 } else if r == "PIIIIIP" { 124 let (x, y) = self.position; 125 let (dx, dy) = self.dir; 126 self.position = ((x + dx) % SIZE, (y + dy) % SIZE); 127 } else if r == "PCCCCCP" { 128 let (dx, dy) = self.dir; 129 self.dir = (dy, SIZE - dx); 130 } else if r == "PFFFFFP" { 131 let (dx, dy) = self.dir; 132 self.dir = (SIZE - dy, dx); 133 } else if r == "PCCIFFP" { 134 self.mark = self.position; 135 } else if r == "PFFICCP" { 136 // TODO: Can I rework this to reduce casts or locals? 137 let x0 = self.position.0 as isize; 138 let y0 = self.position.1 as isize; 139 let x1 = self.mark.0 as isize; 140 let y1 = self.mark.1 as isize; 141 let dx = x1 - x0; 142 let dy = y1 - y0; 143 let d = max(dx.abs(), dy.abs()); 144 let c = if dx * dy <= 0 { 1 } else { 0 }; 145 let mut x = x0 * d + (d - c) / 2; 146 let mut y = y0 * d + (d - c) / 2; 147 for _ in 0..d { 148 self.set_pixel(((x / d) as usize, (y / d) as usize)); 149 x += dx; 150 y += dy; 151 } 152 self.set_pixel((x1 as usize, y1 as usize)); 153 } else if r == "PIIPIIP" { 154 if let Some(b) = self.bitmaps.last_mut() { 155 let old = *b.pixel(self.position); 156 let new = self.bucket.current_pixel(); 157 if new == old { 158 continue; 159 } 160 let mut to_fill = Vec::new(); 161 to_fill.push(self.position); 162 while let Some(p) = to_fill.pop() { 163 if *b.pixel(p) == old { 164 *b.pixel_mut(p) = new; 165 166 let (x, y) = p; 167 if x > 0 { 168 to_fill.push((x - 1, y)); 169 } 170 if x < SIZE - 1 { 171 to_fill.push((x + 1, y)); 172 } 173 if y > 0 { 174 to_fill.push((x, y - 1)); 175 } 176 if y < SIZE - 1 { 177 to_fill.push((x, y + 1)); 178 } 179 } 180 } 181 } 182 } else if r == "PCCPFFP" { 183 if self.bitmaps.len() < 10 { 184 self.bitmaps.push(Bitmap::new()); 185 } 186 } else if r == "PFFPCCP" { 187 // TODO: Better structure 188 if let Some(bmp0) = self.bitmaps.pop() { 189 if let Some(mut bmp1) = self.bitmaps.pop() { 190 for x in 0..SIZE { 191 for y in 0..SIZE { 192 let (r0, g0, b0, a0) = *bmp0.pixel((x, y)); 193 let (r1, g1, b1, a1) = *bmp1.pixel((x, y)); 194 let r = r0 + ((r1 as usize) * (255 - a0 as usize) / 255) as u8; 195 let g = g0 + ((g1 as usize) * (255 - a0 as usize) / 255) as u8; 196 let b = b0 + ((b1 as usize) * (255 - a0 as usize) / 255) as u8; 197 let a = a0 + ((a1 as usize) * (255 - a0 as usize) / 255) as u8; 198 *bmp1.pixel_mut((x, y)) = (r, g, b, a); 199 } 200 } 201 self.bitmaps.push(bmp1); 202 } else { 203 self.bitmaps.push(bmp0); 204 } 205 } 206 } else if r == "PFFICCF" { 207 if let Some(bmp0) = self.bitmaps.pop() { 208 if let Some(mut bmp1) = self.bitmaps.pop() { 209 for x in 0..SIZE { 210 for y in 0..SIZE { 211 let (_, _, _, a0) = *bmp0.pixel((x, y)); 212 let (r1, g1, b1, a1) = *bmp1.pixel((x, y)); 213 let r = ((r1 as usize) * (a0 as usize) / 255) as u8; 214 let g = ((g1 as usize) * (a0 as usize) / 255) as u8; 215 let b = ((b1 as usize) * (a0 as usize) / 255) as u8; 216 let a = ((a1 as usize) * (a0 as usize) / 255) as u8; 217 *bmp1.pixel_mut((x, y)) = (r, g, b, a); 218 } 219 } 220 self.bitmaps.push(bmp1); 221 } else { 222 self.bitmaps.push(bmp0); 223 } 224 } 225 } 226 } 227 } 228 229 pub fn bitmap(&self) -> Option<&Bitmap> { 230 self.bitmaps.last() 231 } 232}