use crossterm::{
cursor,
event::{read, Event, KeyCode, KeyEvent, KeyEventKind},
style::{self, Stylize},
terminal::{Clear, ClearType},
ExecutableCommand,
};
use threes::game::Game;
use std::io::{self, stdout, Write};
fn printone(n: u32) -> io::Result<()> {
match n {
0 => {
stdout().execute(style::PrintStyledContent(
" 0 ".with(style::Color::White).on(style::Color::Black),
))?;
}
1 => {
stdout().execute(style::PrintStyledContent(
" 1 ".with(style::Color::White).on(style::Color::Blue),
))?;
}
2 => {
stdout().execute(style::PrintStyledContent(
" 2 ".with(style::Color::White).on(style::Color::Red),
))?;
}
n => {
let p = if n < 10 {
format!(" {} ", n)
.with(style::Color::Black)
.on(style::Color::Grey)
} else if n < 100 {
format!(" {}", n)
.with(style::Color::Black)
.on(style::Color::Grey)
} else {
format!("{}", n)
.with(style::Color::Black)
.on(style::Color::Grey)
};
stdout().execute(style::PrintStyledContent(p))?;
}
};
Ok(())
}
fn printboard(g: &Game) -> io::Result<()> {
stdout()
.execute(Clear(ClearType::All))?
.execute(cursor::MoveTo(1, 1))?;
write!(stdout(), "Next: ")?;
match g.next().as_slice() {
[n] => printone(*n)?,
[n @ ..] => {
stdout().execute(style::PrintStyledContent(
format!("{:?}", n)
.with(style::Color::Black)
.on(style::Color::Grey),
))?;
()
}
};
stdout().execute(cursor::MoveTo(1, 2))?;
write!(stdout(), "----------------")?;
let b = g.board().0;
for row in 0..4 {
stdout().execute(cursor::MoveTo(1, 3 + row))?;
for col in 0..4 {
let n = b[(row * 4 + col) as usize];
if n < 1000 {
print!(" ");
}
printone(n)?;
}
}
stdout().execute(cursor::MoveTo(1, 10))?;
write!(stdout(), "Arrows to move; 'b' to undo; Esc or 'q' to exit.")?;
stdout().execute(cursor::MoveTo(1, 11))?;
Ok(())
}
fn main() -> io::Result<()> {
let mut g = Game::new();
let mut old_g = g.clone();
crossterm::terminal::enable_raw_mode()?;
stdout().execute(crossterm::cursor::Hide)?;
loop {
printboard(&g)?;
if !g.can_move() {
break;
}
match read()? {
Event::Key(KeyEvent {
code: KeyCode::Up,
kind: KeyEventKind::Press,
..
}) => {
old_g = g.clone();
let _ = g.up();
}
Event::Key(KeyEvent {
code: KeyCode::Down,
kind: KeyEventKind::Press,
..
}) => {
old_g = g.clone();
let _ = g.down();
}
Event::Key(KeyEvent {
code: KeyCode::Left,
kind: KeyEventKind::Press,
..
}) => {
old_g = g.clone();
let _ = g.left();
}
Event::Key(KeyEvent {
code: KeyCode::Right,
kind: KeyEventKind::Press,
..
}) => {
old_g = g.clone();
let _ = g.right();
}
Event::Key(KeyEvent {
code: KeyCode::Esc,
kind: KeyEventKind::Press,
..
})
| Event::Key(KeyEvent {
code: KeyCode::Char('q'),
kind: KeyEventKind::Press,
..
}) => {
break;
}
Event::Key(KeyEvent {
code: KeyCode::Char('b'),
kind: KeyEventKind::Press,
..
}) => {
g = old_g.clone();
}
_ => {}
}
}
stdout().execute(crossterm::style::ResetColor)?;
stdout().execute(crossterm::cursor::Show)?;
crossterm::terminal::disable_raw_mode()?;
println!("\nexited");
Ok(())
}