mod args;
mod bag;
mod gamescore;
mod gamestate;
mod tetlib;
mod tetrominoe;
use std::{
io::{stdout, Write},
thread::sleep,
time::Duration,
};
use crossterm::{
cursor::Show,
execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
};
use clap::Parser;
use gamestate::GameState;
use tetlib::*;
pub const WIDTH: usize = 10;
pub const HEIGHT: usize = 20;
fn main() {
let mut args = args::Args::parse();
if args.og {
args.no_colors = true;
args.chars = "[]".to_string();
}
const MAX_LEVEL: usize = 20;
const GRAV_TICK: usize = 40;
const LEVEL_MULT: f64 = 0.85;
let mut stdout = stdout();
execute!(stdout, EnterAlternateScreen).unwrap();
enable_raw_mode().unwrap();
let mut gs = if let Some(path) = &args.save {
if path_exists(path) {
GameState::deserial(path.clone(), WIDTH, HEIGHT)
} else {
GameState::new(WIDTH, HEIGHT)
}
} else {
GameState::new(WIDTH, HEIGHT)
};
if gs.is_game_over {
gs.gamescore.stop_timer();
}
if args.sirtet {
sirtet_borders(WIDTH, HEIGHT);
}
loop {
loop {
let prev_display = gs.display.clone();
let key = get_input();
if key == 'q' {
break;
}
if key == 'p' {
let mut key = get_input();
put_text(WIDTH as u16, HEIGHT as u16, "P A U S E D");
stdout.flush().unwrap();
while key != 'p' && key != 'q' {
key = get_input();
sleep(Duration::from_millis(10));
}
}
if gs.counter
>= (GRAV_TICK as f64 * LEVEL_MULT.powf(gs.gamescore.level as f64)) as usize
{
if gravity(&mut gs) {
gs.is_game_over = true;
break;
}
gs.counter = if gs.gamescore.level < MAX_LEVEL {
0
} else {
100
};
}
handle_input(&mut gs, key);
if key == 'c' && !args.hold {
hold(&mut gs);
}
full_line(&mut gs);
if !args.ghost {
ghost_piece(&mut gs);
}
let is_updated = gs.display != prev_display || gs.is_game_over;
render(
&mut gs,
is_updated,
&args.chars,
&args.no_colors,
&args.sirtet,
);
sleep(Duration::from_millis(args.gravity));
stdout.flush().unwrap();
gs.counter += 1;
}
if !gs.serial() {
break;
}
gs = GameState::new(WIDTH, HEIGHT);
}
disable_raw_mode().unwrap();
execute!(stdout, LeaveAlternateScreen).unwrap();
execute!(stdout, Show).unwrap();
}
fn path_exists(path: &String) -> bool {
std::path::Path::new(path).exists()
}