8x8 Tetris
Tetris style game on an 8x8 LED
Components and supplies
1
MAX7219 8x8 LED matrix
3
Push Button
1
Breadboard 100x160
1
10 jumper wires 150mm male
Tools and machines
1
Arduino Web Editor
Apps and platforms
1
Arduino IDE 2.0 (beta)
Project description
Code
tetris
js
completed tetris style code
1#include <LedControl.h> 2 3// Pin configurations 4const int DIN_PIN = 12; // Data in pin 5const int CS_PIN = 10; // Chip Select pin 6const int CLK_PIN = 11; // Clock pin 7const int LEFT_BUTTON_PIN = 2; // Button to move left 8const int RIGHT_BUTTON_PIN = 3; // Button to move right 9const int ROTATE_BUTTON_PIN = 7; // Button to rotate 10 11LedControl lc = LedControl(DIN_PIN, CLK_PIN, CS_PIN, 1); // Initialize LedControl 12 13// Tetris game variables 14const int MATRIX_WIDTH = 8; 15const int MATRIX_HEIGHT = 8; 16uint8_t currentPiece[3][3]; // Current tetris piece 17int currentX, currentY; // Current position of the piece 18unsigned long lastDropTime; // Time of the last fall. 19const int dropInterval = 1000; // Interval before fall in ms 20unsigned long lastRotateTime; // Time since the last turn. 21const int rotateDebounceTime = 300; // Debounce time for rotation in ms 22unsigned long startTime; // Time for the game to begin 23bool gameOver = false; // Game ended status 24int score = 0; // Score 25 26// Keep the blocked sections. 27bool board[MATRIX_HEIGHT][MATRIX_WIDTH] = {false}; 28 29// Define some Tetris shapes. 30const uint8_t shapes[7][3][3] = { 31 {{1, 1, 1}, {0, 0, 0}, {0, 0, 0}}, // I shape 32 {{1, 1, 1}, {0, 1, 0}, {0, 0, 0}}, // T shape 33 {{1, 1, 0}, {0, 1, 1}, {0, 0, 0}}, // Z shape 34 {{1, 0, 0}, {1, 1, 1}, {0, 0, 0}}, // L shape 35 {{1, 1, 0}, {1, 1, 0}, {0, 0, 0}}, // O shape 36 {{0, 1, 1}, {1, 1, 0}, {0, 0, 0}}, // Z shape 37 {{0, 0, 1}, {1, 1, 1}, {0, 0, 0}}, // L shape 38}; 39 40void setup() { 41 lc.shutdown(0, false); // Start MAX7219 42 lc.setIntensity(0, 8); // Set brightness level (0 is min, 15 is max) 43 lc.clearDisplay(0); // Clear the display. 44 45 pinMode(LEFT_BUTTON_PIN, INPUT_PULLUP); 46 pinMode(RIGHT_BUTTON_PIN, INPUT_PULLUP); 47 pinMode(ROTATE_BUTTON_PIN, INPUT_PULLUP); 48 49 // Spawn random piece 50 spawnPiece(); 51 lastDropTime = millis(); // Start the timer for automatic drop 52 lastRotateTime = 0; // Initialize last rotate time 53 startTime = millis(); // Start the timer to survive. 54} 55 56void loop() { 57 if (gameOver) { 58 displayGameOver(); // Show final result 59 return; 60 } 61 62 // Process buttons with lower sensitivity. 63 static unsigned long lastLeftPress = 0; 64 static unsigned long lastRightPress = 0; 65 66 if (digitalRead(LEFT_BUTTON_PIN) == LOW && millis() - lastLeftPress > 300) { 67 movePiece(-1); // Move to the left 68 lastLeftPress = millis(); // Update from the last press. 69 } 70 if (digitalRead(RIGHT_BUTTON_PIN) == LOW && millis() - lastRightPress > 300) { 71 movePiece(1); // Move to the right 72 lastRightPress = millis(); // Update the last press time. 73 } 74 75 // Check if the rotary button is pressed and the debounce time has elapsed. 76 if (digitalRead(ROTATE_BUTTON_PIN) == LOW && (millis() - lastRotateTime > rotateDebounceTime)) { 77 rotatePiece(); // Turn around. 78 lastRotateTime = millis(); // Update the latest turnaround time. 79 } 80 81 // Check if the piece should fall. 82 if (millis() - lastDropTime >= dropInterval) { 83 dropPiece(); // Let it fall 84 lastDropTime = millis(); // Reset the timer 85 } 86 87 // Update the display 88 drawBoard(); 89 delay(100); // Check time 90} 91 92// Function to generate new piece 93void spawnPiece() { 94 currentX = MATRIX_WIDTH / 2 - 1; // start in the middle 95 currentY = 0; // start at the top 96 int randShape = random(0, 7); // choose random shape 97 memcpy(currentPiece, shapes[randShape], sizeof(currentPiece)); // copy piece 98} 99 100// Move current piece 101void movePiece(int dx) { 102 if (canMove(currentX + dx, currentY)) { 103 currentX += dx; // change x position 104 } 105} 106 107// Function to drop the piece 108void dropPiece() { 109 // Check if the piece can fall 110 if (canMove(currentX, currentY + 1)) { 111 currentY++; // increase y position if it can fall 112 } else { 113 addPieceToBoard(); // add piece to board 114 checkForFullRows(); // Check for full rows 115 // Spawn new piece 116 spawnPiece(); 117 // Check if piece has hit top 118 if (!canMove(currentX, currentY)) { 119 gameOver = true; // set game over status 120 } 121 } 122} 123 124// Function to draw board 125void drawBoard() { 126 lc.clearDisplay(0); 127 // Draw board 128 for (int y = 0; y < MATRIX_HEIGHT; y++) { 129 for (int x = 0; x < MATRIX_WIDTH; x++) { 130 if (board[y][x]) { 131 lc.setLed(0, y, x, true); 132 } 133 } 134 } 135 drawPiece(); // Draw current piece 136} 137 138// Function to draw the current piece 139void drawPiece() { 140 for (int y = 0; y < 3; y++) { 141 for (int x = 0; x < 3; x++) { 142 if (currentPiece[y][x]) { 143 lc.setLed(0, currentY + y, currentX + x, true); // draw current piece on board 144 } 145 } 146 } 147} 148 149// Function to add piece to board 150void addPieceToBoard() { 151 for (int y = 0; y < 3; y++) { 152 for (int x = 0; x < 3; x++) { 153 if (currentPiece[y][x]) { 154 board[currentY + y][currentX + x] = true; // Mark the board 155 } 156 } 157 } 158} 159 160// Function to reset game 161void resetGame() { 162 memset(board, false, sizeof(board)); // Reset the board 163 spawnPiece(); // Spawn new piece 164 currentY = 0; // reset the y position to the top 165 gameOver = false; // set game over to false 166 score = 0; // Reset the score 167} 168 169// Function to check if movement is possible 170bool canMove(int x, int y) { 171 for (int i = 0; i < 3; i++) { 172 for (int j = 0; j < 3; j++) { 173 if (currentPiece[i][j]) { 174 int newX = x + j; 175 int newY = y + i; 176 if (newX < 0 || newX >= MATRIX_WIDTH || newY >= MATRIX_HEIGHT) { 177 return false; // Outside the borders 178 } 179 if (newY >= 0 && board[newY][newX]) { 180 return false; // Collision with an existing block 181 } 182 } 183 } 184 } 185 return true; // movement is possible 186} 187 188// Function to rotate piece 189void rotatePiece() { 190 uint8_t tempPiece[3][3]; // temporary storage for rotated piece 191 192 // Rotate piece 90 degrees 193 for (int i = 0; i < 3; i++) { 194 for (int j = 0; j < 3; j++) { 195 tempPiece[j][2 - i] = currentPiece[i][j]; // apply rotational logic 196 } 197 } 198 199 // Check if rotated position is possible and move if necessary 200 if (canMove(currentX, currentY)) { 201 memcpy(currentPiece, tempPiece, sizeof(currentPiece)); // update the current piece 202 } else if (canMove(currentX - 1, currentY)) { // try to move to the left 203 currentX -= 1; 204 memcpy(currentPiece, tempPiece, sizeof(currentPiece)); // Update the current piece 205 } else if (canMove(currentX + 1, currentY)) { // try to move to the right 206 currentX += 1; 207 memcpy(currentPiece, tempPiece, sizeof(currentPiece)); // Update the current piece 208 } 209} 210 211// Function to display end screen 212void displayGameOver() { 213 lc.clearDisplay(0); // clear the display 214 215 // Display the score (up to two digits) 216 String scoreStr = String(score); 217 if (scoreStr.length() > 2) { 218 scoreStr = scoreStr.substring(0, 2); // Limit to 2 digits 219 } 220 221 // Display the score (up to two digits) 222 for (int i = 0; i < scoreStr.length(); i++) { 223 int digit = scoreStr.charAt(i) - '0'; // Convert char to int 224 if (digit >= 0 && digit <= 9) { 225 displayDigit(digit, i); // Pass digit and position (i) 226 } 227 } 228 229 delay(2000); // Show the score for 2 seconds 230 231 resetGame(); // Reset the game 232} 233 234void displayDigit(int digit, int pos) { 235 const int digits[10][5][3] = { 236 {{1, 1, 1}, {1, 0, 1}, {1, 0, 1}, {1, 0, 1}, {1, 1, 1}}, // 0 237 {{0, 1, 0}, {1, 1, 0}, {0, 1, 0}, {0, 1, 0}, {1, 1, 1}}, // 1 238 {{1, 1, 1}, {0, 0, 1}, {1, 1, 1}, {1, 0, 0}, {1, 1, 1}}, // 2 239 {{1, 1, 1}, {0, 0, 1}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 3 240 {{1, 0, 1}, {1, 0, 1}, {1, 1, 1}, {0, 0, 1}, {0, 0, 1}}, // 4 241 {{1, 1, 1}, {1, 0, 0}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 5 242 {{1, 1, 1}, {1, 0, 0}, {1, 1, 1}, {1, 0, 1}, {1, 1, 1}}, // 6 243 {{1, 1, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}}, // 7 244 {{1, 1, 1}, {1, 0, 1}, {1, 1, 1}, {1, 0, 1}, {1, 1, 1}}, // 8 245 {{1, 1, 1}, {1, 0, 1}, {1, 1, 1}, {0, 0, 1}, {1, 1, 1}}, // 9 246}; 247 248 // Ensure the digit is valid 249 if (digit < 0 || digit > 9) { 250 return; // Invalid digit, exit 251 } 252 253 // Loop through the rows and columns of the selected digit's pattern 254 for (int row = 0; row < 5; row++) { 255 for (int col = 0; col < 3; col++) { 256 bool ledState = digits[digit][row][col]; // Get the LED state for the current position 257 258 // Adjust positioning to ensure digits don't overlap or cut off 259 lc.setLed(0, row, pos * 4 + col, ledState); // Place it at the correct position 260 } 261 } 262} 263 264// Function to check full rows 265void checkForFullRows() { 266 bool rowCleared = false; // Flag to track if any row is cleared 267 for (int y = MATRIX_HEIGHT - 1; y >= 0; y--) { 268 bool fullRow = true; 269 for (int x = 0; x < MATRIX_WIDTH; x++) { 270 if (!board[y][x]) { 271 fullRow = false; 272 break; 273 } 274 } 275 if (fullRow) { 276 rowCleared = true; // Mark that we cleared a row 277 // remove full row 278 for (int i = y; i > 0; i--) { 279 for (int j = 0; j < MATRIX_WIDTH; j++) { 280 board[i][j] = board[i - 1][j]; 281 } 282 } 283 // set top row to false 284 for (int j = 0; j < MATRIX_WIDTH; j++) { 285 board[0][j] = false; 286 } 287 score++; // Increase score for cleared row 288 y++; // Check the new row 289 } 290 } 291 292 // Only update score if a row is cleared 293}
Downloadable files
tetris code
completed tetris code
finaltetris.ino
Documentation
schematic
schematic for tetris game
Picture1.png

Comments
Only logged in users can leave comments