Add alien-message
This commit is contained in:
parent
bc31197653
commit
eb7c1e98c9
211
src/bin/alien-message/main.rs
Normal file
211
src/bin/alien-message/main.rs
Normal file
@ -0,0 +1,211 @@
|
||||
use std::env::args;
|
||||
use std::io::stdout;
|
||||
use std::io::Write;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use lowdim::bb2d;
|
||||
use lowdim::p2d;
|
||||
use lowdim::v2d;
|
||||
use lowdim::Array2d;
|
||||
use lowdim::BBox2d;
|
||||
use lowdim::Point2d;
|
||||
|
||||
use pixelfoo_apps::color::Color;
|
||||
|
||||
type Error = Box<dyn std::error::Error>;
|
||||
type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
const MESSAGES: &[&str] = &[
|
||||
// Arecibo message
|
||||
"\
|
||||
00000010101010000000000\
|
||||
00101000001010000000100\
|
||||
10001000100010010110010\
|
||||
10101010101010100100100\
|
||||
00000000000000000000000\
|
||||
00000000000011000000000\
|
||||
00000000001101000000000\
|
||||
00000000001101000000000\
|
||||
00000000010101000000000\
|
||||
00000000011111000000000\
|
||||
00000000000000000000000\
|
||||
11000011100011000011000\
|
||||
10000000000000110010000\
|
||||
11010001100011000011010\
|
||||
11111011111011111011111\
|
||||
00000000000000000000000\
|
||||
00010000000000000000010\
|
||||
00000000000000000000000\
|
||||
00001000000000000000001\
|
||||
11111000000000000011111\
|
||||
00000000000000000000000\
|
||||
11000011000011100011000\
|
||||
10000000100000000010000\
|
||||
11010000110001110011010\
|
||||
11111011111011111011111\
|
||||
00000000000000000000000\
|
||||
00010000001100000000010\
|
||||
00000000001100000000000\
|
||||
00001000001100000000001\
|
||||
11111000001100000011111\
|
||||
00000000001100000000000\
|
||||
00100000000100000000100\
|
||||
00010000001100000001000\
|
||||
00001100001100000010000\
|
||||
00000011000100001100000\
|
||||
00000000001100110000000\
|
||||
00000011000100001100000\
|
||||
00001100001100000010000\
|
||||
00010000001000000001000\
|
||||
00100000001100000000100\
|
||||
01000000001100000000100\
|
||||
01000000000100000001000\
|
||||
00100000001000000010000\
|
||||
00010000000000001100000\
|
||||
00001100000000110000000\
|
||||
00100011101011000000000\
|
||||
00100000001000000000000\
|
||||
00100000111110000000000\
|
||||
00100001011101001011011\
|
||||
00000010011100100111111\
|
||||
10111000011100000110111\
|
||||
00000000010100000111011\
|
||||
00100000010100000111111\
|
||||
00100000010100000110000\
|
||||
00100000110110000000000\
|
||||
00000000000000000000000\
|
||||
00111000001000000000000\
|
||||
00111010100010101010101\
|
||||
00111000000000101010100\
|
||||
00000000000000101000000\
|
||||
00000000111110000000000\
|
||||
00000011111111100000000\
|
||||
00001110000000111000000\
|
||||
00011000000000001100000\
|
||||
00110100000000010110000\
|
||||
01100110000000110011000\
|
||||
01000101000001010001000\
|
||||
01000100100010010001000\
|
||||
00000100010100010000000\
|
||||
00000100001000010000000\
|
||||
00000100000000010000000\
|
||||
00000001001010000000000\
|
||||
01111001111101001111000\
|
||||
",
|
||||
];
|
||||
|
||||
const COLORS: usize = 3;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
enum Pixel {
|
||||
Background,
|
||||
Foreground,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Frame {
|
||||
pixels: Array2d<i64, Pixel>,
|
||||
}
|
||||
impl Frame {
|
||||
pub fn new(bbox: BBox2d) -> Frame {
|
||||
let pixels = Array2d::with(bbox, |_| Pixel::Background);
|
||||
Frame { pixels }
|
||||
}
|
||||
pub fn bbox(&self) -> BBox2d {
|
||||
self.pixels.bbox()
|
||||
}
|
||||
pub fn set(&mut self, pos: Point2d, pixel: Pixel) {
|
||||
if self.bbox().contains(&pos) {
|
||||
self.pixels[pos] = pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn send<T: Write>(w: &mut T, frame: &Frame) -> Result<()> {
|
||||
for y in frame.bbox().y_range().rev() {
|
||||
for x in frame.bbox().x_range() {
|
||||
let pixel = frame.pixels[p2d(x, y)];
|
||||
let color = match pixel {
|
||||
Pixel::Background => Color::black(),
|
||||
Pixel::Foreground => Color::new(0x99, 0xcc, 0),
|
||||
};
|
||||
w.write_all(&color.rgb())?;
|
||||
}
|
||||
}
|
||||
Ok(w.flush()?)
|
||||
}
|
||||
|
||||
const DEFAULT_ARG: usize = 0;
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let args = args().collect::<Vec<_>>();
|
||||
eprintln!("executing {}", args[0]);
|
||||
|
||||
let x_size = args[1].parse::<usize>().unwrap();
|
||||
let y_size = args[2].parse::<usize>().unwrap();
|
||||
let arg = if let Some(s) = args.get(3) {
|
||||
s.parse::<usize>().unwrap_or(DEFAULT_ARG)
|
||||
} else {
|
||||
DEFAULT_ARG
|
||||
};
|
||||
eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg);
|
||||
|
||||
let frame_size = x_size * y_size * COLORS;
|
||||
|
||||
let x_size = i64::try_from(x_size)?;
|
||||
let y_size = i64::try_from(y_size)?;
|
||||
|
||||
let bbox = bb2d(0..x_size as i64, 0..y_size as i64);
|
||||
let mut frame = Frame::new(bbox);
|
||||
|
||||
let delay = Duration::from_millis(1000);
|
||||
|
||||
let raw_message = *MESSAGES.get(arg).unwrap_or(&MESSAGES[0]);
|
||||
let msg = raw_message.chars().map(|c| c == '1').collect::<Vec<bool>>();
|
||||
let len = msg.len();
|
||||
eprintln!("Message has length {}", len);
|
||||
|
||||
// Factor length
|
||||
let mut msg_size = None;
|
||||
for i in 2..len {
|
||||
if len % i == 0 {
|
||||
let x = i64::try_from(len / i).unwrap();
|
||||
let y = i64::try_from(i).unwrap();
|
||||
msg_size = Some(v2d(x, y));
|
||||
break;
|
||||
}
|
||||
}
|
||||
let msg_size = msg_size.ok_or("message length cannot be factorized")?;
|
||||
let x_msg_size = msg_size.x();
|
||||
let y_msg_size = msg_size.y();
|
||||
let msg_bbox = bb2d(0..x_msg_size, 0..y_msg_size);
|
||||
eprintln!("Message has format ({}, {})", x_msg_size, y_msg_size);
|
||||
|
||||
// Start positions for rendering (lower left pixel).
|
||||
let x_margin = (x_size - x_msg_size).max(0) / 2;
|
||||
let y_margin = (y_size - y_msg_size).max(0) / 2;
|
||||
let x0 = bbox.x_start() + x_margin;
|
||||
let y0 = bbox.y_start() + y_margin;
|
||||
let p0 = p2d(x0, y0);
|
||||
|
||||
for p_msg in msg_bbox {
|
||||
let v_msg = p_msg.to_vec();
|
||||
let x = v_msg.x();
|
||||
let y = v_msg.y();
|
||||
// TODO Automatically determine orientation
|
||||
// let i = usize::try_from(x + y * x_msg_size).unwrap();
|
||||
let i = usize::try_from(y + x * y_msg_size).unwrap();
|
||||
if msg[i] {
|
||||
frame.set(p0 + v_msg, Pixel::Foreground);
|
||||
}
|
||||
}
|
||||
|
||||
loop {
|
||||
let mut buf = Vec::with_capacity(frame_size);
|
||||
send(&mut buf, &frame)?;
|
||||
stdout().write_all(&buf)?;
|
||||
stdout().flush()?;
|
||||
sleep(delay);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user