Arduino Tetris 4

Almost there now! What we have to do today is remove rows that are full so the game can be played and “won”. While we’re at it, we’ll add a game over sign. Previously, we got pieces to fall and collide with the rubble.

Removing full rows

void remove_full_rows() {
  int x, y, c;
  for(y=0;y<GRID_H;++y) {
                               // count the filled spots in this row
    c = 0;
    for(x=0;x<GRID_W;++x) {
      if( grid[y*GRID_W+x] > 0 ) c++;
    }
    if(c==GRID_W) {
      // row full!
      delete_row(y);
    }
  }  
}

// Move everything down 1 space, destroying the old row number y 
// in the process.
void delete_row(int y) {
  int x;
  for(;y>0;--y) {
    for(x=0;x<GRID_W;++x) {
      grid[y*GRID_W+x] = grid[(y-1)*GRID_W+x];
    }
  }
  // everything moved down 1, so the top row must be empty.
  for(x=0;x<GRID_W;++x) {
    grid[x]=0;
  }
}

Basically, this segment removes the row(s) that are full and shifts everything else down by whatever it took away until the pieces hit the bottom again. What we’ll do now is incorporate that into our fall_piece() code.

void fall_piece() {
  // 2 times a second, (timed event)
  if(millis()-clock>500) {
    // get ready to wait another 1/10th of a second
    clock=millis();

    remove_piece_from_grid();
    
    if(piece_can_fit(px,py+1,piece_rotation)==1) {
      py++;
      add_piece_to_grid();
    } else {
      add_piece_to_grid();
      remove_full_rows();
      if(game_is_over()==1) {
        game_over_animation();
      }
      next_piece();
    }
  }
}

// looks a lot like piece_outside_grid(), but now all we care 
// about is the top of the grid.
int game_is_over() {
  int x,y;
  const char *piece = pieces[piece_id] + (piece_rotation * PIECE_H * PIECE_W);
  
  for(y=0;y<PIECE_H;++y) {
    for(x=0;x<PIECE_W;++x) {      
      int ny=piece_y+y;
      int nx=piece_x+x;
      if(piece[y*PIECE_W+x]>0) {
        if(ny<0) return 1;    // yes: off the top!
      }
    }
  }
  return 0;  // not over yet...
}

void game_over() {
  int x,y;

  while(1) {
    // fill the screen with color
    for(x=0;x<GRID_W;++x) {
      for(y=0;y<GRID_H;++y) {
        p(x,y,150);
      }
    }
    // until the player clicks the button
    if(digitalRead(1)==0) {
      // restart!
      setup();
      return;
    }
  }
}

Now, when pieces can no longer fit on the 8×8 display, it’ll display the game over scene. It’s not all bad stuff, though, since the user can choose to restart the game if they want.

That concludes the tutorials for Tetris! If you’ve missed any of the code, you can find all it here at Arduino Starter Kit Github page.

Note that our joystick used in the code has debounce – can’t hold the joystick in one direction to move it all the way across the display; you have to manually click once per pixel.

Okay! That wraps up this chunk of the tutorial. I hope you guys have had as fun a time as I have. Now that we’re done with Tetris, we can look to combine it with some of the other tutorials!

All of it

If you’re missing any part of the tutorial, or would simply like to jump straight to the end, you can checkout the full list of code here at the Arduino Starter Kit github page.

Questions

  • Add a “game over” message. Can you animate it?
  • Add a “you win” after the user clears random(8), exlcuding 0, rows.