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 let x0 = self.position.0 as isize;
137 let y0 = self.position.1 as isize;
138 let x1 = self.mark.0 as isize;
139 let y1 = self.mark.1 as isize;
140 let dx = x1 - x0;
141 let dy = y1 - y0;
142 let d = max(dx.abs(), dy.abs());
143 let c = if dx * dy <= 0 { 1 } else { 0 };
144 let mut x = x0 * d + (d - c) / 2;
145 let mut y = y0 * d + (d - c) / 2;
146 for _ in 0..d {
147 self.set_pixel(((x / d) as usize, (y / d) as usize));
148 x += dx;
149 y += dy;
150 }
151 self.set_pixel((x1 as usize, y1 as usize));
152 } else if r == "PIIPIIP" {
153 if let Some(b) = self.bitmaps.last_mut() {
154 let old = *b.pixel(self.position);
155 let new = self.bucket.current_pixel();
156 if new == old {
157 continue;
158 }
159 let mut to_fill = Vec::new();
160 to_fill.push(self.position);
161 while let Some(p) = to_fill.pop() {
162 if *b.pixel(p) == old {
163 *b.pixel_mut(p) = new;
164
165 let (x, y) = p;
166 if x > 0 {
167 to_fill.push((x - 1, y));
168 }
169 if x < SIZE - 1 {
170 to_fill.push((x + 1, y));
171 }
172 if y > 0 {
173 to_fill.push((x, y - 1));
174 }
175 if y < SIZE - 1 {
176 to_fill.push((x, y + 1));
177 }
178 }
179 }
180 }
181 } else if r == "PCCPFFP" {
182 if self.bitmaps.len() < 10 {
183 self.bitmaps.push(Bitmap::new());
184 }
185 } else if r == "PFFPCCP" {
186 if self.bitmaps.len() >= 2 {
187 let bmp0 = self.bitmaps.pop().unwrap();
188 let mut bmp1 = self.bitmaps.pop().unwrap();
189 for x in 0..SIZE {
190 for y in 0..SIZE {
191 let (r0, g0, b0, a0) = *bmp0.pixel((x, y));
192 let (r1, g1, b1, a1) = *bmp1.pixel((x, y));
193 let r = r0 + ((r1 as usize) * (255 - a0 as usize) / 255) as u8;
194 let g = g0 + ((g1 as usize) * (255 - a0 as usize) / 255) as u8;
195 let b = b0 + ((b1 as usize) * (255 - a0 as usize) / 255) as u8;
196 let a = a0 + ((a1 as usize) * (255 - a0 as usize) / 255) as u8;
197 *bmp1.pixel_mut((x, y)) = (r, g, b, a);
198 }
199 }
200 self.bitmaps.push(bmp1);
201 }
202 } else if r == "PFFICCF" {
203 if self.bitmaps.len() >= 2 {
204 let bmp0 = self.bitmaps.pop().unwrap();
205 let mut bmp1 = self.bitmaps.pop().unwrap();
206 for x in 0..SIZE {
207 for y in 0..SIZE {
208 let (_, _, _, a0) = *bmp0.pixel((x, y));
209 let (r1, g1, b1, a1) = *bmp1.pixel((x, y));
210 let r = ((r1 as usize) * (a0 as usize) / 255) as u8;
211 let g = ((g1 as usize) * (a0 as usize) / 255) as u8;
212 let b = ((b1 as usize) * (a0 as usize) / 255) as u8;
213 let a = ((a1 as usize) * (a0 as usize) / 255) as u8;
214 *bmp1.pixel_mut((x, y)) = (r, g, b, a);
215 }
216 }
217 self.bitmaps.push(bmp1);
218 }
219 }
220 }
221 }
222
223 pub fn bitmap(&self) -> Option<&Bitmap> {
224 self.bitmaps.last()
225 }
226}