summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOxore <oxore@protonmail.com>2023-08-01 23:30:27 +0300
committerOxore <oxore@protonmail.com>2023-08-01 23:32:49 +0300
commitb65e091d2397bcceb66099f81533810c3157528a (patch)
tree92f6cb28e96c7d59afcd42ca29063f9c6a87e586
parentce039cad28945e23c89b193bb24cb63c06963640 (diff)
Fix flickering by disabling cursor, introduce TUI struct
-rw-r--r--src/main.rs226
1 files changed, 126 insertions, 100 deletions
diff --git a/src/main.rs b/src/main.rs
index 57da584..f8002f0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -388,143 +388,169 @@ impl Game {
}
}
-fn display_hold(figure: &Figure, y_global: usize) {
- let offset = DISPLAY_HOLD_OFFSET_DOWN;
- let at_figure = y_global >= (1 + offset) && y_global < FIGURE_SIZE_ROWS + (1 + offset);
- if y_global == offset {
- print!(" Hold: ");
- } else if at_figure {
- print!(" ");
- let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset);
- for x in 0..FIGURE_SIZE_COLS {
- let c = figure.cells[y * FIGURE_SIZE_COLS + x];
- if c == 0 {
- print!(" ");
- } else {
- print!("██");
+struct TUI {
+ state: termios::Termios,
+}
+
+impl TUI {
+ fn display_hold(&self, figure: &Figure, y_global: usize) {
+ let offset = DISPLAY_HOLD_OFFSET_DOWN;
+ let at_figure = y_global >= (1 + offset) && y_global < FIGURE_SIZE_ROWS + (1 + offset);
+ if y_global == offset {
+ print!(" Hold: ");
+ } else if at_figure {
+ print!(" ");
+ let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset);
+ for x in 0..FIGURE_SIZE_COLS {
+ let c = figure.cells[y * FIGURE_SIZE_COLS + x];
+ if c == 0 {
+ print!(" ");
+ } else {
+ print!("██");
+ }
}
+ print!(" ");
+ } else {
+ print!(" ");
}
- print!(" ");
- } else {
- print!(" ");
}
-}
-fn display_next(figure: &[Figure; NEXT_COUNT], y_global: usize) {
- let offset = DISPLAY_NEXT_OFFSET_DOWN;
- if y_global == offset {
- print!(" Next: ");
- } else {
- for i in 0..NEXT_COUNT {
- let at_figure = y_global >= (1 + offset + FIGURE_SIZE_ROWS * i) && y_global < (1 + offset + FIGURE_SIZE_ROWS * (i + 1));
- if at_figure {
- print!(" ");
- let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset - FIGURE_SIZE_ROWS * i);
- for x in 0..FIGURE_SIZE_COLS {
- let c = figure[i].cells[y * FIGURE_SIZE_COLS + x];
- if c == 0 {
- print!(" ");
- } else {
- print!("██");
+ fn display_next(&self, figure: &[Figure; NEXT_COUNT], y_global: usize) {
+ let offset = DISPLAY_NEXT_OFFSET_DOWN;
+ if y_global == offset {
+ print!(" Next: ");
+ } else {
+ for i in 0..NEXT_COUNT {
+ let at_figure = y_global >= (1 + offset + FIGURE_SIZE_ROWS * i) && y_global < (1 + offset + FIGURE_SIZE_ROWS * (i + 1));
+ if at_figure {
+ print!(" ");
+ let y = FIGURE_SIZE_ROWS - 1 - (y_global - 1 - offset - FIGURE_SIZE_ROWS * i);
+ for x in 0..FIGURE_SIZE_COLS {
+ let c = figure[i].cells[y * FIGURE_SIZE_COLS + x];
+ if c == 0 {
+ print!(" ");
+ } else {
+ print!("██");
+ }
}
+ break;
}
- break;
}
}
}
-}
-fn display_field(field: &Field, y: usize) {
- print!("|");
- for x in 0..FIELD_COLS {
- let color = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & !GHOST_MASK;
- let ghost = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & GHOST_MASK != 0;
- if color == 0 {
- print!(" ");
- } else if ghost {
- print!("░░");
+ fn display_field(&self, field: &Field, y: usize) {
+ print!("|");
+ for x in 0..FIELD_COLS {
+ let color = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & !GHOST_MASK;
+ let ghost = field.cells[(FIELD_ROWS_VISIBLE - 1 - y) * FIELD_COLS + x] & GHOST_MASK != 0;
+ if color == 0 {
+ print!(" ");
+ } else if ghost {
+ print!("░░");
+ } else {
+ print!("██");
+ }
+ }
+ print!("|");
+ }
+
+ fn display_game(&self, game: &Game) {
+ self.cursor_to_home();
+ let mut field = game.field.clone();
+ let mut ghost = game.figure.clone();
+ for i in 0..FIGURE_SIZE {
+ ghost.cells[i] |= GHOST_MASK;
+ }
+ let mut y_ghost = game.y;
+ while !field.has_collision(&ghost, game.x, y_ghost) {
+ y_ghost -= 1;
+ }
+ y_ghost += 1;
+ field.render(&ghost, game.x, y_ghost);
+ field.render(&game.figure, game.x, game.y);
+ for y in 0..FIELD_ROWS_VISIBLE {
+ self.display_hold(&game.figure_on_hold, y);
+ self.display_field(&field, y);
+ self.display_next(&game.figure_next, y);
+ print!("\r\x1b[1B");
+ }
+ if game.field.has_collision(&game.figure, game.x, game.y) {
+ println!("Collision!");
} else {
- print!("██");
+ self.clear_line();
}
}
- print!("|");
-}
-fn display_game(game: &Game) {
- cursor_to_home();
- let mut field = game.field.clone();
- let mut ghost = game.figure.clone();
- for i in 0..FIGURE_SIZE {
- ghost.cells[i] |= GHOST_MASK;
- }
- let mut y_ghost = game.y;
- while !field.has_collision(&ghost, game.x, y_ghost) {
- y_ghost -= 1;
- }
- y_ghost += 1;
- field.render(&ghost, game.x, y_ghost);
- field.render(&game.figure, game.x, game.y);
- for y in 0..FIELD_ROWS_VISIBLE {
- display_hold(&game.figure_on_hold, y);
- display_field(&field, y);
- display_next(&game.figure_next, y);
- print!("\r\x1b[1B");
- }
- if game.field.has_collision(&game.figure, game.x, game.y) {
- println!("Collision!");
- } else {
- clear_line();
+ fn clear_screen(&self) {
+ print!("\x1B[2J");
+ }
+
+ fn cursor_to_home(&self) {
+ print!("\x1B[H");
+ }
+
+ fn clear_line(&self) {
+ println!("\x1B[2K");
+ }
+
+ fn hide_cursor(&self) {
+ println!("\x1B[?25l");
}
-}
-fn clear_screen() {
- print!("\x1B[2J");
+ fn show_cursor(&self) {
+ println!("\x1B[?25h");
+ }
}
-fn cursor_to_home() {
- print!("\x1B[H");
+impl Default for TUI {
+ fn default() -> Self {
+ let termios_state_initial = termios::Termios::from_fd(0).unwrap();
+ let mut termios_state = termios_state_initial.clone();
+ let c_lflag = termios_state.c_lflag;
+ termios_state.c_lflag &= !(termios::ICANON | termios::ECHO);
+ termios::tcsetattr(0, termios::TCSADRAIN, &termios_state).unwrap();
+ termios_state.c_lflag = c_lflag;
+ let tui = Self{state: termios_state_initial};
+ tui.clear_screen();
+ tui.hide_cursor();
+ tui
+ }
}
-fn clear_line() {
- println!("\x1B[2K");
+impl Drop for TUI {
+ fn drop(&mut self) {
+ self.show_cursor();
+ termios::tcsetattr(0, termios::TCSADRAIN, &self.state).unwrap();
+ }
}
fn main() {
- let termios_state_initial = termios::Termios::from_fd(0).unwrap();
- let mut termios_state = termios_state_initial.clone();
- let c_lflag = termios_state.c_lflag;
- termios_state.c_lflag &= !(termios::ICANON | termios::ECHO);
- termios::tcsetattr(0, termios::TCSADRAIN, &termios_state).unwrap();
- termios_state.c_lflag = c_lflag;
- clear_screen();
+ let tui = TUI::default();
let mut game = Game::default();
- display_game(&game);
+ tui.display_game(&game);
let mut noblock_stdin = NonBlockingReader::from_fd(std::io::stdin()).unwrap();
'outer: while !noblock_stdin.is_eof() {
let mut buf = String::new();
noblock_stdin.read_available_to_string(&mut buf).unwrap();
let mut changed = false;
- if buf.len() > 0 {
- for c in buf.bytes() {
- if let Some(result) = game.step(Some(c as char)) {
- match result {
- StepResult::StateChanged => changed = true,
- StepResult::Quit => break 'outer,
- }
- }
- }
- } else {
- if let Some(result) = game.step(None) {
+ for c in buf.bytes() {
+ if let Some(result) = game.step(Some(c as char)) {
match result {
StepResult::StateChanged => changed = true,
StepResult::Quit => break 'outer,
}
}
}
+ if let Some(result) = game.step(None) {
+ match result {
+ StepResult::StateChanged => changed = true,
+ StepResult::Quit => break 'outer,
+ }
+ }
if changed {
- display_game(&game);
+ tui.display_game(&game);
}
std::thread::sleep(std::time::Duration::from_millis(1));
}
- termios::tcsetattr(0, termios::TCSADRAIN, &termios_state_initial).unwrap();
}