1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use action::Action;
use coord::{Dir, RotateDir};
use errors::*;
use play::Play;
use screen::{Modal, Screen};
use std::io::{Read, Write};
use std::thread;
use std::time::Duration;

const FRAME: u64 = 50;
const TICK: u64 = 1000 / FRAME;
const UPDATE: u64 = TICK / 2;

pub struct Game<R: Read, W: Write> {
    screen: Screen<R, W>,
    help_modal: Modal<'static>,
}

impl<R, W> Game<R, W>
where
    R: Read,
    W: Write,
{
    pub fn new(screen: Screen<R, W>) -> Self {
        Game {
            screen,
            help_modal: Modal {
                title: "HELP",
                content: &[
                    "h - Move left",
                    "l - Move right",
                    "j - Speed up",
                    "d,f - Rotate",
                    "q - Quit",
                ],
                actions: Some(&[Action::Ok, Action::Reset, Action::Quit]),
            },
        }
    }

    pub fn stop_by_error(&mut self, err: Error) {
        self.screen
            .show_modal(&Modal {
                title: "ERROR",
                content: &[
                    "Sorry, unexpected error occurred.",
                    "details:",
                    &err.to_string(),
                ],
                actions: None,
            })
            .expect(&format!("show error dialog ({})", err));
    }

    pub fn start(&mut self) -> Result<()> {
        self.screen.render_title()?;
        thread::sleep(Duration::from_millis(800));

        let mut next = self.play(Play::new())?;
        while next != Action::Quit {
            next = self.play(Play::new())?;
        }
        Ok(())
    }

    fn play(&mut self, mut play: Play) -> Result<Action> {
        self.screen.render_header()?;

        let interval = Duration::from_millis(FRAME);
        let mut t = 0;
        loop {
            match self.handle_user_input(&mut play)? {
                Some(action) => {
                    if action != Action::Ok {
                        return Ok(action);
                    }
                }
                _ => {}
            };

            if t % UPDATE == 0 {
                if let Err(_) = play.update() {
                    return self.screen.render_game_over(&play);
                }
            }
            if t % TICK == 0 {
                play.tick();
            }

            self.screen.render(&play)?;
            thread::sleep(interval);
            t += 1;
        }
    }

    fn handle_user_input(&mut self, play: &mut Play) -> Result<Option<Action>> {
        match self.screen.next_input() {
            Some(Ok(key)) => match key {
                b'q' => return Ok(Some(Action::Quit)),
                b'h' => play.slide_tetro(Dir::Left),
                b'l' => play.slide_tetro(Dir::Right),
                b'j' => play.slide_tetro(Dir::Down),
                b'd' => play.rotate_tetro(RotateDir::AntiClockwise),
                b'f' => play.rotate_tetro(RotateDir::Clockwise),
                b'?' => {
                    return self.screen
                        .show_modal(&self.help_modal)
                        .map(|action| Some(action));
                }
                _ => {}
            },
            Some(Err(err)) => return Err(err.into()),
            None => {}
        };
        Ok(None)
    }
}