James Dennis (jdennis@gmail.com) and Glen Coppersmith (coppersmith@gmail.com)
Modify Colin Fahey's Tetris API
3.17.04


Table of Contents:

  1. Where to start
  2. Implementing your algorithm
  3. Things to consider
  4. Inserting your algorithm into Colin's implementation
  5. Links

Where to start
First, you'll need Colin Fahey's Tetris. Get it here.

Get familiar with standard_tetris_strategy.h and standard_tetris_strategy.cpp. This is where the algorithms are actually selected from. The format may seem a little hairy at first, but it's not so bad.

Obviously, a next step would be to read the other algorithms and see how they're implemented.

Implementing your algorithm
First thing you want to do is make your own tetris strategy file, which implements your algorithm. This can be named whatever you like, but the convention is standard_tetris_strategy_numpiece_author.cpp. Glen and I called this file "standard_tetris_strategy_twopiece_glamestris.cpp".

The source files consist of one function that must be available and public and then generally two other private functions. The public function must be named GetBestMove() and look like:

static void GetBestMove (
  StandardTetrisBoard &   ref_CurrentBoard,
  StandardTetrisPiece &   ref_CopyOfCurrentPiece,
  int &                   ref_i32_BestRotationDelta,    // 0 or {0,1,2,3} 
  int &                   ref_i32_BestTranslationDelta  // 0 or {...,-2,-1,0,1,2,...}
);
As we can see, the two delta's are passed by reference so we set these inside our function and that's that. The other two values, the current board, and a copy of the current piece, or for us to evaluate moves by. You can have unlimited functions if you really want, but Glen and I found it easier to just stick to the convention of Private_Strategy() and Private_Strategy_Evaluate().

Things to consider

  • The main thing to think about is how you play tetris and what you would do if you were a faster thinker. The computer has no problem beating the time limit for decisions, as the tetris standard is defined for humans, not computers.
  • How much do you think creating a hole will effect your player?
  • If your player removes a line, but creates a hole in process, how should that weigh into the heuristic?
  • What makes a good fit for a piece?
  • Inserting your algorithm into Colin's implementation
    So now that you've read through the other algorithms and want to start coding, let's insert your code into the framework and get it playing.

    Step 1: Make a header file and source file following the file naming convention.

    Step 2: Tell Colin's framework about them.
    Start by editing the enum in the StandardTetrisStrategy class in standard_tetris_strategy.h. You'll see something like:

    class StandardTetrisStrategy
    {
    public:
      enum
        {
        STRATEGY_AI_DEFAULTS                     = 0,
        STRATEGY_AI_USER                         = 1,
    ...
    
    Just tack your name, in all upper case, to the back of that enumeration list.

    Now open standard_tetris_strategy.cpp and modify the StandardTetrisStrategy::SelectNextStrategy function to include your algorithm. Keep the text upper case for your name as the name will be defined to be your specific algorithm later. It should look something like this:

    void StandardTetrisStrategy::SelectNextStrategy( void )
    {
    switch( m_i32_CurrentStrategy )
      {
      case STRATEGY_AI_DEFAULTS:
        m_i32_CurrentStrategy = STRATEGY_AI_USER;  break;
      case STRATEGY_AI_USER:
        m_i32_CurrentStrategy = STRATEGY_AI_ONE_PIECE_GLAMESTRIS;  break;
      case STRATEGY_AI_ONE_PIECE_GLAMESTRIS:
            m_i32_CurrentStrategy = STRATEGY_AI_TWO_PIECE_GLAMESTRIS;  break;
      case STRATEGY_AI_TWO_PIECE_GLAMESTRIS:
        m_i32_CurrentStrategy = STRATEGY_AI_DEFAULTS;  break;
      default:
        m_i32_CurrentStrategy = STRATEGY_AI_DEFAULTS;  break;
      }
    }
    
    You'll also want to edit StandardTetrisStrategy::GetSelectedAIName so that the text for your algorithm is displayed properly. This part looks like:
    void StandardTetrisStrategy::GetSelectedAIName( char * pcstrText )
    {
      if (((char *)(0)) == pcstrText) return;
    
      pcstrText[0] = ((char)(0));
    
      switch( m_i32_CurrentStrategy )
        {
        case STRATEGY_AI_DEFAULTS:
          strcat( pcstrText, "James/Glen (hybrid)" );  break;
    
        case STRATEGY_AI_USER:
          strcat( pcstrText, "User" );  break;
    
            case STRATEGY_AI_ONE_PIECE_GLAMESTRIS:
              strcat( pcstrText, "James/Glen (1P)" ); break;
    
            case STRATEGY_AI_TWO_PIECE_GLAMESTRIS:
              strcat( pcstrText, "James/Glen (2P)" ); break ;
    
        default:
          strcat( pcstrText, "(unknown)" );  break;
        }
    
    }
    
    Now is where we connect the uppercase algorithm name to our code. Here we edit StandardTetrisStrategy::GetBestMove_OncePerPiece. Inside StandardTetrisStrategy::GetBestMove_OncePerPiece you will see a switch statement that checks for the case of the currently selected algorithm and runs code based on this. If you've stuck to the convention of using a normal looking GetBestMove, then you can simply add your case to look like:
    switch( m_i32_CurrentStrategy )
        {
    
            case STRATEGY_AI_ONE_PIECE_GLAMESTRIS:
          {
          StandardTetrisStrategyOnePieceGlamesTris::GetBestMove
            (
            ref_CurrentBoard,
            ref_Piece,
            ref_i32_BestRotationDelta,     // 0 or {0,1,2,3}
            ref_i32_BestTranslationDelta   // 0 or {...,-2,-1,0,1,2,...}
            );
          }
          break;
    ...
    
    If you've decided to add anything else, well, you'll have to figure out how to get it passed along appropriately. You are given the next piece in StandardTetrisStrategy::GetBestMove_OncePerPiece so obviously if you've chosen to do a two ply algorithm, this is where you get the next piece.

    Finally, you'll want to include you're header file into standard_tetris_strategy.cpp so right at the top of this page make sure to add a line for this. It should look like:

    // ############################################################################
    
    #include "standard_tetris_strategy_user.h"
    #include "standard_tetris_strategy_onepiece_glamestris.h"
    #include "standard_tetris_strategy_twopiece_glamestris.h"
    
    #include 
    

    At this point, you're on your own, so happy hacking!


    Links

    1. Colin Fahey's site
    2. Glamestris official site