Rick's Tech Talk

All Tech Talk, Most of the Time

An Approach for Tetris Shapes in C++

I've been noodling with a Win32 version of Tetris, the ubiquitous "shape placing" game. I'm working in C++ using the Simple Directmedia Layer for my graphics. One of the interesting things in working out the game is the "shape" data. Below is the code for one my shapes, and the methods to "rotate" and "draw" it.

  1. /*
  2.  * LeftEll is the piece that looks like this
  3.  *
  4.  * ##
  5.  * ##
  6.  * ####
  7.  */
  8.  
  9. LeftEll::LeftEll()  : Shape ()
  10. {
  11.   shape_height[0] = 3;
  12.   shape_height[1] = 2;
  13.   shape_height[2] = 3;
  14.   shape_height[3] = 2;
  15.   shape_width[0] = 2;
  16.   shape_width[1] = 3;
  17.   shape_width[2] = 2;
  18.   shape_width[3] = 3;
  19.   shape_data[0] = "# # ##";
  20.   shape_data[1] = "####  ";
  21.   shape_data[2] = "## # #";
  22.   shape_data[3] = "  ####";
  23. }
  24.  
  25. int LeftEll::rotate_left()
  26. {
  27.   rotate(-1);
  28. }
  29.  
  30. void LeftEll::draw(int start_x, int start_y)
  31. {
  32.   for (int row = 0; row < shape_height[rotation]; row++) {
  33.     for (int col = 0; col < shape_width[rotation]; col++) {
  34.       cout << shape_data[rotation][(row*shape_width[rotation])+col];
  35.     }
  36.     cout << endl;
  37.   }
  38. }

For some reason, I was pretty happy with this, especially when my testing produced the correct behavior. (Note the "rotate" method just loops through the numbers 0, 1, 2, and 3, which correspond to a shape's four possible positions.)

  1. C:\cygwin\home\rumali\MinGW\tetris
  2.  9:46:03.62 > testshape
  3. (1) Square, (2) Pyramid,
  4. (3) Left Slant, (4) Right Slant,
  5. (5) Long Row,
  6. (6) Left Ell, (7) Right Ell,
  7. (q)uit
  8. 6
  9. (l)eft rotate, (r)ight rotate, (d)raw
  10. d
  11. #
  12. #
  13. ##
  14. (1) Square, (2) Pyramid,
  15. (3) Left Slant, (4) Right Slant,
  16. (5) Long Row,
  17. (6) Left Ell, (7) Right Ell,
  18. (q)uit
  19. 6
  20. (l)eft rotate, (r)ight rotate, (d)raw
  21. l
  22. LeftEll::rotation = 3
  23.   #
  24. ###
  25. (1) Square, (2) Pyramid,
  26. (3) Left Slant, (4) Right Slant,
  27. (5) Long Row,
  28. (6) Left Ell, (7) Right Ell,
  29. (q)uit
  30. 6
  31. (l)eft rotate, (r)ight rotate, (d)raw
  32. l
  33. LeftEll::rotation = 2
  34. ##
  35.  #
  36.  #

However, the more I thought about it, the more I realized that I was simply hardcoding the shape diagrams for each rotation. Couldn't I store the start rotation once, and just derive the other rotations? As I pondered this, I realized that the answer would involve matrix algebra. I studied this in school, but that was ages ago. I'm sure more searching would yield an algorithm (and rotating in arbitrary 90 degree "increments" reduces the complexity), but my proggie is a toy, running on Win32. If my game were targeted for a handheld, I may need to worry about that extra 18 bytes that my code is using, trading that off against the CPU cycles that an algorithm would need to calculate the new shape data. So in the end, I decided to remain happy with it. For now.