Compare commits
43 Commits
aa06318c07
...
main
Author | SHA1 | Date | |
---|---|---|---|
3891d90f43
|
|||
a7ef306800
|
|||
a1e1205247
|
|||
1007b6744d
|
|||
f0701fe9e7
|
|||
b462ae3c7e
|
|||
8ad2a1342a
|
|||
99007047eb
|
|||
|
d8b9430120 | ||
|
4f4d598eb6 | ||
|
2f065f4917 | ||
3e8d6d9557
|
|||
|
6c8d033629 | ||
|
3dfe314836 | ||
|
ca546e5ba6 | ||
|
6b01273580 | ||
625d607ef0
|
|||
|
14869f4a83 | ||
|
47b880e737 | ||
efd60b89e4
|
|||
bbd92bfa8b | |||
65227d12ab | |||
d2fbaa4af6
|
|||
|
2ae5de715d | ||
8d75c055c0 | |||
83eb22e627 | |||
30cd5c4af8 | |||
faa0e236b6 | |||
|
12a009b7db | ||
|
373c186075 | ||
|
9821f78c87 | ||
|
9fb66b6755 | ||
50b3312f49
|
|||
6127e4cf37 | |||
|
8636bcfb0c | ||
|
b4c2f84ea0 | ||
|
c9f83c396f | ||
|
5a77578699 | ||
|
0fbe762391 | ||
|
85d22b4736 | ||
|
d1286469c3 | ||
|
de0cbf5a8b | ||
|
e24ebcfc0b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
.vscode/
|
||||
.idea/
|
||||
build/
|
||||
docs/
|
||||
*.exe
|
||||
*.txt
|
||||
chess
|
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "ChessUtils.h"
|
||||
|
||||
std::vector<std::string> ChessUtils::split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
std::stringstream ss(s);
|
||||
std::string item;
|
||||
while (std::getline(ss, item, delim)) {
|
||||
elems.push_back(item);
|
||||
}
|
||||
return elems;
|
||||
}
|
||||
//a4
|
||||
std::pair<int, int> ChessUtils::convertPosition(const std::string &pos) {
|
||||
int y = pos[pos.size()-2] - 'a';
|
||||
int x = ChessUtils::fileConvertion.find((pos[pos.size()-1] - '0')-1)->second;
|
||||
return std::make_pair(x, y);
|
||||
}
|
34
ChessUtils.h
34
ChessUtils.h
@@ -1,34 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 20.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSUTILS_H
|
||||
#define CHESSUTILS_H
|
||||
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class ChessUtils {
|
||||
public:
|
||||
inline static const std::unordered_map<int, int> fileConvertion = {
|
||||
{0, 7},
|
||||
{1, 6},
|
||||
{2, 5},
|
||||
{3, 4},
|
||||
{4, 3},
|
||||
{5, 2},
|
||||
{6, 1},
|
||||
{7, 0}
|
||||
};
|
||||
static std::vector<std::string> split(const std::string &s, char delim);
|
||||
|
||||
static std::pair<int, int> convertPosition(const std::string &pos);
|
||||
};
|
||||
|
||||
#endif //CHESSUTILS_H
|
1025
Chessboard.cpp
1025
Chessboard.cpp
File diff suppressed because it is too large
Load Diff
143
Chessboard.h
143
Chessboard.h
@@ -1,143 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 20.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSBOARD_H
|
||||
#define CHESSBOARD_H
|
||||
|
||||
#include "Chesspiece.h"
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
class Chessboard {
|
||||
private:
|
||||
/* Constants */
|
||||
// Chars to display board
|
||||
// Corners
|
||||
const std::string topLeft = "┌";
|
||||
const std::string topRight = "┐";
|
||||
const std::string bottomLeft = "└";
|
||||
const std::string bottomRight = "┘";
|
||||
|
||||
// Line chars
|
||||
const std::string horizontal = "─";
|
||||
const std::string vertical = "│";
|
||||
const std::string topIntersection = "┬";
|
||||
const std::string bottomIntersection = "┴";
|
||||
const std::string middleIntersection = "┼";
|
||||
|
||||
// White pieces
|
||||
const std::string whiteSquare = "□";
|
||||
const std::string whiteKing = "♔";
|
||||
const std::string whiteQueen = "♕";
|
||||
const std::string whiteRook = "♖";
|
||||
const std::string whiteBischop = "♗";
|
||||
const std::string whiteKnight = "♘";
|
||||
const std::string whitePawn = "♙";
|
||||
|
||||
// Black pieces
|
||||
const std::string blackSquare = "■";
|
||||
const std::string blackKing = "♚";
|
||||
const std::string blackQueen = "♛";
|
||||
const std::string blackRook = "♜";
|
||||
const std::string blackBischop = "♝";
|
||||
const std::string blackKnight = "♞";
|
||||
const std::string blackPawn = "♟";
|
||||
|
||||
/* class fields */
|
||||
std::vector<std::vector<char>> currentBoard;
|
||||
|
||||
std::unordered_map<char, std::vector<std::unique_ptr<Chesspiece>>> playingPieces;
|
||||
|
||||
// Starting formatting
|
||||
std::vector<std::vector<char>> startBoard = {
|
||||
{'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'},
|
||||
{'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
|
||||
{'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'},
|
||||
};
|
||||
|
||||
// ToDo: Mathematisch sicherlich weg rationalisierbar
|
||||
std::vector<std::vector<char>> emptyBoard = {
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'},
|
||||
{'w', 'x', 'w', 'x' ,'w', 'x', 'w', 'x'},
|
||||
{'x', 'w', 'x', 'w', 'x', 'w', 'x', 'w'}
|
||||
};
|
||||
|
||||
// Saves turn order; true = white and false = black
|
||||
bool turnOrder = true;
|
||||
|
||||
// ToDo: Max Size definieren?
|
||||
std::queue<std::string> queue;
|
||||
|
||||
/* methods */
|
||||
// Method returns unicode for chess icon depending on the identifier
|
||||
std::string getChessIcon(char identifier);
|
||||
|
||||
void generateTopLine();
|
||||
|
||||
void generatePlayingField(const std::vector<std::vector<char>>& chessboard);
|
||||
|
||||
void generateBottomLine();
|
||||
|
||||
public:
|
||||
/* fields */
|
||||
std::string display;
|
||||
int boardSize = 8;
|
||||
|
||||
/* methods */
|
||||
bool getTurnOrder();
|
||||
void setTurnOrder(bool turnOrder);
|
||||
|
||||
std::vector<std::vector<char>> getBoard();
|
||||
void setBoard(std::vector<std::vector<char>> board);
|
||||
|
||||
std::vector<std::vector<char>> getStartBoard();
|
||||
|
||||
std::vector<std::vector<char>> getEmptyBoard();
|
||||
|
||||
void draw ();
|
||||
|
||||
void draw (const std::vector<std::vector<char>>& chessboard);
|
||||
|
||||
// ToDo:
|
||||
// Methode um mögliche Züge anzuzeigen
|
||||
// Rochade
|
||||
// Mate
|
||||
// Schachmate
|
||||
// En Passond
|
||||
// Restlichen moves
|
||||
// Angabe mit Menü Optionen als Zahlen
|
||||
// Figuren wählen mit Schachnotation
|
||||
|
||||
void init();
|
||||
|
||||
void initPieces();
|
||||
|
||||
void move();
|
||||
|
||||
char getCorrectPiece(char pieceIdentifier);
|
||||
|
||||
//
|
||||
void move(std::string move);
|
||||
|
||||
// This method saves the current board state
|
||||
void saveBoard();
|
||||
|
||||
// This method loads a save state
|
||||
void loadBoard(std::string filepath);
|
||||
};
|
||||
|
||||
|
||||
#endif //CHESSBOARD_H
|
@@ -1 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
@@ -1,168 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizerGraphic.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
void ChessboardVisualizerGraphic::SetConsoleColor(Colors foreground, Colors background) {
|
||||
const std::string SEQ_FOREGROUND = "\x1b[3";
|
||||
const std::string SEQ_FOREGROUND_LIGHT = "\x1b[9";
|
||||
const std::string SEQ_BACKGROUND = "\x1b[4";
|
||||
const std::string SEQ_BACKGROUND_LIGHT = "\x1b[10";
|
||||
|
||||
// set foreground color
|
||||
switch (foreground) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_FOREGROUND_LIGHT << foreground << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
}
|
||||
|
||||
// set background color
|
||||
switch (background) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_BACKGROUND_LIGHT << background << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void ChessboardVisualizerGraphic::Draw(Chessboard* chessboard) {
|
||||
std::cout << "\033[2J"; // clear the console
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << " " << chessboard->GetPlayer(ChessPieceColor::White)->GetName() << " vs. " << chessboard->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2554";
|
||||
}
|
||||
std::cout << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550";
|
||||
if (i == 7) {
|
||||
std::cout << "\u2557";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
for (int i = 0; i < 3; i++) {
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (i == 1) {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << rank << " ";
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
} else {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
}
|
||||
if (file % 2 == (rank % 2)) {
|
||||
this->SetConsoleColor(BLACK, WHITE);
|
||||
|
||||
if (i == 1) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
} else {
|
||||
this->SetConsoleColor(WHITE, BLACK);
|
||||
|
||||
if (i == 1) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
if (file == 'H') {
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << "\u2551";
|
||||
}
|
||||
}
|
||||
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
if (rank == 1) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u255A";
|
||||
}
|
||||
std::cout << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550" << "\u2550";
|
||||
if (i == 7) {
|
||||
std::cout << "\u255D";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
std::cout << " ";
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << " " << file << " ";
|
||||
if (file == 'H') {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
std::cout << std::endl;
|
||||
}
|
@@ -1,21 +0,0 @@
|
||||
#ifndef ChessboardVisualizerGraphic_H
|
||||
#define ChessboardVisualizerGraphic_H
|
||||
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
||||
|
||||
enum Colors {
|
||||
BLACK = 0, RED = 1, GREEN = 2, YELLOW = 3, BLUE = 4, MAGENTA = 5, CYAN = 6, WHITE = 7,
|
||||
LIGHT_BLACK = 10, LIGHT_RED = 11, LIGHT_GREEN = 12, LIGHT_YELLOW = 13, LIGHT_BLUE = 14,
|
||||
LIGHT_MAGENTA = 15, LIGHT_CYAN = 16, LIGHT_WHITE = 17, DEFAULT = 9
|
||||
};
|
||||
|
||||
class ChessboardVisualizerGraphic : public ChessboardVisualizer {
|
||||
private:
|
||||
void SetConsoleColor(Colors foreground, Colors background);
|
||||
|
||||
public:
|
||||
ChessboardVisualizerGraphic() = default;
|
||||
void Draw(Chessboard* chessboard);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,91 +0,0 @@
|
||||
#include "../Chessboard/ChessboardVisualizerText.hpp"
|
||||
#include "../ChessPieces/ChessPiecePosition.hpp"
|
||||
|
||||
void ChessboardVisualizerText::Draw(Chessboard* chessboard) {
|
||||
std::cout << "\033[2J"; // clear the console
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << " " << chessboard->GetPlayer(ChessPieceColor::White)->GetName() << " vs. " << chessboard->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::cout << std::endl;
|
||||
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u250F";
|
||||
} else {
|
||||
std::cout << "\u2533";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u2513";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') { // Beginn der Zeile
|
||||
std::cout << " " << rank << " ";
|
||||
std::cout << "\u2503";
|
||||
}
|
||||
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
|
||||
if (chessboard->IsEmptyField(position)) {
|
||||
std::cout << " " << " " << " ";
|
||||
} else {
|
||||
ChessPiece* piece = chessboard->GetChessPiece(position);
|
||||
std::cout << " " << piece->GetUnicode() << " ";
|
||||
}
|
||||
|
||||
std::cout << "\u2503";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
if (rank != 1) {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2523";
|
||||
} else {
|
||||
std::cout << "\u254B";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u252B";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
} else {
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0) {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << "\u2517";
|
||||
} else {
|
||||
std::cout << "\u253B";
|
||||
}
|
||||
std::cout << "\u2501" << "\u2501" << "\u2501";
|
||||
if (i == 7) {
|
||||
std::cout << "\u251B";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
std::cout << " " << " " << " ";
|
||||
std::cout << " ";
|
||||
} else {
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << " " << file << " ";
|
||||
if (file == 'H') {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
@@ -1,15 +0,0 @@
|
||||
#ifndef ChessboardVisualizerText_H
|
||||
#define ChessboardVisualizerText_H
|
||||
|
||||
#include "../Chessboard/ChessboardVisualizer.hpp"
|
||||
|
||||
class ChessboardVisualizerText : public ChessboardVisualizer {
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
public:
|
||||
ChessboardVisualizerText() = default;
|
||||
void Draw(Chessboard* chessboard);
|
||||
};
|
||||
|
||||
#endif
|
@@ -1,25 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include "Chesspiece.h"
|
||||
|
||||
Chesspiece::Chesspiece(char color, std::pair<int, int> position)
|
||||
: color(color), position(position) {}
|
||||
|
||||
std::pair<int, int> Chesspiece::getPosition() { return this->position; };
|
||||
void Chesspiece::setPosition(std::pair<int, int> position) {
|
||||
this->position = position;
|
||||
//Chesspiece::calcAvaibleMoves(); // Brett -> Auswahl Figuren -> Züge gewählte
|
||||
}
|
||||
|
||||
char Chesspiece::getColor() { return color; }
|
||||
void Chesspiece::setColor(char color) { color = color; }
|
||||
|
||||
std::vector<std::string> Chesspiece::getAvaibleMoves() { return avaibleMoves; }
|
||||
|
||||
bool Chesspiece::checkNotation(std::string notation) {
|
||||
std::regex pattern("R^([KQRNBP]?)([a-h][1-8])[-x]([a-h][1-8])([+#]?)$");
|
||||
std::smatch match;
|
||||
return (std::regex_search(notation, match, pattern) ? true : false);
|
||||
}
|
46
Chesspiece.h
46
Chesspiece.h
@@ -1,46 +0,0 @@
|
||||
//
|
||||
// Created by hamac on 19.12.2024.
|
||||
//
|
||||
|
||||
#ifndef CHESSPIECE_H
|
||||
#define CHESSPIECE_H
|
||||
|
||||
//
|
||||
// Created by hamac on 18.12.2024.
|
||||
//
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
class Chesspiece {
|
||||
private:
|
||||
/* fields */
|
||||
// ToDo: von char auf enum Color {W, B} umstellen
|
||||
char color;
|
||||
char identifier; // P,K,...
|
||||
std::pair<int, int> position;
|
||||
// std::vector<std::pair<int, int>>
|
||||
std::vector<std::string> avaibleMoves;
|
||||
|
||||
/* methods */
|
||||
virtual std::vector<std::string> calcAvaibleMoves() = 0;
|
||||
|
||||
public:
|
||||
Chesspiece(char color, std::pair<int, int> position);
|
||||
|
||||
virtual ~Chesspiece() = default;
|
||||
|
||||
std::pair<int, int> getPosition();
|
||||
void setPosition(std::pair<int, int> position);
|
||||
|
||||
char getColor();
|
||||
void setColor(char color);
|
||||
|
||||
std::vector<std::string> getAvaibleMoves();
|
||||
|
||||
bool checkNotation(std::string notation);
|
||||
};
|
||||
|
||||
|
||||
#endif //CHESSPIECE_H
|
60
OldCode.txt
60
OldCode.txt
@@ -1,60 +0,0 @@
|
||||
void firstVersion() {
|
||||
const std::string white = "\u2B1C";
|
||||
const std::string black = "\u2B1B";
|
||||
|
||||
std::string brett[8][8];
|
||||
|
||||
std::string field;
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
if (y % 2 == 0) {
|
||||
field = (x % 2 == 0) ? "\u2B1C" : "\u2B1B";
|
||||
}
|
||||
else {
|
||||
field = (x % 2 == 0) ? "⬛" : "⬜";
|
||||
}
|
||||
std::cout << field;
|
||||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
void secondVersion() {
|
||||
//wchar_t t = 0x25FF;
|
||||
|
||||
// Horizontale Linie u2500
|
||||
// Vertikale Linie u2502
|
||||
// Top Right Corner u250C
|
||||
// Top Left Corner u2510
|
||||
// Bottom Right Corner u2514
|
||||
// Bottom Left Corner u2518
|
||||
|
||||
std::string topRightCorner = "\u2554";
|
||||
std::string topLeftCorner = "\u2557";
|
||||
std::string bottomLeftCorner = "\u255A";
|
||||
std::string bottomRightCorner = "\u255D";
|
||||
std::string horizontalLine = "\u2550\u2550";
|
||||
std::string verticalLine = "\u2551";
|
||||
std::string crossSuc = "\u256C";
|
||||
std::string leftSide = "\u2560";
|
||||
std::string rightSide = "\u2563";
|
||||
std::string topSide = "\u2566";
|
||||
std::string bottomSide = "\u2569";
|
||||
|
||||
std::string firstLine = "\u2554\u2550\u2566";
|
||||
std::string line;
|
||||
|
||||
for (int row = 0; row < 9; ++row) {
|
||||
for (int col = 0; col < 8; ++col) {
|
||||
if (row == 0 && col > 0) line += topSide + horizontalLine;
|
||||
if (row == 8 && col > 0) line += bottomSide + horizontalLine;
|
||||
if (col == 0 && row < 8 && row > 0) line += leftSide + horizontalLine;
|
||||
if (row > 0 && row < 8 && col > 0) line += crossSuc + horizontalLine;
|
||||
if (col == 7 && row < 8 && row > 0) line += rightSide;
|
||||
if (row == 0 && col == 0) line += topRightCorner + horizontalLine;
|
||||
if (row == 8 && col == 0) line += bottomLeftCorner + horizontalLine;
|
||||
if (row == 0 && col == 7) line += topLeftCorner + "\n" + verticalLine;
|
||||
if (row == 8 && col == 7) line += bottomRightCorner;
|
||||
}
|
||||
line += "\n";
|
||||
}
|
172
README.md
172
README.md
@@ -1,121 +1,69 @@
|
||||
# c/c++ Abschlussprojekt - Schach
|
||||
# TurboSchach
|
||||
|
||||
## Notwendige Umsetzungen
|
||||
|
||||
1. Klasse für Spielbrett
|
||||
2. Oberklasse für Spielfiguren
|
||||
1. Bauer
|
||||
2. Dame
|
||||
3. König
|
||||
4. Läufer
|
||||
5. Turm
|
||||
6. Springer
|
||||
3. Fancy User Interface
|
||||
4. Speicherung des Spielbretts
|
||||
5. Unentschieden anbieten
|
||||
6. Aufgegeben
|
||||
|
||||
### Spielbrett
|
||||
|
||||
- 8x8 Matrix
|
||||
- ANSI Linien checken
|
||||
- Unterscheidung von schwarzen und weißen Feldern
|
||||
- UTF-8 Spielfiguren
|
||||
- draw() Funktion
|
||||
- movement
|
||||
- Schachnotation
|
||||
- oder Klickbar?
|
||||
- Beschriftung des Spielbretts
|
||||
|
||||
### Spielfiguren
|
||||
|
||||
- Interface für Implementierung?
|
||||
- Default Felder:
|
||||
- Art der Figure
|
||||
- UTF-8 Code
|
||||
- Schlagen: Ich sehe dich nach movement Regeln -> Du stirbst
|
||||
- Bauer:
|
||||
- Movement: 1 Felder, außer bei Start 1-2 Felder
|
||||
- Schlagen: 1 Feld vor Diagonal
|
||||
- Spezialmove:
|
||||
- Beförderung
|
||||
- En Passent - Wie?
|
||||
- Dame:
|
||||
- Movement: Fuck it, i do what i want
|
||||
- König:
|
||||
- Movement: Körperklaus. Ich kann nur ein Feld nach überall
|
||||
- Spezialmove: Castlen
|
||||
- Läufer:
|
||||
- Movement: Die Diagnal ist mir
|
||||
- Turm:
|
||||
- Movement: Vertikal und Horizontal
|
||||
- Springer:
|
||||
- Movement: L-Bewegung (2 nach vorn + 1 nach links oder rechts); Krake
|
||||
- Spezial Moves:
|
||||
- Rochade -> Kurz/Lang
|
||||
- En Passant
|
||||
- Stalemate
|
||||
- Bauer: 2 Felder
|
||||
- Umwandeln
|
||||
|
||||
## Optional wenn Lust und Zeit?
|
||||
|
||||
1. Bedienung per Maus
|
||||
2. Multiplayer
|
||||
3. Historie der Spielzüge
|
||||
4. Gravejard der geschlagenen Figuren
|
||||
5. König platzieren -> Anzeigen wer gewinnt
|
||||
|
||||
# Gedankensammlung
|
||||
- Initialisierung:
|
||||
- Brett zeichnen
|
||||
- Figuren mit Zugmöglichkeiten ermitteln
|
||||
- Züge kalkulieren
|
||||
- Objekt mit allen Figuren erstellen -> alle Figuren initialisieren
|
||||
- Kalkulation der Züge
|
||||
- Anhand der aktuellen Position
|
||||
- Mit einbeziehen, dass Zug König nicht in Mate versetzt (verboten)
|
||||
- Sonder Züge, wie En passant, Rochade (Lang, Kurz), Bauern zwei Feld, beachten
|
||||
- Prüfen, ob andere Figuren im Weg stehen
|
||||
- Array von Linked Lists
|
||||
- Array Index steht für Richtung von Bewegungen (diagonalen, L, Gerade)
|
||||
- alles droppen, was nach pos mit Figur kommt
|
||||
|
||||
## Figuren
|
||||
|
||||
- Läufer (Bishop)
|
||||
- König (King)
|
||||
- Königin (Queen)
|
||||
- Turm (Rook)
|
||||
- Bauer (Pawn)
|
||||
- Pferd (Knight)
|
||||
|
||||
## ToDo
|
||||
- Speicherfunktion
|
||||
- Menü (ASCII Art of TurboSchach)
|
||||
- Startmenü
|
||||
- Spielmenü mit Historie, Kommand
|
||||
- Plattformunabhängiges CMD clearing vor dem Zeichnen
|
||||
|
||||
## Kompilieren und Ausführen
|
||||
Um TurboSchach kompilieren zu können wird mindestens C++ 17 benötigt.
|
||||
|
||||
### Windows
|
||||
|
||||
```
|
||||
g++ -std=c++17 -o chess.exe main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
./chess.exe
|
||||
```
|
||||
## Kompilieren / Ausführen
|
||||
Für die Ausführung von TurboSchach sollte die Konsole / das Terminal im Vollbildmodus geöffnet sein. Durch ein zu kleines Terminal kann es zu Verschiebungen in der Benutzeroberfläche kommen. Um TurboSchach kompilieren zu können wird mindestens C++ 17 benötigt.
|
||||
|
||||
### Linux und MacOS
|
||||
|
||||
```
|
||||
# compile the project
|
||||
# build
|
||||
make
|
||||
|
||||
# run the project
|
||||
# run
|
||||
make run
|
||||
```
|
||||
|
||||
# remove all output files
|
||||
make clean
|
||||
```
|
||||
### Microsoft Windows
|
||||
|
||||
```
|
||||
# build
|
||||
g++ -std=c++17 -o chess.exe main.cpp ChessPieces/*.cpp Chessboard/*.cpp Controller/*.cpp Player/*.cpp Visualizer/*.cpp
|
||||
|
||||
# run
|
||||
./chess.exe
|
||||
|
||||
# build and run (PowerShell)
|
||||
.\run
|
||||
```
|
||||
|
||||
## Algebraische Notation
|
||||
Um die Figuren auf dem Schachbrett zu bewegen, wird die kurze algebraische Notation nach [FIDE](https://handbook.fide.com/chapter/E012023) (siehe Appendix C) unterstützt. Es werden die Schachfiguren sowohl in deutscher als auch in englischer Sprache unterstützt.
|
||||
|
||||
| Schachfigur | Deutsch | Englisch |
|
||||
| ----------- | ------- | -------- |
|
||||
| Bauer (Pawn) | B | P |
|
||||
| Springer (Knight) | S | N |
|
||||
| Läufer (Bishop) | L | B |
|
||||
| Turm (Rook) | T | R |
|
||||
| Dame (Queen) | D | Q |
|
||||
| König (King) | K | K |
|
||||
|
||||
Bei der kurzen Notation wird immer nur das Zielfeld eines Spielzuges genannt. Sollte der Ursprung nicht eindeutig sein kann auch die Spalte oder Zeile der zu bewegenden Figur genannt werden. So gibt der Spielzug `dxe5` an dass der Bauer in der Spalte D auf das Feld E5 zieht. Das `x` gibt an dass dabei eine Spielfigur des Gegeners geschlagen wird. Dies muss aber nicht zwingend angegeben werden.
|
||||
Der Bauer wird in den Spielzügen nicht benannt. Der Spielzug `b4` ist daher der Zug eines Bauern auf das Feld B4. Alle anderen Schachfiguren werden im Zug mit ihrem entsprechenden Buchstaben genannt. So gibt der Spielzug `Bc4` an dass der Läufer auf das Feld C4 gezogen wird.
|
||||
|
||||
### Beispiele
|
||||
|
||||
- `(=)` Draw: Das Draw wird dann aktiv wenn dieses im nächsten Spielzug vom Gegner bestätigt wird.
|
||||
- `b4` Der Bauer zieht auf das Feld B4.
|
||||
- `Bc4` Der Läufer zieht auf das Feld C4.
|
||||
- `0-0` Kleine Rochade (Rochade am Königsflügel)
|
||||
- `0-0-0` Große Rochade (Rochade am Damenflügel)
|
||||
- `d8Q` Umwandlung: Der Bauer zieht auf D8 und wandelt sich zur Dame.
|
||||
|
||||
## PGN (Portable Game Notation)
|
||||
TurboSchach unterstützt das Datenformat [PGN (Portable Game Notation)](https://www.saremba.de/chessgml/standards/pgn/pgn-complete.htm), welches zur Speicherung von Schachpartien verwendet wird. Auf der Website https://www.chessgames.com/ werden beispielsweise viele Schachpartien von offiziellen Turnieren im PGN-Format zur Verfügung gestellt. Diese Dateien können in TurboSchach importiert werden. Über den Menüpunkt 2 direkt nach dem Start der Anwendung ist dieser Import möglich.
|
||||
|
||||
Diese PGN-Dateien wurden auch zum Testen der Anwendung verwendet. Nachfolgend einige Schachspiele mit bestimmten Eigenschaften:
|
||||
|
||||
- [Jack Rudd vs Martin Simons](https://www.chessgames.com/perl/chessgame?gid=1588906) vom 09.08.2000 - Schachmatt
|
||||
- [Tim Jaksland vs Line Jin Jorgensen](https://www.chessgames.com/perl/chessgame?gid=1482551) vom 22.01.2008 - Schachmatt
|
||||
- [Gabriel Sargissian vs Nigel Short](https://www.chessgames.com/perl/chessgame?gid=1775611) vom 04.10.2014 - En Passant (`axb6`)
|
||||
- [Ulf Andersson vs Daniel Stellwagen](https://www.chessgames.com/perl/chessgame?gid=1427255) vom 27.08.2006 - En Passant (`bxc6+` und `dxe6`)
|
||||
- [Garry Kasparov vs Kiril Georgiev](https://www.chessgames.com/perl/chessgame?gid=1258478) vom 20.02.1988 - Stalemate
|
||||
- [Magnus Carlsen vs Hans Niemann](https://www.chessgames.com/perl/chessgame?gid=2821644) vom 31.12.2024
|
||||
|
||||
## Ausblick
|
||||
|
||||
- Multiplayer-Modus
|
||||
- Abspielen der Schachpartien (Schritt für Schritt) aus einer PGN-Datei
|
||||
- Anzeige der nächstmöglichen Züge bei Auswahl einer Figur
|
12
chessgames/save_games/20250116 - E gegen F - Runde 2.PGN
Normal file
12
chessgames/save_games/20250116 - E gegen F - Runde 2.PGN
Normal file
@@ -0,0 +1,12 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "2"]
|
||||
[White "E"]
|
||||
[Black "F"]
|
||||
[PlyCount "7"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e5 2. e4 f5 3. f3 g5
|
||||
4. g4 *
|
11
chessgames/save_games/20250116 - F gegen E - Runde 1
Normal file
11
chessgames/save_games/20250116 - F gegen E - Runde 1
Normal file
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "F"]
|
||||
[Black "E"]
|
||||
[PlyCount "4"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e5 2. e4 f5 *
|
10
chessgames/save_games/20250116 - F gegen E - Runde 1.PGN
Normal file
10
chessgames/save_games/20250116 - F gegen E - Runde 1.PGN
Normal file
@@ -0,0 +1,10 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "F"]
|
||||
[Black "E"]
|
||||
[PlyCount "0"]
|
||||
[Result "*"]
|
||||
|
||||
*
|
@@ -0,0 +1,9 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Player 1"]
|
||||
[Black "Player 2"]
|
||||
[PlyCount "0"]
|
||||
[Result "*"]
|
||||
*
|
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Player 2"]
|
||||
[Black "Player 1"]
|
||||
[PlyCount "3"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 e6 2. f4 *
|
@@ -0,0 +1,11 @@
|
||||
[Event "Private Game"]
|
||||
[Site "Horb am Neckar, Germany"]
|
||||
[Date "2025.01.16"]
|
||||
[Round "1"]
|
||||
[White "Sebro"]
|
||||
[Black "Fabian"]
|
||||
[PlyCount "1"]
|
||||
[Result "*"]
|
||||
|
||||
|
||||
1. e3 *
|
2970
doc/Doxyfile
Normal file
2970
doc/Doxyfile
Normal file
File diff suppressed because it is too large
Load Diff
128
main.cpp
128
main.cpp
@@ -1,128 +0,0 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <fstream>
|
||||
#include "Player/Player.hpp"
|
||||
#include "ChessPieces/Knight.hpp"
|
||||
#include "ChessPieces/Bishop.hpp"
|
||||
#include "ChessPieces/King.hpp"
|
||||
#include "ChessPieces/Pawn.hpp"
|
||||
#include "ChessPieces/Queen.hpp"
|
||||
#include "ChessPieces/Rook.hpp"
|
||||
#include "ChessPieces/ChessPiece.hpp"
|
||||
#include "Chessboard/Chessboard.hpp"
|
||||
#include "ChessPieces/ChessPiecePosition.hpp"
|
||||
#include "Chessboard/ChessboardVisualizerText.hpp"
|
||||
#include "Chessboard/ChessboardVisualizerGraphic.hpp"
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
std::cout << "Spieler A: ";
|
||||
std::string namePlayerA;
|
||||
getline(std::cin, namePlayerA);
|
||||
std::cout << "Spieler B: ";
|
||||
std::string namePlayerB;
|
||||
getline(std::cin, namePlayerB);
|
||||
|
||||
Player* playerA = new Player(namePlayerA);
|
||||
Player* playerB = new Player(namePlayerB);
|
||||
|
||||
Chessboard chessboard = Chessboard();
|
||||
chessboard.SetPlayers(playerA, playerB);
|
||||
|
||||
// set black chess pieces
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::Black, ChessPiecePosition{'A', 8}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::Black, ChessPiecePosition{'B', 8}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::Black, ChessPiecePosition{'C', 8}});
|
||||
chessboard.SetChessPiece(new Queen{ChessPieceColor::Black, ChessPiecePosition{'D', 8}});
|
||||
chessboard.SetChessPiece(new King{ChessPieceColor::Black, ChessPiecePosition{'E', 8}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::Black, ChessPiecePosition{'F', 8}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::Black, ChessPiecePosition{'G', 8}});
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::Black, ChessPiecePosition{'H', 8}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'A', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'B', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'C', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'D', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'E', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'F', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'G', 7}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::Black, ChessPiecePosition{'H', 7}});
|
||||
|
||||
// set white chess pieces
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::White, ChessPiecePosition{'A', 1}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::White, ChessPiecePosition{'B', 1}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::White, ChessPiecePosition{'C', 1}});
|
||||
chessboard.SetChessPiece(new Queen{ChessPieceColor::White, ChessPiecePosition{'D', 1}});
|
||||
chessboard.SetChessPiece(new King{ChessPieceColor::White, ChessPiecePosition{'E', 1}});
|
||||
chessboard.SetChessPiece(new Bishop{ChessPieceColor::White, ChessPiecePosition{'F', 1}});
|
||||
chessboard.SetChessPiece(new Knight{ChessPieceColor::White, ChessPiecePosition{'G', 1}});
|
||||
chessboard.SetChessPiece(new Rook{ChessPieceColor::White, ChessPiecePosition{'H', 1}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'A', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'B', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'C', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'D', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'E', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'F', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'G', 2}});
|
||||
chessboard.SetChessPiece(new Pawn{ChessPieceColor::White, ChessPiecePosition{'H', 2}});
|
||||
|
||||
// Jetzt kann man Moves machen. Nach jedem Move müssen die ChessPieces aktualisiert werden.
|
||||
chessboard.UpdateChessPieces();
|
||||
|
||||
//ChessboardVisualizerText* visualizer = new ChessboardVisualizerText();
|
||||
ChessboardVisualizerGraphic* visualizer = new ChessboardVisualizerGraphic();
|
||||
visualizer->Draw(&chessboard);
|
||||
|
||||
// Import chessboard from PGN file.
|
||||
// https://www.chessgames.com/perl/chessgame?gid=1799484
|
||||
// 1588906 - Checkmate
|
||||
// 1482551 - Checkmate
|
||||
// 1348060 - Checkmate
|
||||
// 1799484 - Checkmate
|
||||
// 1284086 - Stalemate
|
||||
// 1258478 - Stalemate
|
||||
// 1229276 - En Passant (black fxg3)
|
||||
// 1775611 - En Passant (white axb6)
|
||||
// 1427255 - En Passant (white bxc6+ and dxe6)
|
||||
chessboard.ImportFilePGN("./chessgames/1258478.pgn");
|
||||
visualizer->Draw(&chessboard);
|
||||
|
||||
while (chessboard.IsCheckmate() == false && chessboard.IsStalemate() == false) {
|
||||
std::string move;
|
||||
std::cout << "Move [" << ((chessboard.GetCurrentPlayer()->GetColor() == ChessPieceColor::White) ? "White" : "Black") << "] : ";
|
||||
std::cin >> move;
|
||||
chessboard.MoveChessPiece(move);
|
||||
visualizer->Draw(&chessboard);
|
||||
}
|
||||
|
||||
std::cout << "Game is over! - " << chessboard.GetOpponentPlayer()->GetName() << " has won the game!" << std::endl;
|
||||
/**
|
||||
std::vector<std::vector<ChessPiece>> chessmatrix;
|
||||
|
||||
Chessboard chessboard;
|
||||
|
||||
if (argc == 2) {
|
||||
std::cout << "Spielstand" << std::endl;
|
||||
chessboard.loadBoard(std::string(argv[1]));
|
||||
} else {
|
||||
chessboard.setBoard(chessboard.getStartBoard());
|
||||
}
|
||||
|
||||
//chessboard.init();
|
||||
chessboard.draw();
|
||||
|
||||
while (true) {
|
||||
std::string move;
|
||||
std::cout << "Move [" << (chessboard.getTurnOrder() ? "white" : "black") << "]: ";
|
||||
std::cin >> move;
|
||||
|
||||
chessboard.move(move);
|
||||
chessboard.saveBoard();
|
||||
|
||||
}
|
||||
*/
|
||||
return 0;
|
||||
}
|
12
makefile
12
makefile
@@ -1,10 +1,12 @@
|
||||
all:
|
||||
g++ -std=c++17 -o chess main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
g++ -std=c++17 -o build/chess src/main.cpp src/ChessPieces/*.cpp src/Chessboard/*.cpp src/Controller/*.cpp src/Player/*.cpp src/Visualizer/*.cpp
|
||||
|
||||
run:
|
||||
./chess
|
||||
./build/chess
|
||||
|
||||
clean:
|
||||
rm -f main.exe
|
||||
rm -f chess.exe
|
||||
rm -f chess
|
||||
rm -f build/*
|
||||
rm -f -r doc/html
|
||||
|
||||
doc:
|
||||
doxygen doc/Doxyfile
|
4
run.ps1
4
run.ps1
@@ -1,2 +1,2 @@
|
||||
& "g++" -std=c++17 -o chess main.cpp ChessPieces/*.cpp Chessboard/*.cpp Player/*.cpp
|
||||
./chess.exe
|
||||
& "g++" -std=c++17 -o build/chess.exe src/main.cpp src/ChessPieces/*.cpp src/Chessboard/*.cpp src/Controller/*.cpp src/Player/*.cpp src/Visualizer/*.cpp
|
||||
./build/chess.exe
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"saves": [
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
],
|
||||
[
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[]
|
||||
]
|
||||
]
|
||||
}
|
@@ -5,13 +5,10 @@
|
||||
* @param move The move that uses the short algebraic notation.
|
||||
*/
|
||||
ChessPieceMove::ChessPieceMove(std::string move) {
|
||||
move = this->Normalize(move);
|
||||
this->_move = this->Normalize(move);
|
||||
|
||||
if (this->IsValidShortNotation(move)) {
|
||||
this->_move = move;
|
||||
if (this->IsValidShortNotation()) {
|
||||
this->ParseShortNotation();
|
||||
} else {
|
||||
throw std::invalid_argument("invalid move notation");
|
||||
}
|
||||
}
|
||||
|
@@ -41,6 +41,8 @@ std::set<ChessPiecePosition> King::GetNextPositions(Chessboard* chessboard, std:
|
||||
for (ChessPiece* chessPiece : chessboard->GetChessPieces()) {
|
||||
if (chessPiece && chessPiece->GetColor() != this->GetColor()) {
|
||||
if (chessPiece->GetNextPositions().count(this->GetPosition()) == 1) {
|
||||
if (chessPiece->IsPawn()) continue; // is checked by under attack
|
||||
|
||||
if (chessPiece->GetNextPositions(chessboard, {this->GetPosition(), *nextPosition}).count(*nextPosition) == 1) {
|
||||
isUnderAttackAfterMove = true;
|
||||
break;
|
@@ -67,7 +67,7 @@ std::set<ChessPiecePosition> Pawn::GetNextPositions(Chessboard* chessboard, std:
|
||||
// 3.7.3.1. A pawn occupying a square on the same rank as and on an adjacent file to an opponent's pawn which has just advanced two squares
|
||||
// in one move from its original square may capture this opponent's pawn as though the latter had been moved only one square.
|
||||
// 3.7.3.2. This capture is only legal on the move following this advance and is called an "en passant" capture.
|
||||
if (chessboard->HasMoves()) {
|
||||
if (chessboard->GetCountMoves() > 0) {
|
||||
std::pair<ChessPiecePosition, ChessPiecePosition> lastMovePositions = chessboard->GetLastMovePositions();
|
||||
std::string moveDifference = ChessPiecePosition::GetDifference(lastMovePositions.first, lastMovePositions.second);
|
||||
|
@@ -1,9 +1,62 @@
|
||||
#include <memory>
|
||||
#include <regex>
|
||||
#include <set>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../ChessPieces/Rook.hpp"
|
||||
#include "../ChessPieces/Queen.hpp"
|
||||
#include "../ChessPieces/Bishop.hpp"
|
||||
#include "../ChessPieces/Knight.hpp"
|
||||
#include "../ChessPieces/ChessPiece.hpp"
|
||||
#include "../ChessPieces/Knight.hpp"
|
||||
#include "../ChessPieces/Bishop.hpp"
|
||||
#include "../ChessPieces/King.hpp"
|
||||
#include "../ChessPieces/Pawn.hpp"
|
||||
#include "../ChessPieces/Queen.hpp"
|
||||
#include "../ChessPieces/Rook.hpp"
|
||||
|
||||
void Chessboard::SetStartingPosition() {
|
||||
|
||||
// black chess pieces
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::Black, ChessPiecePosition("A8")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::Black, ChessPiecePosition("B8")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::Black, ChessPiecePosition("C8")));
|
||||
this->SetChessPiece(new Queen(ChessPieceColor::Black, ChessPiecePosition("D8")));
|
||||
this->SetChessPiece(new King(ChessPieceColor::Black, ChessPiecePosition("E8")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::Black, ChessPiecePosition("F8")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::Black, ChessPiecePosition("G8")));
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::Black, ChessPiecePosition("H8")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("A7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("B7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("C7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("D7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("E7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("F7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("G7")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::Black, ChessPiecePosition("H7")));
|
||||
|
||||
// white chess pieces
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::White, ChessPiecePosition("A1")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::White, ChessPiecePosition("B1")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::White, ChessPiecePosition("C1")));
|
||||
this->SetChessPiece(new Queen(ChessPieceColor::White, ChessPiecePosition("D1")));
|
||||
this->SetChessPiece(new King(ChessPieceColor::White, ChessPiecePosition("E1")));
|
||||
this->SetChessPiece(new Bishop(ChessPieceColor::White, ChessPiecePosition("F1")));
|
||||
this->SetChessPiece(new Knight(ChessPieceColor::White, ChessPiecePosition("G1")));
|
||||
this->SetChessPiece(new Rook(ChessPieceColor::White, ChessPiecePosition("H1")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("A2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("B2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("C2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("D2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("E2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("F2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("G2")));
|
||||
this->SetChessPiece(new Pawn(ChessPieceColor::White, ChessPiecePosition("H2")));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current player.
|
||||
@@ -66,7 +119,7 @@ bool Chessboard::HasMoves() {
|
||||
* @param filePath The file path of the PGN file to load.
|
||||
* @return The status whether the PGN file was loaded successfully.
|
||||
*/
|
||||
bool Chessboard::ImportFilePGN(std::string filePath) {
|
||||
std::string Chessboard::ImportFilePGN(std::string filePath) {
|
||||
std::ifstream pgnFile(filePath);
|
||||
std::regex rgxMetaInfo = std::regex("^[\\[]([A-Za-z]+) [\"](.*)[\"][\\]]$");
|
||||
std::regex rgxMoveInfo = std::regex("(?:([RNBQKP]?)([a-h]?)([1-8]?)(x?)([a-h])([1-8])((?:[=])?[QRBN])?|(O-O(?:-O)?)|(\\(=\\)))([+#!?]| e.p.)*");
|
||||
@@ -103,19 +156,25 @@ bool Chessboard::ImportFilePGN(std::string filePath) {
|
||||
|
||||
pgnFile.close();
|
||||
|
||||
if (expectedNumberOfMoves != moves.size()) {
|
||||
return false;
|
||||
}
|
||||
// this was removed because it doesn't match all the time because of wrong data?
|
||||
// https://www.chessgames.com/nodejs/game/viewGamePGN?text=1&gid=2821644 (77 not 78)
|
||||
// if (expectedNumberOfMoves != moves.size()) {
|
||||
// return "moves doesn't match!";
|
||||
// }
|
||||
|
||||
this->players = {playerBlack, playerWhite};
|
||||
this->currentPlayer = playerWhite;
|
||||
|
||||
for (std::string move : moves) {
|
||||
this->MoveChessPiece(move);
|
||||
std::string status = this->MoveChessPiece(move);
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return "";
|
||||
} else {
|
||||
return false;
|
||||
return "file not found!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -288,13 +347,6 @@ void Chessboard::SwitchCurrentPlayer() {
|
||||
this->currentPlayer = this->GetOpponentPlayer();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void Chessboard::RemoveChessPiece(ChessPiecePosition position) {
|
||||
if (this->chessboard.count(position) == 1) {
|
||||
delete this->chessboard[position];
|
||||
@@ -312,26 +364,36 @@ ChessPiece* Chessboard::GetChessPiece(ChessPiecePosition* position) {
|
||||
}
|
||||
|
||||
|
||||
bool Chessboard::IsDraw() {
|
||||
return this->draw.first == true && this->draw.second == true;
|
||||
}
|
||||
bool Chessboard::IsFinished() {
|
||||
return this->game_status.first == true || this->game_status.second == true;
|
||||
}
|
||||
|
||||
bool Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
std::string Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
ChessPiecePosition fromPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition("E1") : ChessPiecePosition("E8");
|
||||
ChessPiecePosition fromPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "H1" : "A1") : ChessPiecePosition(shortCastling ? "H8" : "A8");
|
||||
ChessPiecePosition toPositionKing = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "G1" : "C1") : ChessPiecePosition(shortCastling ? "G8" : "C8");
|
||||
ChessPiecePosition toPositionRook = (color == ChessPieceColor::White) ? ChessPiecePosition(shortCastling ? "F1" : "D1") : ChessPiecePosition(shortCastling ? "F8" : "D8");
|
||||
|
||||
if (this->IsEmptyField(&fromPositionRook) || this->IsEmptyField(&fromPositionKing)) {
|
||||
return "Castling: Unknown chess piece position!";
|
||||
}
|
||||
|
||||
ChessPiece* chessPieceRook = this->GetChessPiece(&fromPositionRook);
|
||||
ChessPiece* chessPieceKing = this->GetChessPiece(&fromPositionKing);
|
||||
|
||||
if (chessPieceKing == nullptr || chessPieceRook == nullptr) {
|
||||
return false;
|
||||
return "Castling: Chess pieces not found!";
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsKing() == false || chessPieceRook->IsRook() == false) {
|
||||
return false;
|
||||
return "Castling: Wrong chess pieces found!";
|
||||
}
|
||||
|
||||
if (chessPieceKing->IsFirstMove() == false || chessPieceRook->IsFirstMove() == false) {
|
||||
return false;
|
||||
return "Castling: Chess pieces already moved!";
|
||||
}
|
||||
|
||||
std::string step = ChessPiecePosition::GetStep(chessPieceKing->GetPosition(), toPositionKing);
|
||||
@@ -344,7 +406,7 @@ bool Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
if (field.second->GetNextPositions().count(*nextPosition) == 0) {
|
||||
continue;
|
||||
} else {
|
||||
return false;
|
||||
return "Castling: Field " + nextPosition->ToString() + " is under attack!";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,7 +414,7 @@ bool Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
return "Castling: Field " + nextPosition->ToString() + " is not empty!";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,23 +426,46 @@ bool Chessboard::MoveCastling(ChessPieceColor color, bool shortCastling) {
|
||||
this->chessboard.erase(chessPieceRook->GetPosition());
|
||||
this->SetToHistory(chessPieceRook->GetPosition(), toPositionRook);
|
||||
chessPieceRook->SetPosition(toPositionRook);
|
||||
return true;
|
||||
return "";
|
||||
}
|
||||
|
||||
void Chessboard::MoveChessPiece(std::string move) {
|
||||
std::string Chessboard::MoveChessPiece(std::string move) {
|
||||
ChessPieceMove chessPieceMove = ChessPieceMove(move);
|
||||
|
||||
if (chessPieceMove.IsValidShortNotation() == false) {
|
||||
return;
|
||||
return move + " not valid!";
|
||||
}
|
||||
|
||||
// reset a started draw offer.
|
||||
if (this->draw.first == true && this->draw.second == false && chessPieceMove.IsDrawOffer() == false) {
|
||||
this->draw = {false, false};
|
||||
} else if (this->draw.second == true && this->draw.first == false && chessPieceMove.IsDrawOffer() == false) {
|
||||
this->draw = {false, false};
|
||||
}
|
||||
|
||||
if (chessPieceMove.IsShortCastling()) {
|
||||
this->MoveCastling(this->GetCurrentPlayer()->GetColor(), true);
|
||||
std::string status = this->MoveCastling(this->GetCurrentPlayer()->GetColor(), true);
|
||||
this->draw = {false, false};
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
} else if (chessPieceMove.IsLongCastling()) {
|
||||
this->MoveCastling(this->GetCurrentPlayer()->GetColor(), false);
|
||||
std::string status = this->MoveCastling(this->GetCurrentPlayer()->GetColor(), false);
|
||||
this->draw = {false, false};
|
||||
if (status.empty() == false) {
|
||||
return status;
|
||||
}
|
||||
} else if (chessPieceMove.IsDrawOffer()) {
|
||||
// Remis
|
||||
if (this->GetCurrentPlayer()->GetColor() == ChessPieceColor::White) {
|
||||
this->draw.second = true;
|
||||
} else {
|
||||
this->draw.first = true;
|
||||
}
|
||||
if (this->draw.first == true && this->draw.second == true) {
|
||||
this->game_status = {true, true};
|
||||
}
|
||||
} else {
|
||||
this->draw = {false, false};
|
||||
ChessPiece* chessPiece = nullptr;
|
||||
ChessPiecePosition toChessPiecePosition = ChessPiecePosition(chessPieceMove.GetToPositionFile(), chessPieceMove.GetToPositionRank());
|
||||
char fromPositionFile = chessPieceMove.GetFromPositionFile();
|
||||
@@ -388,28 +473,35 @@ void Chessboard::MoveChessPiece(std::string move) {
|
||||
|
||||
for (std::pair<ChessPiecePosition, ChessPiece*> field : this->chessboard) {
|
||||
if (field.second->GetColor() == this->GetCurrentPlayer()->GetColor()) {
|
||||
if (field.second->GetChar() == chessPieceMove.GetChessPieceChar() && field.second->GetNextPositions().count(toChessPiecePosition) == 1) {
|
||||
if (field.second->GetChar() == chessPieceMove.GetChessPieceChar()) {
|
||||
if (field.second->GetNextPositions().count(toChessPiecePosition) == 1) {
|
||||
|
||||
if (fromPositionFile >= 'a' && fromPositionFile <= 'h') {
|
||||
if (field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
if ((fromPositionFile >= 'a' && fromPositionFile <= 'h') && (fromPositionRank >= 1 && fromPositionRank <= 8)) {
|
||||
if ((field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) && (field.second->GetPosition().GetRank() == fromPositionRank)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (fromPositionFile >= 'a' && fromPositionFile <= 'h') {
|
||||
if (field.second->GetPosition().GetFile() == std::toupper(fromPositionFile)) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
} else if (fromPositionRank >= 1 && fromPositionRank <= 8) {
|
||||
if (field.second->GetPosition().GetRank() == fromPositionRank) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fromPositionRank >= 1 && fromPositionRank <= 8) {
|
||||
if (field.second->GetPosition().GetRank() == fromPositionRank) {
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
}
|
||||
|
||||
chessPiece = field.second;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,12 +595,15 @@ void Chessboard::MoveChessPiece(std::string move) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "chess piece not found!";
|
||||
}
|
||||
}
|
||||
|
||||
this->SetToHistory(chessPieceMove);
|
||||
this->UpdateChessPieces();
|
||||
this->SwitchCurrentPlayer();
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
@@ -531,8 +626,13 @@ std::vector<ChessPiece*> Chessboard::GetChessPieces() {
|
||||
return chessPieces;
|
||||
}
|
||||
|
||||
void Chessboard::SetPlayers(Player* playerA, Player* playerB) {
|
||||
this->players = {playerB, playerA};
|
||||
|
||||
|
||||
this->GetPlayer(ChessPieceColor::White)->SetColor(ChessPieceColor::White);
|
||||
this->GetPlayer(ChessPieceColor::Black)->SetColor(ChessPieceColor::Black);
|
||||
this->currentPlayer = this->GetPlayer(ChessPieceColor::White);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -541,7 +641,7 @@ std::vector<ChessPiece*> Chessboard::GetChessPieces() {
|
||||
* @param Player* playerA The first player.
|
||||
* @param Player* playerB The second player.
|
||||
*/
|
||||
void Chessboard::SetPlayers(Player* playerA, Player* playerB) {
|
||||
void Chessboard::SetPlayersRdm(Player* playerA, Player* playerB) {
|
||||
std::random_device rngdevice;
|
||||
std::mt19937 generator(rngdevice());
|
||||
std::uniform_int_distribution<int> distr(0, 1);
|
||||
@@ -626,40 +726,189 @@ ChessPiece* Chessboard::GetChessPieceKing(ChessPieceColor color) {
|
||||
|
||||
|
||||
bool Chessboard::ExportFilePGN(std::string filePath) {
|
||||
std::string moveList;
|
||||
if (std::filesystem::exists(filePath)) {
|
||||
if (std::filesystem::is_directory(filePath)) {
|
||||
|
||||
filePath = this->GenerateExportFilePath(filePath);
|
||||
std::string player1 = this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
std::string player2 = this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
std::string round;
|
||||
|
||||
// Regex-Pattern, um die Zahl nach "Runde " zu finden
|
||||
std::regex pattern(R"(\bRunde\s+(\d+))");
|
||||
std::smatch match;
|
||||
|
||||
if (std::regex_search(filePath, match, pattern)) {
|
||||
round = match[1]; // Die gefundene Zahl (Gruppe 1)
|
||||
}
|
||||
|
||||
std::ofstream file(filePath);
|
||||
if (file.is_open()) {
|
||||
file << GeneratePGNContent(GetTodaysDate("%Y.%m.%d"), player1, player2, round);
|
||||
file.close();
|
||||
} else {
|
||||
throw "File could not be created and opened";
|
||||
}
|
||||
} else {
|
||||
throw "Path exists but is not a directory";
|
||||
}
|
||||
} else {
|
||||
throw "Path could not be found";
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Chessboard::GenerateExportFilePath(std::string& filePath) {
|
||||
if (this->GetCurrentSaveFilename().empty()) {
|
||||
std::string player1 = this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
std::string player2 = this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
|
||||
std::string fileName = GetTodaysDate("%Y%m%d").append(" - ").append(player1).append(" gegen ").append(player2);
|
||||
|
||||
fileName.append(" - Runde ").append(GetRound(filePath, fileName));
|
||||
|
||||
this->SetCurrentSaveFilename(fileName);
|
||||
|
||||
filePath.append(fileName).append(".PGN");
|
||||
return filePath;
|
||||
} else {
|
||||
return filePath.append(this->GetCurrentSaveFilename()).append(".PGN");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GetTodaysDate(std::string format) {
|
||||
// Hole aktuelle Zeit
|
||||
std::time_t now = std::time(nullptr);
|
||||
// Zerlege die Zeit in eine Struktur
|
||||
std::tm* localTime = std::localtime(&now);
|
||||
|
||||
// Formatiere das Datum
|
||||
std::ostringstream dateStream;
|
||||
dateStream << std::put_time(localTime, format.c_str());
|
||||
|
||||
return dateStream.str();
|
||||
}
|
||||
|
||||
// ToDo: Zählt noch nicht richtig
|
||||
std::string Chessboard::GetRound(const std::string& folderPath, const std::string& baseFileName) {
|
||||
size_t count = 0;
|
||||
|
||||
// Escape-Funktion für Regex
|
||||
auto escapeRegex = [](const std::string& str) {
|
||||
std::string escaped;
|
||||
for (char c : str) {
|
||||
if (std::string(".^$|()[]*+?\\").find(c) != std::string::npos) {
|
||||
escaped += '\\';
|
||||
}
|
||||
escaped += c;
|
||||
}
|
||||
return escaped;
|
||||
};
|
||||
|
||||
// Erstelle das Regex-Pattern
|
||||
std::string pattern = "^" + escapeRegex(baseFileName) + R"(\d+\.pgn$)";
|
||||
std::regex regexPattern(pattern, std::regex::icase); // Case-insensitive
|
||||
|
||||
std::cout << "Regex-Pattern: " << pattern << std::endl;
|
||||
|
||||
// Iteriere durch den Ordner
|
||||
for (const auto& entry : std::filesystem::directory_iterator(folderPath)) {
|
||||
if (entry.is_regular_file()) {
|
||||
std::string fileName = entry.path().filename().string();
|
||||
std::cout << "Prüfe Datei: " << fileName << std::endl;
|
||||
|
||||
if (std::regex_match(fileName, regexPattern)) {
|
||||
std::cout << "Datei passt: " << fileName << std::endl;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return std::to_string(count + 1);
|
||||
}
|
||||
|
||||
std::string Chessboard::GetWinner() {
|
||||
if (this->game_status.first == true && this->game_status.second == true) {
|
||||
return "";
|
||||
} else if (this->game_status.first == true) {
|
||||
return "Black";
|
||||
//return this->GetPlayer(ChessPieceColor::Black)->GetName();
|
||||
} else if (this->game_status.second == true) {
|
||||
return "White";
|
||||
//return this->GetPlayer(ChessPieceColor::White)->GetName();
|
||||
} else {
|
||||
return "Unknown";
|
||||
}
|
||||
}
|
||||
void Chessboard::SetWinner(Player* winner) {
|
||||
if (winner->GetColor() == ChessPieceColor::White) {
|
||||
this->game_status = {false, true};
|
||||
} else {
|
||||
this->game_status = {true, false};
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GeneratePGNContent(std::string today, std::string player1, std::string player2, std::string round) {
|
||||
return std::string("[Event \"Private Game\"]\n") // ersten vier werden nicht berücksichtigt
|
||||
.append("[Site \"Horb am Neckar, Germany\"]\n")
|
||||
.append("[Date \"").append(today).append("\"]\n")
|
||||
.append("[Round \"").append(round).append("\"]\n")
|
||||
.append("[White \"").append(player1).append("\"]\n")
|
||||
.append("[Black \"").append(player2).append("\"]\n")
|
||||
.append("[PlyCount \"").append(std::to_string(this->GetHistoryMoves().size())).append("\"]\n")
|
||||
.append("[Result \"").append(GetPGNResult()).append("\"]\n")
|
||||
.append("\n")
|
||||
.append(GenerateMoveList());
|
||||
}
|
||||
|
||||
std::string Chessboard::GenerateMoveList() {
|
||||
std::string result;
|
||||
std::vector<ChessPieceMove> moves = this->GetHistoryMoves();
|
||||
|
||||
time_t timestamp = time(NULL);
|
||||
struct tm datetime = *localtime(×tamp);
|
||||
char output[50];
|
||||
strftime(output, 50, "%Y.%m.%d", &datetime);
|
||||
|
||||
/**
|
||||
|
||||
[Result "1/2-1/2"]
|
||||
|
||||
[ECO "A29"]
|
||||
[WhiteElo "2750"]
|
||||
[BlackElo "2595"]
|
||||
[PlyCount "155"]
|
||||
*/
|
||||
|
||||
moveList.append("[Date \"").append(output).append("\"]").append("\n");
|
||||
moveList.append("[White \"").append(this->GetPlayer(ChessPieceColor::White)->GetName()).append("\"]").append("\n");
|
||||
moveList.append("[Black \"").append(this->GetPlayer(ChessPieceColor::Black)->GetName()).append("\"]").append("\n");
|
||||
|
||||
|
||||
for (int moveIndex = 0; moveIndex < moves.size() - 1; moveIndex++) {
|
||||
if (moveIndex % 6 == 0) {
|
||||
moveList.append("\n");
|
||||
if (this->HasMoves()) {
|
||||
for (size_t moveIndex = 0; moveIndex < moves.size() ; ++moveIndex) {
|
||||
if (moveIndex % 6 == 0) {
|
||||
result.append("\n");
|
||||
}
|
||||
if (moveIndex % 2 == 0) {
|
||||
result.append(std::to_string((moveIndex / 2) + 1)).append(".");
|
||||
}
|
||||
result.append(" ").append(moves[moveIndex].ToString()).append(" ");
|
||||
}
|
||||
if (moveIndex % 2 == 0) {
|
||||
moveList.append(std::to_string((moveIndex / 2) + 1)).append(".");
|
||||
}
|
||||
moveList.append(" ").append(moves[moveIndex].ToString()).append(" ");
|
||||
}
|
||||
|
||||
std::cout << moveList;
|
||||
return true;
|
||||
result.append(GetPGNResult());
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::pair<bool, bool> Chessboard::GetGameState() {
|
||||
return this->game_status;
|
||||
};
|
||||
|
||||
void Chessboard::SetGameState(std::pair<bool, bool> gameState) {
|
||||
this->game_status = gameState;
|
||||
};
|
||||
|
||||
std::string Chessboard::GetPGNResult() {
|
||||
std::pair<bool, bool> state = GetGameState();
|
||||
|
||||
if (state.first == true && state.second == true) {
|
||||
return std::string("1/2-1/2");
|
||||
} else if (state.first == true && state.second == false) {
|
||||
return std::string("0-1");
|
||||
} else if (state.first == false && state.second == true) {
|
||||
return std::string("1-0");
|
||||
} else {
|
||||
return std::string("*");
|
||||
}
|
||||
}
|
||||
|
||||
std::string Chessboard::GetCurrentSaveFilename() {
|
||||
return this->currentSaveFilename;
|
||||
}
|
||||
|
||||
void Chessboard::SetCurrentSaveFilename(std::string currentSaveFilename) {
|
||||
this->currentSaveFilename = currentSaveFilename;
|
||||
}
|
@@ -1,15 +1,17 @@
|
||||
#ifndef Chessboard_H
|
||||
#define Chessboard_H
|
||||
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <memory>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <filesystem>
|
||||
#include "../Player/Player.hpp"
|
||||
#include "../ChessPieces/ChessPieceColor.hpp"
|
||||
#include "../ChessPieces/ChessPieceMove.hpp"
|
||||
@@ -19,10 +21,22 @@ class ChessPiece;
|
||||
|
||||
class Chessboard {
|
||||
private:
|
||||
inline static const std::string save_path = "chessgames/save_files/";
|
||||
|
||||
Player* winner = nullptr;
|
||||
std::string currentSaveFilename;
|
||||
|
||||
// false, false => Laufend
|
||||
// true, false => black win
|
||||
// false, true => white win
|
||||
// true, true => Draw/Stalmate
|
||||
std::pair<bool, bool> game_status = std::make_pair(false, false);
|
||||
|
||||
std::vector<ChessPieceMove> _historyMoves;
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> _historyPositions;
|
||||
std::map<ChessPiecePosition, ChessPiece*> chessboard;
|
||||
std::pair<Player*, Player*> players;
|
||||
std::pair<bool, bool> draw = std::make_pair(false, false);;
|
||||
Player* currentPlayer;
|
||||
void RemoveChessPiece(ChessPiecePosition position);
|
||||
|
||||
@@ -30,13 +44,16 @@ class Chessboard {
|
||||
~Chessboard();
|
||||
std::vector<ChessPieceMove> GetHistoryMoves();
|
||||
std::vector<std::pair<ChessPiecePosition, ChessPiecePosition>> GetHistoryPositions();
|
||||
std::string GetTodaysDate(std::string format);
|
||||
void SetStartingPosition();
|
||||
void SetChessPiece(ChessPiece* chesspiece);
|
||||
bool IsDraw();
|
||||
bool IsEmptyField(ChessPiecePosition* position);
|
||||
ChessPiece* GetChessPiece(ChessPiecePosition* position);
|
||||
std::vector<ChessPiece*> GetChessPieces();
|
||||
void UpdateChessPieces();
|
||||
void MoveChessPiece(std::string move);
|
||||
bool MoveCastling(ChessPieceColor color, bool shortCastling);
|
||||
std::string MoveCastling(ChessPieceColor color, bool shortCastling);
|
||||
std::string MoveChessPiece(std::string move);
|
||||
void SetToHistory(ChessPieceMove move);
|
||||
void SetToHistory(ChessPiecePosition fromPosition, ChessPiecePosition toPosition);
|
||||
int GetCountMoves();
|
||||
@@ -48,12 +65,25 @@ class Chessboard {
|
||||
bool IsPositionUnderAttack(ChessPiecePosition position, ChessPieceColor color);
|
||||
Player* GetCurrentPlayer();
|
||||
Player* GetOpponentPlayer();
|
||||
void SetPlayersRdm(Player* playerA, Player* playerB);
|
||||
void SetPlayers(Player* playerA, Player* playerB);
|
||||
void SwitchCurrentPlayer();
|
||||
Player* GetPlayer(ChessPieceColor color);
|
||||
ChessPiece* GetChessPieceKing(ChessPieceColor color);
|
||||
bool ImportFilePGN(std::string filePath);
|
||||
std::string ImportFilePGN(std::string filePath);
|
||||
bool ExportFilePGN(std::string filePath);
|
||||
void SetWinner(Player* winner);
|
||||
std::string GeneratePGNContent(std::string today, std::string player1, std::string player2, std::string round);
|
||||
std::string GenerateMoveList();
|
||||
std::pair<bool, bool> GetGameState();
|
||||
void SetGameState(std::pair<bool, bool> gameState);
|
||||
std::string GetPGNResult();
|
||||
std::string GetRound(const std::string& folderPath, const std::string& baseFileName);
|
||||
std::string GetCurrentSaveFilename();
|
||||
void SetCurrentSaveFilename(std::string currentSaveFileName);
|
||||
std::string GenerateExportFilePath(std::string& filePath);
|
||||
std::string GetWinner();
|
||||
bool IsFinished();
|
||||
};
|
||||
|
||||
#endif
|
1
src/Chessboard/ChessboardVisualizer.cpp
Normal file
1
src/Chessboard/ChessboardVisualizer.cpp
Normal file
@@ -0,0 +1 @@
|
||||
//#include "../Chessboard/ChessboardVisualizer.hpp"
|
@@ -1,4 +1,4 @@
|
||||
#ifndef ChessboardVisualizer_H
|
||||
/*#ifndef ChessboardVisualizer_H
|
||||
#define ChessboardVisualizer_H
|
||||
|
||||
#include "../ChessPieces/ChessPiece.hpp"
|
||||
@@ -10,4 +10,4 @@ class ChessboardVisualizer {
|
||||
virtual void Draw(Chessboard* chessboard) = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif*/
|
254
src/Controller/MenuController.cpp
Normal file
254
src/Controller/MenuController.cpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#include "MenuController.hpp"
|
||||
#include "../Player/Player.hpp"
|
||||
#include "../Visualizer/BaseVisualizer.hpp"
|
||||
#include "../Visualizer/InstructionsVisualizer.hpp"
|
||||
#include "../Visualizer/ImportVisualizer.hpp"
|
||||
#include "../Visualizer/PlayingViewVisualizer.hpp"
|
||||
#include "../Visualizer/PlaySelectVisualizer.hpp"
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
MenuController::MenuController() {
|
||||
// Konstruktor, falls nötig
|
||||
}
|
||||
|
||||
MenuController::~MenuController() {
|
||||
// Destruktor, falls nötig
|
||||
}
|
||||
|
||||
void MenuController::HandlePlayingNavigation(std::string choice, Chessboard& chessboard, PlayingViewVisualizer& playView, bool isGameOver) {
|
||||
if (choice.empty() == false) {
|
||||
if (choice.at(0) == '$') {
|
||||
if (choice == "$0") {
|
||||
return;
|
||||
} else if (choice == "$1") {
|
||||
HandleThirdOption();
|
||||
} else if (choice == "$2") {
|
||||
chessboard.ExportFilePGN("chessgames/save_games/");
|
||||
} else if (choice == "$3") {
|
||||
if (isGameOver) {
|
||||
playView.SetMessage("Game is over! No moves allowed.");
|
||||
} else {
|
||||
chessboard.SetWinner(chessboard.GetOpponentPlayer());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (isGameOver) {
|
||||
playView.SetMessage("Game is over! No moves allowed.");
|
||||
} else {
|
||||
playView.SetMessage(chessboard.MoveChessPiece(choice));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuController::HandleFirstOption() {
|
||||
PlaySelectVisualizer playerSelect(3);
|
||||
|
||||
std::string choiceA;
|
||||
std::string choiceB;
|
||||
|
||||
do {
|
||||
playerSelect.SetLabelPlayerName("first player");
|
||||
choiceA = playerSelect.ShowMenu();
|
||||
|
||||
if (choiceA.length() > 40) {
|
||||
choiceA.clear();
|
||||
}
|
||||
} while (choiceA.empty());
|
||||
|
||||
do {
|
||||
playerSelect.SetLabelPlayerName("second player");
|
||||
choiceB = playerSelect.ShowMenu();
|
||||
|
||||
if (choiceB.length() > 40) {
|
||||
choiceB.clear();
|
||||
};
|
||||
} while (choiceB.empty());
|
||||
|
||||
// Spieler initialisieren
|
||||
Player* playerA = new Player(choiceA);
|
||||
Player* playerB = new Player(choiceB);
|
||||
|
||||
// Schachbrett initialisieren
|
||||
Chessboard chessboard;
|
||||
chessboard.SetPlayersRdm(playerA, playerB);
|
||||
chessboard.SetStartingPosition();
|
||||
chessboard.UpdateChessPieces();
|
||||
|
||||
SetChessboard(&chessboard);
|
||||
|
||||
PlayingViewVisualizer playView(&chessboard, 4, 12);
|
||||
|
||||
std::string choiceChessboard;
|
||||
|
||||
do {
|
||||
while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, false);
|
||||
}
|
||||
|
||||
std::string winner = chessboard.GetWinner();
|
||||
choiceChessboard = "$0";
|
||||
|
||||
if (winner.empty()) {
|
||||
playView.SetMessage("Game is over! - Draw");
|
||||
} else {
|
||||
playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
}
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
do {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, true);
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
|
||||
// while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
// playView.DisplayElement();
|
||||
|
||||
// std::string input;
|
||||
// std::cout << "\x1B[u"; // Cursor-Positionierung
|
||||
// std::cin >> input;
|
||||
|
||||
// std::string command = ExtractAfterDollar(input);
|
||||
// if (!command.empty()) {
|
||||
// HandleCommandOptions(command);
|
||||
// if (command == "0") {
|
||||
// return;
|
||||
// }
|
||||
// } else {
|
||||
// std::string status = chessboard.MoveChessPiece(input);
|
||||
// if (status.empty() == false) {
|
||||
// playView.SetMessage(status);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::string winner = chessboard.GetWinner();
|
||||
|
||||
// if (winner.empty()) {
|
||||
// playView.SetMessage("Game is over! - Draw");
|
||||
// } else {
|
||||
// playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
// }
|
||||
|
||||
// while (true) {
|
||||
// playView.DisplayElement();
|
||||
// std::string input;
|
||||
// std::cout << "\x1B[u"; // Cursor-Positionierung
|
||||
// std::cin >> input;
|
||||
|
||||
// std::string command = ExtractAfterDollar(input);
|
||||
// if (command == "0") {
|
||||
// return;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
void MenuController::HandleSecondOption() {
|
||||
ImportVisualizer importSelect;
|
||||
|
||||
std::string filePath;
|
||||
|
||||
do {
|
||||
filePath = importSelect.ShowMenu();
|
||||
|
||||
if (std::filesystem::exists(filePath) == false) {
|
||||
filePath.clear();
|
||||
}
|
||||
} while (filePath.empty());
|
||||
|
||||
Chessboard chessboard;
|
||||
chessboard.SetStartingPosition();
|
||||
chessboard.UpdateChessPieces();
|
||||
SetChessboard(&chessboard);
|
||||
|
||||
std::string status = chessboard.ImportFilePGN(filePath);
|
||||
|
||||
PlayingViewVisualizer playView(&chessboard, 4, 12);
|
||||
playView.SetMessage(status);
|
||||
std::string choiceChessboard;
|
||||
|
||||
do {
|
||||
while (!chessboard.IsCheckmate() && !chessboard.IsStalemate() && !chessboard.IsDraw() && chessboard.IsFinished() == false) {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, false);
|
||||
}
|
||||
|
||||
std::string winner = chessboard.GetWinner();
|
||||
choiceChessboard = "$0";
|
||||
|
||||
if (winner.empty()) {
|
||||
playView.SetMessage("Game is over! - Draw");
|
||||
} else {
|
||||
playView.SetMessage("Game is over! - " + winner + " has won the game!");
|
||||
}
|
||||
} while (choiceChessboard != "$0");
|
||||
|
||||
do {
|
||||
choiceChessboard = playView.ShowMenu();
|
||||
this->HandlePlayingNavigation(choiceChessboard, chessboard, playView, true);
|
||||
} while (choiceChessboard != "$0");
|
||||
}
|
||||
|
||||
// ToDo:: Hier muss aus irgendeinem Grund immer zweimal die Eingabe abgeschickt werden. Why!?
|
||||
void MenuController::HandleThirdOption() {
|
||||
InstructionsVisualizer instructions;
|
||||
instructions.DrawView();
|
||||
}
|
||||
|
||||
// void MenuController::HandleCommandOptions(const std::string& command) {
|
||||
// if (command == "1") {
|
||||
// HandleThirdOption();
|
||||
// return;
|
||||
// } else if (command == "2") {
|
||||
// CHESSBOARD->ExportFilePGN("chessgames/save_games/");
|
||||
// std::cout << "Save game functionality is not implemented yet.\n";
|
||||
// } else if (command == "3") {
|
||||
// CHESSBOARD->SetWinner(CHESSBOARD->GetOpponentPlayer());
|
||||
// return;
|
||||
// } else if (command == "0") { // exit
|
||||
// return;
|
||||
// } else {
|
||||
// std::cout << "Invalid command. Please try again.\n";
|
||||
// }
|
||||
// }
|
||||
|
||||
// std::string MenuController::ExtractAfterDollar(const std::string& userInput) {
|
||||
// if (!userInput.empty() && userInput[0] == '$') {
|
||||
// return userInput.substr(1); // Rückgabe des Teils nach '$'
|
||||
// }
|
||||
// return ""; // Leerer String, wenn kein '$' am Anfang
|
||||
// }
|
||||
|
||||
// Chessboard* MenuController::GetChessboard() {
|
||||
// return CHESSBOARD;
|
||||
// }
|
||||
|
||||
void MenuController::SetChessboard(Chessboard* chessboard) {
|
||||
CHESSBOARD = chessboard;
|
||||
}
|
||||
|
||||
// std::string MenuController::trim(const std::string& str) {
|
||||
// size_t start = str.find_first_not_of(" \t\n\r\f\v");
|
||||
// if (start == std::string::npos) return ""; // Nur Leerzeichen
|
||||
// size_t end = str.find_last_not_of(" \t\n\r\f\v");
|
||||
// return str.substr(start, end - start + 1);
|
||||
// }
|
||||
|
||||
// std::vector<std::string> MenuController::split(const std::string& str, char delimiter, bool trimWhitespace) {
|
||||
// std::vector<std::string> tokens;
|
||||
// std::istringstream stream(str);
|
||||
// std::string token;
|
||||
|
||||
// while (std::getline(stream, token, delimiter)) {
|
||||
// if (trimWhitespace) {
|
||||
// token = trim(token); // Trimme die Tokens, falls gewünscht
|
||||
// }
|
||||
// tokens.push_back(token);
|
||||
// }
|
||||
|
||||
// return tokens;
|
||||
// }
|
29
src/Controller/MenuController.hpp
Normal file
29
src/Controller/MenuController.hpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef MENU_CONTROLLER_HPP
|
||||
#define MENU_CONTROLLER_HPP
|
||||
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../Visualizer/PlayingViewVisualizer.hpp"
|
||||
#include <string>
|
||||
|
||||
class MenuController {
|
||||
private:
|
||||
std::string ExtractAfterDollar(const std::string& userInput);
|
||||
void HandlePlayingNavigation(std::string choice, Chessboard& chessboard, PlayingViewVisualizer& playView, bool isGameOver);
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
public:
|
||||
MenuController();
|
||||
~MenuController();
|
||||
|
||||
void HandleFirstOption();
|
||||
void HandleSecondOption();
|
||||
void HandleThirdOption();
|
||||
// void HandleCommandOptions(const std::string& command);
|
||||
// Chessboard* GetChessboard();
|
||||
void SetChessboard(Chessboard* chessboard);
|
||||
// std::string trim(const std::string& str);
|
||||
// std::vector<std::string> split(const std::string& str, char delimiter, bool trimWhitespace = false);
|
||||
};
|
||||
|
||||
#endif // MENU_CONTROLLER_HPP
|
281
src/Visualizer/BaseVisualizer.cpp
Normal file
281
src/Visualizer/BaseVisualizer.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
||||
void BaseVisualizer::ClearTerminal() {
|
||||
#ifdef __linux__
|
||||
system("clear");
|
||||
#elif _WIN32
|
||||
system("cls");
|
||||
#else
|
||||
system("clear");
|
||||
#endif
|
||||
}
|
||||
|
||||
std::vector<std::vector<std::string>>* BaseVisualizer::GetDisplayVector() {
|
||||
return &display_vector;
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::CountVisibleCharacters(const std::string& str) {
|
||||
size_t count = 0;
|
||||
size_t i = 0;
|
||||
|
||||
while (i < str.size()) {
|
||||
if (str[i] == '\x1B' && i + 1 < str.size() && str[i + 1] == '[') {
|
||||
// ANSI-Escape-Sequenz erkennen und überspringen
|
||||
i += 2; // Überspringe '\x1B['
|
||||
while (i < str.size() && !std::isalpha(str[i])) {
|
||||
++i; // Fortsetzung der Sequenz überspringen
|
||||
}
|
||||
if (i < str.size() && std::isalpha(str[i])) {
|
||||
++i; // Buchstaben am Ende der Sequenz überspringen
|
||||
}
|
||||
} else {
|
||||
// UTF-8 Startbytes zählen (kein Fortsetzungsbyte)
|
||||
if ((str[i] & 0b11000000) != 0b10000000) {
|
||||
++count;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::GetSumAllCharsFromVector(const std::vector<std::string>& vec) {
|
||||
size_t sum = 0;
|
||||
for (const std::string& str : vec) {
|
||||
sum += CountVisibleCharacters(str);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateEmptyLine(const int lengthOfMenu, const bool single) {
|
||||
std::string result = "";
|
||||
for (int i = 0; i < lengthOfMenu; ++i) {
|
||||
if (i == 0) {
|
||||
result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
} else if (i == lengthOfMenu-1) {
|
||||
result += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
} else {
|
||||
result += " ";
|
||||
}
|
||||
}
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
// ToDo: Auf Max länge bringen
|
||||
void BaseVisualizer::GenerateBoxMenuLine(const size_t length, const std::string& str, const bool single, const size_t padding) {
|
||||
std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE) + std::string(padding, ' ') + str;
|
||||
while (CountVisibleCharacters(result) < length-1) {
|
||||
result += " ";
|
||||
}
|
||||
display_vector.push_back({result.append(((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE))});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateCenteredString(const size_t widthOfMenu, const std::string& str, const bool single) {
|
||||
std::string result = (single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE;
|
||||
|
||||
float newLength = widthOfMenu - CountVisibleCharacters(str) - 2;
|
||||
|
||||
int firstHalfLength = std::floor(newLength / 2);
|
||||
int secondHalfLength = std::ceil(newLength / 2);
|
||||
|
||||
for (int i = 0; i < firstHalfLength; ++i) {
|
||||
result += " ";
|
||||
}
|
||||
|
||||
result += str;
|
||||
|
||||
for (int i = 0; i < secondHalfLength; ++i) {
|
||||
result += " ";
|
||||
}
|
||||
|
||||
display_vector.push_back({result+ ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE)});
|
||||
}
|
||||
|
||||
void BaseVisualizer::DisplayElement() {
|
||||
for (const auto& row : display_vector) {
|
||||
for (const auto& cell : row) {
|
||||
std::cout << cell;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::CalculateMaxMenuWidth(const size_t longestStringLength, const size_t padding) {
|
||||
return longestStringLength + 2*padding + 2;
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTopBottomBorder(const size_t totalLength, const bool top, const bool single) {
|
||||
std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
for (size_t i = 0; i < totalLength-2; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
void BaseVisualizer::AddEmptyLines(const size_t lines, const size_t length, const bool sinlge) {
|
||||
for (size_t i = 0; i < lines; ++i) {
|
||||
BaseVisualizer::GenerateEmptyLine(length, sinlge);
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTableTopBottom(const size_t totalLength, const bool top, const bool single) {
|
||||
int firstHalfLength = std::floor(totalLength / 2);
|
||||
|
||||
std::string result = (top) ? ((single) ? BaseVisualizer::TOP_LEFT_CORNER_SINGLE : BaseVisualizer::TOP_LEFT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE : BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
|
||||
for (size_t i = 0; i < firstHalfLength-1; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
|
||||
result += (top) ? ((single) ? BaseVisualizer::TOP_CROSS_SINGLE : BaseVisualizer::TOP_CROSS) : ((single) ? BaseVisualizer::BOTTOM_CROSS_SINGLE : BaseVisualizer::BOTTOM_CROSS);
|
||||
|
||||
for (size_t i = 0; i < firstHalfLength-1; ++i) {
|
||||
result += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
|
||||
display_vector.push_back({result + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
// Todo: pair anstatt vector
|
||||
void BaseVisualizer::GenerateTableLine(const float length, const std::vector<std::string>& str, const bool single) {
|
||||
int firstHalfLength = std::floor(length / 2);
|
||||
std::string result = ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
std::string temp;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
temp += " " + str[i];
|
||||
|
||||
while (CountVisibleCharacters(temp) < firstHalfLength-1) {
|
||||
temp += " ";
|
||||
}
|
||||
temp += ((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE);
|
||||
result += temp;
|
||||
temp = "";
|
||||
}
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateTableSeperator(const float length, const bool single) {
|
||||
int firstHalfLength = std::floor(length / 2);
|
||||
std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);
|
||||
std::string temp;
|
||||
|
||||
for (size_t i = 0; i < 2; ++i) {
|
||||
while (CountVisibleCharacters(temp) < firstHalfLength-1) {
|
||||
temp += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
|
||||
}
|
||||
temp += (i != 1) ? ((single) ? BaseVisualizer::CROSS_SINGLE : BaseVisualizer::CROSS) : "";
|
||||
result += temp;
|
||||
temp = "";
|
||||
}
|
||||
result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);
|
||||
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::GenerateBoxSeperator(const float length, const bool single) {
|
||||
std::string result = ((single) ? BaseVisualizer::RIGHT_CROSS_SINGLE : BaseVisualizer::RIGHT_CROSS);
|
||||
|
||||
while (CountVisibleCharacters(result) < length-1) {
|
||||
result += ((single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE);
|
||||
}
|
||||
|
||||
result += ((single) ? BaseVisualizer::LEFT_CROSS_SINGLE : BaseVisualizer::LEFT_CROSS);
|
||||
|
||||
display_vector.push_back({result});
|
||||
}
|
||||
|
||||
void BaseVisualizer::SetConsoleColor(Colors foreground, Colors background) {
|
||||
const std::string SEQ_FOREGROUND = "\x1b[3";
|
||||
const std::string SEQ_FOREGROUND_LIGHT = "\x1b[9";
|
||||
const std::string SEQ_BACKGROUND = "\x1b[4";
|
||||
const std::string SEQ_BACKGROUND_LIGHT = "\x1b[10";
|
||||
|
||||
// set foreground color
|
||||
switch (foreground) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_FOREGROUND_LIGHT << foreground << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_FOREGROUND << foreground << "m";
|
||||
break;
|
||||
}
|
||||
|
||||
// set background color
|
||||
switch (background) {
|
||||
case BLACK:
|
||||
case RED:
|
||||
case GREEN:
|
||||
case YELLOW:
|
||||
case BLUE:
|
||||
case MAGENTA:
|
||||
case CYAN:
|
||||
case WHITE:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
case LIGHT_BLACK:
|
||||
case LIGHT_RED:
|
||||
case LIGHT_GREEN:
|
||||
case LIGHT_YELLOW:
|
||||
case LIGHT_BLUE:
|
||||
case LIGHT_MAGENTA:
|
||||
case LIGHT_CYAN:
|
||||
case LIGHT_WHITE:
|
||||
std::cout << SEQ_BACKGROUND_LIGHT << background << "m";
|
||||
break;
|
||||
case DEFAULT:
|
||||
default:
|
||||
std::cout << SEQ_BACKGROUND << background << "m";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
size_t BaseVisualizer::FindMaxLength(const std::vector<std::string> vec) {
|
||||
size_t max = 0;
|
||||
size_t currentLength = 0;
|
||||
for (const std::string& str : vec) {
|
||||
currentLength = CountVisibleCharacters(str);
|
||||
(currentLength > max) ? max = CountVisibleCharacters(str) : max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
std::pair<int, int> BaseVisualizer::GetCursorPosition() {
|
||||
std::cout << "\033[6n"; // ANSI-Escape-Sequenz, um die Cursorposition abzufragen
|
||||
std::fflush(stdout); // Ausgabe sofort erzwingen
|
||||
|
||||
int row, col;
|
||||
|
||||
// Eingabe im Format "\033[row;colR" lesen
|
||||
char buf[32];
|
||||
if (std::fgets(buf, sizeof(buf), stdin)) {
|
||||
if (std::sscanf(buf, "\033[%d;%dR", &row, &col) != 2) {
|
||||
row = col = -1; // Fehlerbehandlung
|
||||
}
|
||||
} else {
|
||||
row = col = -1; // Fehlerbehandlung
|
||||
}
|
||||
|
||||
return std::pair<int, int>(row, col); // Rückgabe als Tupel
|
||||
};
|
100
src/Visualizer/BaseVisualizer.hpp
Normal file
100
src/Visualizer/BaseVisualizer.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef BASEVISUALIZER_H
|
||||
#define BASEVISUALIZER_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
|
||||
enum Colors {
|
||||
BLACK = 0, RED = 1, GREEN = 2, YELLOW = 3, BLUE = 4, MAGENTA = 5, CYAN = 6, WHITE = 7,
|
||||
LIGHT_BLACK = 10, LIGHT_RED = 11, LIGHT_GREEN = 12, LIGHT_YELLOW = 13, LIGHT_BLUE = 14,
|
||||
LIGHT_MAGENTA = 15, LIGHT_CYAN = 16, LIGHT_WHITE = 17, DEFAULT = 9
|
||||
};
|
||||
|
||||
class BaseVisualizer {
|
||||
protected:
|
||||
inline static const std::string TOP_LEFT_CORNER = "\u2554";
|
||||
inline static const std::string TOP_RIGHT_CORNER = "\u2557";
|
||||
inline static const std::string HORIZONTAL_LINE = "\u2550";
|
||||
inline static const std::string VERTICAL_LINE = "\u2551";
|
||||
inline static const std::string BOTTOM_LEFT_CORNER = "\u255A";
|
||||
inline static const std::string BOTTOM_RIGHT_CORNER = "\u255D";
|
||||
inline static const std::string RIGHT_CROSS = "\u2560";
|
||||
inline static const std::string LEFT_CROSS = "\u2563";
|
||||
inline static const std::string CROSS = "\u256C";
|
||||
inline static const std::string TOP_CROSS = "\u2566";
|
||||
inline static const std::string BOTTOM_CROSS = "\u2569";
|
||||
|
||||
inline static const std::string TOP_LEFT_CORNER_SINGLE = "\u250C";
|
||||
inline static const std::string TOP_RIGHT_CORNER_SINGLE = "\u2510";
|
||||
inline static const std::string HORIZONTAL_LINE_SINGLE = "\u2500";
|
||||
inline static const std::string VERTICAL_LINE_SINGLE = "\u2502";
|
||||
inline static const std::string BOTTOM_LEFT_CORNER_SINGLE = "\u2514";
|
||||
inline static const std::string BOTTOM_RIGHT_CORNER_SINGLE = "\u2518";
|
||||
inline static const std::string RIGHT_CROSS_SINGLE = "\u251C";
|
||||
inline static const std::string LEFT_CROSS_SINGLE = "\u2524";
|
||||
inline static const std::string CROSS_SINGLE = "\u253C";
|
||||
inline static const std::string TOP_CROSS_SINGLE = "\u252C";
|
||||
inline static const std::string BOTTOM_CROSS_SINGLE = "\u2534";
|
||||
|
||||
const size_t MAX_MENU_WIDTH;
|
||||
const size_t PADDING;
|
||||
|
||||
std::vector<std::vector<std::string>> display_vector;
|
||||
|
||||
void GenerateEmptyLine(const int lengthOfMenu, const bool single);
|
||||
void GenerateBoxMenuLine(const size_t length, const std::string& str, const bool single, const size_t padding);
|
||||
void GenerateCenteredString(const size_t widthOfMenu, const std::string& str, const bool single);
|
||||
size_t CalculateMaxMenuWidth(const size_t longestStringLength, const size_t padding);
|
||||
size_t FindMaxLength(const std::vector<std::string> vec);
|
||||
void GenerateTopBottomBorder(const size_t totalLength, const bool top, const bool single);
|
||||
void AddEmptyLines(const size_t lines, const size_t length, const bool sinlge);
|
||||
void GenerateTableTopBottom(const size_t totalLength, const bool top, const bool single);
|
||||
void GenerateTableLine(const float length, const std::vector<std::string>& str, const bool single);
|
||||
void GenerateTableSeperator(const float length, const bool single);
|
||||
void GenerateBoxSeperator(const float length, const bool single);
|
||||
void SetConsoleColor(Colors foreground, Colors background);
|
||||
std::pair<int, int> GetCursorPosition();
|
||||
|
||||
static size_t GetSumAllCharsFromVector(const std::vector<std::string>& vec);
|
||||
static size_t CountVisibleCharacters(const std::string& str);
|
||||
|
||||
private:
|
||||
virtual void GenerateElement() = 0;
|
||||
|
||||
public:
|
||||
virtual ~BaseVisualizer() = default;
|
||||
static void ClearTerminal();
|
||||
void DisplayElement();
|
||||
std::vector<std::vector<std::string>>* GetDisplayVector();
|
||||
BaseVisualizer(size_t longestStringLength, size_t padding) : MAX_MENU_WIDTH(BaseVisualizer::CalculateMaxMenuWidth(longestStringLength, padding)), PADDING(padding) {}
|
||||
};
|
||||
|
||||
#endif //BASEVISUALIZER_H
|
||||
|
||||
/**
|
||||
*
|
||||
ChessboardVisualizer.cpp
|
||||
HistorieVisualizer.cpp
|
||||
CommandVisualizer.cpp
|
||||
|
||||
PlayVisualizer.cpp {
|
||||
ChessboardVisualizer.display_vector
|
||||
|
||||
|
||||
HistorieVisualizer.display_vector;
|
||||
|
||||
CommandVisualizer.display_vector;
|
||||
|
||||
st::cout << ChessboardVisualizer.display_vector[i] (isEmpty) ? << std:endl : << Padding << Menus.display_vector[i] << std:endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
166
src/Visualizer/ChessboardVisualizer.cpp
Normal file
166
src/Visualizer/ChessboardVisualizer.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include "ChessboardVisualizer.hpp"
|
||||
|
||||
size_t ChessboardVisualizer::GetMaxBoardWidth() {
|
||||
std::string temp;
|
||||
|
||||
temp.append(3, ' ');
|
||||
|
||||
temp += BaseVisualizer::TOP_LEFT_CORNER;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 7; j++) {
|
||||
temp += BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
}
|
||||
temp += BaseVisualizer::TOP_RIGHT_CORNER;
|
||||
|
||||
return BaseVisualizer::CountVisibleCharacters(temp);
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateTopBottomBorder(bool top, bool single) {
|
||||
std::string temp;
|
||||
|
||||
temp.append(3, ' '); // ToDo: Padding?
|
||||
|
||||
temp += (top)
|
||||
? ((single)
|
||||
? BaseVisualizer::TOP_LEFT_CORNER_SINGLE
|
||||
: BaseVisualizer::TOP_LEFT_CORNER)
|
||||
: ((single)
|
||||
? BaseVisualizer::BOTTOM_LEFT_CORNER_SINGLE
|
||||
: BaseVisualizer::BOTTOM_LEFT_CORNER);
|
||||
for (int i = 0; i < 8; i++) {
|
||||
for (int j = 0; j < 7; j++) {
|
||||
temp += (single) ? BaseVisualizer::HORIZONTAL_LINE_SINGLE : BaseVisualizer::HORIZONTAL_LINE;
|
||||
}
|
||||
}
|
||||
display_vector.push_back({temp + ((top) ? ((single) ? BaseVisualizer::TOP_RIGHT_CORNER_SINGLE : BaseVisualizer::TOP_RIGHT_CORNER) : ((single) ? BaseVisualizer::BOTTOM_RIGHT_CORNER_SINGLE : BaseVisualizer::BOTTOM_RIGHT_CORNER))});
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateElement() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
|
||||
GeneratePlayers();
|
||||
|
||||
GenerateChessboard();
|
||||
|
||||
//GenerateDisplayVector();
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GeneratePlayers() {
|
||||
std::string result;
|
||||
result.append(3, ' ');
|
||||
display_vector.push_back({result + CHESSBOARD->GetPlayer(ChessPieceColor::White)->GetName()
|
||||
+ " vs. " + CHESSBOARD->GetPlayer(ChessPieceColor::Black)->GetName()});
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateChessboard() {
|
||||
std::vector<std::string> temp;
|
||||
for (int rank = 8; rank >= 1; rank--) {
|
||||
if (rank == 8) GenerateTopBottomBorder(true, true);
|
||||
for (int heightOfField = 0; heightOfField < 3; heightOfField++) {
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
temp.push_back((heightOfField == 1) ? " " + std::to_string(rank) + " " : std::string(3, ' '));
|
||||
temp.push_back(BaseVisualizer::VERTICAL_LINE_SINGLE);
|
||||
}
|
||||
|
||||
temp.push_back(GenerateBoardField(file, rank, heightOfField));
|
||||
|
||||
if (file == 'H') {
|
||||
temp.push_back(BaseVisualizer::VERTICAL_LINE_SINGLE);
|
||||
}
|
||||
}
|
||||
display_vector.push_back(temp);
|
||||
temp.clear();
|
||||
}
|
||||
if (rank == 1) {
|
||||
GenerateTopBottomBorder(false, true);
|
||||
GenerateFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ChessboardVisualizer::GenerateBoardField(char file, int rank, int height) {
|
||||
ChessPiecePosition* position = new ChessPiecePosition(file, rank);
|
||||
if (height == 1 && !CHESSBOARD->IsEmptyField(position)) {
|
||||
ChessPiece* piece = CHESSBOARD->GetChessPiece(position);
|
||||
return std::string(3, ' ') + piece->GetUnicode() + std::string(3, ' ');
|
||||
}
|
||||
return std::string(7, ' ');
|
||||
}
|
||||
|
||||
void ChessboardVisualizer::GenerateFiles() {
|
||||
std::string temp;
|
||||
|
||||
for (char file = 'A'; file <= 'H'; file++) {
|
||||
if (file == 'A') {
|
||||
temp += (std::string(4, ' '));
|
||||
}
|
||||
|
||||
temp += (std::string(3, ' ') + std::string(1, file) + std::string(3, ' '));
|
||||
|
||||
if (file == 'H') {
|
||||
temp += " ";
|
||||
}
|
||||
}
|
||||
display_vector.push_back({temp});
|
||||
}
|
||||
|
||||
|
||||
// board[2] bis board[25] Feld des Schachbretts
|
||||
// in vectoren von 2 bis 25 index von 2 bis 9
|
||||
void ChessboardVisualizer::DisplayElement() {
|
||||
size_t size;
|
||||
std::string temp;
|
||||
for (int row = 0; row < display_vector.size(); ++row) {
|
||||
for (int column = 0; column < display_vector[row].size(); ++column) {
|
||||
if (row >= 2 && row <= 25 && column >= 2 && column <= 9) {
|
||||
bool isSecondRowOfField = (row % 3 == 2);
|
||||
bool isBlackWhite = (column % 2 == row % 2);
|
||||
|
||||
if ((row - 1) % 3 == 0) { // Change after 3 rows
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
}
|
||||
} else {
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << display_vector[row][column];
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
/*void ChessboardVisualizer::GenerateDisplayVector() {
|
||||
std::string temp;
|
||||
size_t size;
|
||||
|
||||
for (auto& row : draw_vector) {
|
||||
if (row.size() > 1) {
|
||||
for (const auto& element : row) {
|
||||
temp += element;
|
||||
}
|
||||
display_vector.push_back(FillStringToMaxLength(temp));
|
||||
temp = "";
|
||||
} else {
|
||||
display_vector.push_back(FillStringToMaxLength(row[0]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ChessboardVisualizer::FillStringToMaxLength(std::string& str) {
|
||||
size_t size = BaseVisualizer::CountVisibleCharacters(str);
|
||||
return ((size == MAX_MENU_WIDTH)
|
||||
? str
|
||||
: str.append(std::string(MAX_MENU_WIDTH - size, ' ')));
|
||||
}*/
|
32
src/Visualizer/ChessboardVisualizer.hpp
Normal file
32
src/Visualizer/ChessboardVisualizer.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef CHESSBOARDVISUALIZER_HPP
|
||||
#define CHESSBOARDVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
#include "../Chesspieces/Chesspiece.hpp"
|
||||
|
||||
class ChessboardVisualizer : public BaseVisualizer {
|
||||
|
||||
private:
|
||||
Chessboard* CHESSBOARD;
|
||||
std::vector<std::vector<std::string>> draw_vector;
|
||||
|
||||
static size_t GetMaxBoardWidth();
|
||||
|
||||
void GenerateTopBottomBorder(bool top, bool single);
|
||||
void GenerateElement() override;
|
||||
void GeneratePlayers();
|
||||
void GenerateChessboard();
|
||||
void GenerateFiles();
|
||||
std::string GenerateBoardField(char file, int rank, int height);
|
||||
void GenerateDisplayVector();
|
||||
std::string FillStringToMaxLength(std::string& str);
|
||||
|
||||
public:
|
||||
ChessboardVisualizer(Chessboard* chessboard, size_t padding) : BaseVisualizer(ChessboardVisualizer::GetMaxBoardWidth(), padding), CHESSBOARD(chessboard) {
|
||||
ChessboardVisualizer::GenerateElement();
|
||||
};
|
||||
void DisplayElement();
|
||||
};
|
||||
|
||||
#endif //CHESSBOARDVISUALIZER_HPP
|
20
src/Visualizer/CommandMenuVisualizer.cpp
Normal file
20
src/Visualizer/CommandMenuVisualizer.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "CommandMenuVisualizer.hpp"
|
||||
|
||||
// ToDo: Cursor wird nicht an die richtige Stelle gesetzt
|
||||
void CommandMenuVisualizer::GenerateElement() {
|
||||
BaseVisualizer::display_vector.push_back({" Commands"});
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, true);
|
||||
for (const auto& content : menuContent) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, true, PADDING);
|
||||
}
|
||||
BaseVisualizer::GenerateBoxSeperator(MAX_MENU_WIDTH, true);
|
||||
std::string str_temp = ((CHESSBOARD->GetCurrentPlayer()->GetColor() == ChessPieceColor::White) ? "White" : "Black");
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Move [" + str_temp + "] : \x1B[s", true, PADDING);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, true);
|
||||
display_vector.push_back({" "});
|
||||
BaseVisualizer::display_vector.push_back({std::string(" ").append(GetMessage())});
|
||||
}
|
||||
|
||||
std::string CommandMenuVisualizer::GetMessage() {
|
||||
return this->message;
|
||||
}
|
32
src/Visualizer/CommandMenuVisualizer.hpp
Normal file
32
src/Visualizer/CommandMenuVisualizer.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#ifndef COMMANDMENUVISUALIZER_HPP
|
||||
#define COMMANDMENUVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class CommandMenuVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"To execute command: $<command_no>",
|
||||
"",
|
||||
"1 - Instructions",
|
||||
"2 - Save",
|
||||
"3 - Resign",
|
||||
"",
|
||||
"0 - Exit",
|
||||
};
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
std::string message;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
CommandMenuVisualizer(Chessboard* chessboard, size_t padding, std::string msg) : BaseVisualizer(CommandMenuVisualizer::FindMaxLength(menuContent), padding), CHESSBOARD(chessboard), message(msg) {
|
||||
CommandMenuVisualizer::GenerateElement();
|
||||
}
|
||||
std::string GetMessage();
|
||||
};
|
||||
|
||||
#endif //COMMANDMENUVISUALIZER_HPP
|
52
src/Visualizer/HistorieVisualizer.cpp
Normal file
52
src/Visualizer/HistorieVisualizer.cpp
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "HistorieVisualizer.hpp"
|
||||
#include <algorithm>
|
||||
#include "../ChessPieces/ChessPieceMove.hpp"
|
||||
|
||||
void HistorieVisualizer::GenerateElement() {
|
||||
BaseVisualizer::display_vector.push_back({"Historie"});
|
||||
BaseVisualizer::GenerateTableTopBottom(MAX_MENU_WIDTH, true, true);
|
||||
|
||||
std::string playerName1 = HistorieVisualizer::PLAYER1;
|
||||
std::string playerName2 = HistorieVisualizer::PLAYER2;
|
||||
|
||||
if (playerName1.length() > 14) {
|
||||
playerName1 = playerName1.substr(0, 11) + "...";
|
||||
}
|
||||
if(playerName2.length() > 14) {
|
||||
playerName2 = playerName2.substr(0, 11) + "...";
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, {playerName1, playerName2}, true);
|
||||
BaseVisualizer::GenerateTableSeperator(MAX_MENU_WIDTH, true);
|
||||
|
||||
std::vector<ChessPieceMove> moves = this->CHESSBOARD->GetHistoryMoves();
|
||||
|
||||
if (moves.size() % 2 == 0) {
|
||||
moves = std::vector<ChessPieceMove>(moves.end() - std::min<int>(moves.size(), 10), moves.end());
|
||||
} else {
|
||||
moves = std::vector<ChessPieceMove>(moves.end() - std::min<int>(moves.size(), 9), moves.end());
|
||||
}
|
||||
|
||||
std::vector<std::string> rowMoves;
|
||||
int rows = 0;
|
||||
|
||||
for (int moveIndex = 0; moveIndex < moves.size(); moveIndex++) {
|
||||
if (moveIndex % 2 == 0) rowMoves.clear();
|
||||
rowMoves.push_back(moves[moveIndex].ToString());
|
||||
|
||||
if (moveIndex % 2 == 1) {
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, rowMoves, true);
|
||||
rows++;
|
||||
} else if (moveIndex == moves.size() - 1) {
|
||||
rowMoves.push_back("");
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, rowMoves, true);
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
|
||||
for (int rowIndex = rows; rowIndex < 5; rowIndex++) {
|
||||
BaseVisualizer::GenerateTableLine(MAX_MENU_WIDTH, {"", ""}, true);
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTableTopBottom(MAX_MENU_WIDTH, false, true);
|
||||
}
|
27
src/Visualizer/HistorieVisualizer.hpp
Normal file
27
src/Visualizer/HistorieVisualizer.hpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef HISTORIEVISUALIZER_HPP
|
||||
#define HISTORIEVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class HistorieVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
const std::string PLAYER1;
|
||||
const std::string PLAYER2;
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
HistorieVisualizer(Chessboard* chessbord,const size_t menuWidth, const size_t padding) :
|
||||
BaseVisualizer(menuWidth, padding),
|
||||
CHESSBOARD(chessbord),
|
||||
PLAYER1(chessbord->GetPlayer(ChessPieceColor::White)->GetName()),
|
||||
PLAYER2(chessbord->GetPlayer(ChessPieceColor::Black)->GetName())
|
||||
{
|
||||
HistorieVisualizer::GenerateElement();
|
||||
};
|
||||
};
|
||||
|
||||
#endif //HISTORIEVISUALIZER_HPP
|
36
src/Visualizer/ImportVisualizer.cpp
Normal file
36
src/Visualizer/ImportVisualizer.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#include "ImportVisualizer.hpp"
|
||||
|
||||
void ImportVisualizer::GenerateElement() {
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
// BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
// for (const auto& content : menuContent) {
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
// }
|
||||
// BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "You can get a lot of PGN files from chessgames.com.", false, PADDING);
|
||||
// BaseVisualizer::AddEmptyLines(5, MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
void ImportVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->display_vector.clear();
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Please enter a path to a PGN (Portable Game Notation) file:", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "\x1B[s", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "On https://chessgames.com/ you will find many more chess", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "games in PGN format, to import into TurboSchach.", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
std::string ImportVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
22
src/Visualizer/ImportVisualizer.hpp
Normal file
22
src/Visualizer/ImportVisualizer.hpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef ImportVisualizer_HPP
|
||||
#define ImportVisualizer_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class ImportVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"Please enter the path to the PGN file:",
|
||||
"\x1B[s"
|
||||
};
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
ImportVisualizer() : BaseVisualizer(60, 4) {
|
||||
ImportVisualizer::GenerateElement();
|
||||
};
|
||||
std::string ShowMenu();
|
||||
void DrawView();
|
||||
};
|
||||
|
||||
#endif //INSTRUCTIONSVISUALIZER_HPP
|
20
src/Visualizer/InstructionsVisualizer.cpp
Normal file
20
src/Visualizer/InstructionsVisualizer.cpp
Normal file
@@ -0,0 +1,20 @@
|
||||
#include "InstructionsVisualizer.hpp"
|
||||
|
||||
void InstructionsVisualizer::GenerateElement() {
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
for (const auto& content : menuContent) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
}
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Press enter to continue: \x1B[s", false, PADDING);
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
void InstructionsVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
}
|
60
src/Visualizer/InstructionsVisualizer.hpp
Normal file
60
src/Visualizer/InstructionsVisualizer.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#ifndef INSTRUCTIONSVISUALIZER_HPP
|
||||
#define INSTRUCTIONSVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class InstructionsVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"1. Algebraische Notation",
|
||||
"",
|
||||
"Um die Figuren auf dem Schachbrett zu bewegen, wird die kurze algebraische Notation",
|
||||
"FIDE-Handbuch (siehe Appendix C) unterstützt. Es werden die Schachfiguren sowohl in",
|
||||
"deutscher als auch in englischer Sprache unterstützt.",
|
||||
"",
|
||||
"┌───────────────────┬─────────┬──────────┐",
|
||||
"│ Schachfigur │ Deutsch │ Englisch │",
|
||||
"├───────────────────┼─────────┼──────────┤",
|
||||
"│ Bauer (Pawn) │ B │ P │",
|
||||
"│ Springer (Knight) │ S │ N │",
|
||||
"│ Läufer (Bishop) │ L │ B │",
|
||||
"│ Turm (Rook) │ T │ R │",
|
||||
"│ Dame (Queen) │ D │ Q │",
|
||||
"│ König (King) │ K │ K │",
|
||||
"└───────────────────┴─────────┴──────────┘",
|
||||
"",
|
||||
"Bei der kurzen Notation wird immer nur das Zielfeld eines Spielzuges genannt. Sollte",
|
||||
"der Ursprung nicht eindeutig sein kann auch die Spalte oder Zeile der zu bewegenden Figur",
|
||||
"genannt werden. So gibt der Spielzug 'dxe5' an dass der Bauer in der Spalte D auf das Feld",
|
||||
"E5 zieht. Das 'x' gibt an dass dabei eine Spielfigur des Gegeners geschlagen wird. Dies muss",
|
||||
"aber nicht zwingend angegeben werden. Der Bauer wird in den Spielzügen nicht benannt. Der",
|
||||
"Spielzug 'b4' ist daher der Zug eines Bauern auf das Feld B4. Alle anderen Schachfiguren werden",
|
||||
"im Zug mit ihrem entsprechenden Buchstaben genannt. So gibt der Spielzug 'Bc4' an dass der Läufer",
|
||||
"auf das Feld C4 gezogen wird.",
|
||||
"",
|
||||
"Beispiele:",
|
||||
"",
|
||||
" - (=) Angebot für ein Draw. Um das Spiel mit einem Draw zu beenden muss das Angebot direkt im",
|
||||
" nächsten Zug bestätigt werden.",
|
||||
" - b4 Der Bauer zieht auf das Feld B4.",
|
||||
" - Bc4 Der Läufer zieht auf das Feld C4.",
|
||||
" - 0-0 Kleine Rochade (Rochade am Königsflügel)",
|
||||
" - 0-0-0 Große Rochade (Rochade am Damenflügel)",
|
||||
" - d8Q Umwandlung: Der Bauer zieht auf D8 und wandelt sich zur Dame.",
|
||||
"",
|
||||
"2. PGN (Portable Game Notation)",
|
||||
"",
|
||||
"TurboSchach unterstützt das Datenformat PGN, welches zur Speicherung von Schachpartien verwendet",
|
||||
"wird. Auf der Website https://www.chessgames.com/ werden viele Schachpartien von offiziellen Turnieren",
|
||||
"im PGN-Format zur Verfügung gestellt. Diese Dateien können in TurboSchach importiert werden."
|
||||
};
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
InstructionsVisualizer() : BaseVisualizer(BaseVisualizer::FindMaxLength(menuContent), 4) {
|
||||
InstructionsVisualizer::GenerateElement();
|
||||
};
|
||||
void DrawView();
|
||||
};
|
||||
|
||||
#endif //INSTRUCTIONSVISUALIZER_HPP
|
43
src/Visualizer/PlaySelectVisualizer.cpp
Normal file
43
src/Visualizer/PlaySelectVisualizer.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "PlaySelectVisualizer.hpp"
|
||||
|
||||
void PlaySelectVisualizer::GenerateElement() {
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
// BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
// for (const auto& content : menuContent) {
|
||||
// BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, content, false, PADDING);
|
||||
// }
|
||||
// BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
// BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
|
||||
std::vector<std::pair<int, int>> PlaySelectVisualizer::GetCursorPositions() {
|
||||
return this->cursorPositions;
|
||||
}
|
||||
|
||||
void PlaySelectVisualizer::AddToCursorPositions(const std::pair<int, int>& position) {
|
||||
this->cursorPositions.push_back(position);
|
||||
}
|
||||
void PlaySelectVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->display_vector.clear();
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
if (this->labelPlayerName.empty()) {
|
||||
this->labelPlayerName = "player";
|
||||
}
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "Please enter a name for the " + this->labelPlayerName + ":", false, PADDING);
|
||||
BaseVisualizer::GenerateBoxMenuLine(MAX_MENU_WIDTH, "\x1B[s", false, PADDING);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
std::string PlaySelectVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
||||
void PlaySelectVisualizer::SetLabelPlayerName(std::string label) {
|
||||
this->labelPlayerName = label;
|
||||
}
|
30
src/Visualizer/PlaySelectVisualizer.hpp
Normal file
30
src/Visualizer/PlaySelectVisualizer.hpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef PLAYSELECTVISUALIZER_HPP
|
||||
#define PLAYSELECTVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class PlaySelectVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
std::string labelPlayerName;
|
||||
// ToDo: Exit
|
||||
inline static const std::vector<std::string> menuContent = {
|
||||
"Please enter your names! Enter your names with '&' seperated.",
|
||||
"",
|
||||
"Playernames: \x1B[s"
|
||||
};
|
||||
std::vector<std::pair<int, int>> cursorPositions;
|
||||
|
||||
|
||||
public:
|
||||
PlaySelectVisualizer(size_t padding) : BaseVisualizer(PlaySelectVisualizer::FindMaxLength(menuContent), padding) {
|
||||
PlaySelectVisualizer::GenerateElement();
|
||||
}
|
||||
void GenerateElement();
|
||||
void AddToCursorPositions(const std::pair<int, int>& position);
|
||||
std::vector<std::pair<int, int>> GetCursorPositions();
|
||||
void DrawView();
|
||||
std::string ShowMenu();
|
||||
void SetLabelPlayerName(std::string label);
|
||||
};
|
||||
|
||||
#endif //PLAYSELECTVISUALIZER_HPP
|
129
src/Visualizer/PlayingViewVisualizer.cpp
Normal file
129
src/Visualizer/PlayingViewVisualizer.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "PlayingViewVisualizer.hpp"
|
||||
#include "ChessboardVisualizer.hpp"
|
||||
#include "HistorieVisualizer.hpp"
|
||||
#include "CommandMenuVisualizer.hpp"
|
||||
|
||||
|
||||
// ToDo: Beim Fenster größer ziehen verschiebt sich die Ansicht
|
||||
void PlayingViewVisualizer::GenerateElement() {
|
||||
position_vector.clear();
|
||||
display_vector.clear();
|
||||
ChessboardVisualizer chessboardVisualizer = ChessboardVisualizer(this->CHESSBOARD, 2);
|
||||
HistorieVisualizer historieVisualizer = HistorieVisualizer(this->CHESSBOARD, 32, 2);
|
||||
CommandMenuVisualizer cmdMenuVisualizer = CommandMenuVisualizer(this->CHESSBOARD, 2, this->GetMessage());
|
||||
|
||||
GeneratePositionVector(chessboardVisualizer.GetDisplayVector(), historieVisualizer.GetDisplayVector(), cmdMenuVisualizer.GetDisplayVector());
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
|
||||
std::vector<std::string> temp;
|
||||
|
||||
//((single) ? BaseVisualizer::VERTICAL_LINE_SINGLE : BaseVisualizer::VERTICAL_LINE) + std::string(padding, ' ')
|
||||
|
||||
for (const auto& row : position_vector) {
|
||||
display_vector.push_back(row);
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateEmptyLine(MAX_MENU_WIDTH, false);
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
//size_t maxWidth = BaseVisualizer::FindMaxLength(chessboardVisualizer.display_vector);
|
||||
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::GeneratePositionVector(
|
||||
std::vector<std::vector<std::string>>* chessboard_display_vector,
|
||||
std::vector<std::vector<std::string>>* historie_display_vector,
|
||||
std::vector<std::vector<std::string>>* command_menu_display_vector)
|
||||
{
|
||||
for (size_t i = 0; i < chessboard_display_vector->size(); ++i) {
|
||||
size_t test;
|
||||
std::vector<std::string> temp;
|
||||
temp.push_back({BaseVisualizer::VERTICAL_LINE + " "});
|
||||
if (i == 0) {
|
||||
const std::string& first_element = chessboard_display_vector->at(i).at(0);
|
||||
temp.push_back(first_element);
|
||||
temp.push_back(std::string(62-BaseVisualizer::CountVisibleCharacters(first_element), ' '));
|
||||
} else if (chessboard_display_vector->at(i).size() > 1 && i != 0) {
|
||||
temp.insert(temp.end(), chessboard_display_vector->at(i).begin(), chessboard_display_vector->at(i).end());
|
||||
} else {
|
||||
temp.push_back(chessboard_display_vector->at(i).at(0));
|
||||
}
|
||||
|
||||
temp.push_back(std::string(DISTANCE_BETWEEN_ELEMENTS, ' '));
|
||||
|
||||
if (i < historie_display_vector->size()) {
|
||||
temp.push_back(historie_display_vector->at(i)[0]);
|
||||
} else if (i-3-historie_display_vector->size() < command_menu_display_vector->size()) {
|
||||
temp.push_back(command_menu_display_vector->at(i-3-historie_display_vector->size())[0]);
|
||||
//} else if (i-3-historie_display_vector->size()-command_menu_display_vector->size()-1 == 0 && !this->GetMessage().empty()) {
|
||||
//temp.push_back(this->GetMessage());
|
||||
} else {
|
||||
temp.push_back({"", ""});
|
||||
}
|
||||
|
||||
BaseVisualizer::GetSumAllCharsFromVector(temp);
|
||||
temp.push_back(std::string(MAX_MENU_WIDTH-BaseVisualizer::GetSumAllCharsFromVector(temp)-1, ' ') + BaseVisualizer::VERTICAL_LINE);
|
||||
|
||||
position_vector.push_back(temp);
|
||||
}
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::DisplayElement() {
|
||||
PlayingViewVisualizer::GenerateElement();
|
||||
size_t size;
|
||||
std::string temp;
|
||||
for (int row = 0; row < display_vector.size(); ++row) {
|
||||
for (int column = 0; column < display_vector[row].size(); ++column) {
|
||||
if (row >= 4 && row <= 27 && column >= 3 && column <= 10) {
|
||||
bool isSecondRowOfField = ((row-1) % 3 == 2);
|
||||
bool isBlackWhite = ((column-1) % 2 == (row-1) % 2);
|
||||
|
||||
if ((row - 1) % 3 == 0) { // Change after 3 rows
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
}
|
||||
} else {
|
||||
if (isSecondRowOfField) {
|
||||
this->SetConsoleColor(isBlackWhite ? WHITE : BLACK, isBlackWhite ? BLACK : WHITE);
|
||||
} else {
|
||||
this->SetConsoleColor(isBlackWhite ? BLACK : WHITE, isBlackWhite ? WHITE : BLACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << display_vector[row][column];
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
}
|
||||
this->SetConsoleColor(DEFAULT, DEFAULT);
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::GetMove() {
|
||||
return move;
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::GetMessage() {
|
||||
return this->message;
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::SetMessage(std::string message) {
|
||||
this->message = message;
|
||||
}
|
||||
|
||||
void PlayingViewVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
this->DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
std::string PlayingViewVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
this->SetMessage("");
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
return choice;
|
||||
}
|
34
src/Visualizer/PlayingViewVisualizer.hpp
Normal file
34
src/Visualizer/PlayingViewVisualizer.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef PLAYINGVIEWVISUALIZER_HPP
|
||||
#define PLAYINGVIEWVISUALIZER_HPP
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
#include "../Chessboard/Chessboard.hpp"
|
||||
|
||||
class PlayingViewVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
const size_t DISTANCE_BETWEEN_ELEMENTS;
|
||||
|
||||
Chessboard* CHESSBOARD;
|
||||
std::string move;
|
||||
std::string message = "";
|
||||
|
||||
std::vector<std::vector<std::string>> position_vector;
|
||||
|
||||
void GenerateElement();
|
||||
void GeneratePositionVector(
|
||||
std::vector<std::vector<std::string>>* chessboard_display_vector,
|
||||
std::vector<std::vector<std::string>>* historie_display_vector,
|
||||
std::vector<std::vector<std::string>>* command_menu_display_vector);
|
||||
|
||||
public:
|
||||
PlayingViewVisualizer(Chessboard* chessboard, size_t padding, size_t distance) :
|
||||
BaseVisualizer(110, padding), CHESSBOARD(chessboard), DISTANCE_BETWEEN_ELEMENTS(distance) {}
|
||||
void DisplayElement();
|
||||
std::string GetMove();
|
||||
std::string GetMessage();
|
||||
void SetMessage(std::string message);
|
||||
void DrawView();
|
||||
std::string ShowMenu();
|
||||
};
|
||||
|
||||
#endif //PLAYINGVIEWVISUALIZER_HPP
|
71
src/Visualizer/StartMenuVisualizer.cpp
Normal file
71
src/Visualizer/StartMenuVisualizer.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#include "StartMenuVisualizer.hpp"
|
||||
|
||||
void StartMenuVisualizer::GenerateElement() {
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, true, false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
for (const auto& str : StartMenuVisualizer::ACSII_ART_TURBO_SCHACH) {
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, str, false);
|
||||
}
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "Welcome to TurboSchach!", false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "Please select one of the menu options:", false);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, "\x1B[s", false);
|
||||
|
||||
BaseVisualizer::AddEmptyLines(1, MAX_MENU_WIDTH, false);
|
||||
|
||||
// ToDo: Attribute zum direkten setzen des Types der Außenbegrenzung -> Allgemein in BaseVisualizer auch?
|
||||
// ToDo: Überarbeiten -> Extra Methode um Menus im Menu zu generieren
|
||||
BaseVisualizer::GenerateTopBottomBorder(24, true, true);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
|
||||
for (const auto& str : StartMenuVisualizer::MENU_OPTIONS) {
|
||||
BaseVisualizer::GenerateBoxMenuLine(24, str, true, 1);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
}
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(24, false, true);
|
||||
BaseVisualizer::GenerateCenteredString(MAX_MENU_WIDTH, BaseVisualizer::display_vector[BaseVisualizer::display_vector.size()-1][0], false);
|
||||
BaseVisualizer::display_vector.erase(BaseVisualizer::display_vector.begin() + (BaseVisualizer::display_vector.size() - 2));
|
||||
|
||||
|
||||
BaseVisualizer::AddEmptyLines(2, MAX_MENU_WIDTH, false);
|
||||
|
||||
BaseVisualizer::GenerateTopBottomBorder(MAX_MENU_WIDTH, false, false);
|
||||
}
|
||||
|
||||
int StartMenuVisualizer::GetSelectedOption() {
|
||||
return selectedOption;
|
||||
}
|
||||
|
||||
void StartMenuVisualizer::SetSelectedOption(int optionSelect) {
|
||||
selectedOption = selectedOption;
|
||||
};
|
||||
|
||||
void StartMenuVisualizer::DrawView() {
|
||||
BaseVisualizer::ClearTerminal();
|
||||
BaseVisualizer::DisplayElement();
|
||||
std::cout << "\x1B[u";
|
||||
}
|
||||
|
||||
StartMenuVisualizer::StartMenuOption StartMenuVisualizer::ShowMenu() {
|
||||
this->DrawView();
|
||||
std::string choice;
|
||||
std::getline(std::cin, choice);
|
||||
|
||||
if (choice == "1") return StartMenuOption::NewGame;
|
||||
if (choice == "2") return StartMenuOption::LoadGame;
|
||||
if (choice == "3") return StartMenuOption::Instructions;
|
||||
if (choice == "0") return StartMenuOption::Exit;
|
||||
return StartMenuOption::None;
|
||||
}
|
46
src/Visualizer/StartMenuVisualizer.hpp
Normal file
46
src/Visualizer/StartMenuVisualizer.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef STARTMENUVISUALIZER_H
|
||||
#define STARTMENUVISUALIZER_H
|
||||
|
||||
#include "BaseVisualizer.hpp"
|
||||
|
||||
class StartMenuVisualizer : public BaseVisualizer {
|
||||
private:
|
||||
inline static const std::vector<std::string> ACSII_ART_TURBO_SCHACH = {
|
||||
"████████╗██╗░░░██╗██████╗░██████╗░░█████╗░░██████╗░█████╗░██╗░░██╗░█████╗░░█████╗░██╗░░██╗",
|
||||
"╚══██╔══╝██║░░░██║██╔══██╗██╔══██╗██╔══██╗██╔════╝██╔══██╗██║░░██║██╔══██╗██╔══██╗██║░░██║",
|
||||
"░░░██║░░░██║░░░██║██████╔╝██████╦╝██║░░██║╚█████╗░██║░░╚═╝███████║███████║██║░░╚═╝███████║",
|
||||
"░░░██║░░░██║░░░██║██╔══██╗██╔══██╗██║░░██║░╚═══██╗██║░░██╗██╔══██║██╔══██║██║░░██╗██╔══██║",
|
||||
"░░░██║░░░╚██████╔╝██║░░██║██████╦╝╚█████╔╝██████╔╝╚█████╔╝██║░░██║██║░░██║╚█████╔╝██║░░██║",
|
||||
"░░░╚═╝░░░░╚═════╝░╚═╝░░╚═╝╚═════╝░░╚════╝░╚═════╝░░╚════╝░╚═╝░░╚═╝╚═╝░░╚═╝░╚════╝░╚═╝░░╚═╝"
|
||||
};
|
||||
|
||||
inline static const std::vector<std::string> MENU_OPTIONS = {
|
||||
"1 - New Game",
|
||||
"2 - Load Game",
|
||||
"3 - Instructions",
|
||||
"",
|
||||
"0 - Exit"
|
||||
};
|
||||
|
||||
int selectedOption = -1;
|
||||
|
||||
void GenerateElement() override;
|
||||
|
||||
public:
|
||||
StartMenuVisualizer(size_t padding) : BaseVisualizer(BaseVisualizer::CountVisibleCharacters(StartMenuVisualizer::ACSII_ART_TURBO_SCHACH[0]), padding) {
|
||||
StartMenuVisualizer::GenerateElement();
|
||||
}
|
||||
enum StartMenuOption {
|
||||
NewGame,
|
||||
LoadGame,
|
||||
Instructions,
|
||||
Exit,
|
||||
None
|
||||
};
|
||||
int GetSelectedOption();
|
||||
void SetSelectedOption(int selectedOption);
|
||||
void DrawView();
|
||||
StartMenuOption ShowMenu();
|
||||
};
|
||||
|
||||
#endif //STARTMENUVISUALIZER_H
|
38
src/main.cpp
Normal file
38
src/main.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include "./Controller/MenuController.hpp"
|
||||
#include "./Visualizer/StartMenuVisualizer.hpp"
|
||||
#include "./Visualizer/BaseVisualizer.hpp"
|
||||
#include "./Visualizer/PlaySelectVisualizer.hpp"
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
#ifdef _WIN32
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
#endif
|
||||
|
||||
StartMenuVisualizer startMenu(3);
|
||||
MenuController menuController;
|
||||
StartMenuVisualizer::StartMenuOption optionStartMenu = StartMenuVisualizer::StartMenuOption::None;
|
||||
|
||||
do {
|
||||
switch (optionStartMenu = startMenu.ShowMenu()) {
|
||||
case StartMenuVisualizer::StartMenuOption::NewGame:
|
||||
menuController.HandleFirstOption();
|
||||
break;
|
||||
case StartMenuVisualizer::StartMenuOption::LoadGame:
|
||||
menuController.HandleSecondOption();
|
||||
break;
|
||||
case StartMenuVisualizer::StartMenuOption::Instructions:
|
||||
menuController.HandleThirdOption();
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
} while (optionStartMenu != StartMenuVisualizer::StartMenuOption::Exit);
|
||||
|
||||
return 0;
|
||||
}
|
Reference in New Issue
Block a user