Browse Source

Initial commit.

master
Juergen Stuber 2 years ago
commit
759c9c4f8a
7 changed files with 562 additions and 0 deletions
  1. 3
    0
      .gitignore
  2. 8
    0
      Cargo.toml
  3. 12
    0
      README.txt
  4. 141
    0
      src/bin/bimood/main.rs
  5. 225
    0
      src/bin/maze/main.rs
  6. 166
    0
      src/bin/predprey/main.rs
  7. 7
    0
      src/lib.rs

+ 3
- 0
.gitignore View File

@@ -0,0 +1,3 @@
1
+/target
2
+**/*.rs.bk
3
+*~

+ 8
- 0
Cargo.toml View File

@@ -0,0 +1,8 @@
1
+[package]
2
+name = "pixelfoo"
3
+version = "0.1.0"
4
+authors = ["juergen <juergen@chaospott.de>"]
5
+edition = "2018"
6
+
7
+[dependencies]
8
+rand = "0.6.0"

+ 12
- 0
README.txt View File

@@ -0,0 +1,12 @@
1
+bimood - color cycling mood lamp with two complementary colors
2
+    parameter is the seconds for one cycle through the colors
3
+
4
+predprey - grass-prey-predator simulation
5
+    parameter is number of actions per 40ms frame
6
+
7
+maze - draws a maze
8
+    parameter is number of actions per 40ms frame
9
+
10
+Compile with "cargo build --release".
11
+
12
+The binary executables are in the "target/release" subdirectory.

+ 141
- 0
src/bin/bimood/main.rs View File

@@ -0,0 +1,141 @@
1
+use std::env::args;
2
+use std::io::stdout;
3
+use std::io::Write;
4
+use std::iter::repeat;
5
+use std::thread::sleep;
6
+use std::time::Duration;
7
+
8
+#[derive(Clone, Copy, Debug)]
9
+struct Color(u8, u8, u8);
10
+
11
+impl Color {
12
+    fn black() -> Color {
13
+        Color(0, 0, 0)
14
+    }
15
+    fn white() -> Color {
16
+        Color(255, 255, 255)
17
+    }
18
+    fn gray50() -> Color {
19
+        Color(128, 128, 128)
20
+    }
21
+    fn red() -> Color {
22
+        Color(255, 0, 0)
23
+    }
24
+    fn green() -> Color {
25
+        Color(0, 255, 0)
26
+    }
27
+    fn blue() -> Color {
28
+        Color(0, 0, 255)
29
+    }
30
+    fn yellow() -> Color {
31
+        Color(255, 255, 0)
32
+    }
33
+    fn cyan() -> Color {
34
+        Color(0, 255, 255)
35
+    }
36
+    fn magenta() -> Color {
37
+        Color(255, 0, 255)
38
+    }
39
+    fn complement(&self) -> Color {
40
+        Color(255 - self.0, 255 - self.1, 255 - self.2)
41
+    }
42
+}
43
+
44
+fn interpolate_u8(b0: u8, b1: u8, a: f64) -> u8 {
45
+    let b0 = b0 as f64;
46
+    let b1 = b1 as f64;
47
+    ((1.0 - a) * b0 + a * b1) as u8
48
+}
49
+
50
+fn interpolate(c0: Color, c1: Color, a: f64) -> Color {
51
+    Color(
52
+        interpolate_u8(c0.0, c1.0, a),
53
+        interpolate_u8(c0.1, c1.1, a),
54
+        interpolate_u8(c0.2, c1.2, a),
55
+    )
56
+}
57
+
58
+type Frame = Vec<Vec<Color>>;
59
+
60
+fn send<T: Write>(w: &mut T, f: &Frame) -> std::io::Result<()> {
61
+    for l in f {
62
+        for c in l {
63
+            let Color(r, g, b) = c;
64
+            let buf = &[*r, *g, *b];
65
+            w.write_all(buf)?;
66
+        }
67
+    }
68
+    w.flush()
69
+}
70
+
71
+const DEFAULT_LOOP_TIME: usize = 120;
72
+
73
+fn main() -> std::io::Result<()> {
74
+    let args = args().collect::<Vec<_>>();
75
+    eprintln!("executing {}", args[0]);
76
+
77
+    let x_size = args[1].parse::<usize>().unwrap();
78
+    let y_size = args[2].parse::<usize>().unwrap();
79
+    let loop_time = args[3].parse::<usize>().unwrap_or(DEFAULT_LOOP_TIME);
80
+    eprintln!(
81
+        "screen size {}x{}, loop time {:?}s",
82
+        x_size, y_size, loop_time
83
+    );
84
+
85
+    let mut border = 0;
86
+    while (x_size - 2 * border) * (y_size - 2 * border) > x_size * y_size / 2 {
87
+        border += 1;
88
+    }
89
+
90
+    let t_frame = 0.040; // s
91
+    let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32);
92
+
93
+    let mut previous_color = Color::blue();
94
+    let colors = vec![
95
+        Color::red(),
96
+        Color::yellow(),
97
+        Color::green(),
98
+        Color::cyan(),
99
+        Color::blue(),
100
+        Color::magenta(),
101
+    ];
102
+    let mut color_index = 0;
103
+    let mut next_color = colors[color_index];
104
+
105
+    // time to interpolate from one color to the next
106
+    let t_interpolate = (loop_time as f64) / (colors.len() as f64); // s
107
+    let delta_a = t_frame / t_interpolate;
108
+    let mut a = 0.0;
109
+
110
+    eprint!("delta_a {}", delta_a);
111
+    loop {
112
+        let c0 = interpolate(previous_color, next_color, a);
113
+        let c1 = c0.complement();
114
+        let mut frame = repeat(repeat(c0).take(x_size).collect::<Vec<_>>())
115
+            .take(y_size)
116
+            .collect::<Vec<_>>();
117
+        for x in border..(x_size - border) {
118
+            for y in border..(y_size - border) {
119
+                frame[y][x] = c1
120
+            }
121
+        }
122
+
123
+        a += delta_a;
124
+        if a >= 1.0 {
125
+            a = 0.0;
126
+
127
+            color_index += 1;
128
+            if color_index >= colors.len() {
129
+                color_index = 0;
130
+            }
131
+
132
+            previous_color = next_color;
133
+            next_color = colors[color_index];
134
+        }
135
+        let mut buf = Vec::with_capacity(x_size * y_size * 3);
136
+        send(&mut buf, &frame)?;
137
+        stdout().write_all(&buf)?;
138
+        stdout().flush()?;
139
+        sleep(delay);
140
+    }
141
+}

+ 225
- 0
src/bin/maze/main.rs View File

@@ -0,0 +1,225 @@
1
+use std::env::args;
2
+use std::io::stdout;
3
+use std::io::Write;
4
+use std::thread::sleep;
5
+use std::time::Duration;
6
+
7
+use rand::thread_rng;
8
+use rand::Rng;
9
+
10
+#[derive(Clone, Copy, Debug)]
11
+struct Color(u8, u8, u8);
12
+
13
+#[allow(unused)]
14
+impl Color {
15
+    fn black() -> Color {
16
+        Color(0, 0, 0)
17
+    }
18
+    fn white() -> Color {
19
+        Color(255, 255, 255)
20
+    }
21
+    fn gray50() -> Color {
22
+        Color(128, 128, 128)
23
+    }
24
+    fn red() -> Color {
25
+        Color(255, 0, 0)
26
+    }
27
+    fn green() -> Color {
28
+        Color(0, 255, 0)
29
+    }
30
+    fn blue() -> Color {
31
+        Color(0, 0, 255)
32
+    }
33
+    fn yellow() -> Color {
34
+        Color(255, 255, 0)
35
+    }
36
+    fn cyan() -> Color {
37
+        Color(0, 255, 255)
38
+    }
39
+    fn magenta() -> Color {
40
+        Color(255, 0, 255)
41
+    }
42
+    fn complement(&self) -> Color {
43
+        Color(255 - self.0, 255 - self.1, 255 - self.2)
44
+    }
45
+}
46
+
47
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
48
+enum Square {
49
+    Unknown,
50
+    Corridor,
51
+    Wall,
52
+    Start,
53
+    Finish,
54
+}
55
+
56
+struct Board(Vec<Vec<Square>>);
57
+
58
+fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> {
59
+    for line in &board.0 {
60
+        for square in line {
61
+            let Color(r, g, b) = match square {
62
+                Square::Unknown => Color::black(),
63
+                Square::Corridor => Color::yellow(),
64
+                Square::Wall => Color::blue(),
65
+                Square::Start => Color::red(),
66
+                Square::Finish => Color::green(),
67
+            };
68
+            let buf = &[r, g, b];
69
+            w.write_all(buf)?;
70
+        }
71
+    }
72
+    w.flush()
73
+}
74
+
75
+impl Board {
76
+    fn new(x_size: i32, y_size: i32, x_maze_size: i32, y_maze_size: i32) -> Board {
77
+        Board(
78
+            (0..y_size)
79
+                .map(move |y| {
80
+                    (0..x_size)
81
+                        .map(|x| {
82
+                            if x < x_maze_size && y < y_maze_size {
83
+                                if x == 0
84
+                                    || x == x_maze_size - 1
85
+                                    || y == 0
86
+                                    || y == y_maze_size - 1
87
+                                    || (x % 2 == 0 && y % 2 == 0)
88
+                                {
89
+                                    Square::Wall
90
+                                } else {
91
+                                    Square::Unknown
92
+                                }
93
+                            } else {
94
+                                Square::Unknown
95
+                            }
96
+                        })
97
+                        .collect::<Vec<_>>()
98
+                })
99
+                .collect::<Vec<_>>(),
100
+        )
101
+    }
102
+    fn get(&self, pos: (i32, i32)) -> Square {
103
+        let (x, y) = pos;
104
+        self.0[y as usize][x as usize]
105
+    }
106
+    fn set(&mut self, pos: (i32, i32), sq: Square) {
107
+        let (x, y) = pos;
108
+        self.0[y as usize][x as usize] = sq;
109
+    }
110
+}
111
+
112
+struct Move {
113
+    from: (i32, i32),
114
+    dir: (i32, i32),
115
+    prio: i32,
116
+}
117
+
118
+fn add_move(open: &mut Vec<Move>, arg: isize, from: (i32, i32), dir: (i32, i32)) {
119
+    open.push(Move { from, dir, prio: 0 });
120
+    open.sort_unstable_by(|Move { prio: pa, .. }, Move { prio: pb, .. }| pa.cmp(pb));
121
+}
122
+
123
+const DEFAULT_ARG: isize = 16;
124
+
125
+fn main() -> std::io::Result<()> {
126
+    let args = args().collect::<Vec<_>>();
127
+    eprintln!("executing {}", args[0]);
128
+
129
+    let x_size = args[1].parse::<usize>().unwrap();
130
+    let y_size = args[2].parse::<usize>().unwrap();
131
+    let arg = args[3].parse::<isize>().unwrap_or(DEFAULT_ARG);
132
+    eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg);
133
+
134
+    let mut rng = thread_rng();
135
+
136
+    let t_frame = 0.040; // s
137
+    let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32);
138
+    let mut t_wait = 0.0; // s
139
+
140
+    let x_size = x_size as i32;
141
+    let y_size = y_size as i32;
142
+    let x_maze_size = (x_size - 1) / 2 * 2 + 1;
143
+    let y_maze_size = (y_size - 1) / 2 * 2 + 1;
144
+    let x_maze_mid = (x_maze_size - 1) / 4 * 2 + 1;
145
+    let y_maze_mid = (y_maze_size - 1) / 4 * 2 + 1;
146
+
147
+    let mut board = Board(Vec::new());
148
+    let mut open = Vec::new();
149
+    loop {
150
+        if open.is_empty() {
151
+            if t_wait > 0.0 {
152
+                t_wait -= t_frame;
153
+            } else {
154
+                t_wait = 60.0; // s
155
+                board = Board::new(x_size, y_size, x_maze_size, y_maze_size);
156
+
157
+                // start in the middle
158
+                let mid = (x_maze_mid, y_maze_mid);
159
+                board.set(mid, Square::Corridor);
160
+                add_move(&mut open, arg, mid, (1, 0));
161
+                add_move(&mut open, arg, mid, (0, 1));
162
+                add_move(&mut open, arg, mid, (-1, 0));
163
+                add_move(&mut open, arg, mid, (0, -1));
164
+            }
165
+        } else {
166
+            let work = arg.max(1);
167
+            let mut count = 0;
168
+            while !open.is_empty() && count < work {
169
+                let mut start = 0;
170
+                let mut limit = 0;
171
+                let mut prio = open[limit].prio;
172
+                loop {
173
+                    limit += 1;
174
+                    if limit >= open.len() {
175
+                        break;
176
+                    }
177
+                    if open[limit].prio > prio {
178
+                        if rng.gen::<f64>() >= 0.4 {
179
+                            break;
180
+                        }
181
+                        start = limit;
182
+                        prio = open[limit].prio;
183
+                    }
184
+                }
185
+                let r = rng.gen_range(start, limit);
186
+                let Move {
187
+                    from: (x0, y0),
188
+                    dir: (dx, dy),
189
+                    ..
190
+                } = open.remove(r);
191
+
192
+                let (x1, y1) = (x0 + dx, y0 + dy);
193
+                let (x2, y2) = (x1 + dx, y1 + dy);
194
+                if board.get((x1, y1)) == Square::Unknown {
195
+                    board.set((x1, y1), Square::Corridor);
196
+                    board.set((x2, y2), Square::Corridor);
197
+
198
+                    for (dx, dy) in vec![(1, 0), (0, 1), (-1, 0), (0, -1)] {
199
+                        let (x3, y3) = (x2 + dx, y2 + dy);
200
+                        let (x4, y4) = (x3 + dx, y3 + dy);
201
+                        if board.get((x3, y3)) == Square::Unknown {
202
+                            if board.get((x4, y4)) == Square::Unknown {
203
+                                add_move(&mut open, arg, (x2, y2), (dx, dy));
204
+                            } else {
205
+                                board.set((x3, y3), Square::Wall);
206
+                            }
207
+                        }
208
+                    }
209
+
210
+                    count += 1;
211
+                }
212
+            }
213
+            if open.is_empty() {
214
+                board.set((1, 1), Square::Start);
215
+                board.set((x_maze_size - 2, y_maze_size - 2), Square::Finish);
216
+            }
217
+        }
218
+
219
+        let mut buf = Vec::with_capacity((x_size * y_size * 3) as usize);
220
+        send(&mut buf, &board)?;
221
+        stdout().write_all(&buf)?;
222
+        stdout().flush()?;
223
+        sleep(delay);
224
+    }
225
+}

+ 166
- 0
src/bin/predprey/main.rs View File

@@ -0,0 +1,166 @@
1
+use std::env::args;
2
+use std::io::stdout;
3
+use std::io::Write;
4
+use std::iter::repeat_with;
5
+use std::thread::sleep;
6
+use std::time::Duration;
7
+
8
+use rand::thread_rng;
9
+use rand::Rng;
10
+
11
+#[derive(Clone, Copy, Debug)]
12
+struct Color(u8, u8, u8);
13
+
14
+#[allow(unused)]
15
+impl Color {
16
+    fn black() -> Color {
17
+        Color(0, 0, 0)
18
+    }
19
+    fn white() -> Color {
20
+        Color(255, 255, 255)
21
+    }
22
+    fn gray50() -> Color {
23
+        Color(128, 128, 128)
24
+    }
25
+    fn red() -> Color {
26
+        Color(255, 0, 0)
27
+    }
28
+    fn green() -> Color {
29
+        Color(0, 255, 0)
30
+    }
31
+    fn blue() -> Color {
32
+        Color(0, 0, 255)
33
+    }
34
+    fn yellow() -> Color {
35
+        Color(255, 255, 0)
36
+    }
37
+    fn cyan() -> Color {
38
+        Color(0, 255, 255)
39
+    }
40
+    fn magenta() -> Color {
41
+        Color(255, 0, 255)
42
+    }
43
+    fn complement(&self) -> Color {
44
+        Color(255 - self.0, 255 - self.1, 255 - self.2)
45
+    }
46
+}
47
+
48
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
49
+enum Square {
50
+    Empty,
51
+    Grass,
52
+    Rabbit,
53
+    Fox,
54
+}
55
+
56
+type Board = Vec<Vec<Square>>;
57
+
58
+fn send<T: Write>(w: &mut T, board: &Board) -> std::io::Result<()> {
59
+    for line in board {
60
+        for square in line {
61
+            let Color(r, g, b) = match square {
62
+                Square::Empty => Color::blue(),
63
+                Square::Grass => Color::green(),
64
+                Square::Rabbit => Color::yellow(),
65
+                Square::Fox => Color::red(),
66
+            };
67
+            let buf = &[r, g, b];
68
+            w.write_all(buf)?;
69
+        }
70
+    }
71
+    w.flush()
72
+}
73
+
74
+const DEFAULT_ARG: usize = 10;
75
+
76
+fn grow(board: &Board, x: usize, y: usize, grow: Square, die: Square) -> Square {
77
+    let x_size = board[0].len() as isize;
78
+    let y_size = board.len() as isize;
79
+    let x = x as isize;
80
+    let y = y as isize;
81
+    for (dx, dy) in vec![(1, 0), (0, 1), (-1, 0), (0, -1)] {
82
+        let x1 = x + dx;
83
+        let y1 = y + dy;
84
+        if 0 <= x1 && x1 < x_size && 0 <= y1 && y1 < y_size {
85
+            let neigh_sq = board[y1 as usize][x1 as usize];
86
+            if neigh_sq == grow {
87
+                return grow;
88
+            }
89
+        }
90
+    }
91
+    die
92
+}
93
+
94
+fn main() -> std::io::Result<()> {
95
+    let args = args().collect::<Vec<_>>();
96
+    eprintln!("executing {}", args[0]);
97
+
98
+    let x_size = args[1].parse::<usize>().unwrap();
99
+    let y_size = args[2].parse::<usize>().unwrap();
100
+    let arg = args[3].parse::<usize>().unwrap_or(DEFAULT_ARG);
101
+    eprintln!("screen size {}x{}, arg {}", x_size, y_size, arg);
102
+
103
+    let mut rng = thread_rng();
104
+
105
+    let p_empty = 0.25;
106
+    let p_grass = 0.25;
107
+    let p_rabbit = 0.25;
108
+    // p_fox = 0.05
109
+    let mut board = repeat_with(|| {
110
+        repeat_with(|| {
111
+            let p = rng.gen::<f64>();
112
+            if p < p_empty {
113
+                Square::Empty
114
+            } else if p < p_empty + p_grass {
115
+                Square::Grass
116
+            } else if p < p_empty + p_grass + p_rabbit {
117
+                Square::Rabbit
118
+            } else {
119
+                Square::Fox
120
+            }
121
+        })
122
+        .take(x_size)
123
+        .collect::<Vec<_>>()
124
+    })
125
+    .take(y_size)
126
+    .collect::<Vec<_>>();
127
+
128
+    let t_frame = 0.040; // s
129
+    let delay = Duration::new(0, (1_000_000_000.0 * t_frame) as u32);
130
+
131
+    let x_mid = (x_size - 1) as f64 / 2.0;
132
+    let y_mid = (y_size - 1) as f64 / 2.0;
133
+    let r = (x_size.min(y_size) - 1) as f64 / 2.5;
134
+    loop {
135
+        for _ in 0..arg {
136
+            let x = rng.gen_range(0, x_size);
137
+            let y = rng.gen_range(0, y_size);
138
+            let sq = board[y][x];
139
+            let dx = (x as f64 - x_mid as f64) / r as f64;
140
+            let dy = (y as f64 - y_mid as f64) / r as f64;
141
+            let p0 = (dx * dx + dy * dy).min(1.0);
142
+            let p_survive = match sq {
143
+                Square::Empty => 1.0,
144
+                Square::Grass => p0,
145
+                Square::Rabbit => p0,
146
+                Square::Fox => 0.8 * p0,
147
+            };
148
+            let new_sq = if rng.gen::<f64>() < p_survive {
149
+                sq
150
+            } else {
151
+                Square::Empty
152
+            };
153
+            board[y][x] = match sq {
154
+                Square::Empty => grow(&board, x, y, Square::Grass, new_sq),
155
+                Square::Grass => grow(&board, x, y, Square::Rabbit, new_sq),
156
+                Square::Rabbit => grow(&board, x, y, Square::Fox, new_sq),
157
+                Square::Fox => new_sq,
158
+            };
159
+        }
160
+        let mut buf = Vec::with_capacity(x_size * y_size * 3);
161
+        send(&mut buf, &board)?;
162
+        stdout().write_all(&buf)?;
163
+        stdout().flush()?;
164
+        sleep(delay);
165
+    }
166
+}

+ 7
- 0
src/lib.rs View File

@@ -0,0 +1,7 @@
1
+#[cfg(test)]
2
+mod tests {
3
+    #[test]
4
+    fn it_works() {
5
+        assert_eq!(2 + 2, 4);
6
+    }
7
+}

Loading…
Cancel
Save