ICFP 2007 Contest: https://web.archive.org/web/20090301164728/https://save-endo.cs.uu.nl/

First implementation of rna2bmp

+2 -1
.gitignore
···
task/endo.dna
-
dna2rna/target/
+
dna2rna/target/
+
rna2bmp/target/
+1
rna2bmp/.dir-locals.el
···
+
((nil . ((default-directory . "~/repos/endo/rna2bmp/"))))
+7
rna2bmp/Cargo.lock
···
+
# This file is automatically @generated by Cargo.
+
# It is not intended for manual editing.
+
version = 4
+
+
[[package]]
+
name = "rna2bmp"
+
version = "0.1.0"
+58
rna2bmp/src/bitmap.rs
···
+
// TODO: Better wrapper here
+
pub const SIZE: usize = 600;
+
pub type Bitmap = [[(u8, u8, u8, u8); SIZE]; SIZE];
+
+
pub fn new_bitmap() -> Bitmap {
+
[[(0, 0, 0, 0); SIZE]; SIZE]
+
}
+
+
fn output_u8(vec: &mut Vec<u8>, n: u8) {
+
vec.push(n);
+
}
+
+
fn output_u16(vec: &mut Vec<u8>, n: u16) {
+
vec.push(n as u8);
+
vec.push((n >> 8) as u8);
+
}
+
+
fn output_u32(vec: &mut Vec<u8>, n: u32) {
+
vec.push(n as u8);
+
vec.push((n >> 8) as u8);
+
vec.push((n >> 16) as u8);
+
vec.push((n >> 24) as u8);
+
}
+
+
pub fn to_data(bmp: &Bitmap) -> Vec<u8> {
+
let mut ret = Vec::new();
+
let row_padding = 3 - (3 * SIZE % 4);
+
output_u16(&mut ret, 0x4d42); // BM
+
output_u32(&mut ret, (0x36 + SIZE * (3 * SIZE + row_padding)) as u32); // Size
+
output_u16(&mut ret, 0x0); // Reserved
+
output_u16(&mut ret, 0x0); // Reserved
+
output_u32(&mut ret, 0x36); // Offset of pixel array
+
output_u32(&mut ret, 0x28); // Length of DIB header
+
output_u32(&mut ret, SIZE as u32); // Width
+
output_u32(&mut ret, SIZE as u32); // Height
+
output_u16(&mut ret, 0x1); // Color planes
+
output_u16(&mut ret, 0x18); // Bits per pixel
+
output_u32(&mut ret, 0x0); // No pixel array compression
+
output_u32(&mut ret, 0x0); // Horizontal resolution
+
output_u32(&mut ret, 0x0); // Vertical resolution
+
output_u32(&mut ret, 0x0); // Colors in the palette
+
output_u32(&mut ret, 0x0); // All colors are important
+
+
for y in (0..SIZE).rev() {
+
for x in 0..SIZE {
+
let (r, g, b, _) = bmp[x][y];
+
output_u8(&mut ret, b);
+
output_u8(&mut ret, g);
+
output_u8(&mut ret, r);
+
}
+
+
for _ in 0..row_padding {
+
output_u8(&mut ret, 0);
+
}
+
}
+
+
return ret;
+
}
+26 -1
rna2bmp/src/main.rs
···
+
mod bitmap;
+
mod rna_processor;
+
+
use crate::rna_processor::RnaProcessor;
+
use std::env;
+
use std::fs;
+
fn main() {
-
println!("Hello, world!");
+
let args: Vec<String> = env::args().collect();
+
if args.len() < 3 {
+
println!("Usage: {} <rna file> <bmp file>", args[0]);
+
return;
+
}
+
+
let contents = fs::read_to_string(&args[1]);
+
if let Ok(rna) = contents {
+
let mut processor = RnaProcessor::new();
+
processor.process_rna(rna.lines().collect());
+
if let Some(bmp) = processor.bitmap() {
+
if fs::write(&args[2], bitmap::to_data(bmp)).is_err() {
+
println!("Could not write to {}", args[2]);
+
}
+
}
+
} else {
+
println!("Could not open {}", args[1]);
+
return;
+
}
}
+227
rna2bmp/src/rna_processor.rs
···
+
use crate::bitmap::Bitmap;
+
use crate::bitmap::SIZE;
+
use crate::bitmap::new_bitmap;
+
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: (usize, usize),
+
mark: (usize, usize),
+
dir: (usize, usize),
+
bitmaps: Vec<Bitmap>,
+
}
+
+
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) -> (u8, u8, u8, u8) {
+
let r = if self.count_rgb == 0 {
+
0
+
} else {
+
self.total_r / self.count_rgb
+
};
+
let g = if self.count_rgb == 0 {
+
0
+
} else {
+
self.total_g / self.count_rgb
+
};
+
let b = if self.count_rgb == 0 {
+
0
+
} else {
+
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,
+
(r * g / 255) as u8,
+
(r * b / 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::new(),
+
}
+
}
+
+
fn set_pixel(&mut self, x: usize, y: usize) {
+
if let Some(b) = self.bitmaps.last_mut() {
+
b[x][y] = 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 = x0 * 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" {
+
let (x, y) = self.position;
+
if let Some(b) = self.bitmaps.last_mut() {
+
let old = b[x][y];
+
let new = self.bucket.current_pixel();
+
let mut to_fill = Vec::new();
+
to_fill.push(self.position);
+
while let Some((x, y)) = to_fill.pop() {
+
if b[x][y] == old {
+
b[x][y] = new;
+
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(new_bitmap());
+
}
+
} else if r == "PFFPCCP" {
+
if self.bitmaps.len() >= 2 {
+
let bmp0 = self.bitmaps[self.bitmaps.len() - 1];
+
let mut bmp1 = self.bitmaps[self.bitmaps.len() - 2];
+
for x in 0..SIZE {
+
for y in 0..SIZE {
+
let (r0, b0, g0, a0) = bmp0[x][y];
+
let (r1, b1, g1, a1) = bmp1[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[x][y] = (r, g, b, a);
+
}
+
}
+
self.bitmaps.pop();
+
}
+
} else if r == "PFFICCF" {
+
if self.bitmaps.len() >= 2 {
+
let bmp0 = self.bitmaps[self.bitmaps.len() - 1];
+
let mut bmp1 = self.bitmaps[self.bitmaps.len() - 2];
+
for x in 0..SIZE {
+
for y in 0..SIZE {
+
let (_, _, _, a0) = bmp0[x][y];
+
let (r1, b1, g1, a1) = bmp1[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[x][y] = (r, g, b, a);
+
}
+
}
+
self.bitmaps.pop();
+
}
+
}
+
}
+
}
+
+
pub fn bitmap(&self) -> Option<&Bitmap> {
+
self.bitmaps.last()
+
}
+
}