]> git.lizzy.rs Git - rs2048.git/blob - src/display.rs
fba426af462e4c403e52fa6c14e8717dde8d4ba1
[rs2048.git] / src / display.rs
1 use super::game::{Board, Pos};
2 use crossterm::{cursor, queue, style::*};
3
4 enum Mode {
5     Roof_,
6     Data_,
7     Floor,
8     Empty,
9     Base_,
10 }
11
12 const FIELD_HEIGHT: usize = 3;
13 const FIELD_WIDTH: usize = 8;
14
15 fn write_line(stdout: &mut std::io::Stdout, vec: &[u32], mode: Mode) -> crossterm::Result<()> {
16     let mut vec = vec;
17     let len = vec.len();
18
19     queue!(
20         stdout,
21         Print(match mode {
22             Mode::Roof_ => "┏",
23             Mode::Data_ => "┃",
24             Mode::Floor => "┠",
25             Mode::Empty => "┃",
26             Mode::Base_ => "┗",
27         })
28     )?;
29
30     for i in 0..len {
31         let &n = vec.last().unwrap();
32         vec = &vec[0..vec.len() - 1];
33
34         match mode {
35             Mode::Data_ | Mode::Empty => queue!(stdout, Print(" "))?,
36             _ => {}
37         }
38
39         match mode {
40             Mode::Data_ | Mode::Empty if n != 0 => {
41                 let (r, g, b) = hsl::HSL {
42                     h: (n * 360 / 12) as f64,
43                     s: 1.0,
44                     l: 0.5,
45                 }
46                 .to_rgb();
47
48                 queue!(
49                     stdout,
50                     SetColors(Colors::new(Color::Black, Color::Rgb { r, g, b }))
51                 )?;
52             }
53             _ => {}
54         };
55
56         if let Mode::Data_ = mode {
57             if n == 0 {
58                 queue!(stdout, Print(" ".repeat(FIELD_WIDTH - 2)))?;
59             } else {
60                 queue!(
61                     stdout,
62                     Print(format!("{:^w$}", 1 << n, w = FIELD_WIDTH - 2))
63                 )?;
64             }
65         } else {
66             queue!(
67                 stdout,
68                 Print(match mode {
69                     Mode::Roof_ | Mode::Base_ => "━".repeat(FIELD_WIDTH),
70                     Mode::Floor => "─".repeat(FIELD_WIDTH),
71                     Mode::Empty => " ".repeat(FIELD_WIDTH - 2),
72                     Mode::Data_ => panic!("unreachable"),
73                 })
74             )?;
75         }
76
77         match mode {
78             Mode::Data_ | Mode::Empty => {
79                 queue!(stdout, Print(" "), SetAttribute(Attribute::Reset))?
80             }
81             _ => {}
82         }
83
84         if i != len - 1 {
85             queue!(
86                 stdout,
87                 Print(match mode {
88                     Mode::Roof_ => "┯",
89                     Mode::Data_ => "│",
90                     Mode::Floor => "┼",
91                     Mode::Empty => "│",
92                     Mode::Base_ => "┷",
93                 })
94             )?;
95         }
96     }
97
98     queue!(
99         stdout,
100         Print(match mode {
101             Mode::Roof_ => "┓",
102             Mode::Data_ => "┃",
103             Mode::Floor => "┨",
104             Mode::Empty => "┃",
105             Mode::Base_ => "┛",
106         }),
107         cursor::MoveToNextLine(1),
108     )?;
109
110     Ok(())
111 }
112
113 pub fn display_board(stdout: &mut std::io::Stdout, board: &Board) -> crossterm::Result<()> {
114     let dummy = vec![0; board.size.x as usize];
115
116     write_line(stdout, &dummy, Mode::Roof_)?;
117
118     for y in 0..board.size.y {
119         let vec = (0..board.size.x)
120             .rev()
121             .map(|x| board.get(Pos::new(x, y)).value())
122             .collect::<Vec<u32>>();
123
124         for i in 0..FIELD_HEIGHT {
125             write_line(
126                 stdout,
127                 &vec,
128                 if i == FIELD_HEIGHT / 2 {
129                     Mode::Data_
130                 } else {
131                     Mode::Empty
132                 },
133             )?;
134         }
135
136         if y != board.size.y - 1 {
137             write_line(stdout, &dummy, Mode::Floor)?;
138         }
139     }
140
141     write_line(stdout, &dummy, Mode::Base_)?;
142
143     Ok(())
144 }