Initial commit.
This commit is contained in:
commit
759c9c4f8a
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
*~
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "pixelfoo"
|
||||
version = "0.1.0"
|
||||
authors = ["juergen <juergen@chaospott.de>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.6.0"
|
12
README.txt
Normal file
12
README.txt
Normal file
@ -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.
|
141
src/bin/bimood/main.rs
Normal file
141
src/bin/bimood/main.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
225
src/bin/maze/main.rs
Normal file
225
src/bin/maze/main.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
166
src/bin/predprey/main.rs
Normal file
166
src/bin/predprey/main.rs
Normal file
@ -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);
|
||||
}
|
||||
}
|
7
src/lib.rs
Normal file
7
src/lib.rs
Normal file
@ -0,0 +1,7 @@
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user