sac/life/render.rs
1use super::*;
2
3impl LifeField {
4 /// Renders the field as a vector of ratatui Lines using Braille characters.
5 ///
6 /// Each Braille character represents a 2x4 block of cells, allowing for
7 /// compact display of the life field.
8 ///
9 /// # Arguments
10 /// * `char_width` - Width in characters (each char is 2 cells wide)
11 /// * `char_height` - Height in characters (each char is 4 cells tall)
12 ///
13 /// # Returns
14 /// Vector of Lines representing the rendered field
15 pub fn render_lines(&self, char_width: usize, char_height: usize) -> Vec<Line<'static>> {
16 let mut lines = Vec::with_capacity(char_height);
17 for char_y in 0..char_height {
18 let mut text = String::with_capacity(char_width);
19 for char_x in 0..char_width {
20 let dot_x = char_x * 2;
21 let dot_y = char_y * 4;
22 text.push(self.braille_char(dot_x, dot_y));
23 }
24 lines.push(Line::from(Span::raw(text)));
25 }
26 lines
27 }
28
29 /// Generates a Braille character representing a 2x4 cell block.
30 ///
31 /// Braille dots are mapped to cell positions:
32 /// - Dots 1-4 map to left column (top to bottom)
33 /// - Dots 5-8 map to right column (top to bottom)
34 ///
35 /// # Arguments
36 /// * `dot_x` - X coordinate of the left cell in the block
37 /// * `dot_y` - Y coordinate of the top cell in the block
38 ///
39 /// # Returns
40 /// A Braille Unicode character (U+2800 to U+28FF)
41 pub fn braille_char(&self, dot_x: usize, dot_y: usize) -> char {
42 let mut bits = 0u32;
43 for local_y in 0..4 {
44 for local_x in 0..2 {
45 let x = dot_x + local_x;
46 let y = dot_y + local_y;
47 if x < self.width && y < self.height && self.cells[self.index(x, y)] {
48 bits |= match (local_x, local_y) {
49 (0, 0) => 0x01,
50 (0, 1) => 0x02,
51 (0, 2) => 0x04,
52 (0, 3) => 0x40,
53 (1, 0) => 0x08,
54 (1, 1) => 0x10,
55 (1, 2) => 0x20,
56 (1, 3) => 0x80,
57 _ => 0,
58 };
59 }
60 }
61 }
62 char::from_u32(0x2800 + bits).unwrap_or(' ')
63 }
64}