use std::collections::VecDeque;
use crossterm::{
cursor::{self, MoveToNextLine},
style::{self, Print},
terminal, QueueableCommand,
};
use falling_tetromino_engine::{InGameTime, Notification, State};
use super::*;
#[derive(
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Clone,
Debug,
Default,
serde::Serialize,
serde::Deserialize,
)]
pub struct PrototypeRenderer {
notification_feed_buffer: VecDeque<(Notification, InGameTime)>,
}
impl Renderer for PrototypeRenderer {
fn push_game_notification_feed(
&mut self,
feed: impl IntoIterator<Item = (Notification, InGameTime)>,
) {
for x in feed {
self.notification_feed_buffer.push_front(x);
}
}
fn reset_game_associated_state(&mut self) {
self.notification_feed_buffer.clear();
}
fn reset_view_diff_state(&mut self) {
}
fn set_render_offset(&mut self, _x: usize, _y: usize) {
}
fn render<T>(
&mut self,
term: &mut T,
game: &Game,
_meta_data: &GameMetaData,
_settings: &Settings,
_temp_data: &TemporaryAppData,
_keybinds_legend: &KeybindsLegend,
_replay_extra: Option<(InGameTime, f64)>,
) -> io::Result<()>
where
T: Write,
{
let State {
time: game_time,
board,
..
} = game.state();
let mut board = *board;
if let Some(piece) = game.phase().piece() {
for ((x, y), tile_type_id) in piece.tiles() {
board[y as usize][x as usize] = Some(tile_type_id);
}
}
term.queue(cursor::MoveTo(0, 0))?
.queue(terminal::Clear(terminal::ClearType::FromCursorDown))?;
term.queue(Print(" +--------------------+"))?
.queue(MoveToNextLine(1))?;
for (idx, line) in board.iter().take(20).enumerate().rev() {
let txt_line = format!(
"{idx:02} |{}|",
line.iter()
.map(|cell| {
cell.map_or(" .", |tile| match tile.get() {
1 => "OO",
2 => "II",
3 => "SS",
4 => "ZZ",
5 => "TT",
6 => "LL",
7 => "JJ",
253 => "WW",
254 => "WW",
255 => "WW",
t => unimplemented!("formatting unknown tile id {t}"),
})
})
.collect::<Vec<_>>()
.join("")
);
term.queue(Print(txt_line))?.queue(MoveToNextLine(1))?;
}
term.queue(Print(" +--------------------+"))?
.queue(MoveToNextLine(1))?;
term.queue(style::Print(format!(" {:?}", game_time)))?
.queue(MoveToNextLine(1))?;
let mut feed_evt_msgs = Vec::new();
for (notification, _) in self.notification_feed_buffer.iter() {
feed_evt_msgs.push(match notification {
Notification::Accolade {
score_bonus,
tetromino,
is_spin: spin,
lineclears,
is_perfect_clear: perfect_clear,
combo,
} => {
let mut msg = Vec::new();
msg.push(format!("+{score_bonus}"));
if *perfect_clear {
msg.push("Perfect".to_owned());
}
if *spin {
msg.push(format!("{tetromino:?}-Spin"));
}
let clear_action = match lineclears {
1 => "Single",
2 => "Double",
3 => "Triple",
4 => "Quadruple",
5 => "Quintuple",
6 => "Sextuple",
7 => "Septuple",
8 => "Octuple",
9 => "Nonuple",
10 => "Decuple",
11 => "Undecuple",
12 => "Duodecuple",
13 => "Tredecuple",
14 => "Quattuordecuple",
15 => "Quindecuple",
16 => "Sexdecuple",
17 => "Septendecuple",
18 => "Octodecuple",
19 => "Novemdecuple",
20 => "Vigintuple",
_ => "Absurduple",
}
.to_string();
msg.push(clear_action);
if *combo > 1 {
msg.push(format!("#{combo}."));
}
msg.join(" ")
}
feedback => format!("{feedback:?}"),
});
}
for str in feed_evt_msgs.iter().take(16) {
term.queue(Print(str))?.queue(MoveToNextLine(1))?;
}
term.flush()?;
Ok(())
}
}