@ -0,0 +1,3 @@ | |||
/target | |||
**/*.rs.bk | |||
*~ |
@ -0,0 +1,8 @@ | |||
[package] | |||
name = "pixelfoo" | |||
version = "0.1.0" | |||
authors = ["juergen <juergen@chaospott.de>"] | |||
edition = "2018" | |||
[dependencies] | |||
rand = "0.6.0" |
@ -0,0 +1,12 @@ | |||
bimood - color cycling mood lamp with two complementary colors | |||
parameter is the seconds for one cycle through the colors | |||
predprey - grass-prey-predator simulation | |||
parameter is number of actions per 40ms frame | |||
maze - draws a maze | |||
parameter is number of actions per 40ms frame | |||
Compile with "cargo build --release". | |||
The binary executables are in the "target/release" subdirectory. |
@ -0,0 +1,141 @@ | |||
use std::env::args; | |||
use std::io::stdout; | |||
use std::io::Write; | |||
use std::iter::repeat; | |||
use std::thread::sleep; | |||
use std::time::Duration; | |||
#[derive(Clone, Copy, Debug)] | |||
struct Color(u8, u8, u8); | |||
impl Color { | |||
fn black() -> Color { | |||
Color(0, 0, 0) | |||
} | |||
fn white() -> Color { | |||
Color(255, 255, 255) | |||
} | |||
fn gray50() -> Color { | |||
Color(128, 128, 128) | |||
} | |||
fn red() -> Color { | |||
Color(255, 0, 0) | |||
} | |||
fn green() -> Color { | |||
Color(0, 255, 0) | |||
} | |||
fn blue() -> Color { | |||
Color(0, 0, 255) | |||
} | |||
fn yellow() -> Color { | |||
Color(255, 255, 0) | |||
} | |||
fn cyan() -> Color { | |||
Color(0, 255, 255) | |||
} | |||
fn magenta() -> Color { | |||
Color(255, 0, 255) | |||
} | |||
fn complement(&self) -> Color { | |||
Color(255 - self.0, 255 - self.1, 255 - self.2) | |||
} | |||
} | |||
fn interpolate_u8(b0: u8, b1: u8, a: f64) -> u8 { | |||
let b0 = b0 as f64; | |||
let b1 = b1 as f64; | |||
((1.0 - a) * b0 + a * b1) as u8 | |||
} | |||
fn interpolate(c0: Color, c1: Color, a: f64) -> Color { | |||
Color( | |||
interpolate_u8(c0.0, c1.0, a), | |||
interpolate_u8(c0.1, c1.1, a), | |||
interpolate_u8(c0.2, c1.2, a), | |||
) | |||
} | |||
type Frame = Vec<Vec<Color>>; | |||
fn send<T: Write>(w: &mut T, f: &Frame) -> std::io::Result<()> { | |||
for l in f { | |||
for c in l { | |||
let Color(r, g, b) = c; | |||
let buf = &[*r, *g, *b]; | |||
w.write_all(buf)?; | |||
} | |||
} | |||
w.flush() | |||
} | |||
const DEFAULT_LOOP_TIME: usize = 120; | |||
fn main() -> std::io::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 loop_time = args[3].parse::<usize>().unwrap_or(DEFAULT_LOOP_TIME); | |||
eprintln!( | |||
"screen size {}x{}, loop time {:?}s", | |||
x_size, y_size, loop_time | |||
); | |||
let mut border = 0; | |||
while (x_size - 2 * border) * (y_size - 2 * border) > x_size * y_size / 2 { | |||
border += 1; | |||
} | |||
let t_frame = 0.040; // s | |||
let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32); | |||
let mut previous_color = Color::blue(); | |||
let colors = vec![ | |||
Color::red(), | |||
Color::yellow(), | |||
Color::green(), | |||
Color::cyan(), | |||
Color::blue(), | |||
Color::magenta(), | |||
]; | |||
let mut color_index = 0; | |||
let mut next_color = colors[color_index]; | |||
// time to interpolate from one color to the next | |||
let t_interpolate = (loop_time as f64) / (colors.len() as f64); // s | |||
let delta_a = t_frame / t_interpolate; | |||
let mut a = 0.0; | |||
eprint!("delta_a {}", delta_a); | |||
loop { | |||
let c0 = interpolate(previous_color, next_color, a); | |||
let c1 = c0.complement(); | |||
let mut frame = repeat(repeat(c0).take(x_size).collect::<Vec<_>>()) | |||
.take(y_size) | |||
.collect::<Vec<_>>(); | |||
for x in border..(x_size - border) { | |||
for y in border..(y_size - border) { | |||
frame[y][x] = c1 | |||
} | |||
} | |||
a += delta_a; | |||
if a >= 1.0 { | |||
a = 0.0; | |||
color_index += 1; | |||
if color_index >= colors.len() { | |||
color_index = 0; | |||
} | |||
previous_color = next_color; | |||
next_color = colors[color_index]; | |||
} | |||
let mut buf = Vec::with_capacity(x_size * y_size * 3); | |||
send(&mut buf, &frame)?; | |||
stdout().write_all(&buf)?; | |||
stdout().flush()?; | |||
sleep(delay); | |||
} | |||
} |
@ -0,0 +1,225 @@ | |||
use std::env::args; | |||
use std::io::stdout; | |||
use std::io::Write; | |||
use std::thread::sleep; | |||
use std::time::Duration; | |||
use rand::thread_rng; | |||
use rand::Rng; | |||
#[derive(Clone, Copy, Debug)] | |||
struct Color(u8, u8, u8); | |||
#[allow(unused)] | |||
impl Color { | |||
fn black() -> Color { | |||
Color(0, 0, 0) | |||
} | |||
fn white() -> Color { | |||
Color(255, 255, 255) | |||
} | |||
fn gray50() -> Color { | |||
Color(128, 128, 128) | |||
} | |||
fn red() -> Color { | |||
Color(255, 0, 0) | |||
} | |||
fn green() -> Color { | |||
Color(0, 255, 0) | |||
} | |||
fn blue() -> Color { | |||
Color(0, 0, 255) | |||
} | |||
fn yellow() -> Color { | |||
Color(255, 255, 0) | |||
} | |||
fn cyan() -> Color { | |||
Color(0, 255, 255) | |||
} | |||
fn magenta() -> Color { | |||
Color(255, 0, 255) | |||
} | |||
fn complement(&self) -> Color { | |||
Color(255 - self.0, 255 - self.1, 255 - self.2) | |||
} | |||
} | |||
#[derive(Clone, Copy, Debug, PartialEq, Eq)] | |||
enum Square { | |||
Unknown, | |||
Corridor, | |||
Wall, | |||
Start, | |||
Finish, | |||
} | |||
struct Board(Vec<Vec<Square>>); | |||
fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> { | |||
for line in &board.0 { | |||
for square in line { | |||
let Color(r, g, b) = match square { | |||
Square::Unknown => Color::black(), | |||
Square::Corridor => Color::yellow(), | |||
Square::Wall => Color::blue(), | |||
Square::Start => Color::red(), | |||
Square::Finish => Color::green(), | |||
}; | |||
let buf = &[r, g, b]; | |||
w.write_all(buf)?; | |||
} | |||
} | |||
w.flush() | |||
} | |||
impl Board { | |||
fn new(x_size: i32, y_size: i32, x_maze_size: i32, y_maze_size: i32) -> Board { | |||
Board( | |||
(0..y_size) | |||
.map(move |y| { | |||
(0..x_size) | |||
.map(|x| { | |||
if x < x_maze_size && y < y_maze_size { | |||
if x == 0 | |||
|| x == x_maze_size - 1 | |||
|| y == 0 | |||
|| y == y_maze_size - 1 | |||
|| (x % 2 == 0 && y % 2 == 0) | |||
{ | |||
Square::Wall | |||
} else { | |||
Square::Unknown | |||
} | |||
} else { | |||
Square::Unknown | |||
} | |||
}) | |||
.collect::<Vec<_>>() | |||
}) | |||
.collect::<Vec<_>>(), | |||
) | |||
} | |||
fn get(&self, pos: (i32, i32)) -> Square { | |||
let (x, y) = pos; | |||
self.0[y as usize][x as usize] | |||
} | |||
fn set(&mut self, pos: (i32, i32), sq: Square) { | |||
let (x, y) = pos; | |||
self.0[y as usize][x as usize] = sq; | |||
} | |||
} | |||
struct Move { | |||
from: (i32, i32), | |||
dir: (i32, i32), | |||
prio: i32, | |||
} | |||
fn add_move(open: &mut Vec<Move>, arg: isize, from: (i32, i32), dir: (i32, i32)) { | |||
open.push(Move { from, dir, prio: 0 }); | |||
open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb)); | |||
} | |||
const DEFAULT_ARG: isize = 16; | |||
fn main() -> std::io::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 = args[3].parse::<isize>().unwrap_or(DEFAULT_ARG); | |||
eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg); | |||
let mut rng = thread_rng(); | |||
let t_frame = 0.040; // s | |||
let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32); | |||
let mut t_wait = 0.0; // s | |||
let x_size = x_size as i32; | |||
let y_size = y_size as i32; | |||
let x_maze_size = (x_size - 1) / 2 * 2 + 1; | |||
let y_maze_size = (y_size - 1) / 2 * 2 + 1; | |||
let x_maze_mid = (x_maze_size - 1) / 4 * 2 + 1; | |||
let y_maze_mid = (y_maze_size - 1) / 4 * 2 + 1; | |||
let mut board = Board(Vec::new()); | |||
let mut open = Vec::new(); | |||
loop { | |||
if open.is_empty() { | |||
if t_wait > 0.0 { | |||
t_wait -= t_frame; | |||
} else { | |||
t_wait = 60.0; // s | |||
board = Board::new(x_size, y_size, x_maze_size, y_maze_size); | |||
// start in the middle | |||
let mid = (x_maze_mid, y_maze_mid); | |||
board.set(mid, Square::Corridor); | |||
add_move(&mut open, arg, mid, (1, 0)); | |||
add_move(&mut open, arg, mid, (0, 1)); | |||
add_move(&mut open, arg, mid, (-1, 0)); | |||
add_move(&mut open, arg, mid, (0, -1)); | |||
} | |||
} else { | |||
let work = arg.max(1); | |||
let mut count = 0; | |||
while !open.is_empty() && count < work { | |||
let mut start = 0; | |||
let mut limit = 0; | |||
let mut prio = open[limit].prio; | |||
loop { | |||
limit += 1; | |||
if limit >= open.len() { | |||
break; | |||
} | |||
if open[limit].prio > prio { | |||
if rng.gen::<f64>() >= 0.4 { | |||
break; | |||
} | |||
start = limit; | |||
prio = open[limit].prio; | |||
} | |||
} | |||
let r = rng.gen_range(start, limit); | |||
let Move { | |||
from: (x0, y0), | |||
dir: (dx, dy), | |||
.. | |||
} = open.remove(r); | |||
let (x1, y1) = (x0 + dx, y0 + dy); | |||
let (x2, y2) = (x1 + dx, y1 + dy); | |||
if board.get((x1, y1)) == Square::Unknown { | |||
board.set((x1, y1), Square::Corridor); | |||
board.set((x2, y2), Square::Corridor); | |||
for (dx, dy) in vec![(1, 0), (0, 1), (-1, 0), (0, -1)] { | |||
let (x3, y3) = (x2 + dx, y2 + dy); | |||
let (x4, y4) = (x3 + dx, y3 + dy); | |||
if board.get((x3, y3)) == Square::Unknown { | |||
if board.get((x4, y4)) == Square::Unknown { | |||
add_move(&mut open, arg, (x2, y2), (dx, dy)); | |||
} else { | |||
board.set((x3, y3), Square::Wall); | |||
} | |||
} | |||
} | |||
count += 1; | |||
} | |||
} | |||
if open.is_empty() { | |||
board.set((1, 1), Square::Start); | |||
board.set((x_maze_size - 2, y_maze_size - 2), Square::Finish); | |||
} | |||
} | |||
let mut buf = Vec::with_capacity((x_size * y_size * 3) as usize); | |||
send(&mut buf, &board)?; | |||
stdout().write_all(&buf)?; | |||
stdout().flush()?; | |||
sleep(delay); | |||
} | |||
} |
@ -0,0 +1,166 @@ | |||
use std::env::args; | |||
use std::io::stdout; | |||
use std::io::Write; | |||
use std::iter::repeat_with; | |||
use std::thread::sleep; | |||
use std::time::Duration; | |||
use rand::thread_rng; | |||
use rand::Rng; | |||
#[derive(Clone, Copy, Debug)] | |||
struct Color(u8, u8, u8); | |||
#[allow(unused)] | |||
impl Color { | |||
fn black() -> Color { | |||
Color(0, 0, 0) | |||
} | |||
fn white() -> Color { | |||
Color(255, 255, 255) | |||
} | |||
fn gray50() -> Color { | |||
Color(128, 128, 128) | |||
} | |||
fn red() -> Color { | |||
Color(255, 0, 0) | |||
} | |||
fn green() -> Color { | |||
Color(0, 255, 0) | |||
} | |||
fn blue() -> Color { | |||
Color(0, 0, 255) | |||
} | |||
fn yellow() -> Color { | |||
Color(255, 255, 0) | |||
} | |||
fn cyan() -> Color { | |||
Color(0, 255, 255) | |||
} | |||
fn magenta() -> Color { | |||
Color(255, 0, 255) | |||
} | |||
fn complement(&self) -> Color { | |||
Color(255 - self.0, 255 - self.1, 255 - self.2) | |||
} | |||
} | |||
#[derive(Clone, Copy, Debug, PartialEq, Eq)] | |||
enum Square { | |||
Empty, | |||
Grass, | |||
Rabbit, | |||
Fox, | |||
} | |||
type Board = Vec<Vec<Square>>; | |||
fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> { | |||
for line in board { | |||
for square in line { | |||
let Color(r, g, b) = match square { | |||
Square::Empty => Color::blue(), | |||
Square::Grass => Color::green(), | |||
Square::Rabbit => Color::yellow(), | |||
Square::Fox => Color::red(), | |||
}; | |||
let buf = &[r, g, b]; | |||
w.write_all(buf)?; | |||
} | |||
} | |||
w.flush() | |||
} | |||
const DEFAULT_ARG: usize = 10; | |||
fn grow(board: &Board, x: usize, y: usize, grow: Square, die: Square) -> Square { | |||
let x_size = board[0].len() as isize; | |||
let y_size = board.len() as isize; | |||
let x = x as isize; | |||
let y = y as isize; | |||
for (dx, dy) in vec![(1, 0), (0, 1), (-1, 0), (0, -1)] { | |||
let x1 = x + dx; | |||
let y1 = y + dy; | |||
if 0 <= x1 && x1 < x_size && 0 <= y1 && y1 < y_size { | |||
let neigh_sq = board[y1 as usize][x1 as usize]; | |||
if neigh_sq == grow { | |||
return grow; | |||
} | |||
} | |||
} | |||
die | |||
} | |||
fn main() -> std::io::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 = args[3].parse::<usize>().unwrap_or(DEFAULT_ARG); | |||
eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg); | |||
let mut rng = thread_rng(); | |||
let p_empty = 0.25; | |||
let p_grass = 0.25; | |||
let p_rabbit = 0.25; | |||
// p_fox = 0.05 | |||
let mut board = repeat_with(|| { | |||
repeat_with(|| { | |||
let p = rng.gen::<f64>(); | |||
if p < p_empty { | |||
Square::Empty | |||
} else if p < p_empty + p_grass { | |||
Square::Grass | |||
} else if p < p_empty + p_grass + p_rabbit { | |||
Square::Rabbit | |||
} else { | |||
Square::Fox | |||
} | |||
}) | |||
.take(x_size) | |||
.collect::<Vec<_>>() | |||
}) | |||
.take(y_size) | |||
.collect::<Vec<_>>(); | |||
let t_frame = 0.040; // s | |||
let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32); | |||
let x_mid = (x_size - 1) as f64 / 2.0; | |||
let y_mid = (y_size - 1) as f64 / 2.0; | |||
let r = (x_size.min(y_size) - 1) as f64 / 2.5; | |||
loop { | |||
for _ in 0..arg { | |||
let x = rng.gen_range(0, x_size); | |||
let y = rng.gen_range(0, y_size); | |||
let sq = board[y][x]; | |||
let dx = (x as f64 - x_mid as f64) / r as f64; | |||
let dy = (y as f64 - y_mid as f64) / r as f64; | |||
let p0 = (dx * dx + dy * dy).min(1.0); | |||
let p_survive = match sq { | |||
Square::Empty => 1.0, | |||
Square::Grass => p0, | |||
Square::Rabbit => p0, | |||
Square::Fox => 0.8 * p0, | |||
}; | |||
let new_sq = if rng.gen::<f64>() < p_survive { | |||
sq | |||
} else { | |||
Square::Empty | |||
}; | |||
board[y][x] = match sq { | |||
Square::Empty => grow(&board, x, y, Square::Grass, new_sq), | |||
Square::Grass => grow(&board, x, y, Square::Rabbit, new_sq), | |||
Square::Rabbit => grow(&board, x, y, Square::Fox, new_sq), | |||
Square::Fox => new_sq, | |||
}; | |||
} | |||
let mut buf = Vec::with_capacity(x_size * y_size * 3); | |||
send(&mut buf, &board)?; | |||
stdout().write_all(&buf)?; | |||
stdout().flush()?; | |||
sleep(delay); | |||
} | |||
} |
@ -0,0 +1,7 @@ | |||
#[cfg(test)] | |||
mod tests { | |||
#[test] | |||
fn it_works() { | |||
assert_eq!(2 + 2, 4); | |||
} | |||
} |