-
-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3711 from muebau/tetris-ai
Tetris AI usermod
- Loading branch information
Showing
11 changed files
with
1,313 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/****************************************************************************** | ||
* @file : gridbw.h | ||
* @brief : contains the tetris grid as binary so black and white version | ||
****************************************************************************** | ||
* @attention | ||
* | ||
* Copyright (c) muebau 2023 | ||
* All rights reserved.</center></h2> | ||
* | ||
****************************************************************************** | ||
*/ | ||
|
||
#ifndef __GRIDBW_H__ | ||
#define __GRIDBW_H__ | ||
|
||
#include <iterator> | ||
#include <vector> | ||
#include "pieces.h" | ||
|
||
using namespace std; | ||
|
||
class GridBW | ||
{ | ||
private: | ||
public: | ||
uint8_t width; | ||
uint8_t height; | ||
std::vector<uint32_t> pixels; | ||
|
||
GridBW(uint8_t width, uint8_t height): | ||
width(width), | ||
height(height), | ||
pixels(height) | ||
{ | ||
if (width > 32) | ||
{ | ||
throw std::invalid_argument("maximal width is 32"); | ||
} | ||
} | ||
|
||
void placePiece(Piece* piece, uint8_t x, uint8_t y) | ||
{ | ||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++) | ||
{ | ||
pixels[y + (row - (4 - piece->getRotation().height))] |= piece->getGridRow(x, row, width); | ||
} | ||
} | ||
|
||
void erasePiece(Piece* piece, uint8_t x, uint8_t y) | ||
{ | ||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++) | ||
{ | ||
pixels[y + (row - (4 - piece->getRotation().height))] &= ~piece->getGridRow(x, row, width); | ||
} | ||
} | ||
|
||
bool noCollision(Piece* piece, uint8_t x, uint8_t y) | ||
{ | ||
//if it touches a wall it is a collision | ||
if (x > (this->width - piece->getRotation().width) || y > this->height - piece->getRotation().height) | ||
{ | ||
return false; | ||
} | ||
|
||
for (uint8_t row = 4 - piece->getRotation().height; row < 4; row++) | ||
{ | ||
if (piece->getGridRow(x, row, width) & pixels[y + (row - (4 - piece->getRotation().height))]) | ||
{ | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
void findLandingPosition(Piece* piece) | ||
{ | ||
// move down until the piece bumps into some occupied pixels or the 'wall' | ||
while (noCollision(piece, piece->x, piece->landingY)) | ||
{ | ||
piece->landingY++; | ||
} | ||
|
||
//at this point the positon is 'in the wall' or 'over some occupied pixel' | ||
//so the previous position was the last correct one (clamped to 0 as minimum). | ||
piece->landingY = piece->landingY > 0 ? piece->landingY - 1 : 0; | ||
} | ||
|
||
void cleanupFullLines() | ||
{ | ||
uint8_t offset = 0; | ||
|
||
//from "height - 1" to "0", so from bottom row to top | ||
for (uint8_t row = height; row-- > 0; ) | ||
{ | ||
//full line? | ||
if (isLineFull(row)) | ||
{ | ||
offset++; | ||
pixels[row] = 0x0; | ||
continue; | ||
} | ||
|
||
if (offset > 0) | ||
{ | ||
pixels[row + offset] = pixels[row]; | ||
pixels[row] = 0x0; | ||
} | ||
} | ||
} | ||
|
||
bool isLineFull(uint8_t y) | ||
{ | ||
return pixels[y] == (uint32_t)((1 << width) - 1); | ||
} | ||
}; | ||
|
||
#endif /* __GRIDBW_H__ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
/****************************************************************************** | ||
* @file : gridcolor.h | ||
* @brief : contains the tetris grid as 8bit indexed color version | ||
****************************************************************************** | ||
* @attention | ||
* | ||
* Copyright (c) muebau 2023 | ||
* All rights reserved.</center></h2> | ||
* | ||
****************************************************************************** | ||
*/ | ||
|
||
#ifndef __GRIDCOLOR_H__ | ||
#define __GRIDCOLOR_H__ | ||
#include <stdint.h> | ||
#include <stdbool.h> | ||
#include <vector> | ||
#include "gridbw.h" | ||
#include "gridcolor.h" | ||
|
||
using namespace std; | ||
|
||
class GridColor | ||
{ | ||
private: | ||
public: | ||
uint8_t width; | ||
uint8_t height; | ||
GridBW gridBW; | ||
std::vector<uint8_t> pixels; | ||
|
||
GridColor(uint8_t width, uint8_t height): | ||
width(width), | ||
height(height), | ||
gridBW(width, height), | ||
pixels(width* height) | ||
{} | ||
|
||
void clear() | ||
{ | ||
for (uint8_t y = 0; y < height; y++) | ||
{ | ||
gridBW.pixels[y] = 0x0; | ||
for (int8_t x = 0; x < width; x++) | ||
{ | ||
*getPixel(x, y) = 0; | ||
} | ||
} | ||
} | ||
|
||
void placePiece(Piece* piece, uint8_t x, uint8_t y) | ||
{ | ||
for (uint8_t pieceY = 0; pieceY < piece->getRotation().height; pieceY++) | ||
{ | ||
for (uint8_t pieceX = 0; pieceX < piece->getRotation().width; pieceX++) | ||
{ | ||
if (piece->getPixel(pieceX, pieceY)) | ||
{ | ||
*getPixel(x + pieceX, y + pieceY) = piece->pieceData->colorIndex; | ||
} | ||
} | ||
} | ||
} | ||
|
||
void erasePiece(Piece* piece, uint8_t x, uint8_t y) | ||
{ | ||
for (uint8_t pieceY = 0; pieceY < piece->getRotation().height; pieceY++) | ||
{ | ||
for (uint8_t pieceX = 0; pieceX < piece->getRotation().width; pieceX++) | ||
{ | ||
if (piece->getPixel(pieceX, pieceY)) | ||
{ | ||
*getPixel(x + pieceX, y + pieceY) = 0; | ||
} | ||
} | ||
} | ||
} | ||
|
||
void cleanupFullLines() | ||
{ | ||
uint8_t offset = 0; | ||
//from "height - 1" to "0", so from bottom row to top | ||
for (uint8_t y = height; y-- > 0; ) | ||
{ | ||
if (gridBW.isLineFull(y)) | ||
{ | ||
offset++; | ||
for (uint8_t x = 0; x < width; x++) | ||
{ | ||
pixels[y * width + x] = 0; | ||
} | ||
continue; | ||
} | ||
|
||
if (offset > 0) | ||
{ | ||
if (gridBW.pixels[y]) | ||
{ | ||
for (uint8_t x = 0; x < width; x++) | ||
{ | ||
pixels[(y + offset) * width + x] = pixels[y * width + x]; | ||
pixels[y * width + x] = 0; | ||
} | ||
} | ||
} | ||
} | ||
gridBW.cleanupFullLines(); | ||
} | ||
|
||
uint8_t* getPixel(uint8_t x, uint8_t y) | ||
{ | ||
return &pixels[y * width + x]; | ||
} | ||
|
||
void sync() | ||
{ | ||
for (uint8_t y = 0; y < height; y++) | ||
{ | ||
gridBW.pixels[y] = 0x0; | ||
for (int8_t x = 0; x < width; x++) | ||
{ | ||
gridBW.pixels[y] <<= 1; | ||
if (*getPixel(x, y) != 0) | ||
{ | ||
gridBW.pixels[y] |= 0x1; | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
|
||
#endif /* __GRIDCOLOR_H__ */ |
Oops, something went wrong.