ajouté interface textuelle
This commit is contained in:
323
src/TextUI/TextApp.cpp
Normal file
323
src/TextUI/TextApp.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
#include "TextApp.h"
|
||||
|
||||
#include "../Core/Menu.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
|
||||
static const int FRAMES_PER_INPUT = FRAMES_PER_SECOND / 2;
|
||||
static const int MAXIMUM_PIECE_SIZE = 10;
|
||||
static const int DEFAULT_PIECE_SIZE = 4;
|
||||
static const int MAXIMUM_BOARD_WIDTH = 30;
|
||||
static const int MAXIMYM_BOARD_HEIGHT = 40;
|
||||
static const Gamemode DEFAULT_GAMEMODE = SPRINT;
|
||||
|
||||
|
||||
TextApp::TextApp() {
|
||||
this->defaultKeybinds();
|
||||
|
||||
this->gameMenu.getPiecesList().loadPieces(MAXIMUM_PIECE_SIZE);
|
||||
this->gameMenu.getPiecesList().selectAllPieces(DEFAULT_PIECE_SIZE);
|
||||
|
||||
this->gameMenu.getPlayerControls().setDAS(FRAMES_PER_INPUT - 1);
|
||||
this->gameMenu.getPlayerControls().setARR(FRAMES_PER_INPUT);
|
||||
this->gameMenu.getPlayerControls().setSDR(0);
|
||||
}
|
||||
|
||||
void TextApp::run() {
|
||||
bool quit = false;
|
||||
std::string answer;
|
||||
int selectedAnswer = 0;
|
||||
while (!quit) {
|
||||
std::cout << "\n\n\n";
|
||||
std::cout << "===| WELCOME TO JMINOS! |===" << std::endl;
|
||||
std::cout << "1- Change pieces" << std::endl;
|
||||
std::cout << "2- Change board" << std::endl;
|
||||
std::cout << "3- See controls" << std::endl;
|
||||
std::cout << "4- Start game" << std::endl;
|
||||
std::cout << "5- Quit" << std::endl;
|
||||
std::cout << "Choice: ";
|
||||
std::getline(std::cin, answer);
|
||||
try {
|
||||
selectedAnswer = std::stoi(answer);
|
||||
}
|
||||
catch (std::exception ignored) {}
|
||||
|
||||
switch (selectedAnswer) {
|
||||
case 1 : {this->choosePieces(); break;}
|
||||
case 2 : {this->chooseBoardSize(); break;}
|
||||
case 3 : {this->seeKeybinds(); break;}
|
||||
case 4 : {this->startGame(); break;}
|
||||
case 5 : {quit = true; break;}
|
||||
default : std::cout << "Invalid answer!" << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << "===| SEE YA NEXT TIME! |===";
|
||||
}
|
||||
|
||||
void TextApp::choosePieces() {
|
||||
std::cout << "\n\n\n";
|
||||
std::cout << "Choose which piece sizes to play with (from 1 to " << MAXIMUM_PIECE_SIZE << "), separate mutltiple sizes with blank spaces." << std::endl;
|
||||
std::cout << "Choice: ";
|
||||
std::string answer;
|
||||
std::getline(std::cin, answer);
|
||||
|
||||
this->gameMenu.getPiecesList().unselectAll();
|
||||
std::cout << "Selected pieces of sizes:";
|
||||
std::stringstream answerStream(answer);
|
||||
for (std::string size; std::getline(answerStream, size, ' ');) {
|
||||
try {
|
||||
int selectedSize = std::stoi(size);
|
||||
if (selectedSize >= 1 && selectedSize <= MAXIMUM_PIECE_SIZE) {
|
||||
if (this->gameMenu.getPiecesList().selectAllPieces(selectedSize)) {
|
||||
std::cout << " " << selectedSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception ignored) {}
|
||||
}
|
||||
|
||||
std::string waiting;
|
||||
std::getline(std::cin, waiting);
|
||||
}
|
||||
|
||||
void TextApp::chooseBoardSize() {
|
||||
std::string answer;
|
||||
|
||||
std::cout << "\n\n\n";
|
||||
std::cout << "Current board width and height: " << this->gameMenu.getBoardWidth() << "x" << this->gameMenu.getBoardHeight() << std::endl;
|
||||
|
||||
std::cout << "Choose the width of the board (from 1 to " << MAXIMUM_BOARD_WIDTH << ")." << std::endl;
|
||||
std::cout << "Choice: ";
|
||||
std::getline(std::cin, answer);
|
||||
try {
|
||||
int selectedSize = std::stoi(answer);
|
||||
if (selectedSize >= 1 && selectedSize <= MAXIMUM_BOARD_WIDTH) {
|
||||
this->gameMenu.setBoardWidth(selectedSize);
|
||||
}
|
||||
}
|
||||
catch (std::exception ignored) {}
|
||||
|
||||
std::cout << "Choose the height of the board (from 1 to " << MAXIMYM_BOARD_HEIGHT << ")." << std::endl;
|
||||
std::cout << "Choice: ";
|
||||
std::getline(std::cin, answer);
|
||||
try {
|
||||
int selectedSize = std::stoi(answer);
|
||||
if (selectedSize >= 1 && selectedSize <= MAXIMYM_BOARD_HEIGHT) {
|
||||
this->gameMenu.setBoardHeight(selectedSize);
|
||||
}
|
||||
}
|
||||
catch (std::exception ignored) {}
|
||||
|
||||
std::cout << "New board width and height: " << this->gameMenu.getBoardWidth() << "x" << this->gameMenu.getBoardHeight();
|
||||
|
||||
std::string waiting;
|
||||
std::getline(std::cin, waiting);
|
||||
}
|
||||
|
||||
void TextApp::seeKeybinds() const {
|
||||
std::cout << "\n\n\n";
|
||||
std::cout << "Quit/Pause/Retry: quit/pause/retry" << std::endl;
|
||||
std::cout << "Hold : h" << std::endl;
|
||||
std::cout << "Soft/Hard drop : sd/hd" << std::endl;
|
||||
std::cout << "Move left/right : l/r" << std::endl;
|
||||
std::cout << "Rotate 0/CW/180/CCW: c/cw/cc/ccw" << std::endl;
|
||||
std::cout << "\n";
|
||||
std::cout << "To do several actions at the same time, separe them with blank spaces." << std::endl;
|
||||
std::cout << "Remember that for certains actions like hard dropping, you need to release it before using it again, even if a different piece spawned.";
|
||||
std::string waiting;
|
||||
std::getline(std::cin, waiting);
|
||||
}
|
||||
|
||||
void TextApp::defaultKeybinds() {
|
||||
this->keybinds.clear();
|
||||
this->keybinds.insert({"quit", QUIT});
|
||||
this->keybinds.insert({"pause", PAUSE});
|
||||
this->keybinds.insert({"retry", RETRY});
|
||||
this->keybinds.insert({"h", HOLD});
|
||||
this->keybinds.insert({"sd", SOFT_DROP});
|
||||
this->keybinds.insert({"hd", HARD_DROP});
|
||||
this->keybinds.insert({"l", MOVE_LEFT});
|
||||
this->keybinds.insert({"r", MOVE_RIGHT});
|
||||
this->keybinds.insert({"c", ROTATE_0});
|
||||
this->keybinds.insert({"cw", ROTATE_CW});
|
||||
this->keybinds.insert({"cc", ROTATE_180});
|
||||
this->keybinds.insert({"ccw", ROTATE_CCW});
|
||||
}
|
||||
|
||||
void TextApp::startGame() const {
|
||||
Game game = this->gameMenu.startGame(DEFAULT_GAMEMODE);
|
||||
game.start();
|
||||
|
||||
std::cout << "\n\n\n";
|
||||
this->printGame(game);
|
||||
|
||||
bool quit = false;
|
||||
bool paused = false;
|
||||
std::string answer;
|
||||
while (!quit) {
|
||||
std::cout << "Actions: ";
|
||||
std::getline(std::cin, answer);
|
||||
std::stringstream answerStream(answer);
|
||||
std::vector<std::string> actions;
|
||||
for (std::string action; std::getline(answerStream, action, ' ');) {
|
||||
actions.push_back(action);
|
||||
}
|
||||
|
||||
std::set<Action> playerActions;
|
||||
for (std::string action : actions) {
|
||||
if (this->keybinds.contains(action)) {
|
||||
playerActions.insert(this->keybinds.at(action));
|
||||
}
|
||||
}
|
||||
|
||||
if (playerActions.contains(PAUSE)) {
|
||||
paused = (!paused);
|
||||
}
|
||||
|
||||
if (!paused) {
|
||||
if (playerActions.contains(QUIT)) {
|
||||
quit = true;
|
||||
}
|
||||
else if (playerActions.contains(RETRY)) {
|
||||
game.reset();
|
||||
game.start();
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < FRAMES_PER_INPUT; i++) {
|
||||
game.nextFrame(playerActions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n\n\n";
|
||||
if (paused) {
|
||||
std::cout << "--<[PAUSED]>--" << std::endl;
|
||||
}
|
||||
this->printGame(game);
|
||||
|
||||
if (game.hasLost()) {
|
||||
quit = true;
|
||||
std::cout << "You lost!" << std::endl;
|
||||
}
|
||||
else if (game.hasWon()) {
|
||||
quit = true;
|
||||
std::cout << "You won!" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextApp::printGame(const Game& game) const {
|
||||
int maxHeight = game.getBoard().getGridHeight();
|
||||
if (game.getActivePiece() != nullptr) {
|
||||
for (const Position& position : game.getActivePiece()->getPositions()) {
|
||||
maxHeight = std::max(maxHeight, position.y + game.getActivePiecePosition().y);
|
||||
}
|
||||
}
|
||||
|
||||
bool lineCountPrinted = false;
|
||||
bool holdBoxStartedPrinting = false;
|
||||
bool holdBoxFinishedPrinting = false;
|
||||
bool nextQueueStartedPrinting = false;
|
||||
bool nextQueueFinishedPrinting = false;
|
||||
int nextQueuePrintedPiece;
|
||||
int printedPieceLineHeight;
|
||||
|
||||
for (int y = maxHeight; y >= 0; y--) {
|
||||
for (int x = 0; x < game.getBoard().getWidth(); x++) {
|
||||
bool isActivePieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.getActivePiecePosition()));
|
||||
bool isGhostPieceHere = (game.getActivePiece() != nullptr) && (game.getActivePiece()->getPositions().contains(Position{x, y} - game.ghostPiecePosition()));
|
||||
Block block = (isActivePieceHere || isGhostPieceHere) ? game.getActivePiece()->getBlockType() : game.getBoard().getBlock(Position{x, y});
|
||||
|
||||
if (isActivePieceHere || isGhostPieceHere) {
|
||||
std::cout << getConsoleColorCode(block);
|
||||
}
|
||||
else {
|
||||
std::cout << getResetConsoleColorCode();
|
||||
}
|
||||
|
||||
if (block != NOTHING && (!(isGhostPieceHere && !isActivePieceHere))) {
|
||||
std::cout << "*";
|
||||
}
|
||||
else {
|
||||
if (y < game.getBoard().getBaseHeight()) {
|
||||
if (isGhostPieceHere) {
|
||||
std::cout << "=";
|
||||
}
|
||||
else {
|
||||
std::cout << "-";
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (y < game.getBoard().getGridHeight()) {
|
||||
std::cout << " ";
|
||||
if (!lineCountPrinted) {
|
||||
std::cout << getResetConsoleColorCode() << "Lines: " << game.getClearedLines();
|
||||
lineCountPrinted = true;
|
||||
}
|
||||
else if (!holdBoxFinishedPrinting) {
|
||||
if (!holdBoxStartedPrinting) {
|
||||
std::cout << getResetConsoleColorCode() << "Hold:";
|
||||
printedPieceLineHeight = (game.getHeldPiece() == nullptr) ? -1 : (game.getHeldPiece()->getLength() - 1);
|
||||
holdBoxStartedPrinting = true;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < game.getHeldPiece()->getLength(); i++) {
|
||||
if (game.getHeldPiece()->getPositions().contains(Position{i, printedPieceLineHeight})) {
|
||||
std::cout << getConsoleColorCode(game.getHeldPiece()->getBlockType()) << "*";
|
||||
}
|
||||
else {
|
||||
std::cout << getResetConsoleColorCode() << "-";
|
||||
}
|
||||
}
|
||||
printedPieceLineHeight--;
|
||||
}
|
||||
if (printedPieceLineHeight < 0) {
|
||||
holdBoxFinishedPrinting = true;
|
||||
}
|
||||
}
|
||||
else if (!nextQueueFinishedPrinting) {
|
||||
if (!nextQueueStartedPrinting) {
|
||||
std::cout << getResetConsoleColorCode() << "Next:";
|
||||
printedPieceLineHeight = (game.getNextPieces().size() == 0) ? -1 : (game.getNextPieces().at(0).getLength() - 1);
|
||||
nextQueuePrintedPiece = 0;
|
||||
nextQueueStartedPrinting = true;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < game.getNextPieces().at(nextQueuePrintedPiece).getLength(); i++) {
|
||||
if (game.getNextPieces().at(nextQueuePrintedPiece).getPositions().contains(Position{i, printedPieceLineHeight})) {
|
||||
std::cout << getConsoleColorCode(game.getNextPieces().at(nextQueuePrintedPiece).getBlockType()) << "*";
|
||||
}
|
||||
else {
|
||||
std::cout << getResetConsoleColorCode() << "-";
|
||||
}
|
||||
}
|
||||
printedPieceLineHeight--;
|
||||
}
|
||||
if (printedPieceLineHeight < 0) {
|
||||
nextQueuePrintedPiece++;
|
||||
if (nextQueuePrintedPiece >= game.getNextPieces().size()) {
|
||||
nextQueueFinishedPrinting = true;
|
||||
}
|
||||
else {
|
||||
printedPieceLineHeight = game.getNextPieces().at(nextQueuePrintedPiece).getLength() - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
std::cout << getResetConsoleColorCode();
|
||||
}
|
||||
Reference in New Issue
Block a user