Compare commits

..

No commits in common. "main" and "fen" have entirely different histories.

16 changed files with 1056 additions and 3801 deletions

9
.gitignore vendored
View file

@ -23,7 +23,8 @@
*.debug
*.yml
html/
nbproject/*
nbproject/private/
nbproject/Package-*.bash
build/
nbbuild/
dist/
@ -38,8 +39,4 @@ chessmcu_default/
# End of https://www.toptal.com/developers/gitignore/api/mplabx
localTest/
docs/
.ca/
*.kate-swp
*orig
localTest/

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "doxygen-awesome-css"]
path = doxygen-awesome-css
url = https://github.com/jothepro/doxygen-awesome-css.git

289
Board.cpp
View file

@ -6,8 +6,7 @@
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#include "inc/Board.hpp"
#include "inc/Piece.hpp"
#include "Board.hpp"
#include "inc/strFuncs.hpp"
/*
@ -32,8 +31,9 @@
Board::Board() {
boardGrid.resize(8);
for(int i = 0; i < 8; i++)
for(int i = 0; i < 8; i++) {
boardGrid[i].resize(8);
}
}
Board::~Board() {
@ -41,7 +41,7 @@ Board::~Board() {
void Board::setupInitialPosition() {
// set up the board grid with smart pointers
// initialize each square with a Piece or nullptr
// initialize each square with a Piece
playerTurn = PL_WHITE;
for(int i = 0; i < 8; i++) {
switch(i) {
@ -89,226 +89,115 @@ void Board::setupInitialPosition() {
}
return;
}
/**
* Sets entire board to nullptr
*/
void Board::clearBoard() {
for(int i = 0; i < 8; i++) {
for(int j = 0; j < 8; j++)
boardGrid[i][j] = nullptr;
}
}
/**
* Takes a FEN string and creates a board to that spec
* @param strFEN A full FEN string
* @return Returns -1 on failure, 0 on success
*/
int Board::setupFromFEN(std::string strFEN) {
int setupFromFEN(std::string strFEN) {
std::vector<std::string> splitFEN = split(strFEN, ' ');
if(splitFEN.size() != 6) // a valid FEN *must* contain 6 fields
if(splitFEN.size() != 6) { // a valid FEN *must* contain 6 fields
return -1;
// ====== START OF FIELD 1 ======
}
std::vector<std::string> splitField1 = split(splitFEN[0], '/');
int rank = 0, file = 0;
int skip = 0;
Square whiteKing, blackKing;
bool wKingPlaced = false, bKingPlaced = false;
for(auto &ranks : splitField1) {
for(auto &sym : ranks) {
if(skip) {
boardGrid[rank][file] = nullptr; // remove reference
skip--;
file++;
continue;
}
switch(sym) {
case 'R':
// white rook
boardGrid[rank][file] = std::make_unique<Rook>(PIECE_WHITE);
file++;
break;
case 'r':
// black rook
boardGrid[rank][file] = std::make_unique<Rook>(PIECE_BLACK);
file++;
break;
case 'N':
// white knight
boardGrid[rank][file] = std::make_unique<Knight>(PIECE_WHITE);
file++;
break;
case 'n':
// black knight
boardGrid[rank][file] = std::make_unique<Knight>(PIECE_BLACK);
file++;
break;
case 'B':
// white bishop
boardGrid[rank][file] = std::make_unique<Bishop>(PIECE_WHITE);
file++;
break;
case 'b':
// black bishop
boardGrid[rank][file] = std::make_unique<Bishop>(PIECE_BLACK);
file++;
break;
case 'Q':
// white queen
boardGrid[rank][file] = std::make_unique<Queen>(PIECE_WHITE);
file++;
break;
case 'q':
// black queen;
boardGrid[rank][file] = std::make_unique<Queen>(PIECE_BLACK);
file++;
break;
case 'K':
// white king
if(wKingPlaced) {
// invalid FEN, more than 1 white king
return -1;
} else {
boardGrid[rank][file] = std::make_unique<King>(PIECE_WHITE);
wKingPlaced = true;
// store king position for later
whiteKing.file = static_cast<File>(file);
whiteKing.rank = static_cast<Rank>(rank);
file++;
}
break;
case 'k':
// black king
if(bKingPlaced) {
// invalid FEN, more than 1 black king
return -1;
} else {
boardGrid[rank][file] = std::make_unique<King>(PIECE_BLACK);
bKingPlaced = true;
// store king position for later
blackKing.file = static_cast<File>(file);
blackKing.rank = static_cast<Rank>(rank);
file++;
}
break;
case 'P':
// white pawn
boardGrid[rank][file] = std::make_unique<Pawn>(PIECE_WHITE);
file++;
break;
case 'p':
// black pawn
boardGrid[rank][file] = std::make_unique<Pawn>(PIECE_BLACK);
file++;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8': {
std::string skipStr(1, sym);
skip = atoi(skipStr.c_str());
//skip--; // fix off by 1 error
while(skip--) {
boardGrid[rank][file++] = nullptr; // remove reference
}
break;
}
default:
// invalid character?
return -1;
break;
}
if(file > 7) {
file = 0;
case 'R':
// white rook
boardGrid[rank][file] = std::make_unique<Rook>(PIECE_WHITE);
break;
case 'r':
// black rook
boardGrid[rank][file] = std::make_unique<Rook>(PIECE_BLACK);
break;
case 'N':
// white knight
boardGrid[rank][file] = std::make_unique<Knight>(PIECE_WHITE);
break;
case 'n':
// black knight
boardGrid[rank][file] = std::make_unique<Knight>(PIECE_BLACK);
break;
case 'B':
// white bishop
boardGrid[rank][file] = std::make_unique<Bishop>(PIECE_WHITE);
break;
case 'b':
// black bishop
boardGrid[rank][file] = std::make_unique<Bishop>(PIECE_BLACK);
break;
case 'Q':
// white queen
boardGrid[rank][file] = std::make_unique<Queen>(PIECE_WHITE);
break;
case 'q':
// black queen;
boardGrid[rank][file] = std::make_unique<Queen>(PIECE_BLACK);
break;
case 'K':
// white king
if(wKingPlaced) {
// invalid FEN, more than 1 white king
return -1;
} else {
boardGrid[rank][file] = std::make_unique<King>(PIECE_WHITE);
wKingPlaced = true;
}
break;
case 'k':
// black king
if(bKingPlaced) {
// invalid FEN, more than 1 black king
return -1;
} else {
boardGrid[rank][file] = std::make_unique<King>(PIECE_BLACK);
bKingPlaced = true;
}
break;
case 'P':
// white pawn
boardGrid[rank][file] = std::make_unique<Pawn>(PIECE_WHITE);
break;
case 'p':
// black pawn
boardGrid[rank][file] = std::make_unique<Pawn>(PIECE_BLACK);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
skip = atoi(sym);
break;
default:
// invalid character?
return -1;
}
file++;
}
rank++;
if(rank > 7)
break;
}
// ======= END OF FIELD 1 ======
// ======= START OF FIELD 2 ======
std::string w = "w";
std::string b = "b";
if(splitFEN[1] == w)
playerTurn = PL_WHITE;
else if(splitFEN[1] == b)
playerTurn = PL_BLACK;
else {
// invalid FEN
return -1;
}
// ====== END OF FIELD 2 ======
// ====== START OF FIELD 3 ======
std::string k = "k", K = "K", q = "q", Q = "Q";
// yeah this is hacky af but it works... blame SO
Piece *baseBKing = getPieceAt(blackKing);
Piece *baseWKing = getPieceAt(whiteKing);
King *bKing = dynamic_cast<King *>(baseBKing);
King *wKing = dynamic_cast<King *>(baseWKing);
if(splitFEN[2] == "-") {
// nobody can castle, either side
bKing->setCastleKS(false);
bKing->setCastleQS(false);
wKing->setCastleKS(false);
wKing->setCastleQS(false);
}
if(splitFEN[2].find(k) != std::string::npos) {
// black king can castle kingside
bKing->setCastleKS(true);
}
if(splitFEN[2].find(K) != std::string::npos) {
// white king can castle kingside
wKing->setCastleKS(true);
}
if(splitFEN[2].find(q) != std::string::npos) {
// black king can castle queenside
bKing->setCastleQS(true);
}
if(splitFEN[2].find(Q) != std::string::npos) {
// white king can castle queenside
wKing->setCastleQS(true);
}
// ====== END OF FIELD 3 ======
// ====== START OF FIELD 4 ======
// if a pawn has just moved and can be attacked enPassant, it will be listed here
//#ifdef DEBUG
// for(auto &ranks : boardGrid) {
// for(auto &files : ranks) {
// if(files)
// std::cout << files->getPieceName() << " ";
// else
// std::cout << "E ";
// }
// std::cout << "\n";
// }
//#endif
return 0;
}
void Board::nextTurn() {
playerTurn = (playerTurn == PL_WHITE) ? PL_BLACK : PL_WHITE; // switch to other player's turn
// do initial checks -- is their king in check? do they have any legal moves?
// stalemate check - do we really need to call getLegalMoves() on every single Piece?
}
/**
* This function should only be called after you have confirmed the move is legal!
* This will execute the move and assume you've already checked it.
* @param from The Square on which the Piece is departing
* @param to The Square to which the Piece is moving to
*/
void Board::movePiece(Square from, Square to) {
return;
}
void Board::deserializeBoard(uint64_t incomingBoard) {
union {
uint8_t boardRows[8];
uint64_t fullBoard;
} serialBoard;
uint8_t boardRows[8];
for(int i = 0; i < 8; i++)
serialBoard.boardRows[i] = static_cast<uint8_t>((incomingBoard >> (8 * i)) & 0xFF);
boardRows[i] = (incomingBoard >> (8 * i)) & 0xFF;
// how do we then figure out what has moved?
return;
}

47
Board.hpp Normal file
View file

@ -0,0 +1,47 @@
// © 2025 A.M. Rowsell <amr@frzn.dev>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#ifndef BOARD_HPP
#define BOARD_HPP
#include <vector>
#include <memory>
#include <cstdint>
#include "Piece.hpp"
// why do I have to forward declare all these?!
class Piece;
enum Players {
PL_WHITE, PL_BLACK
};
struct Square;
class Board {
private:
friend class Piece;
Players playerTurn;
public:
// this should be protected, but even when Piece is declared as a friend,
// accessing it in Piece.cpp threw an error
std::vector<std::vector<std::unique_ptr<Piece>>> boardGrid;
Board();
virtual ~Board();
void setupInitialPosition();
Piece *getPieceAt(Square square);
void movePiece(Square from, Square to);
int setupFromFEN(std::string strFEN);
bool isInBounds(Square square) const;
bool isEmpty(Square square) const;
uint64_t serialBoard = 0xFFFF00000000FFFF; // opening position
void deserializeBoard(uint64_t incomingBoard);
};
#endif // BOARD_HPP

2990
Doxyfile

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#include "inc/NeoPixel.hpp"
#include "NeoPixel.hpp"
uint8_t setNeoPixel(uint8_t index, uint8_t red, uint8_t green, uint8_t blue) {
return 0;

228
Piece.cpp
View file

@ -6,71 +6,24 @@
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#include "inc/Piece.hpp"
#include "inc/Board.hpp"
#include "Piece.hpp"
Piece::~Piece() {
return;
}
// TODO: Add operator overload for << to allow easy printing
// TODO: Test getPieceAt() function to see if it works as intended
// because the Piece class is instantiated in another class using
// unique_ptr, non-pure virtual functions apparently *must*
// have definitions, or the linker freaks out
// so this is just a stub that does nothing. it doesn't matter
// because only the derived class versions should be called.
std::vector<Move> Piece::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Piece::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
return moveList;
}
bool Piece::finalMoveChecks(std::vector<Move> *moveList, Board &board) {
// This function needs to do the final checks before declaring a move legal
// Check to see if the piece that is being moves is currently blocking check
// Check to see if a castle is trying to go through check or out of check
// Check if it's a piece trying to capture the King (though this shouldn't happen normally)
return true;
}
// *INDENT-OFF*
//
// ## #
// #
// # ## ## # ## ## #
// # # # # # # #
// ## # # # # #
// # # # # # # #
// ## ## ##### ### ## ###
// #
// ###
// *INDENT-ON*
bool King::checkForCheck(Board &board) const {
std::vector<std::vector<int>> kingVulnerable = {
{-1, 0}, // Up
{-1, -1}, // up-left
{-1, 1}, // up-right
{1, 0}, // Down
{1, -1}, // down-left
{1, 1}, // down-right
{0, -1}, // Left
{0, 1}, // Right
{-1, -2}, // 1
{-1, 2}, // 2
{-2, -1}, // 3
{-2, 1}, // 4
{1, -2}, // 5
{1, 2}, // 6
{2, -1}, // 7
{2, 1} // 8
};
// locate our King
return inCheck;
}
std::vector<Move> King::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
std::vector<std::vector<int>> directions = {
{-1, 0}, // Up
@ -86,10 +39,12 @@ std::vector<Move> King::getLegalMoves(const Square &from, Board &board) const {
// establish r/f for square to check
int r = from.rank + dir[0];
int f = from.file + dir[1];
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
if(targetSquare.isValid()) {
const Piece *target = board.getPieceAt(targetSquare); // examine the target square
if(!target) { // if square is empty (nullptr)
const auto &target = board.boardGrid[r][f]; // examine the target square
if(!target) { // if square is empty (NULL)
moveList.push_back({from, targetSquare}); // then it's potentially a legal move
} else if(target && target->getColour() != this->getColour()) { // if it's occupied with a piece of opposite colour
moveList.push_back({from, targetSquare}); // then again it's potentially legal
@ -134,8 +89,7 @@ std::vector<Move> King::getLegalMoves(const Square &from, Board &board) const {
bool diagonal = (abs(dir[0]) + abs(dir[1]) == 2) ? 1 : 0; // check if diagonal
bool knight = (abs(dir[0]) + abs(dir[1]) == 3) ? 1 : 0; // check if knight attack
while(r >= 0 && r < 8 && f >= 0 && f < 8) {
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare); // access the square we're examining
auto &target = board.boardGrid[r][f]; // access the square we're examining
if(!target) {
// empty square, continue
continue;
@ -143,20 +97,18 @@ std::vector<Move> King::getLegalMoves(const Square &from, Board &board) const {
if(target && (target->getColour() != this->getColour())) { // is it occupied & an enemy?
if((target->getPieceType() == QUEEN || target->getPieceType() == BISHOP) && diagonal) {
// we are being attacked diagonally on this square, so remove it
moves.to.rank = INVALID_RANK;
moves.to.file = INVALID_FILE;
} else if(target->getPieceType() == KNIGHT && knight) {
moves.to.rank = INVALID_RANK; moves.to.file = INVALID_FILE;
}
else if(target->getPieceType() == KNIGHT && knight) {
// we are being attacked by a knight, so remove it
moves.to.rank = INVALID_RANK;
moves.to.file = INVALID_FILE;
} else if(target->getPieceType() == ROOK || target->getPieceType() == QUEEN && (!diagonal && !knight)) {
moves.to.rank = INVALID_RANK; moves.to.file = INVALID_FILE;
}
else if(target->getPieceType() == ROOK || target->getPieceType() == QUEEN && (!diagonal && !knight)) {
// again, being attacked, remove it
moves.to.rank = INVALID_RANK;
moves.to.file = INVALID_FILE;
moves.to.rank = INVALID_RANK; moves.to.file = INVALID_FILE;
}
if(target->getPieceType() == PAWN && (abs(r - startSquare.rank) == 1 && abs(f - startSquare.file) == 1)) {
moves.to.rank = INVALID_RANK;
moves.to.file = INVALID_FILE;
moves.to.rank = INVALID_RANK; moves.to.file = INVALID_FILE;
}
}
if(target && (target->getColour() == this->getColour())) {
@ -173,26 +125,15 @@ std::vector<Move> King::getLegalMoves(const Square &from, Board &board) const {
}
// will this actually work?
moveList.erase(
std::remove_if(moveList.begin(), moveList.end(),
[&](const auto & x) {
return !x.to.isValid();
}));
std::remove_if(moveList.begin(), moveList.end(),
[&](const Square &x) {
return std::find(x.begin(), x.end(), !x.isValid()) != x.end();
}),
moveList.end());
return moveList;
}
// *INDENT-OFF*
//
// ##
// #
// # ### ## ## # ##
// # # # # # # #
// # # # # # ##
// # # # # # # #
// #### ## ## ## ##
//
// *INDENT-OM*
std::vector<Move> Rook::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Rook::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
const int directions[4][2] = {
{-1, 0}, // Up
@ -200,12 +141,14 @@ std::vector<Move> Rook::getLegalMoves(const Square &from, Board &board) const {
{0, -1}, // Left
{0, 1} // Right
};
for(auto &dir : directions) {
for(auto& dir : directions) {
int r = from.rank + dir[0];
int f = from.file + dir[1];
while(r >= 0 && r < 8 && f >= 0 && f < 8) {
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
if(!target) {
moveList.push_back({from, targetSquare});
} else if(target && target->getColour() != this->getColour()) {
@ -220,113 +163,22 @@ std::vector<Move> Rook::getLegalMoves(const Square &from, Board &board) const {
return moveList;
}
// *INDENT-OFF*
// ## # ## ## ## ## # ##
// # # # # # # # # # #
// # # # # ### ### # #
// # # # # # # # #
// ### ## # ### ### ### ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Queen::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Queen::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
std::vector<std::vector<int>> directions = {
{-1, 0}, // Up
{-1, -1}, // up-left
{-1, 1}, // up-right
{1, 0}, // Down
{1, -1}, // down-left
{1, 1}, // down-right
{0, -1}, // Left
{0, 1} // Right
};
for(auto &dir : directions) {
// establish r/f for square to check
int r = from.rank + dir[0];
int f = from.file + dir[1];
while(r >= 0 && r < 8 && f >= 0 && f < 8) {
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);// examine the target square
if(!target) { // if square is empty (NULL)
moveList.push_back({from, targetSquare}); // then it's potentially a legal move
} else if(target && target->getColour() != this->getColour()) { // if it's occupied with a piece of opposite colour
moveList.push_back({from, targetSquare}); // then again it's potentially legal
break;
} else {
// otherwise it's one of our pieces
break;
}
r += dir[0];
f += dir[1];
}
}
return moveList;
}
// *INDENT-OFF*
// ## # ## #
// # # #
// # ## # ## ## ## # ### ####
// # # # # # # # # # #
// ## # # # # # # # #
// # # # # # # # # # # #
// ## ## ### ## ##### ### ### ## ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Knight::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Knight::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
std::vector<std::vector<int>> directions = {
{-1, -2},
{-1, 2},
{-2, -1},
{-2, 1},
{1, -2},
{1, 2},
{2, -1},
{2, 1}
};
return moveList;
}
// *INDENT-OFF*
// ## # ##
// # #
// ### ## ### ### ## # ##
// # # # # # # # # # #
// # # # ## # # # # # #
// # # # # # # # # # #
// #### ##### ### ### ## ## ###
// #
// ###
// *INDENT-ON*
std::vector<Move> Bishop::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Bishop::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
std::vector<std::vector<int>> directions = {
{-1, -1}, // up-left
{-1, 1}, // up-right
{1, -1}, // down-left
{1, 1}, // down-right
};
return moveList;
}
// *INDENT-OFF*
//
// # ## ## # # ## # ##
// # # # # # # # #
// # # ### # # # # #
// # # # # # # # #
// ### ## # # # ### ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Pawn::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> Pawn::getLegalMoves(const Square &from, const Board &board) const {
std::vector<Move> moveList;
const int directions[2][4][2] = {
{
@ -350,11 +202,13 @@ std::vector<Move> Pawn::getLegalMoves(const Square &from, Board &board) const {
int r = from.rank + dir[0];
int f = from.file + dir[1];
if(r >= 0 && r < 8 && f >= 0 && f < 8) { // no need for a while loop as we only have finite moves in limited directions
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
if(dir[0] == -2 && !this->checkIfMoved()) {
// then 2 is potentially legal
if(!target && board.isSquareEmpty(Square{static_cast<Rank>(r + 1), static_cast<File>(f)})) // check both squares for pieces of any colour
if(!target && !(board.boardGrid[r + 1][f])) // check both squares for pieces of any colour
moveList.push_back({from, targetSquare});
else
continue;
@ -377,11 +231,13 @@ std::vector<Move> Pawn::getLegalMoves(const Square &from, Board &board) const {
int r = from.rank + dir[0];
int f = from.file + dir[1];
if(r >= 0 && r < 8 && f >= 0 && f < 8) { // no need for a while loop as we only have finite moves in limited directions
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
if(dir[0] == 2 && !this->checkIfMoved()) {
// then 2 is potentially legal
if(!target && board.isSquareEmpty(Square{static_cast<Rank>(r + 1), static_cast<File>(f)}))
if(!target && !(board.boardGrid[r - 1][f]))
moveList.push_back({from, targetSquare});
else
continue;

172
Piece.hpp Normal file
View file

@ -0,0 +1,172 @@
// © 2025 A.M. Rowsell <amr@frzn.dev>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#ifndef PIECE_HPP
#define PIECE_HPP
#pragma once
#include <cstdint>
#include <utility>
#include <string>
#include <memory>
#include <vector>
#include "Board.hpp"
class Board;
enum PieceType {
PAWN, BISHOP, KNIGHT, ROOK, QUEEN, KING, EMPTY
};
enum PieceColour {
PIECE_WHITE, PIECE_BLACK, PIECE_EMPTY
};
enum Rank {
R1 = 0, R2 = 1, R3 = 2, R4 = 3, R5 = 4, R6 = 5, R7 = 6, R8 = 7, INVALID_RANK = 255
};
enum File {
A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, INVALID_FILE = 255
};
struct Square {
Rank rank;
File file;
bool isValid() const {
return rank >= 0 && rank < 8 && file >= 0 && file < 8;
}
};
struct Move {
Square from;
Square to;
};
class Piece {
private:
friend class Board;
protected:
PieceColour colour;
PieceType pieceType;
std::string pieceName;
char pieceSymbol;
bool hasMoved = false;
public:
Piece(PieceColour pColour) : colour(pColour) {
}
virtual ~Piece();
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const;
PieceColour getColour() const {
return colour;
}
std::string getPieceName() const {
return pieceName;
}
char getPieceSymbol() const {
return pieceSymbol;
}
PieceType getPieceType() const {
return pieceType;
}
bool checkIfMoved() const {
return hasMoved;
}
};
class King : public Piece {
friend class Board;
public:
King(PieceColour colour) : Piece(colour) {
pieceName = "King";
pieceSymbol = 'K';
pieceType = KING;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
bool checkForCheck() const {
return inCheck;
}
bool checkForCastle() const {
return canCastle;
}
protected:
bool canCastle = true;
bool inCheck = false;
};
class Rook : public Piece {
friend class Board;
public:
Rook(PieceColour colour) : Piece(colour) {
pieceName = "Rook";
pieceSymbol = 'R';
pieceType = ROOK;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
};
class Queen : public Piece {
friend class Board;
public:
Queen(PieceColour colour) : Piece(colour) {
pieceName = "Queen";
pieceSymbol = 'Q';
pieceType = QUEEN;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
};
class Knight : public Piece {
friend class Board;
public:
Knight(PieceColour colour) : Piece(colour) {
pieceName = "Knight";
pieceSymbol = 'N';
pieceType = KNIGHT;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
};
class Bishop : public Piece {
friend class Board;
public:
Bishop(PieceColour colour) : Piece(colour) {
pieceName = "Bishop";
pieceSymbol = 'B';
pieceType = BISHOP;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
};
class Pawn : public Piece {
friend class Board;
public:
Pawn(PieceColour colour) : Piece(colour) {
pieceName = "Pawn";
pieceSymbol = 'P';
pieceType = PAWN;
}
virtual std::vector<Move> getLegalMoves(const Square &from, const Board &board) const override;
};
#endif // PIECE_HPP

@ -1 +0,0 @@
Subproject commit 60366c3d0423a7181e94a0cfab404f0422eca3c7

View file

@ -1,169 +0,0 @@
// © 2025 A.M. Rowsell <amr@frzn.dev>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
/** @file Board.hpp
* @brief The header file for the Board class
*
* This contains the class definition for the logical representation of the chessboard
* itself, as well as a few ancillary enums and forward declarations to make the code
* easier to read (hopefully). Unlike the Piece.hpp header, there's no inheritance
* or virtual functions so this "half" of the code is a bit simpler to follow.
*/
#ifndef BOARD_HPP
#define BOARD_HPP
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "Piece.hpp"
class Piece;
/** @enum Players
* @brief An enum for the white and black players
*/
enum Players { PL_WHITE, PL_BLACK };
struct Square;
/** @class Board Board.hpp inc/Board.hpp
* @brief This class abstracts the chess board itself
*
* The heart of the entire code is contained in the member variable boardGrid, which
* is a representation of the board. It's a 2D vector of Pieces, which are stored using
* smart pointers. When other functions want to view the board, they do so with the included
* getPieceAt() getters, which return raw pointers so ownership isn't transferred.
*
* Outside functions/methods can also change the state of the board with setPieceAt() which
* can allow one to move a piece (empty squares being nullptr) or add pieces to the Board when
* required.
*/
class Board {
private:
std::vector<std::vector<std::unique_ptr<Piece>>> boardGrid; /**< This holds the game state.
* It is a 2D vector of Piece types, or nullptr for empty squares
* @image html boardGrid.svg "Logical diagram of boardGrid vector" */
Players playerTurn;
// let's get super object-oriented, baby
// these help the getters and setters access the boardGrid
// and also make them shorter and less duplicative
std::unique_ptr<Piece>& at(int r, int f) {
return boardGrid[r][f];
}
const std::unique_ptr<Piece> &at(int r, int f) const {
return boardGrid[r][f];
}
std::unique_ptr<Piece> &at(const Square& sq) {
return boardGrid[static_cast<int>(sq.rank)][static_cast<int>(sq.file)];
}
const std::unique_ptr<Piece> &at(const Square& sq) const {
return boardGrid[static_cast<int>(sq.rank)][static_cast<int>(sq.file)];
}
public:
Board();
virtual ~Board();
// These are to allow Piece to access Board in a controlled way
// instead of adding a friend declaration for every subclass
// ----- Getters -----
Piece* getPieceAt(int r, int f) {
return at(r, f).get();
}
const Piece* getPieceAt(int r, int f) const {
return at(r, f).get();
}
Piece* getPieceAt(const Square& sq) {
return at(sq).get();
}
const Piece* getPieceAt(const Square& sq) const {
return at(sq).get();
}
// ----- Setters -----
void setPieceAt(int r, int f, std::unique_ptr<Piece> piece) {
at(r, f) = std::move(piece);
}
void setPieceAt(const Square& sq, std::unique_ptr<Piece> piece) {
at(sq) = std::move(piece);
}
void clearSquare(int r, int f) {
at(r, f).reset();
}
void clearSquare(const Square& sq) {
at(sq).reset();
}
// ----- Utility -----
bool isSquareEmpty(int r, int f) const {
return at(r, f) == nullptr;
}
bool isSquareEmpty(const Square& sq) const {
return at(sq) == nullptr;
}
/** A function to setup the initial board
*
* This initializes the boardGrid with the black and white pieces
* in their normal starting positions. All empty squares are set
* to nullptr.
*/
void setupInitialPosition();
/** This function sets the entire board to nullptr
*
* This should, if I understand correctly, destroy
* all the Piece instances that existed because they will no longer
* have any owners, and smart pointers should auto destruct.
*/
void clearBoard();
/** This does the actual moving of a piece from one square to another
*
* Beware! This function does \e not validate if the move is legal. It
* will simply do whatever it is told to do. So only call this once you
* are positive the move is legal.
* Moves to an empty square are simple, just move the Piece to that other
* square. Captures have to also take note of the piece type captured
* and add it to the total captured by that side. This should also destroy
* the smart pointer automatically.
* @param from The originating square for the Piece that is moving
* @param to And of course, where it will end up
*/
void movePiece(Square from, Square to);
void nextTurn();
/** This function takes a standard FEN string and sets up the board.
*
* FEN is a standard notation that describes only an exact position and
* other important things like whose turn it is, whether sides can castle,
* but it does \e not include the move history of the game. This makes it
* a simpler format for sharing particular interesting positions.
*
* @param strFEN A std::string that contains a valid FEN position
* @return 0 on success, -1 if the FEN string is invalid
*/
int setupFromFEN(std::string strFEN);
bool isInBounds(Square square) const;
// serial shift register stuff
uint64_t serialBoard = 0xFFFF00000000FFFF; // opening position
/** This takes an incoming serial stream and detects if anything has moved.
*
* The input is one bit per piece, so it can only detect the presence or
* absence of pieces on any particular square. This is the crux of our design,
* using simpler reed switches for detection instead of RFID or any other two-way
* communication with the pieces. This moves a lot of the complexity into software,
* though a lot of the complexity is actually quite easy to deal with from a software
* point of view.
*
* @param incomingBoard A 64-bit value, representing 1 bit per piece.
*/
void deserializeBoard(uint64_t incomingBoard);
};
#endif // BOARD_HPP

View file

@ -1,235 +0,0 @@
// © 2025 A.M. Rowsell <amr@frzn.dev>
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#ifndef PIECE_HPP
#define PIECE_HPP
/** @file Piece.hpp
* @brief The header files for the Piece class.
*
* This file contains not only the definition of the Piece class itself, but also all
* of the derived classes (King, Queen, Rook, etc.) I was considering having them be in
* separate files, but each derived class does not contain that much code, so keeping them
* all in one place seemed easier to deal with. This may change in the future!
*
* Also defined here are important enums that help abstract chess terms, for example the
* PieceType, PieceColour, Rank, File, etc. These allow the code to be more readable and
* it helps make it obvious what certain bits of code are doing.
*/
#include <cstdint>
#include <algorithm>
#include <utility>
#include <string>
#include <memory>
#include <vector>
class Board;
enum PieceType {
PAWN, BISHOP, KNIGHT, ROOK, QUEEN, KING, EMPTY
};
enum PieceColour {
PIECE_WHITE, PIECE_BLACK, PIECE_EMPTY
};
enum Rank {
R1 = 0, R2 = 1, R3 = 2, R4 = 3, R5 = 4, R6 = 5, R7 = 6, R8 = 7, INVALID_RANK = 255
};
enum File {
A = 0, B = 1, C = 2, D = 3, E = 4, F = 5, G = 6, H = 7, INVALID_FILE = 255
};
enum CastleSide {
KINGSIDE = 1, QUEENSIDE = 2
};
/** @struct Square
* A struct that represents a square on the chess board.
*/
struct Square {
Rank rank; /**< enum Rank rank represents the rank of the Square */
File file; /**< enum File file represents the file of the Square */
/**
* A function to test if the square is a valid square on the chessboard
* @return True if the square is within the chessboard, False otherwise
*/
bool isValid() const {
return rank >= 0 && rank < 8 && file >= 0 && file < 8;
}
};
/**
* A struct representing the start and end squares of a Move.
*/
struct Move {
Square from;
Square to;
};
/**
* @class Piece Piece.hpp inc/Piece.hpp
* @brief A class abstracting chess pieces
*
* This is a polymorphic base class containing the basic properties all chess pieces have.
* It is intended to be extended by a child class for each piece Type, i.e. King, Queen, etc.
*/
class Piece {
private:
friend class Board;
protected:
PieceColour colour;
PieceType pieceType;
std::string pieceName; /**< std::string pieceName is a string showing the full name of the piece, i.e. "PAWN" */
std::string
pieceSymbol; /**< std::string pieceSymbol is a single character, using the standard algebraic chess notation, ie N for Knight */
bool hasMoved = false;
public:
Piece(PieceColour pColour) : colour(pColour) {
}
virtual ~Piece();
PieceColour getColour() const {
return colour;
}
std::string getPieceName() const {
return pieceName;
}
std::string getPieceSymbol() const {
return pieceSymbol;
}
PieceType getPieceType() const {
return pieceType;
}
bool checkIfMoved() const {
return hasMoved;
}
/**
* A virtual const function that should get all legal moves for a piece, but it may
* include some moves that need to be pruned, like those exposing the king to check.
* Still working out how to handle this.
*
* @param from the Square the Piece is currently on
* @param board A reference to the Board we are analyzing
* @return std::vector of Move: a list of all potentially legal moves
*/
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const;
bool finalMoveChecks(std::vector<Move> *moveList, Board &board);
};
class King : public Piece {
private:
friend class Board;
public:
King(PieceColour colour) : Piece(colour) {
pieceName = "King";
pieceSymbol = "K";
pieceType = KING;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
bool checkForCheck(Board &board) const;
bool checkForCastle(enum CastleSide side) const {
if(side == KINGSIDE)
return canCastleKS;
else if(side == QUEENSIDE)
return canCastleQS;
else
return false;
}
void setCastleQS(bool canCastle) {
canCastleQS = canCastle;
}
void setCastleKS(bool canCastle) {
canCastleKS = canCastle;
}
protected:
bool canCastleQS = true;
bool canCastleKS = true;
bool inCheck = false;
};
class Rook : public Piece {
friend class Board;
public:
Rook(PieceColour colour) : Piece(colour) {
pieceName = "Rook";
pieceSymbol = "R";
pieceType = ROOK;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
};
class Queen : public Piece {
friend class Board;
public:
Queen(PieceColour colour) : Piece(colour) {
pieceName = "Queen";
pieceSymbol = "Q";
pieceType = QUEEN;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
};
class Knight : public Piece {
friend class Board;
public:
Knight(PieceColour colour) : Piece(colour) {
pieceName = "Knight";
pieceSymbol = "N";
pieceType = KNIGHT;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
};
class Bishop : public Piece {
friend class Board;
public:
Bishop(PieceColour colour) : Piece(colour) {
pieceName = "Bishop";
pieceSymbol = "B";
pieceType = BISHOP;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
};
class Pawn : public Piece {
friend class Board;
public:
Pawn(PieceColour colour) : Piece(colour) {
pieceName = "Pawn";
pieceSymbol = "P";
pieceType = PAWN;
}
virtual std::vector<Move> getLegalMoves(const Square &from, Board &board) const override;
void promote(const Square &promotionSquare, Board &board, PieceType promoteTo);
protected:
bool vulnEnPassant = false;
bool firstMove = true;
};
#endif // PIECE_HPP

View file

@ -1,4 +1,4 @@
/*
/*
* File: strFuncs.hpp
* Author: amr
*

View file

@ -49,9 +49,9 @@
#include <sys/attribs.h> // for ISR macros
#include <sys/kmem.h>
#include "inc/Board.hpp"
#include "inc/Piece.hpp"
#include "inc/NeoPixel.hpp"
#include "Board.hpp"
#include "Piece.hpp"
#include "NeoPixel.hpp"
#define F_CPU 12000000UL // 12MHz
#define F_PER 6000000UL // 6MHz
@ -114,7 +114,7 @@ uint8_t initSystem(void) {
SDI1R = 0b0100; // RB8
RPA0R = 0b0001; // U1TX
SYSKEY = 0x12345678; // lock SYSKEY
ANSELBCLR = 0xFFFF; // port B all digital
ANSELBCLR = 0xFFFF; // port A all digital
SL_TRIS = 0; // RA0 as output
SL_LAT = 1; // set high
/* Set up SPI1 */
@ -157,8 +157,8 @@ void initInterrupts(void) {
INTCONbits.MVEC = 1; // Enable multi-vector interrupts
__builtin_enable_interrupts();
IPC10bits.DMA0IP = 3; // Priority level 3
// IFS1CLR = _IFS1_DMA0IF_MASK; // Clear interrupt flag
// IEC1SET = _IEC1_DMA0IE_MASK; // Enable DMA1 interrupt
IFS1CLR = _IFS1_DMA0IF_MASK; // Clear interrupt flag
IEC1SET = _IEC1_DMA0IE_MASK; // Enable DMA1 interrupt
}
void startSPI_DMA_Transfer(void) {
@ -179,7 +179,6 @@ extern "C" int main(void) {
initInterrupts();
Board gameBoard;
NeoPixel boardLights(64);
gameBoard.setupInitialPosition();
while(1) {
}
}
@ -192,7 +191,7 @@ extern "C" void __ISR(_DMA0_VECTOR, IPL3AUTO) DMA0Handler(void) {
DCH0INTCLR = _DCH0INT_CHBCIF_MASK; // Clear block complete flag
// DMA RX completed — spi_rx_buffer[] now contains the data
}
// IFS1CLR = _IFS1_DMA0IF_MASK; // Clear global DMA0 IRQ flag
IFS1CLR = _IFS1_DMA0IF_MASK; // Clear global DMA0 IRQ flag
}
//extern "C" void __ISR(_USB1_VECTOR, IPL4AUTO) USBHandler(void) {

View file

@ -0,0 +1,692 @@
<?xml version="1.0" encoding="UTF-8"?>
<configurationDescriptor version="65">
<logicalFolder name="root" displayName="root" projectFiles="true">
<logicalFolder name="HeaderFiles"
displayName="Header Files"
projectFiles="true">
<itemPath>Board.hpp</itemPath>
<itemPath>Piece.hpp</itemPath>
<itemPath>NeoPixel.hpp</itemPath>
<itemPath>inc/strFuncs.hpp</itemPath>
</logicalFolder>
<logicalFolder name="ExternalFiles"
displayName="Important Files"
projectFiles="true">
<logicalFolder name="chessmcu_default"
displayName="chessmcu_default"
projectFiles="true">
<logicalFolder name="components" displayName="components" projectFiles="true">
<itemPath>chessmcu_default/components/dfp.yml</itemPath>
<itemPath>chessmcu_default/components/core.yml</itemPath>
</logicalFolder>
<itemPath>chessmcu_default/mcc-config.mc4</itemPath>
</logicalFolder>
<itemPath>Makefile</itemPath>
</logicalFolder>
<logicalFolder name="LibraryFiles"
displayName="LibraryFiles"
projectFiles="true">
</logicalFolder>
<logicalFolder name="LinkerScript"
displayName="Linker Files"
projectFiles="true">
</logicalFolder>
<logicalFolder name="SourceFiles"
displayName="Source Files"
projectFiles="true">
<itemPath>main.cpp</itemPath>
<itemPath>Board.cpp</itemPath>
<itemPath>Piece.cpp</itemPath>
<itemPath>NeoPixel.cpp</itemPath>
<itemPath>graphics.cpp</itemPath>
<itemPath>strFuncs.cpp</itemPath>
</logicalFolder>
</logicalFolder>
<sourceRootList>
<Elem>.</Elem>
<Elem>inc</Elem>
</sourceRootList>
<projectmakefile>Makefile</projectmakefile>
<confs>
<conf name="Debug" type="2">
<toolsSet>
<developmentServer>localhost</developmentServer>
<targetDevice>PIC32MX270F256B</targetDevice>
<targetHeader></targetHeader>
<targetPluginBoard></targetPluginBoard>
<platformTool>noID</platformTool>
<languageToolchain>XC32</languageToolchain>
<languageToolchainVersion>4.60</languageToolchainVersion>
<platform>2</platform>
</toolsSet>
<packs>
<pack name="PIC32MX_DFP" vendor="Microchip" version="1.6.369"/>
</packs>
<ScriptingSettings>
</ScriptingSettings>
<compileType>
<linkerTool>
<linkerLibItems>
</linkerLibItems>
</linkerTool>
<archiverTool>
</archiverTool>
<loading>
<useAlternateLoadableFile>false</useAlternateLoadableFile>
<parseOnProdLoad>true</parseOnProdLoad>
<alternateLoadableFile></alternateLoadableFile>
</loading>
<subordinates>
</subordinates>
</compileType>
<makeCustomizationType>
<makeCustomizationPreStepEnabled>false</makeCustomizationPreStepEnabled>
<makeUseCleanTarget>false</makeUseCleanTarget>
<makeCustomizationPreStep></makeCustomizationPreStep>
<makeCustomizationPostStepEnabled>false</makeCustomizationPostStepEnabled>
<makeCustomizationPostStep></makeCustomizationPostStep>
<makeCustomizationPutChecksumInUserID>false</makeCustomizationPutChecksumInUserID>
<makeCustomizationEnableLongLines>false</makeCustomizationEnableLongLines>
<makeCustomizationNormalizeHexFile>false</makeCustomizationNormalizeHexFile>
</makeCustomizationType>
<C32>
<property key="additional-warnings" value="true"/>
<property key="addresss-attribute-use" value="false"/>
<property key="cast-align" value="false"/>
<property key="code-model" value="default"/>
<property key="const-model" value="default"/>
<property key="data-model" value="default"/>
<property key="disable-instruction-scheduling" value="false"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-procedural-abstraction" value="false"/>
<property key="enable-short-double" value="false"/>
<property key="enable-symbols" value="true"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exclude-floating-point" value="false"/>
<property key="expand-pragma-config" value="false"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="false"/>
<property key="keep-inline" value="false"/>
<property key="make-warnings-into-errors" value="true"/>
<property key="oXC16gcc-errata" value=""/>
<property key="oXC16gcc-large-aggregate" value="false"/>
<property key="oXC16gcc-mpa-lvl" value=""/>
<property key="oXC16gcc-name-text-sec" value=""/>
<property key="oXC16gcc-near-chars" value="false"/>
<property key="oXC16gcc-no-isr-warn" value="false"/>
<property key="oXC16gcc-sfr-warn" value="false"/>
<property key="oXC16gcc-smar-io-lvl" value="1"/>
<property key="oXC16gcc-smart-io-fmt" value=""/>
<property key="optimization-level" value="-O0"/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="scalar-model" value="default"/>
<property key="strict-ansi" value="false"/>
<property key="support-ansi" value="false"/>
<property key="tentative-definitions" value="-fno-common"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
</C32>
<C32-AR>
<property key="additional-options-chop-files" value="false"/>
</C32-AR>
<C32-AS>
<property key="assembler-symbols" value=""/>
<property key="enable-symbols" value="true"/>
<property key="exclude-floating-point-library" value="false"/>
<property key="expand-macros" value="false"/>
<property key="extra-include-directories-for-assembler" value=""/>
<property key="extra-include-directories-for-preprocessor" value=""/>
<property key="false-conditionals" value="false"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="keep-locals" value="false"/>
<property key="list-assembly" value="false"/>
<property key="list-section-info" value="true"/>
<property key="list-source" value="false"/>
<property key="list-symbols" value="false"/>
<property key="oXC16asm-extra-opts" value=""/>
<property key="oXC32asm-list-to-file" value="false"/>
<property key="omit-debug-dirs" value="false"/>
<property key="omit-forms" value="false"/>
<property key="preprocessor-macros" value=""/>
<property key="relax" value="false"/>
<property key="warning-level" value=""/>
</C32-AS>
<C32-CO>
<property key="coverage-enable" value=""/>
<property key="stack-guidance" value="false"/>
</C32-CO>
<C32-LD>
<property key="additional-options-use-response-files" value="false"/>
<property key="additional-options-write-sla" value="false"/>
<property key="allocate-dinit" value="false"/>
<property key="code-dinit" value="false"/>
<property key="ebase-addr" value=""/>
<property key="enable-check-sections" value="false"/>
<property key="enable-data-init" value="true"/>
<property key="enable-default-isr" value="true"/>
<property key="exclude-floating-point-library" value="false"/>
<property key="exclude-standard-libraries" value="false"/>
<property key="extra-lib-directories" value=""/>
<property key="fill-flash-options-addr" value=""/>
<property key="fill-flash-options-const" value=""/>
<property key="fill-flash-options-how" value="0"/>
<property key="fill-flash-options-inc-const" value="1"/>
<property key="fill-flash-options-increment" value=""/>
<property key="fill-flash-options-seq" value=""/>
<property key="fill-flash-options-what" value="0"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-cross-reference-file" value="true"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="heap-size" value="1000"/>
<property key="input-libraries" value=""/>
<property key="kseg-length" value=""/>
<property key="kseg-origin" value=""/>
<property key="linker-symbols" value=""/>
<property key="map-file" value="${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map"/>
<property key="no-device-startup-code" value="false"/>
<property key="no-ivt" value="false"/>
<property key="no-startup-files" value="false"/>
<property key="oXC16ld-force-link" value="false"/>
<property key="oXC16ld-no-smart-io" value="false"/>
<property key="oXC16ld-stackguard" value="16"/>
<property key="oXC32ld-extra-opts" value=""/>
<property key="optimization-level" value="-O1"/>
<property key="preprocessor-macros" value=""/>
<property key="remove-unused-sections" value="true"/>
<property key="report-memory-usage" value="true"/>
<property key="serial-length" value=""/>
<property key="serial-origin" value=""/>
<property key="stack-size" value="100"/>
<property key="symbol-stripping" value=""/>
<property key="trace-symbols" value=""/>
<property key="warn-section-align" value="false"/>
</C32-LD>
<C32CPP>
<property key="additional-warnings" value="false"/>
<property key="addresss-attribute-use" value="false"/>
<property key="check-new" value="true"/>
<property key="eh-specs" value="false"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-symbols" value="true"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exceptions" value="false"/>
<property key="exclude-floating-point" value="false"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="false"/>
<property key="make-warnings-into-errors" value="false"/>
<property key="optimization-level" value=""/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="rtti" value="true"/>
<property key="strict-ansi" value="false"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
<appendMe value="-std=c++17"/>
</C32CPP>
<C32Global>
<property key="combine-sourcefiles" value="false"/>
<property key="common-include-directories" value=""/>
<property key="common-macros" value=""/>
<property key="dual-boot-partition" value="0"/>
<property key="generic-16-bit" value="false"/>
<property key="gp-relative-option" value=""/>
<property key="legacy-libc" value="true"/>
<property key="mdtcm" value=""/>
<property key="mitcm" value=""/>
<property key="mpreserve-all" value="false"/>
<property key="mstacktcm" value="false"/>
<property key="omit-pack-options" value="1"/>
<property key="preserve-all" value="false"/>
<property key="preserve-file" value=""/>
<property key="relaxed-math" value="false"/>
<property key="save-temps" value="false"/>
<property key="stack-smashing" value=""/>
<property key="wpo-lto" value="false"/>
</C32Global>
</conf>
<conf name="Production" type="2">
<toolsSet>
<developmentServer>localhost</developmentServer>
<targetDevice>PIC32MX270F256B</targetDevice>
<targetHeader></targetHeader>
<targetPluginBoard></targetPluginBoard>
<platformTool>noID</platformTool>
<languageToolchain>XC32</languageToolchain>
<languageToolchainVersion>4.60</languageToolchainVersion>
<platform>2</platform>
</toolsSet>
<packs>
<pack name="PIC32MX_DFP" vendor="Microchip" version="1.6.369"/>
</packs>
<ScriptingSettings>
</ScriptingSettings>
<compileType>
<linkerTool>
<linkerLibItems>
</linkerLibItems>
</linkerTool>
<archiverTool>
</archiverTool>
<loading>
<useAlternateLoadableFile>false</useAlternateLoadableFile>
<parseOnProdLoad>true</parseOnProdLoad>
<alternateLoadableFile></alternateLoadableFile>
</loading>
<subordinates>
</subordinates>
</compileType>
<makeCustomizationType>
<makeCustomizationPreStepEnabled>false</makeCustomizationPreStepEnabled>
<makeUseCleanTarget>false</makeUseCleanTarget>
<makeCustomizationPreStep></makeCustomizationPreStep>
<makeCustomizationPostStepEnabled>false</makeCustomizationPostStepEnabled>
<makeCustomizationPostStep></makeCustomizationPostStep>
<makeCustomizationPutChecksumInUserID>false</makeCustomizationPutChecksumInUserID>
<makeCustomizationEnableLongLines>false</makeCustomizationEnableLongLines>
<makeCustomizationNormalizeHexFile>false</makeCustomizationNormalizeHexFile>
</makeCustomizationType>
<C32>
<property key="additional-warnings" value="false"/>
<property key="addresss-attribute-use" value="false"/>
<property key="cast-align" value="false"/>
<property key="code-model" value="default"/>
<property key="const-model" value="default"/>
<property key="data-model" value="default"/>
<property key="disable-instruction-scheduling" value="false"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-procedural-abstraction" value="false"/>
<property key="enable-short-double" value="false"/>
<property key="enable-symbols" value="false"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exclude-floating-point" value="true"/>
<property key="expand-pragma-config" value="false"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="true"/>
<property key="keep-inline" value="false"/>
<property key="make-warnings-into-errors" value="false"/>
<property key="oXC16gcc-errata" value=""/>
<property key="oXC16gcc-large-aggregate" value="false"/>
<property key="oXC16gcc-mpa-lvl" value=""/>
<property key="oXC16gcc-name-text-sec" value=""/>
<property key="oXC16gcc-near-chars" value="false"/>
<property key="oXC16gcc-no-isr-warn" value="false"/>
<property key="oXC16gcc-sfr-warn" value="false"/>
<property key="oXC16gcc-smar-io-lvl" value="1"/>
<property key="oXC16gcc-smart-io-fmt" value=""/>
<property key="optimization-level" value="-O2"/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="scalar-model" value="default"/>
<property key="strict-ansi" value="false"/>
<property key="support-ansi" value="false"/>
<property key="tentative-definitions" value="-fcommon"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
</C32>
<C32-AR>
<property key="additional-options-chop-files" value="false"/>
</C32-AR>
<C32-AS>
<property key="assembler-symbols" value=""/>
<property key="enable-symbols" value="false"/>
<property key="exclude-floating-point-library" value="true"/>
<property key="expand-macros" value="false"/>
<property key="extra-include-directories-for-assembler" value=""/>
<property key="extra-include-directories-for-preprocessor" value=""/>
<property key="false-conditionals" value="false"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="keep-locals" value="false"/>
<property key="list-assembly" value="false"/>
<property key="list-section-info" value="false"/>
<property key="list-source" value="false"/>
<property key="list-symbols" value="false"/>
<property key="oXC16asm-extra-opts" value=""/>
<property key="oXC32asm-list-to-file" value="false"/>
<property key="omit-debug-dirs" value="false"/>
<property key="omit-forms" value="false"/>
<property key="preprocessor-macros" value=""/>
<property key="relax" value="false"/>
<property key="warning-level" value=""/>
</C32-AS>
<C32-CO>
<property key="coverage-enable" value=""/>
<property key="stack-guidance" value="false"/>
</C32-CO>
<C32-LD>
<property key="additional-options-use-response-files" value="false"/>
<property key="additional-options-write-sla" value="false"/>
<property key="allocate-dinit" value="false"/>
<property key="code-dinit" value="false"/>
<property key="ebase-addr" value=""/>
<property key="enable-check-sections" value="false"/>
<property key="enable-data-init" value="true"/>
<property key="enable-default-isr" value="true"/>
<property key="exclude-floating-point-library" value="false"/>
<property key="exclude-standard-libraries" value="false"/>
<property key="extra-lib-directories" value=""/>
<property key="fill-flash-options-addr" value=""/>
<property key="fill-flash-options-const" value=""/>
<property key="fill-flash-options-how" value="0"/>
<property key="fill-flash-options-inc-const" value="1"/>
<property key="fill-flash-options-increment" value=""/>
<property key="fill-flash-options-seq" value=""/>
<property key="fill-flash-options-what" value="0"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-cross-reference-file" value="true"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="heap-size" value="1000"/>
<property key="input-libraries" value=""/>
<property key="kseg-length" value=""/>
<property key="kseg-origin" value=""/>
<property key="linker-symbols" value=""/>
<property key="map-file" value="${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map"/>
<property key="no-device-startup-code" value="false"/>
<property key="no-ivt" value="false"/>
<property key="no-startup-files" value="false"/>
<property key="oXC16ld-force-link" value="false"/>
<property key="oXC16ld-no-smart-io" value="false"/>
<property key="oXC16ld-stackguard" value="16"/>
<property key="oXC32ld-extra-opts" value=""/>
<property key="optimization-level" value="-O1"/>
<property key="preprocessor-macros" value=""/>
<property key="remove-unused-sections" value="true"/>
<property key="report-memory-usage" value="true"/>
<property key="serial-length" value=""/>
<property key="serial-origin" value=""/>
<property key="stack-size" value="100"/>
<property key="symbol-stripping" value=""/>
<property key="trace-symbols" value=""/>
<property key="warn-section-align" value="false"/>
</C32-LD>
<C32CPP>
<property key="additional-warnings" value="false"/>
<property key="addresss-attribute-use" value="false"/>
<property key="check-new" value="false"/>
<property key="eh-specs" value="true"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-symbols" value="false"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exceptions" value="true"/>
<property key="exclude-floating-point" value="true"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="true"/>
<property key="make-warnings-into-errors" value="false"/>
<property key="optimization-level" value="-O2"/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="rtti" value="true"/>
<property key="strict-ansi" value="false"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
</C32CPP>
<C32Global>
<property key="combine-sourcefiles" value="false"/>
<property key="common-include-directories" value=""/>
<property key="common-macros" value=""/>
<property key="dual-boot-partition" value="0"/>
<property key="generic-16-bit" value="false"/>
<property key="gp-relative-option" value=""/>
<property key="legacy-libc" value="true"/>
<property key="mdtcm" value=""/>
<property key="mitcm" value=""/>
<property key="mpreserve-all" value="false"/>
<property key="mstacktcm" value="false"/>
<property key="omit-pack-options" value="1"/>
<property key="preserve-all" value="false"/>
<property key="preserve-file" value=""/>
<property key="relaxed-math" value="false"/>
<property key="save-temps" value="false"/>
<property key="stack-smashing" value=""/>
<property key="wpo-lto" value="false"/>
</C32Global>
</conf>
<conf name="PIC32MM" type="2">
<toolsSet>
<developmentServer>localhost</developmentServer>
<targetDevice>PIC32MM0256GPM028</targetDevice>
<targetHeader></targetHeader>
<targetPluginBoard></targetPluginBoard>
<platformTool>noID</platformTool>
<languageToolchain>XC32</languageToolchain>
<languageToolchainVersion>4.60</languageToolchainVersion>
<platform>2</platform>
</toolsSet>
<packs>
<pack name="PIC32MM-GPM-0XX_DFP" vendor="Microchip" version="1.4.156"/>
</packs>
<ScriptingSettings>
</ScriptingSettings>
<compileType>
<linkerTool>
<linkerLibItems>
</linkerLibItems>
</linkerTool>
<archiverTool>
</archiverTool>
<loading>
<useAlternateLoadableFile>false</useAlternateLoadableFile>
<parseOnProdLoad>true</parseOnProdLoad>
<alternateLoadableFile></alternateLoadableFile>
</loading>
<subordinates>
</subordinates>
</compileType>
<makeCustomizationType>
<makeCustomizationPreStepEnabled>false</makeCustomizationPreStepEnabled>
<makeUseCleanTarget>false</makeUseCleanTarget>
<makeCustomizationPreStep></makeCustomizationPreStep>
<makeCustomizationPostStepEnabled>false</makeCustomizationPostStepEnabled>
<makeCustomizationPostStep></makeCustomizationPostStep>
<makeCustomizationPutChecksumInUserID>false</makeCustomizationPutChecksumInUserID>
<makeCustomizationEnableLongLines>false</makeCustomizationEnableLongLines>
<makeCustomizationNormalizeHexFile>false</makeCustomizationNormalizeHexFile>
</makeCustomizationType>
<C32>
<property key="additional-warnings" value="false"/>
<property key="addresss-attribute-use" value="false"/>
<property key="cast-align" value="false"/>
<property key="code-model" value="default"/>
<property key="const-model" value="default"/>
<property key="data-model" value="default"/>
<property key="disable-instruction-scheduling" value="false"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-procedural-abstraction" value="false"/>
<property key="enable-short-double" value="false"/>
<property key="enable-symbols" value="true"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exclude-floating-point" value="true"/>
<property key="expand-pragma-config" value="false"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="false"/>
<property key="keep-inline" value="false"/>
<property key="make-warnings-into-errors" value="false"/>
<property key="oXC16gcc-errata" value=""/>
<property key="oXC16gcc-large-aggregate" value="false"/>
<property key="oXC16gcc-mpa-lvl" value=""/>
<property key="oXC16gcc-name-text-sec" value=""/>
<property key="oXC16gcc-near-chars" value="false"/>
<property key="oXC16gcc-no-isr-warn" value="false"/>
<property key="oXC16gcc-sfr-warn" value="false"/>
<property key="oXC16gcc-smar-io-lvl" value="1"/>
<property key="oXC16gcc-smart-io-fmt" value=""/>
<property key="optimization-level" value="-O0"/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="scalar-model" value="default"/>
<property key="strict-ansi" value="false"/>
<property key="support-ansi" value="false"/>
<property key="tentative-definitions" value="-fno-common"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
</C32>
<C32-AR>
<property key="additional-options-chop-files" value="false"/>
</C32-AR>
<C32-AS>
<property key="assembler-symbols" value=""/>
<property key="enable-symbols" value="true"/>
<property key="exclude-floating-point-library" value="true"/>
<property key="expand-macros" value="false"/>
<property key="extra-include-directories-for-assembler" value=""/>
<property key="extra-include-directories-for-preprocessor" value=""/>
<property key="false-conditionals" value="false"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="keep-locals" value="false"/>
<property key="list-assembly" value="false"/>
<property key="list-section-info" value="false"/>
<property key="list-source" value="false"/>
<property key="list-symbols" value="false"/>
<property key="oXC16asm-extra-opts" value=""/>
<property key="oXC32asm-list-to-file" value="false"/>
<property key="omit-debug-dirs" value="false"/>
<property key="omit-forms" value="false"/>
<property key="preprocessor-macros" value=""/>
<property key="relax" value="false"/>
<property key="warning-level" value=""/>
</C32-AS>
<C32-CO>
<property key="coverage-enable" value=""/>
<property key="stack-guidance" value="false"/>
</C32-CO>
<C32-LD>
<property key="additional-options-use-response-files" value="false"/>
<property key="additional-options-write-sla" value="false"/>
<property key="allocate-dinit" value="false"/>
<property key="code-dinit" value="false"/>
<property key="ebase-addr" value=""/>
<property key="enable-check-sections" value="false"/>
<property key="enable-data-init" value="true"/>
<property key="enable-default-isr" value="true"/>
<property key="exclude-floating-point-library" value="false"/>
<property key="exclude-standard-libraries" value="false"/>
<property key="extra-lib-directories" value=""/>
<property key="fill-flash-options-addr" value=""/>
<property key="fill-flash-options-const" value=""/>
<property key="fill-flash-options-how" value="0"/>
<property key="fill-flash-options-inc-const" value="1"/>
<property key="fill-flash-options-increment" value=""/>
<property key="fill-flash-options-seq" value=""/>
<property key="fill-flash-options-what" value="0"/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-cross-reference-file" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="heap-size" value="768"/>
<property key="input-libraries" value=""/>
<property key="kseg-length" value=""/>
<property key="kseg-origin" value=""/>
<property key="linker-symbols" value=""/>
<property key="map-file" value="${DISTDIR}/${PROJECTNAME}.${IMAGE_TYPE}.map"/>
<property key="no-device-startup-code" value="false"/>
<property key="no-ivt" value="false"/>
<property key="no-startup-files" value="false"/>
<property key="oXC16ld-force-link" value="false"/>
<property key="oXC16ld-no-smart-io" value="false"/>
<property key="oXC16ld-stackguard" value="16"/>
<property key="oXC32ld-extra-opts" value=""/>
<property key="optimization-level" value="-O1"/>
<property key="preprocessor-macros" value=""/>
<property key="remove-unused-sections" value="true"/>
<property key="report-memory-usage" value="true"/>
<property key="serial-length" value=""/>
<property key="serial-origin" value=""/>
<property key="stack-size" value="100"/>
<property key="symbol-stripping" value=""/>
<property key="trace-symbols" value=""/>
<property key="warn-section-align" value="false"/>
</C32-LD>
<C32CPP>
<property key="additional-warnings" value="false"/>
<property key="addresss-attribute-use" value="false"/>
<property key="check-new" value="false"/>
<property key="eh-specs" value="true"/>
<property key="enable-app-io" value="false"/>
<property key="enable-omit-frame-pointer" value="false"/>
<property key="enable-symbols" value="true"/>
<property key="enable-unroll-loops" value="false"/>
<property key="exceptions" value="true"/>
<property key="exclude-floating-point" value="true"/>
<property key="extra-include-directories" value=""/>
<property key="generate-16-bit-code" value="false"/>
<property key="generate-micro-compressed-code" value="false"/>
<property key="isolate-each-function" value="false"/>
<property key="make-warnings-into-errors" value="false"/>
<property key="optimization-level" value=""/>
<property key="place-data-into-section" value="true"/>
<property key="post-instruction-scheduling" value="default"/>
<property key="pre-instruction-scheduling" value="default"/>
<property key="preprocessor-macros" value=""/>
<property key="rtti" value="true"/>
<property key="strict-ansi" value="false"/>
<property key="toplevel-reordering" value=""/>
<property key="unaligned-access" value=""/>
<property key="use-cci" value="false"/>
<property key="use-iar" value="false"/>
<property key="use-indirect-calls" value="false"/>
</C32CPP>
<C32Global>
<property key="combine-sourcefiles" value="false"/>
<property key="common-include-directories" value=""/>
<property key="common-macros" value=""/>
<property key="dual-boot-partition" value="0"/>
<property key="generic-16-bit" value="false"/>
<property key="gp-relative-option" value=""/>
<property key="legacy-libc" value="true"/>
<property key="mdtcm" value=""/>
<property key="mitcm" value=""/>
<property key="mpreserve-all" value="false"/>
<property key="mstacktcm" value="false"/>
<property key="omit-pack-options" value="1"/>
<property key="preserve-all" value="false"/>
<property key="preserve-file" value=""/>
<property key="relaxed-math" value="false"/>
<property key="save-temps" value="false"/>
<property key="stack-smashing" value=""/>
<property key="wpo-lto" value="false"/>
</C32Global>
</conf>
</confs>
</configurationDescriptor>

View file

@ -4,8 +4,9 @@ template <typename Out>
void split(const std::string &s, char delim, Out result) {
std::istringstream iss(s);
std::string item;
while(std::getline(iss, item, delim))
while (std::getline(iss, item, delim)) {
*result++ = item;
}
}
std::vector<std::string> split(const std::string &s, char delim) {