299 lines
8.6 KiB
C++
299 lines
8.6 KiB
C++
//
|
|
// Created by hamac on 18.12.2024.
|
|
//
|
|
|
|
#include "Utils.cpp"
|
|
#include <iostream>
|
|
#include <queue>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
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;
|
|
|
|
// 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) {
|
|
switch (identifier) {
|
|
case 'x': return blackSquare;
|
|
case 'r': return blackRook;
|
|
case 'n': return blackKnight;
|
|
case 'b': return blackBischop;
|
|
case 'q': return blackQueen;
|
|
case 'k': return blackKing;
|
|
case 'p': return blackPawn;
|
|
case 'w': return whiteSquare;
|
|
case 'R': return whiteRook;
|
|
case 'N': return whiteKnight;
|
|
case 'B': return whiteBischop;
|
|
case 'Q': return whiteQueen;
|
|
case 'K': return whiteKing;
|
|
case 'P': return whitePawn;
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
void generateTopLine() {
|
|
display += " " + horizontal + " " + topLeft;
|
|
for (int col = 0; col < boardSize; ++col) {
|
|
display += horizontal + horizontal + horizontal;
|
|
if (col < boardSize - 1) display += topIntersection;
|
|
}
|
|
display += topRight + "\n";
|
|
}
|
|
|
|
void generatePlayingField(const std::vector<std::vector<char>>& chessboard) {
|
|
char desc = 56;
|
|
for (int row = 0; row < boardSize; ++row) {
|
|
display += " ";
|
|
display += desc--;
|
|
display += " " + vertical;
|
|
for (int col = 0; col < boardSize; ++col) {
|
|
display += " " + getChessIcon(chessboard[row][col]) + " " + vertical;
|
|
}
|
|
display += "\n";
|
|
|
|
// Horizontale Trennlinie (außer nach der letzten Zeile)
|
|
if (row < boardSize - 1) {
|
|
display += " " + horizontal + " " + vertical;
|
|
for (int col = 0; col < boardSize; ++col) {
|
|
display += horizontal + horizontal + horizontal;
|
|
if (col < boardSize - 1) display += middleIntersection;
|
|
}
|
|
display += vertical + "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
void generateBottomLine() {
|
|
char desc = 65;
|
|
display += " " + horizontal + " " + bottomLeft;
|
|
for (int col = 0; col < boardSize; ++col) {
|
|
display += horizontal + horizontal + horizontal;
|
|
if (col < boardSize - 1) display += bottomIntersection;
|
|
}
|
|
display += bottomRight + "\n";
|
|
display += " " + vertical;
|
|
for (int col = 0; col < boardSize; ++col) {
|
|
display += " ";
|
|
display += (desc++);
|
|
display += " " + vertical;
|
|
}
|
|
}
|
|
|
|
public:
|
|
/* fields */
|
|
std::string display;
|
|
int boardSize = 8;
|
|
|
|
bool getTurnOrder() {
|
|
return this->turnOrder;
|
|
}
|
|
|
|
void setTurnOrder(bool turnOrder) {
|
|
this->turnOrder = turnOrder;
|
|
}
|
|
|
|
/* methods */
|
|
void setBoard(std::vector<std::vector<char>> board) {
|
|
this->currentBoard = board;
|
|
}
|
|
|
|
std::vector<std::vector<char>> getBoard() {
|
|
return this->currentBoard;
|
|
}
|
|
|
|
std::vector<std::vector<char>> getStartBoard() {
|
|
return this->startBoard;
|
|
}
|
|
|
|
std::vector<std::vector<char>> getEmptyBoard() {
|
|
return this->emptyBoard;
|
|
}
|
|
|
|
void draw () {
|
|
draw(getStartBoard());
|
|
}
|
|
|
|
void draw (const std::vector<std::vector<char>>& chessboard) {
|
|
// Obere Rahmenlinie
|
|
generateTopLine();
|
|
|
|
// Schachbrett mit vertikalen Linien
|
|
generatePlayingField(chessboard);
|
|
|
|
// Untere Rahmenlinie
|
|
generateBottomLine();
|
|
|
|
setBoard(chessboard);
|
|
|
|
std::cout << display << std::endl;
|
|
}
|
|
|
|
// 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
|
|
|
|
char getCorrectPiece(char pieceIdentifier) {
|
|
bool isWhite = getTurnOrder();
|
|
if (!isWhite) return pieceIdentifier + 32;
|
|
return pieceIdentifier;
|
|
}
|
|
|
|
std::pair<int, int> convertPosition(const std::string &pos) {
|
|
static const std::unordered_map<int, int> fileConvertion = {
|
|
{0, 7},
|
|
{1, 6},
|
|
{2, 5},
|
|
{3, 4},
|
|
{4, 3},
|
|
{5, 2},
|
|
{6, 1},
|
|
{7, 0}
|
|
};
|
|
|
|
int y = pos[pos.size()-2] - 'a';
|
|
int x = fileConvertion.find((pos[pos.size()-1] - '0')-1)->second;
|
|
return std::make_pair(x, y);
|
|
}
|
|
|
|
//
|
|
void move(std::string move) {
|
|
// ToDo:
|
|
// add move to history queue
|
|
|
|
std::vector<std::string> splitMove;
|
|
|
|
if (move.find('#') != std::string::npos) {
|
|
// Schachmate
|
|
// Finish game
|
|
} else if (move.rfind("0-0", 0) == 0) { // Kleine Rochade
|
|
// Check for Rochade
|
|
} else if (move.rfind("0-0-0", 0) == 0) {
|
|
// Große Rochade
|
|
}
|
|
|
|
// Standard move
|
|
if (move.find('-')) {
|
|
splitMove = Utils::split(move, '-');
|
|
} else if (move.find('x')) {
|
|
splitMove = Utils::split(move, 'x');
|
|
}
|
|
|
|
std::pair oldCoords = convertPosition(splitMove[0]);
|
|
std::pair newCoords = convertPosition(splitMove[1]);
|
|
|
|
std::vector<std::vector<char>> board = getBoard();
|
|
|
|
board[oldCoords.first][oldCoords.second] = getEmptyBoard()[oldCoords.first][oldCoords.second];
|
|
board[newCoords.first][newCoords.second] = getCorrectPiece(splitMove[0][0]);
|
|
|
|
draw(board);
|
|
|
|
// Notation
|
|
// Start with current position - dash - new position
|
|
// eg.: b1-c3
|
|
// Letter first than number
|
|
// eg.: a5
|
|
// Pawn: e4 or p e4 (pawn)
|
|
// R for rook
|
|
// N for Knight
|
|
// K for King
|
|
// B for Bischop
|
|
// Q for Queen
|
|
// Special:
|
|
// 0-0 short castle
|
|
// 0-0-0 long castle
|
|
// en passond: write square where pawn lands
|
|
|
|
// capture: x
|
|
// check: +
|
|
// checkmate: #
|
|
// draw/stalemate: 1/2-1/2
|
|
|
|
}
|
|
|
|
// This method saves the current board state
|
|
void saveBoard(Chessboard& chessboard) {
|
|
|
|
}
|
|
|
|
// This method loads a save state
|
|
void loadBoard(int saveState) {
|
|
// readJSONFile
|
|
//
|
|
}
|
|
};
|