mis en place la PR de simon sur les couleurs

This commit is contained in:
2025-02-28 18:42:04 +01:00
parent f0f391ade6
commit 26f501f7e8
29 changed files with 713 additions and 665 deletions

View File

@@ -5,13 +5,16 @@
#include "Bag.h"
#include "LineClear.h"
#include <Vector>
#include <Set>
#include <vector>
#include <set>
#include <memory>
GameBoard::GameBoard(int boardWidth, int boardHeight, const std::vector<Piece>& bag, int nextQueueLength) : board(boardWidth, boardHeight), generator(bag), nextQueueLength(nextQueueLength) {
// initialize queue
GameBoard::GameBoard(int boardWidth, int boardHeight, const std::vector<Piece>& bag, int nextQueueLength) :
board(boardWidth, boardHeight),
generator(bag),
nextQueueLength(nextQueueLength) {
this->nextQueue.clear();
for (int i = 0; i < nextQueueLength; i++) {
this->nextQueue.push_back(this->generator.getNext());
@@ -19,8 +22,7 @@ GameBoard::GameBoard(int boardWidth, int boardHeight, const std::vector<Piece>&
}
bool GameBoard::moveLeft() {
// check if the piece can be moved one cell left
if (this->isActivePieceInWall(Cell{-1, 0})) {
if (this->isActivePieceInWall(Position{-1, 0})) {
return false;
}
else {
@@ -31,8 +33,7 @@ bool GameBoard::moveLeft() {
}
bool GameBoard::moveRight() {
// check if the piece can be moved one cell right
if (this->isActivePieceInWall(Cell{1, 0})) {
if (this->isActivePieceInWall(Position{1, 0})) {
return false;
}
else {
@@ -43,8 +44,7 @@ bool GameBoard::moveRight() {
}
bool GameBoard::moveDown() {
// check if the piece can be moved one cell down
if (this->isActivePieceInWall(Cell{0, -1})) {
if (this->isActivePieceInWall(Position{0, -1})) {
return false;
}
else {
@@ -55,36 +55,35 @@ bool GameBoard::moveDown() {
}
bool GameBoard::rotate(Rotation rotation) {
// copy the original piece before rotating it
Piece stored = *this->activePiece;
this->rotate(rotation);
// check if the piece can rotate
// before trying to kick, check if the piece can rotate without kicking
if (!this->isActivePieceInWall()) {
this->isLastMoveKick = false;
return true;
}
// get the list of cells that touches the original piece
std::set<Cell> safeCells;
for (Cell cell : stored.getPositions()) {
Cell cellInGrid(cell + this->activePiecePosition);
safeCells.insert(cellInGrid);
safeCells.insert(cellInGrid + Cell{0, 1});
safeCells.insert(cellInGrid + Cell{1, 0});
safeCells.insert(cellInGrid + Cell{0, -1});
safeCells.insert(cellInGrid + Cell{-1, 0});
// get the list of positions that touches the original piece
std::set<Position> safePositions;
for (Position position : stored.getPositions()) {
Position positionInGrid(position + this->activePiecePosition);
safePositions.insert(positionInGrid);
safePositions.insert(positionInGrid + Position{0, 1});
safePositions.insert(positionInGrid + Position{1, 0});
safePositions.insert(positionInGrid + Position{0, -1});
safePositions.insert(positionInGrid + Position{-1, 0});
}
// try kicking the piece down
bool suceeded = this->tryKicking(true, safeCells);
bool suceeded = this->tryKicking(true, safePositions);
if (suceeded) {
this->isLastMoveKick = true;
return true;
}
// if it doesn't work try kicking the piece up
suceeded = this->tryKicking(false, safeCells);
suceeded = this->tryKicking(false, safePositions);
if (suceeded) {
this->isLastMoveKick = true;
return true;
@@ -95,8 +94,8 @@ bool GameBoard::rotate(Rotation rotation) {
return false;
}
bool GameBoard::tryKicking(bool testingBottom, const std::set<Cell>& safeCells) {
// we try from the original height of the piece, moving vertically as long as the kicked piece touches the original
bool GameBoard::tryKicking(bool testingBottom, const std::set<Position>& safePositions) {
// we try from the original height of the piece, moving vertically as long as the kicked piece touches the original at least once on this row
bool overlapsVertically = true;
int j = 0;
do {
@@ -107,13 +106,11 @@ bool GameBoard::tryKicking(bool testingBottom, const std::set<Cell>& safeCells)
do {
// check right before right arbitrarly, we don't decide this with rotations since it would still be arbitrary with 180° rotations
if (overlapsRight) {
Cell shift{+i, j};
// the kicked position must touch the original piece
if (!this->activePieceOverlapsOneCell(safeCells, shift)) {
Position shift{+i, j};
if (!this->activePieceOverlapsOnePosition(safePositions, shift)) {
overlapsLeft = false;
}
else {
// if the position is valid we place the active piece there
if (!this->isActivePieceInWall(shift)) {
this->activePiecePosition += shift;
return true;
@@ -123,8 +120,8 @@ bool GameBoard::tryKicking(bool testingBottom, const std::set<Cell>& safeCells)
// do the same on the left side
if (overlapsLeft) {
Cell shift{-i, j};
if (!this->activePieceOverlapsOneCell(safeCells, shift)) {
Position shift{-i, j};
if (!this->activePieceOverlapsOnePosition(safePositions, shift)) {
overlapsLeft = false;
}
else {
@@ -138,12 +135,10 @@ bool GameBoard::tryKicking(bool testingBottom, const std::set<Cell>& safeCells)
i++;
} while (overlapsLeft && overlapsRight);
// test if no position touched the original piece
if (i == 1) {
overlapsVertically = false;
}
// move one line up or down
(testingBottom) ? j-- : j++;
} while (overlapsVertically);
@@ -151,15 +146,11 @@ bool GameBoard::tryKicking(bool testingBottom, const std::set<Cell>& safeCells)
}
bool GameBoard::hold(Rotation initialRotation) {
// swap with held piece
std::swap(this->activePiece, this->heldPiece);
// if it's the first time holding try the next piece
bool isFirstTimeHolding = false;
if (this->activePiece == nullptr) {
isFirstTimeHolding = true;
// if no pieces in next queue look at what the next would be
bool isFirstTimeHolding = (this->activePiece == nullptr);
if (isFirstTimeHolding) {
// try with the next piece in queue since there is no piece in the hold box yet
if (this->nextQueueLength == 0) {
this->activePiece = std::make_shared<Piece>(this->generator.lookNext());
}
@@ -168,10 +159,8 @@ bool GameBoard::hold(Rotation initialRotation) {
}
}
// set the spawned piece to the correct position
this->goToSpawnPosition();
// apply initial rotation
Piece stored = *this->activePiece;
this->rotate(initialRotation);
@@ -189,14 +178,10 @@ bool GameBoard::hold(Rotation initialRotation) {
}
}
// if it's the first time holding, confirm we keep this piece
if (isFirstTimeHolding) {
if (this->nextQueueLength == 0) {
this->generator.getNext();
}
else {
this->spawnNextPiece();
}
// confirm we keep the piece we tried with
this->nextQueue.push_back(this->generator.getNext());
this->nextQueue.erase(this->nextQueue.begin());
}
// this piece has done nothing yet
@@ -206,39 +191,34 @@ bool GameBoard::hold(Rotation initialRotation) {
}
bool GameBoard::spawnNextPiece() {
// add a piece to the queue
// generate a new piece
this->nextQueue.push_back(this->generator.getNext());
// get next piece from queue
this->activePiece = std::make_shared<Piece>(this->nextQueue.front());
this->nextQueue.erase(this->nextQueue.begin());
// set the spawned piece to the correct position
this->goToSpawnPosition();
// this piece has done nothing yet
this->isLastMoveKick = false;
// returns wheter the piece can spawn correctly
return !this->isActivePieceInWall();
}
bool GameBoard::touchesGround() {
return this->isActivePieceInWall(Cell{0, -1});
return this->isActivePieceInWall(Position{0, -1});
}
LineClear GameBoard::lockPiece() {
// check if the piece is locked in place
bool isLocked = (this->isActivePieceInWall(Cell{0, 1}) && this->isActivePieceInWall(Cell{1, 0}) &&
this->isActivePieceInWall(Cell{-1, 0}) && this->isActivePieceInWall(Cell{0, -1}));
bool isLockedInPlace = (this->isActivePieceInWall(Position{0, 1}) && this->isActivePieceInWall(Position{1, 0})
&& this->isActivePieceInWall(Position{-1, 0}) && this->isActivePieceInWall(Position{0, -1}));
// put the piece in the board
for (Cell cell : this->activePiece->getPositions()) {
this->board.addBlock(cell + this->activePiecePosition, this->activePiece->getColor());
for (Position position : this->activePiece->getPositions()) {
this->board.addBlock(position + this->activePiecePosition, this->activePiece->getBlockType());
}
// check for lines to clear
return LineClear{this->board.clearRows(), isLocked, (!isLocked) && this->isLastMoveKick};
return LineClear{this->board.clearRows(), isLockedInPlace, (!isLockedInPlace) && this->isLastMoveKick};
}
Board GameBoard::getBoard() const {
@@ -249,7 +229,7 @@ Piece GameBoard::getActivePiece() const {
return *this->activePiece;
}
Cell GameBoard::getActivePiecePosition() const {
Position GameBoard::getActivePiecePosition() const {
return this->activePiecePosition;
}
@@ -261,31 +241,28 @@ std::vector<Piece> GameBoard::getNextPieces() const {
return this->nextQueue;
}
bool GameBoard::isActivePieceInWall(const Cell& shift) const {
// check if every cell of the active piece is in an empty spot
for (Cell cell : this->activePiece->getPositions()) {
if (this->board.getBlock(cell + this->activePiecePosition + shift) != NOTHING) return true;
bool GameBoard::isActivePieceInWall(const Position& shift) const {
for (Position position : this->activePiece->getPositions()) {
if (this->board.getBlock(position + this->activePiecePosition + shift) != NOTHING) return true;
}
return false;
}
bool GameBoard::activePieceOverlapsOneCell(const std::set<Cell>& safeCells, const Cell& shift) const {
// check if one cell of the translated active piece overlaps with one cell of the given piece set
for (Cell cell : this->activePiece->getPositions()) {
if (safeCells.contains(cell + shift)) return true;
bool GameBoard::activePieceOverlapsOnePosition(const std::set<Position>& safePositions, const Position& shift) const {
for (Position position : this->activePiece->getPositions()) {
if (safePositions.contains(position + this->activePiecePosition + shift)) return true;
}
return false;
}
void GameBoard::goToSpawnPosition() {
// get the lowest cell of the piece
int lowestCell = this->activePiece->getLength() - 1;
for (Cell cell : this->activePiece->getPositions()) {
if (cell.y < lowestCell) lowestCell = cell.y;
int lowestPosition = this->activePiece->getLength() - 1;
for (Position position : this->activePiece->getPositions()) {
if (position.y < lowestPosition) lowestPosition = position.y;
}
// set the piece one line above the board
this->activePiecePosition.y = this->board.getBaseHeight() - lowestCell;
this->activePiecePosition.y = this->board.getBaseHeight() - lowestPosition;
// center the piece horizontally, biased towards left
this->activePiecePosition.x = (this->board.getWidth() - this->activePiece->getLength()) / 2;
@@ -294,15 +271,13 @@ void GameBoard::goToSpawnPosition() {
std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
// print over the board (only the active piece if it is there)
if (gameboard.activePiece != nullptr) {
Block pieceBlockType = gameboard.activePiece->getBlockType();
os << getConsoleColorCode(pieceBlockType);
// change to the color of the active piece
Color pieceColor = gameboard.activePiece->getColor();
os << COLOR_CODES[pieceColor];
// print only the cell were the active piece is
// print only the position were the active piece is
for (int y = gameboard.activePiecePosition.y + gameboard.activePiece->getLength() - 1; y >= gameboard.board.getBaseHeight(); y--) {
for (int x = 0; x < gameboard.board.getWidth(); x++) {
bool hasActivePiece = gameboard.activePiece->getPositions().contains(Cell{x, y} - gameboard.activePiecePosition);
bool hasActivePiece = gameboard.activePiece->getPositions().contains(Position{x, y} - gameboard.activePiecePosition);
if (hasActivePiece) {
os << "*";
}
@@ -315,21 +290,19 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
}
// print the board
Color pieceColor = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getColor();
Block pieceBlockType = (gameboard.activePiece == nullptr) ? NOTHING : gameboard.activePiece->getBlockType();
for (int y = gameboard.board.getBaseHeight() - 1; y >= 0; y--) {
for (int x = 0; x < gameboard.board.getWidth(); x++) {
bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->getPositions().contains(Cell{x, y} - gameboard.activePiecePosition);
bool hasActivePiece = (gameboard.activePiece == nullptr) ? false : gameboard.activePiece->getPositions().contains(Position{x, y} - gameboard.activePiecePosition);
// if the active piece is on this cell, print it
// the active piece takes visual priority over the board
if (hasActivePiece) {
os << COLOR_CODES[pieceColor];
os << getConsoleColorCode(pieceBlockType);
os << "*";
}
// else print the cell of the board
else {
Color block = gameboard.board.getBlock(Cell{x, y});
os << COLOR_CODES[block];
Block block = gameboard.board.getBlock(Position{x, y});
os << getConsoleColorCode(block);
if (block != NOTHING) {
os << "*";
}
@@ -341,7 +314,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
os << std::endl;
}
// print held piece
// print hold box
os << "Hold:" << std::endl;
if (!(gameboard.heldPiece == nullptr)) {
os << *gameboard.heldPiece;
@@ -353,8 +326,7 @@ std::ostream& operator<<(std::ostream& os, const GameBoard& gameboard) {
os << piece;
}
// reset console color
os << COLOR_RESET;
os << getResetConsoleColorCode();
return os;
}