Skip to content

Commit 996ad83

Browse files
committed
Add FEN Exporting
1 parent f2f2a2c commit 996ad83

File tree

16 files changed

+332
-105
lines changed

16 files changed

+332
-105
lines changed

ChessAndroid/app/src/main/cpp/Main.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -213,17 +213,17 @@ Java_net_theluckycoder_chess_Native_setSettings(JNIEnv *, jobject, jint baseSear
213213
jint cacheSizeMb,
214214
jboolean performQuiescenceSearch)
215215
{
216-
BoardManager::setSettings(Settings(static_cast<unsigned>(baseSearchDepth),
217-
static_cast<unsigned>(threadCount),
218-
static_cast<unsigned>(cacheSizeMb),
219-
static_cast<bool>(performQuiescenceSearch)));
216+
BoardManager::setSettings(Settings{ static_cast<unsigned>(baseSearchDepth),
217+
static_cast<unsigned>(threadCount),
218+
static_cast<unsigned>(cacheSizeMb),
219+
static_cast<bool>(performQuiescenceSearch) });
220220
}
221221

222222

223223
external JNIEXPORT void JNICALL
224224
Java_net_theluckycoder_chess_Native_makeMove(JNIEnv *, jobject, jlong move)
225225
{
226-
BoardManager::makeMove(Move(static_cast<unsigned>(move & UINT32_MAX)));
226+
BoardManager::makeMove(Move{ static_cast<unsigned>(move & UINT32_MAX) });
227227
}
228228

229229
external JNIEXPORT void JNICALL
@@ -246,11 +246,11 @@ Java_net_theluckycoder_chess_Native_undoMoves(JNIEnv *, jobject)
246246
}
247247

248248
external JNIEXPORT jboolean JNICALL
249-
Java_net_theluckycoder_chess_Native_loadFen(JNIEnv *pEnv, jobject, jstring fenPosition)
249+
Java_net_theluckycoder_chess_Native_loadFen(JNIEnv *pEnv, jobject, jboolean playerWhite, jstring fenPosition)
250250
{
251251
const char *nativeString = pEnv->GetStringUTFChars(fenPosition, nullptr);
252252

253-
const bool loaded = BoardManager::loadGame(nativeString);
253+
const bool loaded = BoardManager::loadGame(playerWhite, nativeString);
254254

255255
pEnv->ReleaseStringUTFChars(fenPosition, nativeString);
256256

@@ -268,6 +268,14 @@ Java_net_theluckycoder_chess_Native_loadMoves(JNIEnv *pEnv, jobject, jstring mov
268268
pEnv->ReleaseStringUTFChars(moves, nativeString);
269269
}
270270

271+
external JNIEXPORT jstring JNICALL
272+
Java_net_theluckycoder_chess_Native_getFen(JNIEnv *pEnv, jobject)
273+
{
274+
const auto fenString = BoardManager::exportFen();
275+
276+
return pEnv->NewStringUTF(fenString.c_str());
277+
}
278+
271279
external JNIEXPORT jstring JNICALL
272280
Java_net_theluckycoder_chess_Native_saveMoves(JNIEnv *pEnv, jobject)
273281
{

ChessAndroid/app/src/main/cpp/chess/Board.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,18 @@ void Board::setToStartPos()
1111

1212
bool Board::setToFen(const std::string &fen)
1313
{
14-
FenParser parser(*this);
15-
return parser.parseFen(fen);
14+
Board copy = *this;
15+
const bool result = FenParser::parseFen(*this, fen);
16+
17+
if (!result)
18+
*this = copy;
19+
20+
return result;
21+
}
22+
23+
std::string Board::getFen() const
24+
{
25+
return FenParser::exportToFen(*this);
1626
}
1727

1828
bool Board::canCastle(const Color color) const noexcept

ChessAndroid/app/src/main/cpp/chess/Board.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ class Board final
4949

5050
void setToStartPos();
5151
bool setToFen(const std::string &fen);
52+
std::string getFen() const;
5253

5354
bool canCastle(Color color) const noexcept;
5455
template <Color C>

ChessAndroid/app/src/main/cpp/chess/BoardManager.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,13 @@ void BoardManager::initBoardManager(const PieceChangeListener &listener, const b
2626
_workerThread = std::thread(moveComputerPlayer, _settings);
2727
}
2828

29-
bool BoardManager::loadGame(const std::string &fen)
29+
bool BoardManager::loadGame(const bool isPlayerWhite, const std::string &fen)
3030
{
3131
Board tempBoard = _board;
3232

3333
if (tempBoard.setToFen(fen))
3434
{
35+
_isPlayerWhite = isPlayerWhite;
3536
_board = tempBoard;
3637
_listener(getBoardState(), true, {});
3738
return true;
@@ -57,6 +58,11 @@ void BoardManager::loadGame(const std::vector<Move> &moves, const bool isPlayerW
5758
_listener(getBoardState(), true, {});
5859
}
5960

61+
std::string BoardManager::exportFen()
62+
{
63+
return _board.getFen();
64+
}
65+
6066
std::vector<Move> BoardManager::getMovesHistory()
6167
{
6268
std::vector<Move> moves(static_cast<size_t>(_board.historyPly));
@@ -88,7 +94,6 @@ std::vector<Move> BoardManager::getPossibleMoves(const byte from)
8894
return moves;
8995
}
9096

91-
9297
void BoardManager::makeMove(const Move move, const bool movedByPlayer)
9398
{
9499
_board.makeMove(move);

ChessAndroid/app/src/main/cpp/chess/BoardManager.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ class BoardManager final
3434

3535
public:
3636
static void initBoardManager(const PieceChangeListener &listener, bool isPlayerWhite = true);
37-
static bool loadGame(const std::string &fen);
37+
static bool loadGame(bool isPlayerWhite, const std::string &fen);
3838
static void loadGame(const std::vector<Move> &moves, bool isPlayerWhite);
39+
static std::string exportFen();
3940
static bool undoLastMoves();
4041

4142
static const Board &getBoard() { return _board; }

ChessAndroid/app/src/main/cpp/chess/persistence/FenParser.cpp

Lines changed: 91 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,35 @@
33
#include "../algorithm/Evaluation.h"
44
#include "../algorithm/Hash.h"
55

6-
FenParser::FenParser(Board &board)
7-
: _board(board)
8-
{
9-
}
10-
11-
bool FenParser::parseFen(const std::string &fen)
6+
bool FenParser::parseFen(Board &board, const std::string &fen)
127
{
138
std::istringstream stream(fen);
149

1510
if (!stream) return false;
1611

1712
// Clean board
18-
_board = {};
13+
board = {};
1914

20-
parsePieces(stream);
15+
parsePieces(board, stream);
2116

2217
// Next to move
2318
std::string side;
2419
stream >> side;
25-
_board.colorToMove = side == "w" ? WHITE : BLACK;
20+
board.colorToMove = side == "w" ? WHITE : BLACK;
2621

2722
// Castling availability
2823
std::string castling = "-";
2924
stream >> castling;
30-
_board.castlingRights = CastlingRights::CASTLE_NONE;
25+
board.castlingRights = CastlingRights::CASTLE_NONE;
3126
for (char currChar : castling) {
3227
switch (currChar) {
33-
case 'K': _board.castlingRights |= CastlingRights::CASTLE_WHITE_KING;
28+
case 'K': board.castlingRights |= CastlingRights::CASTLE_WHITE_KING;
3429
break;
35-
case 'Q': _board.castlingRights |= CastlingRights::CASTLE_WHITE_QUEEN;
30+
case 'Q': board.castlingRights |= CastlingRights::CASTLE_WHITE_QUEEN;
3631
break;
37-
case 'k': _board.castlingRights |= CastlingRights::CASTLE_BLACK_KING;
32+
case 'k': board.castlingRights |= CastlingRights::CASTLE_BLACK_KING;
3833
break;
39-
case 'q': _board.castlingRights |= CastlingRights::CASTLE_BLACK_QUEEN;
34+
case 'q': board.castlingRights |= CastlingRights::CASTLE_BLACK_QUEEN;
4035
break;
4136
default:
4237
break;
@@ -45,39 +40,96 @@ bool FenParser::parseFen(const std::string &fen)
4540

4641
std::string ep = "-";
4742
stream >> ep;
48-
_board.enPassantSq = SQUARE_NB;
43+
board.enPassantSq = SQUARE_NB;
4944
if (ep != "-")
5045
{
5146
if (ep.length() != 2)
5247
return false;
5348
if (!(ep[0] >= 'a' && ep[0] <= 'h'))
5449
return false;
55-
if (!((side == "w" && ep[1] == '6') || (side == "b" && ep[1] == '3')))
56-
return false;
5750

58-
const byte sq = ::toSquare(static_cast<byte>(ep[0] - 'a'), static_cast<byte>(ep[1] - '1'));
59-
_board.enPassantSq = sq < SQUARE_NB ? sq : SQUARE_NB;
51+
const byte sq = ::toSquare(int(ep[0] - 'a'), int(ep[1] - '1'));
52+
board.enPassantSq = sq < SQUARE_NB ? sq : SQUARE_NB;
6053
}
6154

6255
// HalfMove Clock
6356
int halfMove{};
6457
stream >> halfMove;
65-
_board.fiftyMoveRule = static_cast<byte>(halfMove);
58+
board.fiftyMoveRule = static_cast<byte>(halfMove);
6659

67-
_board.updatePieceList();
68-
_board.updateNonPieceBitboards();
69-
_board.zKey = Hash::compute(_board);
60+
board.updatePieceList();
61+
board.updateNonPieceBitboards();
62+
board.zKey = Hash::compute(board);
7063

71-
_board.kingAttackers = _board.colorToMove ? _board.allKingAttackers<WHITE>() : _board.allKingAttackers<BLACK>();
64+
board.kingAttackers = board.colorToMove ? board.allKingAttackers<WHITE>() : board.allKingAttackers<BLACK>();
7265
return true;
7366
}
7467

75-
std::string FenParser::exportToFen()
68+
std::string FenParser::exportToFen(const Board &board)
7669
{
77-
return {};
70+
std::ostringstream out;
71+
72+
for (int rank = 7; rank >= 0; --rank)
73+
{
74+
for (int file = 0; file <= 7; ++file)
75+
{
76+
int emptyCount = 0;
77+
for (; file <= 7 && board.data[toSquare(file, rank)] == EMPTY_PIECE; ++file)
78+
++emptyCount;
79+
80+
if (emptyCount)
81+
out << emptyCount;
82+
83+
if (file <= 7) {
84+
const Piece piece = board.data[toSquare(file, rank)];
85+
const PieceType type = piece.type();
86+
char pChar = 'K';
87+
88+
if (type == PAWN)
89+
pChar = 'P';
90+
else if (type == KNIGHT)
91+
pChar = 'N';
92+
else if (type == BISHOP)
93+
pChar = 'B';
94+
else if (type == ROOK)
95+
pChar = 'R';
96+
else if (type == QUEEN)
97+
pChar = 'Q';
98+
99+
if (piece.color() == BLACK)
100+
pChar += 32;
101+
102+
out << pChar;
103+
}
104+
}
105+
106+
if (rank > 0)
107+
out << '/';
108+
}
109+
110+
out << (board.colorToMove == WHITE ? " w " : " b ");
111+
112+
if (board.canCastleKs<WHITE>()) out << 'K';
113+
114+
if (board.canCastleQs<WHITE>()) out << 'Q';
115+
116+
if (board.canCastleKs<BLACK>()) out << 'k';
117+
118+
if (board.canCastleQs<BLACK>()) out << 'q';
119+
120+
if (!board.canCastle(WHITE) && !board.canCastle(BLACK)) out << '-';
121+
122+
if (board.enPassantSq < SQ_NONE)
123+
out << ' ' << char('a' + int(col(board.enPassantSq))) << int(row(board.enPassantSq)) << ' ';
124+
else
125+
out << " - ";
126+
127+
out << short(board.fiftyMoveRule / 2);
128+
129+
return out.str();
78130
}
79131

80-
void FenParser::parsePieces(std::istringstream &stream)
132+
void FenParser::parsePieces(Board &board, std::istringstream &stream)
81133
{
82134
std::string token;
83135
token.reserve(32);
@@ -89,40 +141,40 @@ void FenParser::parsePieces(std::istringstream &stream)
89141
switch (currChar)
90142
{
91143
case 'p':
92-
_board.data[boardPos++] = { PAWN, BLACK };
144+
board.data[boardPos++] = { PAWN, BLACK };
93145
break;
94146
case 'r':
95-
_board.data[boardPos++] = { ROOK, BLACK };
147+
board.data[boardPos++] = { ROOK, BLACK };
96148
break;
97149
case 'n':
98-
_board.data[boardPos++] = { KNIGHT, BLACK };
150+
board.data[boardPos++] = { KNIGHT, BLACK };
99151
break;
100152
case 'b':
101-
_board.data[boardPos++] = { BISHOP, BLACK };
153+
board.data[boardPos++] = { BISHOP, BLACK };
102154
break;
103155
case 'q':
104-
_board.data[boardPos++] = { QUEEN, BLACK };
156+
board.data[boardPos++] = { QUEEN, BLACK };
105157
break;
106158
case 'k':
107-
_board.data[boardPos++] = { KING, BLACK };
159+
board.data[boardPos++] = { KING, BLACK };
108160
break;
109161
case 'P':
110-
_board.data[boardPos++] = { PAWN, WHITE };
162+
board.data[boardPos++] = { PAWN, WHITE };
111163
break;
112164
case 'R':
113-
_board.data[boardPos++] = { ROOK, WHITE };
165+
board.data[boardPos++] = { ROOK, WHITE };
114166
break;
115167
case 'N':
116-
_board.data[boardPos++] = { KNIGHT, WHITE };
168+
board.data[boardPos++] = { KNIGHT, WHITE };
117169
break;
118170
case 'B':
119-
_board.data[boardPos++] = { BISHOP, WHITE };
171+
board.data[boardPos++] = { BISHOP, WHITE };
120172
break;
121173
case 'Q':
122-
_board.data[boardPos++] = { QUEEN, WHITE };
174+
board.data[boardPos++] = { QUEEN, WHITE };
123175
break;
124176
case 'K':
125-
_board.data[boardPos++] = { KING, WHITE };
177+
board.data[boardPos++] = { KING, WHITE };
126178
break;
127179
case '/': boardPos -= 16u; // Go down one rank
128180
break;

ChessAndroid/app/src/main/cpp/chess/persistence/FenParser.h

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,9 @@ class Board;
77
class FenParser
88
{
99
public:
10-
explicit FenParser(Board &board);
11-
12-
bool parseFen(const std::string &fen);
13-
std::string exportToFen();
10+
static bool parseFen(Board &board, const std::string &fen);
11+
static std::string exportToFen(const Board &board);
1412

1513
private:
16-
void parsePieces(std::istringstream &stream);
17-
18-
Board &_board;
14+
static void parsePieces(Board &board, std::istringstream &stream);
1915
};

0 commit comments

Comments
 (0)