Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reset usermod TetrisAI back to initial version #3897

Merged
merged 10 commits into from
May 27, 2024
13 changes: 12 additions & 1 deletion usermods/TetrisAI_v2/gridbw.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GridBW
{
if (width > 32)
{
throw std::invalid_argument("maximal width is 32");
this->width = 32;
}
}

Expand Down Expand Up @@ -112,6 +112,17 @@ class GridBW
{
return pixels[y] == (uint32_t)((1 << width) - 1);
}

void reset()
{
if (width > 32)
{
width = 32;
}

pixels.clear();
pixels.resize(height);
}
};

#endif /* __GRIDBW_H__ */
8 changes: 8 additions & 0 deletions usermods/TetrisAI_v2/gridcolor.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ class GridColor
}
}
}

void reset()
{
gridBW.reset();
pixels.clear();
pixels.resize(width* height);
clear();
}
};

#endif /* __GRIDCOLOR_H__ */
4 changes: 2 additions & 2 deletions usermods/TetrisAI_v2/rating.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Rating
uint8_t fullLines;
uint16_t bumpiness;
uint16_t aggregatedHeight;
double score;
float score;
uint8_t width;
std::vector<uint8_t> lineHights;

Expand All @@ -57,7 +57,7 @@ class Rating
this->fullLines = 0;
this->bumpiness = 0;
this->aggregatedHeight = 0;
this->score = -DBL_MAX;
this->score = -FLT_MAX;
}
};

Expand Down
17 changes: 10 additions & 7 deletions usermods/TetrisAI_v2/readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Tetris AI effect usermod

This usermod brings you a effect brings a self playing Tetris game. The mod needs version 0.14 or above as it is based on matrix support. The effect was tested on an ESP32 with a WS2812B 16x16 matrix.
This usermod adds a self-playing Tetris game as an 'effect'. The mod requires version 0.14 or higher as it relies on matrix support. The effect was tested on an ESP32 4MB with a WS2812B 16x16 matrix.

Version 1.0

Expand All @@ -10,7 +10,7 @@ Just activate the usermod with `-D USERMOD_TETRISAI` and the effect will become

## Usage

It is best to set the background color to black, the border color to light grey and the game over color (foreground) to dark grey.
It is best to set the background color to black 🖤, the border color to light grey 🤍, the game over color (foreground) to dark grey 🩶, and color palette to 'Rainbow' 🌈.

### Sliders and boxes

Expand All @@ -19,15 +19,18 @@ It is best to set the background color to black, the border color to light grey
* speed: speed the game plays
* look ahead: how many pieces is the AI allowed to know the next pieces (0 - 2)
* intelligence: how good the AI will play
* Rotate color: make the colors shift (rotate) every few cicles
* Mistakes free: how many good moves between mistakes (if activated)
* Rotate color: make the colors shift (rotate) every few moves
* Mistakes free: how many good moves between mistakes (if enabled)

#### Checkboxes

* show next: if true a space of 5 pixels from the right is used to show the next pieces. The whole segment is used for the grid otherwise.
* show next: if true, a space of 5 pixels from the right will be used to show the next pieces. Otherwise the whole segment is used for the grid.
* show border: if true an additional column of 1 pixel is used to draw a border between the grid and the next pieces
* mistakes: if true the worst instead of the best move is choosen every few moves (read above)
* mistakes: if true, the worst decision will be made every few moves instead of the best (see above).

## Best results

If the speed is set to be a little bit faster than a good human could play with maximal intelligence and very few mistakes it makes people furious/happy at a party.
If the speed is set to be a little bit faster than a good human could play with maximal intelligence and very few mistakes it makes people furious/happy at a party 😉.

## Limits
The game grid is limited to a maximum width of 32 and a maximum height of 255 due to the internal structure of the code.
111 changes: 8 additions & 103 deletions usermods/TetrisAI_v2/tetrisai.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ class TetrisAI
{
private:
public:
double aHeight;
double fullLines;
double holes;
double bumpiness;
float aHeight;
float fullLines;
float holes;
float bumpiness;
bool findWorstMove = false;

uint8_t countOnes(uint32_t vector)
Expand Down Expand Up @@ -107,10 +107,10 @@ class TetrisAI
rating->score = (aHeight * (rating->aggregatedHeight)) + (fullLines * (rating->fullLines)) + (holes * (rating->holes)) + (bumpiness * (rating->bumpiness));
}

TetrisAI(): TetrisAI(-0.510066, 0.760666, -0.35663, -0.184483)
TetrisAI(): TetrisAI(-0.510066f, 0.760666f, -0.35663f, -0.184483f)
{}

TetrisAI(double aHeight, double fullLines, double holes, double bumpiness):
TetrisAI(float aHeight, float fullLines, float holes, float bumpiness):
aHeight(aHeight),
fullLines(fullLines),
holes(holes),
Expand Down Expand Up @@ -178,9 +178,9 @@ class TetrisAI
if(findWorstMove)
{
//init rating for worst
if(bestRating->score == -DBL_MAX)
if(bestRating->score == -FLT_MAX)
{
bestRating->score = DBL_MAX;
bestRating->score = FLT_MAX;
}

// update if we found a worse one
Expand All @@ -202,101 +202,6 @@ class TetrisAI
}
}
}

bool findBestMoveNonBlocking(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end, Rating* bestRating)
{
//vector with pieces
//for every piece
//for every
switch (expression)
{
case INIT:
break;

default:
break;
}
}

bool findBestMoveNonBlocking(GridBW grid, std::vector<Piece>::iterator start, std::vector<Piece>::iterator end, Rating* bestRating)
{
//INIT
grid.cleanupFullLines();
Rating curRating(grid.width);
Rating deeperRating(grid.width);
Piece piece = *start;

// for every rotation of the piece
piece.rotation = 0;

//HANDLE
while (piece.rotation < piece.pieceData->rotCount)
{
// put piece to top left corner
piece.x = 0;
piece.y = 0;

//test for every column
piece.x = 0;
while (piece.x <= grid.width - piece.getRotation().width)
{

//todo optimise by the use of the previous grids height
piece.landingY = 0;
//will set landingY to final position
grid.findLandingPosition(&piece);

// draw piece
grid.placePiece(&piece, piece.x, piece.landingY);

if(start == end - 1)
{
//at the deepest level
updateRating(grid, &curRating);
}
else
{
//go deeper to take another piece into account
findBestMove(grid, start + 1, end, &deeperRating);
curRating = deeperRating;
}

// eraese piece
grid.erasePiece(&piece, piece.x, piece.landingY);

if(findWorstMove)
{
//init rating for worst
if(bestRating->score == -DBL_MAX)
{
bestRating->score = DBL_MAX;
}

// update if we found a worse one
if (bestRating->score > curRating.score)
{
*bestRating = curRating;
(*start) = piece;
}
}
else
{
// update if we found a better one
if (bestRating->score < curRating.score)
{
*bestRating = curRating;
(*start) = piece;
}
}
piece.x++;
}
piece.rotation++;
}

//EXIT

return true;
}
};

#endif /* __AI_H__ */
8 changes: 6 additions & 2 deletions usermods/TetrisAI_v2/tetrisaigame.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class TetrisAIGame
uint8_t width;
uint8_t height;
uint8_t nLookAhead;
uint8_t nPieces;
TetrisBag bag;
GridColor grid;
TetrisAI ai;
Expand All @@ -65,6 +66,7 @@ class TetrisAIGame
width(width),
height(height),
nLookAhead(nLookAhead),
nPieces(nPieces),
bag(nPieces, 1, nLookAhead),
grid(width, height + 4),
ai(),
Expand Down Expand Up @@ -142,8 +144,10 @@ class TetrisAIGame

void reset()
{
grid.clear();
bag.init();
grid.width = width;
grid.height = height + 4;
grid.reset();
bag.reset();
}
};

Expand Down
11 changes: 11 additions & 0 deletions usermods/TetrisAI_v2/tetrisbag.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,15 @@ class TetrisBag
public:
uint8_t nPieces;
uint8_t nBagLength;
uint8_t queueLength;
uint8_t bagIdx;
std::vector<uint8_t> bag;
std::vector<Piece> piecesQueue;

TetrisBag(uint8_t nPieces, uint8_t nBagLength, uint8_t queueLength):
nPieces(nPieces),
nBagLength(nBagLength),
queueLength(queueLength),
bag(nPieces * nBagLength),
piecesQueue(queueLength)
{
Expand Down Expand Up @@ -95,6 +97,15 @@ class TetrisBag
std::rotate(piecesQueue.begin(), piecesQueue.begin() + 1, piecesQueue.end());
piecesQueue[piecesQueue.size() - 1] = Piece(idx % nPieces);
}

void reset()
{
bag.clear();
bag.resize(nPieces * nBagLength);
piecesQueue.clear();
piecesQueue.resize(queueLength);
init();
}
};

#endif /* __TETRISBAG_H__ */
31 changes: 19 additions & 12 deletions usermods/TetrisAI_v2/usermod_v2_tetrisai.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ typedef struct TetrisAI_data
uint8_t colorOffset;
uint8_t colorInc;
uint8_t mistaceCountdown;
uint16_t segcols;
uint16_t segrows;
} tetrisai_data;

void drawGrid(TetrisAIGame* tetris, TetrisAI_data* tetrisai_data)
Expand Down Expand Up @@ -116,12 +118,15 @@ uint16_t mode_2DTetrisAI()
//range 0 - 16
tetrisai_data->colorInc = SEGMENT.custom2 >> 4;

if (!tetrisai_data->tetris || (tetrisai_data->tetris.nLookAhead != nLookAhead
if (tetrisai_data->tetris.nLookAhead != nLookAhead
|| tetrisai_data->segcols != cols
|| tetrisai_data->segrows != rows
|| tetrisai_data->showNext != SEGMENT.check1
|| tetrisai_data->showBorder != SEGMENT.check2
)
)
)
{
tetrisai_data->segcols = cols;
tetrisai_data->segrows = rows;
tetrisai_data->showNext = SEGMENT.check1;
tetrisai_data->showBorder = SEGMENT.check2;

Expand All @@ -143,35 +148,37 @@ uint16_t mode_2DTetrisAI()
}

tetrisai_data->tetris = TetrisAIGame(gridWidth, gridHeight, nLookAhead, piecesData, numPieces);
tetrisai_data->tetris.state = TetrisAIGame::States::INIT;
SEGMENT.fill(SEGCOLOR(1));
}

if (tetrisai_data->intelligence != SEGMENT.custom1)
{
tetrisai_data->intelligence = SEGMENT.custom1;
double dui = 0.2 - (0.2 * (tetrisai_data->intelligence / 255.0));
float dui = 0.2f - (0.2f * (tetrisai_data->intelligence / 255.0f));

tetrisai_data->tetris.ai.aHeight = -0.510066 + dui;
tetrisai_data->tetris.ai.fullLines = 0.760666 - dui;
tetrisai_data->tetris.ai.holes = -0.35663 + dui;
tetrisai_data->tetris.ai.bumpiness = -0.184483 + dui;
tetrisai_data->tetris.ai.aHeight = -0.510066f + dui;
tetrisai_data->tetris.ai.fullLines = 0.760666f - dui;
tetrisai_data->tetris.ai.holes = -0.35663f + dui;
tetrisai_data->tetris.ai.bumpiness = -0.184483f + dui;
}

if (tetrisai_data->tetris.state == TetrisAIGame::ANIMATE_MOVE)
{
if (millis() - tetrisai_data->lastTime > msDelayMove)

if (strip.now - tetrisai_data->lastTime > msDelayMove)
{
drawGrid(&tetrisai_data->tetris, tetrisai_data);
tetrisai_data->lastTime = millis();
tetrisai_data->lastTime = strip.now;
tetrisai_data->tetris.poll();
}
}
else if (tetrisai_data->tetris.state == TetrisAIGame::ANIMATE_GAME_OVER)
{
if (millis() - tetrisai_data->lastTime > msDelayGameOver)
if (strip.now - tetrisai_data->lastTime > msDelayGameOver)
{
drawGrid(&tetrisai_data->tetris, tetrisai_data);
tetrisai_data->lastTime = millis();
tetrisai_data->lastTime = strip.now;
tetrisai_data->tetris.poll();
}
}
Expand Down