Levels and lines sent

The next two being strongly bound (the level depends directly on the number of lines sent), we'll implement them at the same time.

Before doing anything else, let's define the two following const:

const LEVEL_TIMES: [u32; 10] = [1000, 850, 700, 600, 500, 400, 300, 250, 221, 190];
const LEVEL_LINES: [u32; 10] = [20,   40,  60,  80,  100, 120, 140, 160, 180, 200];

The first one corresponds to the times before the current tetrimino descends by one block. Each case being a different level.

The second one corresponds to how many lines the player needs before getting to the next level.

Next, let's add the following method in our Tetris type:

fn increase_line(&mut self) {
    self.nb_lines += 1;
    if self.nb_lines > LEVEL_LINES[self.current_level as usize - 1] {
        self.current_level += 1;
    }
}

Nothing complicated. Just be careful when reading the LEVEL_LINES const because our current_level variable starts at 1 and not 0.

Next, we'll need to update how we determine whether the time is up or not. To do so, let's write another function:

fn is_time_over() {
    match timer.elapsed() {
        Ok(elapsed) => {
            let millis = elapsed.as_secs() as u32 * 1000 + 
elapsed.subsec_nanos() / 1_000_000; millis > LEVEL_TIMES[tetris.current_level as usize - 1] } Err(_) => false, } }

A small but tricky one. The problem is that the type returned by timer.elapsed (which is Duration) doesn't provide a method to get the number of milliseconds, so we need to get it ourselves.

First, we get the number of seconds elapsed and then multiply it by 1,000 (because 1 second = 1,000 milliseconds). Finally, we get the number of nanoseconds (in the current second) and divide it by 1,000,000 (because 1 millisecond = 1 million nanoseconds).

We can now compare the results to see whether the tetrimino should descend or not and return the result:

if is_time_over(&tetris, &timer) {
    let mut make_permanent = false;
    if let Some(ref mut piece) = tetris.current_piece {
        let x = piece.x;
        let y = piece.y + 1;
        make_permanent = !piece.change_position(&tetris.game_map,
x, y); } if make_permanent { tetris.make_permanent(); } timer = SystemTime::now(); }

And with this, we've finished this part. Let's make the last one now: the highscore loading/overwriting!