Sound update

Dependencies:   4DGL-uLCD-SE Physac-MBED PinDetect SDFileSystem mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
jstephens78
Date:
Thu Dec 01 01:46:22 2022 +0000
Parent:
17:3517251daf96
Parent:
15:e9f3b72b7486
Child:
19:6d9bee043ede
Commit message:
merge

Changed in this revision

Tetris/Pieces.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Board.cpp	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,208 @@
+#include "Board.h"
+
+/*
+==================
+Init
+==================
+*/
+Board::Board (Pieces *pPieces, int pScreenHeight)
+{
+    // Get the screen height
+    mScreenHeight = pScreenHeight;
+
+    // Get the pointer to the pieces class
+    mPieces = pPieces;
+
+    //Init the board blocks with free positions
+    InitBoard();
+}
+
+/*
+======================================                                  
+Init the board blocks with free positions
+====================================== 
+*/
+void Board::InitBoard()
+{
+    for (int i = 0; i < BOARD_WIDTH; i++)
+        for (int j = 0; j < BOARD_HEIGHT; j++)
+            mBoard[i][j] = POS_FREE;
+}
+
+/* 
+======================================                                  
+Store a piece in the board by filling the blocks
+
+Parameters:
+
+>> pX:      Horizontal position in blocks
+>> pY:      Vertical position in blocks
+>> pPiece:  Piece to draw
+>> pRotation:   1 of the 4 possible rotations
+====================================== 
+*/
+void Board::StorePiece (int pX, int pY, int pPiece, int pRotation)
+{
+    // Store each block of the piece into the board
+    for (int i1 = pX, i2 = 0; i1 < pX + PIECE_BLOCKS; i1++, i2++)
+    {
+        for (int j1 = pY, j2 = 0; j1 < pY + PIECE_BLOCKS; j1++, j2++)
+        {   
+            // Store only the blocks of the piece that are not holes
+            if (mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0)     
+                mBoard[i1][j1] = POS_FILLED;    
+        }
+    }
+}
+
+/* 
+======================================                                  
+Check if the game is over becase a piece have achived the upper position
+
+Returns true or false
+====================================== 
+*/
+bool Board::IsGameOver()
+{
+    //If the first line has blocks, then, game over
+    for (int i = 0; i < BOARD_WIDTH; i++)
+    {
+        if (mBoard[i][0] == POS_FILLED) return true;
+    }
+
+    return false;
+}
+
+/* 
+======================================                                  
+Delete a line of the board by moving all above lines down
+
+Parameters:
+
+>> pY:      Vertical position in blocks of the line to delete
+====================================== 
+*/
+void Board::DeleteLine (int pY)
+{
+    // Moves all the upper lines one row down
+    for (int j = pY; j > 0; j--)
+    {
+        for (int i = 0; i < BOARD_WIDTH; i++)
+        {
+            mBoard[i][j] = mBoard[i][j-1];
+        }
+    }   
+}
+
+/* 
+======================================                                  
+Delete all the lines that should be removed
+====================================== 
+*/
+int Board::DeletePossibleLines ()
+{
+    int count =0;
+    for (int j = 0; j < BOARD_HEIGHT; j++)
+    {
+        int i = 0;
+        while (i < BOARD_WIDTH)
+        {
+            if (mBoard[i][j] != POS_FILLED) break;
+            i++;
+        }
+
+        if (i == BOARD_WIDTH) 
+        {
+            DeleteLine (j);
+            count++;
+        }
+    }
+    return count;
+}
+
+/* 
+======================================                                  
+Returns 1 (true) if the this block of the board is empty, 0 if it is filled
+
+Parameters:
+
+>> pX:      Horizontal position in blocks
+>> pY:      Vertical position in blocks
+====================================== 
+*/
+bool Board::IsFreeBlock (int pX, int pY)
+{
+    if (mBoard [pX][pY] == POS_FREE) return true; else return false;
+}
+
+/* 
+======================================                                  
+Returns the horizontal position (isn pixels) of the block given like parameter
+
+Parameters:
+
+>> pPos:    Horizontal position of the block in the board
+====================================== 
+*/
+int Board::GetXPosInPixels (int pPos)
+{
+    return  ( ( BOARD_POSITION - (BLOCK_SIZE * (BOARD_WIDTH / 2)) ) + (pPos * BLOCK_SIZE) );
+}
+
+/* 
+======================================                                  
+Returns the vertical position (in pixels) of the block given like parameter
+
+Parameters:
+
+>> pPos:    Horizontal position of the block in the board
+====================================== 
+*/
+int Board::GetYPosInPixels (int pPos)
+{
+    return ( (mScreenHeight - (BLOCK_SIZE * BOARD_HEIGHT)) + (pPos * BLOCK_SIZE) );
+}
+
+/* 
+======================================                                  
+Check if the piece can be stored at this position without any collision
+Returns true if the movement is  possible, false if it not possible
+
+Parameters:
+
+>> pX:      Horizontal position in blocks
+>> pY:      Vertical position in blocks
+>> pPiece:  Piece to draw
+>> pRotation:   1 of the 4 possible rotations
+====================================== 
+*/
+bool Board::IsPossibleMovement (int pX, int pY, int pPiece, int pRotation)
+{
+    // Checks collision with pieces already stored in the board or the board limits
+    // This is just to check the 5x5 blocks of a piece with the appropiate area in the board
+    for (int i1 = pX, i2 = 0; i1 < pX + PIECE_BLOCKS; i1++, i2++)
+    {
+        for (int j1 = pY, j2 = 0; j1 < pY + PIECE_BLOCKS; j1++, j2++)
+        {   
+            // Check if the piece is outside the limits of the board
+            if (    i1 < 0          || 
+                i1 > BOARD_WIDTH  - 1   ||
+                j1 > BOARD_HEIGHT - 1)
+            {
+                if (mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0)
+                    return 0;       
+            }
+
+            // Check if the piece have collisioned with a block already stored in the map
+            if (j1 >= 0)    
+            {
+                if ((mPieces->GetBlockType (pPiece, pRotation, j2, i2) != 0) &&
+                    (!IsFreeBlock (i1, j1)) )
+                    return false;
+            }
+        }
+    }
+
+    // No collision
+    return true;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Board.h	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,50 @@
+#ifndef _BOARD_
+#define _BOARD_
+
+// ------ Includes -----
+
+#include "Pieces.h"
+
+// ------ Defines -----
+
+#define BOARD_LINE_WIDTH 6          // Width of each of the two lines that delimit the board
+#define BLOCK_SIZE 6              // Width and Height of each block of a piece
+#define BOARD_POSITION 50          // Center position of the board from the left of the screen
+#define BOARD_WIDTH 10              // Board width in blocks 
+#define BOARD_HEIGHT 20             // Board height in blocks
+#define MIN_VERTICAL_MARGIN 8      // Minimum vertical margin for the board limit      
+#define MIN_HORIZONTAL_MARGIN 20    // Minimum horizontal margin for the board limit
+#define PIECE_BLOCKS 5              // Number of horizontal and vertical blocks of a matrix piece
+
+
+// --------------------------------------------------------------------------------
+//                                   Board
+// --------------------------------------------------------------------------------
+
+class Board
+{
+public:
+
+    Board                       (Pieces *pPieces, int pScreenHeight);
+
+    int GetXPosInPixels         (int pPos);
+    int GetYPosInPixels         (int pPos);
+    bool IsFreeBlock            (int pX, int pY);
+    bool IsPossibleMovement     (int pX, int pY, int pPiece, int pRotation);
+    void StorePiece             (int pX, int pY, int pPiece, int pRotation);
+    int DeletePossibleLines    ();
+    bool IsGameOver             ();
+
+private:
+
+        // enum holds no value besides the described properties
+    enum { POS_FREE, POS_FILLED };          // POS_FREE = free position of the board; POS_FILLED = filled position of the board
+    int mBoard [BOARD_WIDTH][BOARD_HEIGHT]; // Board that contains the pieces
+    Pieces *mPieces;
+    int mScreenHeight;
+
+    void InitBoard();
+    void DeleteLine (int pY);
+};
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Game.cpp	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,190 @@
+#include "Game.h"
+
+/* 
+======================================                                  
+Init
+====================================== 
+*/
+Game::Game(Board *pBoard, Pieces *pPieces, int pScreenHeight, uLCD_4DGL *pLCD,int initPiece,int initPos,int initNextPiece,int initNextPos) 
+{
+    mScreenHeight = pScreenHeight;
+    
+    // Get the pointer to the Board and Pieces classes
+    mBoard = pBoard;
+    mPieces = pPieces;
+    uLCD = pLCD;
+    // Game initialization
+    InitGame (initPiece,initPos,initNextPiece,initNextPos);
+}
+
+/* 
+======================================                                  
+Initial parameters of the game
+====================================== 
+*/
+void Game::InitGame(int initPiece,int initPos,int initNextPiece,int initNextPos)
+{
+    //points
+    points = 0;
+    clearedLineCount=0;
+
+    // First piece
+    mPiece          = initPiece;
+    mRotation       = initPos;
+    mPosX           = (BOARD_WIDTH / 2) + mPieces->GetXInitialPosition (mPiece, mRotation);
+    mPosY           = mPieces->GetYInitialPosition (mPiece, mRotation);
+
+    //  Next piece
+    mNextPiece      = initNextPiece;
+    mNextRotation   = initNextPos;
+    mNextPosX       = BOARD_WIDTH + 2;
+    mNextPosY       = 2;    
+}
+
+/* 
+======================================                                  
+Create a random piece
+====================================== 
+*/
+void Game::CreateNewPiece(int piece,int pos)
+{
+    // The new piece
+    mPiece          = mNextPiece;
+    mRotation       = mNextRotation;
+    mPosX           = (BOARD_WIDTH / 2) + mPieces->GetXInitialPosition (mPiece, mRotation);
+    mPosY           = mPieces->GetYInitialPosition (mPiece, mRotation);
+
+    // Random next piece
+    mNextPiece      = piece;
+    mNextRotation   = pos;
+}
+
+/* 
+======================================                                  
+Draw piece
+
+Parameters:
+
+>> pX:      Horizontal position in blocks
+>> pY:      Vertical position in blocks
+>> pPiece:  Piece to draw
+>> pRotation:   1 of the 4 possible rotations
+====================================== 
+*/
+void Game::DrawPiece (int pX, int pY, int pPiece, int pRotation, int colorIndex)
+{
+    // Obtain the position in pixel in the screen of the block we want to draw
+    int mPixelsX = mBoard->GetXPosInPixels (pX);
+    int mPixelsY = mBoard->GetYPosInPixels (pY);
+    int mColors [7]={16711680, 15955765, 16761893, 45401, 44763, 12462572, 29669};
+    // Travel the matrix of blocks of the piece and draw the blocks that are filled
+    for (int i = 0; i < PIECE_BLOCKS; i++)
+    {
+        for (int j = 0; j < PIECE_BLOCKS; j++)
+        {
+            if (mPieces->GetBlockType (pPiece, pRotation, j, i) != 0)
+                uLCD->filled_rectangle  (mPixelsX + i * BLOCK_SIZE, 
+                                    mPixelsY + j * BLOCK_SIZE, 
+                                    (mPixelsX + i * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                    (mPixelsY + j * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                    mColors[colorIndex]);
+        }
+    }
+}
+
+/* 
+======================================                                  
+Draw board
+
+Draw the two lines that delimit the board
+====================================== 
+*/
+void Game::DrawBoard ()
+{
+    // Calculate the limits of the board in pixels  
+    int mX1 = BOARD_POSITION - (BLOCK_SIZE * (BOARD_WIDTH / 2)) - 1;
+    int mX2 = BOARD_POSITION + (BLOCK_SIZE * (BOARD_WIDTH / 2));
+    int mY = mScreenHeight - (BLOCK_SIZE * BOARD_HEIGHT);
+    
+    // Check that the vertical margin is not to small
+    //assert (mY > MIN_VERTICAL_MARGIN);
+
+    // Rectangles that delimits the board
+    uLCD->filled_rectangle (mX1 - BOARD_LINE_WIDTH, mY, mX1, mScreenHeight - 1, BLUE);
+    uLCD->filled_rectangle (mX2, mY, mX2 + BOARD_LINE_WIDTH, mScreenHeight - 1, BLUE);
+    
+    // Check that the horizontal margin is not to small
+    //assert (mX1 > MIN_HORIZONTAL_MARGIN);
+
+    // Drawing the blocks that are already stored in the board
+    mX1 += 1;
+    for (int i = 0; i < BOARD_WIDTH; i++)
+    {
+        for (int j = 0; j < BOARD_HEIGHT; j++)
+        {   
+            // Check if the block is filled, if so, draw it
+            if (!mBoard->IsFreeBlock(i, j)) 
+                uLCD->filled_rectangle (    mX1 + i * BLOCK_SIZE, 
+                                        mY + j * BLOCK_SIZE, 
+                                        (mX1 + i * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                        (mY + j * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                        10066329);
+        }
+    }   
+}
+
+/* 
+======================================                                  
+Draw scene
+
+Draw all the objects of the scene
+====================================== 
+*/
+void Game::DrawScene ()
+{
+    DrawBoard();
+    DrawPiece (mPosX, mPosY, mPiece, mRotation, mPiece);                    // Draw the playing piece
+    DrawPiece (mNextPosX, mNextPosY, mNextPiece, mNextRotation, mNextPiece);    // Draw the next piece
+}
+
+void Game::ErasePiece (int pX, int pY, int pPiece, int pRotation)
+{
+    if(pPiece==-1) return;
+    // Obtain the position in pixel in the screen of the block we want to draw
+    int mPixelsX = mBoard->GetXPosInPixels (pX);
+    int mPixelsY = mBoard->GetYPosInPixels (pY);
+
+    // Travel the matrix of blocks of the piece and draw the blocks that are filled
+    for (int i = 0; i < PIECE_BLOCKS; i++)
+    {
+        for (int j = 0; j < PIECE_BLOCKS; j++)
+        {
+            if (mPieces->GetBlockType (pPiece, pRotation, j, i) != 0)
+                uLCD->filled_rectangle  (mPixelsX + i * BLOCK_SIZE, 
+                                    mPixelsY + j * BLOCK_SIZE, 
+                                    (mPixelsX + i * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                    (mPixelsY + j * BLOCK_SIZE) + BLOCK_SIZE - 1, 
+                                    0);
+        }
+    }
+}
+
+void Game::AddPoints(int newGain)
+{
+    points+=newGain;
+}
+
+void Game::AddClearedLines(int newGain)
+{
+    clearedLineCount+=newGain;
+}
+
+int Game::GetPoints()
+{
+    return points;
+}
+
+int Game::GetClearedLines()
+{
+    return clearedLineCount;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Game.h	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,58 @@
+#ifndef _GAME_
+#define _GAME_
+
+// ------ Includes -----
+
+#include "Board.h"
+#include "Pieces.h"
+#include "uLCD_4DGL.h"
+
+// ------ Defines -----
+
+#define WAIT_TIME 700           // Number of milliseconds that the piece remains before going 1 block down */ 
+
+
+// -----------------------------------------------------
+// Game
+// -----------------------------------------------------
+
+class Game
+{
+public:
+
+    Game (Board *pBoard, Pieces *pPieces, int pScreenHeight, uLCD_4DGL *uLCD,int,int,int,int);
+
+    void DrawScene ();
+    void CreateNewPiece (int,int);
+    
+    void ErasePiece(int x,int y,int piece, int rotation);
+    void DrawBoard ();
+    void AddPoints(int);
+    void AddClearedLines(int);
+    int GetPoints();
+    int GetClearedLines();
+    
+    int mPosX, mPosY;               // Position of the piece that is falling down
+    int mPiece, mRotation;          // Kind and rotation the piece that is falling down
+    
+    int points;
+    int clearedLineCount;
+    
+
+private:
+
+    int mScreenHeight;              // Screen height in pixels
+    int mNextPosX, mNextPosY;       // Position of the next piece
+    int mNextPiece, mNextRotation;  // Kind and rotation of the next piece
+    
+    Board *mBoard;
+    Pieces *mPieces;
+    uLCD_4DGL *uLCD;
+
+    
+    void InitGame(int,int,int,int);
+    void DrawPiece (int pX, int pY, int pPiece, int pRotation, int colorIndex);
+    
+};
+
+#endif // _GAME_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Pieces.cpp	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,328 @@
+#include "Pieces.h"
+
+// Define the Pieces
+char mPieces [7 /*kind */ ][4 /* rotation */ ][5 /* horizontal blocks */ ][5 /* vertical blocks */ ] =
+{
+// Square
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    }
+   },
+
+// I
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 1, 2, 1, 1},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0}, 
+    {0, 0, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 1, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {1, 1, 2, 1, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 1, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    }
+   }
+  ,
+// L
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 2, 0, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 1, 2, 1, 0},
+    {0, 1, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 1, 1, 0, 0},
+    {0, 0, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 1, 0},
+    {0, 1, 2, 1, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    }
+   },
+// L mirrored
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 2, 0, 0},
+    {0, 1, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0},
+    {0, 1, 2, 1, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 1, 2, 1, 0},
+    {0, 0, 0, 1, 0},
+    {0, 0, 0, 0, 0}
+    }
+   },
+// N
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 1, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 1, 2, 0, 0},
+    {0, 0, 1, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 1, 2, 0, 0},
+    {0, 1, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 1, 1, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    }
+   },
+// N mirrored
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 0, 1, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 1, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 1, 0, 0, 0},
+    {0, 1, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 1, 0},
+    {0, 1, 2, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    }
+   },
+// T
+  {
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 2, 1, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0},
+    {0, 1, 2, 1, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 1, 2, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 0, 0, 0, 0}
+    },
+   {
+    {0, 0, 0, 0, 0},
+    {0, 0, 1, 0, 0},
+    {0, 1, 2, 1, 0},
+    {0, 0, 0, 0, 0},
+    {0, 0, 0, 0, 0}
+    }
+   }
+};
+
+// Displacement of the piece to the position where it is first drawn in the board when it is created
+int mPiecesInitialPosition  [7 /*kind */ ][4 /* rotation */ ][2 /* position */] =
+{
+/* Square */
+  {
+    {-2, -3}, 
+    {-2, -3},
+    {-2, -3},
+    {-2, -3}
+   },
+/* I */
+  {
+    {-2, -2},
+    {-2, -3},
+    {-2, -2},
+    {-2, -3}
+   },
+/* L */
+  {
+    {-2, -3},
+    {-2, -3},
+    {-2, -3},
+    {-2, -2}
+   },
+/* L mirrored */
+  {
+    {-2, -3},
+    {-2, -2},
+    {-2, -3},
+    {-2, -3}
+   },
+/* N */
+  {
+    {-2, -3},
+    {-2, -3},
+    {-2, -3},
+    {-2, -2}
+   },
+/* N mirrored */
+  {
+    {-2, -3},
+    {-2, -3},
+    {-2, -3},
+    {-2, -2}
+   },
+/* T */
+  {
+    {-2, -3},
+    {-2, -3},
+    {-2, -3},
+    {-2, -2}
+   },
+};
+
+/* 
+======================================                                  
+Return the type of a block (0 = no-block, 1 = normal block, 2 = pivot block)
+
+Parameters:
+
+int pPiece:      Piece to draw
+int pRotation:   1 of the 4 possible rotations
+int pX:          Horizontal position in blocks
+int pY:          Vertical position in blocks
+====================================== 
+*/
+int Pieces::GetBlockType (int pPiece, int pRotation, int pX, int pY)
+{
+    return mPieces [pPiece][pRotation][pX][pY];
+}
+
+/* 
+======================================                                  
+Returns the horizontal displacement of the piece that has to be applied in order to create it in the
+correct position.
+
+Parameters:
+
+int pPiece:  Piece to draw
+int pRotation:   1 of the 4 possible rotations
+====================================== 
+*/
+int Pieces::GetXInitialPosition (int pPiece, int pRotation)
+{
+    return mPiecesInitialPosition [pPiece][pRotation][0];
+}
+
+/* 
+======================================                                  
+Returns the vertical displacement of the piece that has to be applied in order to create it in the
+correct position.
+
+Parameters:
+
+int pPiece:  Piece to draw
+int pRotation:   1 of the 4 possible rotations
+====================================== 
+*/
+int Pieces::GetYInitialPosition (int pPiece, int pRotation)
+{
+    return mPiecesInitialPosition [pPiece][pRotation][1];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/Pieces.h	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,15 @@
+#ifndef _PIECES_
+#define _PIECES_
+
+// Pieces Header to Support Game Pieces
+
+class Pieces
+{
+    public:
+    
+    int GetBlockType(int pPiece, int pRotation, int pX, int pY);
+    int GetXInitialPosition(int pPiece, int pRotation);
+    int GetYInitialPosition(int pPiece, int pRotation);
+};
+
+#endif  // _PIECES_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Tetris/main.cpp	Thu Dec 01 01:46:22 2022 +0000
@@ -0,0 +1,492 @@
+#include "mbed.h"
+#include "Game.h"
+//#include "PinDetect.h"
+//#include "Speaker.h"
+//#include "TextLCD.h"
+//#include "Shiftbrite.h"
+//#include "SDFileSystem.h"
+#include "wave_player.h"
+#include "rtos.h"
+
+uLCD_4DGL uLCD(p28, p27, p29);
+//TextLCD textLCD(p26, p25, p24, p23, p22, p15); 
+//Speaker mySpeaker(p21);
+//Shiftbrite myShiftbrite(p9, p10, p11, p12, p13);
+//SDFileSystem sd(p5, p6, p7, p8, "sd"); //SD card
+Serial pc(USBTX, USBRX);
+
+PinDetect LEFT_KEY(p16);    // need to use NavSwitch for this
+PinDetect RIGHT_KEY(p19);
+PinDetect ROTATE_KEY(p17);
+PinDetect DOWN_KEY(p30);
+
+int SinglePiecePoints = 50;
+int LineClearPoints = 200;
+int key_input = 0;
+bool gameStarted = false;
+void input_left()   // FIX
+{
+    if(!gameStarted)
+    {   gameStarted=true;
+        return;
+    }
+    key_input = 1;
+    //mySpeaker.PlayNote(400.0,0.05,0.025);
+    //mySpeaker.PlayNote(500.0,0.05,0.025);
+}
+
+void input_right()
+{
+    if(!gameStarted)
+    {   gameStarted=true;
+        return;
+    }
+    key_input = 2;
+    //mySpeaker.PlayNote(400.0,0.05,0.025);
+    //mySpeaker.PlayNote(500.0,0.05,0.025);
+}
+
+void input_rotate()
+{
+    if(!gameStarted)
+    {   gameStarted=true;
+        return;
+    }
+    key_input = 3;
+    /*mySpeaker.PlayNote(600.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);*/
+}
+
+void input_down()
+{
+    if(!gameStarted)
+    {   gameStarted=true;
+        return;
+    }
+    key_input=4;
+    /*mySpeaker.PlayNote(500.0,0.05,0.025);
+    mySpeaker.PlayNote(1500.0,0.05,0.025);
+    mySpeaker.PlayNote(500.0,0.05,0.025);
+    mySpeaker.PlayNote(1500.0,0.05,0.025);*/
+}
+
+void clear_board()
+{
+    uLCD.filled_rectangle(20,0,79,128,0);
+}
+
+void clear_next_piece()
+{
+    uLCD.filled_rectangle(92,20,122,50,0);
+}
+
+/*
+void UpdateGameStatus(int points,int lines)
+{
+    textLCD.locate(7,0);
+    textLCD.printf("%d",points);
+    textLCD.locate(13,1);
+    textLCD.printf("%d",lines);
+}*/
+
+/* ShiftBright Code
+void FlashLight(void const *args)
+{
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);
+        
+    myShiftbrite.RGB(0,0,42);
+    myShiftbrite.RGB(0,0,42);
+    Thread::wait(100);
+        
+        
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,42,0);
+    Thread::wait(100);
+        
+    myShiftbrite.RGB(0,0,42);
+    myShiftbrite.RGB(0,0,42);
+    Thread::wait(100);
+        
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);    
+}
+
+void GameOverLight(void const *args)
+{
+    
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);
+        
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);  
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,200);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0); 
+}
+
+void GameStartLight(void const *args)
+{
+    
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);
+        
+    myShiftbrite.RGB(0,200,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,200,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0); 
+    myShiftbrite.RGB(0,0,0); 
+    Thread::wait(100);
+    myShiftbrite.RGB(0,200,0);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0); 
+    myShiftbrite.RGB(0,0,0); 
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,200,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,0,0);  
+    myShiftbrite.RGB(0,0,0);
+    Thread::wait(100);
+    myShiftbrite.RGB(0,200,0);
+    Thread::wait(100); 
+    myShiftbrite.RGB(0,0,0);
+    myShiftbrite.RGB(0,0,0);
+    
+} */
+
+/* Speaker Code
+void PlayStartSound()
+{
+    mySpeaker.PlayNote(500.0,0.05,0.025);
+    mySpeaker.PlayNote(600.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(600.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(1300.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(1300.0,0.05,0.025);
+    mySpeaker.PlayNote(1400.0,0.05,0.025);
+}
+
+void PlayOverSound()
+{
+    mySpeaker.PlayNote(1400.0,0.05,0.025);
+    mySpeaker.PlayNote(1300.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(1300.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(600.0,0.05,0.025);
+    mySpeaker.PlayNote(1200.0,0.05,0.025);
+    mySpeaker.PlayNote(1100.0,0.05,0.025);
+    mySpeaker.PlayNote(1000.0,0.05,0.025);
+    mySpeaker.PlayNote(900.0,0.05,0.025);
+    mySpeaker.PlayNote(800.0,0.05,0.025);
+    mySpeaker.PlayNote(700.0,0.05,0.025);
+    mySpeaker.PlayNote(600.0,0.05,0.025);
+    mySpeaker.PlayNote(500.0,0.05,0.025);
+}
+
+void PlayClearSound()
+{
+    mySpeaker.PlayNote(900.0,0.2,0.025);
+    mySpeaker.PlayNote(1000.0,0.2,0.025);
+    mySpeaker.PlayNote(1100.0,0.2,0.025);
+    mySpeaker.PlayNote(1000.0,0.2,0.025);
+    mySpeaker.PlayNote(9000.0,0.2,0.025);
+} */
+
+int RandomGen(char range)
+{
+    pc.printf("%c",range);
+    while(!pc.readable()) wait(0.5);
+    char buffer[4];
+    pc.gets(buffer,4);
+    int i = buffer[0]-'0';
+    return i;
+}
+
+int main()
+{
+    //hardware setup    // FIX
+    LEFT_KEY.mode(PullUp);
+    RIGHT_KEY.mode(PullUp);
+    ROTATE_KEY.mode(PullUp);
+    DOWN_KEY.mode(PullUp);
+    
+    LEFT_KEY.attach_deasserted(&input_left);
+    RIGHT_KEY.attach_deasserted(&input_right);
+    ROTATE_KEY.attach_deasserted(&input_rotate);
+    DOWN_KEY.attach_deasserted(&input_down);
+    
+    LEFT_KEY.setSampleFrequency();
+    RIGHT_KEY.setSampleFrequency();
+    ROTATE_KEY.setSampleFrequency();
+    DOWN_KEY.setSampleFrequency();  // FIX
+    uLCD.baudrate(3000000);
+    
+    //myShiftbrite.RGB(0,0,0);
+    //myShiftbrite.RGB(0,0,0);
+    
+    /* SD card used for Startup Image
+    sd.disk_initialize();   // ? might need to delete
+    uLCD.media_init();
+    uLCD.set_sector_address(0x001D, 0x7801);
+    uLCD.display_image(0,0);*/
+    
+    /*textLCD.cls();
+    textLCD.locate(0,0);
+    textLCD.printf("Waiting for PC...");*/
+    
+    pc.baud(9600);
+    pc.format(8,SerialBase::None,1);
+    pc.printf("0");
+    while(!pc.readable()) wait(0.5);
+    char buffer[4];
+    pc.gets(buffer,4);
+    /*
+    //wait for game start
+    textLCD.cls();
+    textLCD.locate(0,0);
+    textLCD.printf("TETRIS READY!!");
+    textLCD.locate(0,1);
+    textLCD.printf("PRESS ANY KEY...");
+    while(!gameStarted) wait(0.5);
+    PlayStartSound();
+    textLCD.cls();
+    textLCD.printf("Starting game   now...");
+    wait(2);
+    textLCD.cls();
+    textLCD.locate(0,0);
+    textLCD.printf("Points");
+    textLCD.locate(0,1);
+    textLCD.printf("Cleared Line");*/
+    
+    //Thread t1(GameStartLight);
+    //game classes init
+    bool isGameOver = false;
+    int mScreenHeight = 128;
+    Pieces mPieces;
+    Board mBoard (&mPieces, mScreenHeight);
+    int a = RandomGen('a');
+    int b = RandomGen('b');
+    int c = RandomGen('a');
+    int d = RandomGen('b');
+    Game mGame (&mBoard, &mPieces, mScreenHeight, &uLCD,a,b,c,d);
+
+
+    // ----- Main Loop -----
+    int prevX=0;
+    int prevY=0;
+    int prevPiece=-1;
+    int prevRot=0;
+    Timer timer;
+    timer.start();
+    key_input=0;
+    bool needErase = false;
+    uLCD.cls();
+    while (1)
+    {
+        if(isGameOver) 
+        {
+            wait(1);
+            continue;
+        }
+        // ----- Draw ----
+        if(needErase)
+        {
+            mGame.ErasePiece(prevX,prevY,prevPiece,prevRot);
+            needErase=false;
+        }
+        mGame.DrawScene();
+        
+        prevX=mGame.mPosX;
+        prevY=mGame.mPosY;
+        prevPiece=mGame.mPiece;
+        prevRot=mGame.mRotation;
+
+        // ----- Input -----
+        switch (key_input)
+        {
+            case (2): //right
+            {
+                if (mBoard.IsPossibleMovement (mGame.mPosX + 1, mGame.mPosY, mGame.mPiece, mGame.mRotation))
+                    {mGame.mPosX++;needErase=true;}
+                break;
+            }
+
+            case (1): //left
+            {
+                if (mBoard.IsPossibleMovement (mGame.mPosX - 1, mGame.mPosY, mGame.mPiece, mGame.mRotation))
+                    {mGame.mPosX--;needErase=true;}  
+                break;
+            }
+
+            case (4)://down
+            {
+                // Check collision from up to down
+                while (mBoard.IsPossibleMovement(mGame.mPosX, mGame.mPosY, mGame.mPiece, mGame.mRotation)) { mGame.mPosY++; }
+                needErase=true;
+                mBoard.StorePiece (mGame.mPosX, mGame.mPosY - 1, mGame.mPiece, mGame.mRotation);
+                mGame.AddPoints(SinglePiecePoints);
+                int linesDeleted = mBoard.DeletePossibleLines ();
+                if(linesDeleted>0)
+                {
+                    mGame.AddClearedLines(linesDeleted);
+                    mGame.AddPoints(LineClearPoints*linesDeleted);
+                    //Thread t1(FlashLight);
+                    //PlayClearSound();
+                    clear_board();
+                }
+                UpdateGameStatus(mGame.GetPoints(),mGame.GetClearedLines());
+
+                if (mBoard.IsGameOver())
+                {
+                    isGameOver=true;
+                    uLCD.cls();
+                    
+                    // FIX add Game Over mechanic
+                    
+                    //uLCD.media_init();
+                    //uLCD.set_sector_address(0x001D, 0x7842);
+                    //uLCD.display_image(0,0);
+                    //Thread t2(GameOverLight);
+                    //PlayOverSound();
+                    
+                }
+                
+                if(!isGameOver)
+                {
+                mGame.CreateNewPiece(RandomGen('a'),RandomGen('b'));
+                clear_next_piece();
+                }
+                break;
+            }
+
+            case (3)://rotate
+            {
+                if (mBoard.IsPossibleMovement (mGame.mPosX, mGame.mPosY, mGame.mPiece, (mGame.mRotation + 1) % 4))
+                    {mGame.mRotation = (mGame.mRotation + 1) % 4;needErase=true;}
+                break;
+            }
+            
+            case (0):{break;}
+        }
+        key_input = 0;
+        
+        // ----- Vertical movement -----
+
+        if(timer.read_ms()>WAIT_TIME)
+        {
+            needErase=true;
+            if(!isGameOver)
+            {
+                if (mBoard.IsPossibleMovement (mGame.mPosX, mGame.mPosY + 1, mGame.mPiece, mGame.mRotation))
+                {
+                    mGame.mPosY++;
+                }
+                else
+                {
+                    mBoard.StorePiece (mGame.mPosX, mGame.mPosY, mGame.mPiece, mGame.mRotation);
+                    mGame.AddPoints(SinglePiecePoints);
+                    int linesDeleted = mBoard.DeletePossibleLines ();
+                    if(linesDeleted>0)
+                    {
+                        mGame.AddClearedLines(linesDeleted);
+                        mGame.AddPoints(LineClearPoints*linesDeleted);
+                        //Thread t1(FlashLight);
+                        //PlayClearSound();
+                        clear_board();
+                    }
+                    UpdateGameStatus(mGame.GetPoints(),mGame.GetClearedLines());
+                        
+                    if (mBoard.IsGameOver())
+                    {
+                        isGameOver=true;
+                        uLCD.cls();
+                        
+                        // FIX add Game Over mechanic
+                        
+                        //uLCD.media_init();
+                        //uLCD.set_sector_address(0x001D, 0x7842);
+                        //uLCD.display_image(0,0);
+                        //Thread t2(GameOverLight);
+                        //PlayOverSound();
+                    }
+                    
+                    if(!isGameOver)
+                    {
+                    mGame.CreateNewPiece(RandomGen('a'),RandomGen('b'));
+                    clear_next_piece();
+                    }
+                }
+            }
+            timer.reset();
+        }
+            wait(0.1);
+    }
+}