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