Compare commits

..

20 commits

Author SHA1 Message Date
A.M. Rowsell
5359d0fb05
doxygen: Trying to get the Doxygen output looking like I want 2025-09-16 13:01:55 -04:00
A.M. Rowsell
ab26479c3c
docs: Documented more of the Board class 2025-09-16 13:01:30 -04:00
A.M. Rowsell
d59798b7e8
doxygen: updated doxygen-awesome-css 2025-09-16 03:26:43 -04:00
A.M. Rowsell
fa9d534e94
docs: bringing in doxygen-awesome-css, added more inline documentation
The doxygen-awesome-css project is just a nice, simple, customizable
CSS system for making doxygen look less like 1992 and more like
2022. I need to spend a bunch of time tweaking it to make it
look good, and perhaps match it to the style already used at
chess.frzn.dev.

Added more inline Doxycomments, and also generated an image that
represents the logical layout of the boardGrid member variable,
showing the mirrored layout. This works well for our project
because of the way the serial data comes in.
2025-09-16 03:21:53 -04:00
A.M. Rowsell
a1560f1611
chores: updated gitignore, removal of configurations.xml, formatted header 2025-09-13 11:36:53 -04:00
A.M. Rowsell
a56fb4d60f
dev: refactoring things to be more OOP! whoop whoop
Still struggling to understand all these concepts, and I will admit
to using ChatGPT to try and explain where I was going wrong which
did help quite a bit. But if I get this right it will be much
more robust and less "fragile" as they say.
2025-09-13 11:18:27 -04:00
A.M. Rowsell
c333e3da9e
dev: refactoring Board to be simpler for Piece to use
This commit adds a bunch of getters/setters for accessing the
boardGrid. This is a simpler way to allow both Piece and all
the inherited classes to access the Board without having to
declare every single class a friend. So now when we want to
access boardGrid, we use getPieceAt() or setPieceAt(). They
are overloaded to accept rank/file, Square, or int/int.
There's also a convenience function to check if the square
is empty, though that may get re-written to use the existing
Square.isValid().
2025-09-13 10:43:25 -04:00
A.M. Rowsell
6e05baa87d
docs: Added Doxygen config 2025-09-07 18:00:30 -04:00
A.M. Rowsell
f05dd6d90f
dev: Updates to Board and Piece, formatted code 2025-09-07 17:59:16 -04:00
A.M. Rowsell
8e381cf109
docs: Starting to add Doxygen comments 2025-09-07 17:57:15 -04:00
A.M. Rowsell
ca6468cc62
docs: temporarily added docs/ to .gitignore as they are not ready 2025-09-07 17:46:48 -04:00
A.M. Rowsell
b68169dd2b
cool: I added figlet headings because I'm that cool 2025-09-01 01:42:42 -04:00
A.M. Rowsell
6773da28fb
Piece: expanding getLegalMoves for Queen/Knight/Bishop 2025-08-30 18:46:18 -04:00
A.M. Rowsell
e5a124d193
FEN: major portion of FEN import is working and tested 2025-08-30 18:45:04 -04:00
A.M. Rowsell
21fae88bdb
fmt: reformatted code, changed some function signatures, fairly minor 2025-08-29 04:17:16 -04:00
A.M. Rowsell
76c0c3ce8b
FEN: more work on FEN decoding, handling field 2 and 3 2025-08-29 04:16:20 -04:00
A.M. Rowsell
22fe7bdf0b
organize: moved include files to inc/ 2025-08-28 10:45:41 -04:00
A.M. Rowsell
7722a84b2e
astyle: reformatted all files 2025-08-28 10:41:59 -04:00
A.M. Rowsell
04c7a931d3
fen: Merge branch 'fen' into dev 2025-08-28 10:39:50 -04:00
A.M. Rowsell
78749a6af2
dev: Added QS/KS castle checking; simplified moveList pruning 2025-08-28 10:29:19 -04:00
16 changed files with 3802 additions and 1057 deletions

9
.gitignore vendored
View file

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

3
.gitmodules vendored Normal file
View file

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

291
Board.cpp
View file

@ -6,7 +6,8 @@
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#include "Board.hpp"
#include "inc/Board.hpp"
#include "inc/Piece.hpp"
#include "inc/strFuncs.hpp"
/*
@ -31,9 +32,8 @@
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
// initialize each square with a Piece or nullptr
playerTurn = PL_WHITE;
for(int i = 0; i < 8; i++) {
switch(i) {
@ -89,115 +89,226 @@ void Board::setupInitialPosition() {
}
return;
}
int setupFromFEN(std::string strFEN) {
std::vector<std::string> splitFEN = split(strFEN, ' ');
if(splitFEN.size() != 6) { // a valid FEN *must* contain 6 fields
return -1;
/**
* 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) {
std::vector<std::string> splitFEN = split(strFEN, ' ');
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);
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;
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;
}
break;
case 'k':
// black king
if(bKingPlaced) {
// invalid FEN, more than 1 black king
default:
// invalid character?
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;
break;
}
if(file > 7) {
file = 0;
break;
}
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) {
uint8_t boardRows[8];
union {
uint8_t boardRows[8];
uint64_t fullBoard;
} serialBoard;
for(int i = 0; i < 8; i++)
boardRows[i] = (incomingBoard >> (8 * i)) & 0xFF;
serialBoard.boardRows[i] = static_cast<uint8_t>((incomingBoard >> (8 * i)) & 0xFF);
// how do we then figure out what has moved?
return;
}

View file

@ -1,47 +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 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 Normal file

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 "NeoPixel.hpp"
#include "inc/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,24 +6,71 @@
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, v. 2.0.
#include "Piece.hpp"
#include "inc/Piece.hpp"
#include "inc/Board.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, const Board &board) const {
std::vector<Move> Piece::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> moveList;
return moveList;
}
std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) const {
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> moveList;
std::vector<std::vector<int>> directions = {
{-1, 0}, // Up
@ -39,12 +86,10 @@ std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) co
// establish r/f for square to check
int r = from.rank + dir[0];
int f = from.file + dir[1];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
if(targetSquare.isValid()) {
const auto &target = board.boardGrid[r][f]; // examine the target square
if(!target) { // if square is empty (NULL)
const Piece *target = board.getPieceAt(targetSquare); // examine the target square
if(!target) { // if square is empty (nullptr)
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
@ -89,7 +134,8 @@ std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) co
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) {
auto &target = board.boardGrid[r][f]; // access the square we're examining
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare); // access the square we're examining
if(!target) {
// empty square, continue
continue;
@ -97,18 +143,20 @@ std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) co
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())) {
@ -125,15 +173,26 @@ std::vector<Move> King::getLegalMoves(const Square &from, const Board &board) co
}
// will this actually work?
moveList.erase(
std::remove_if(moveList.begin(), moveList.end(),
[&](const Square &x) {
return std::find(x.begin(), x.end(), !x.isValid()) != x.end();
}),
moveList.end());
std::remove_if(moveList.begin(), moveList.end(),
[&](const auto & x) {
return !x.to.isValid();
}));
return moveList;
}
std::vector<Move> Rook::getLegalMoves(const Square &from, const Board &board) const {
// *INDENT-OFF*
//
// ##
// #
// # ### ## ## # ##
// # # # # # # #
// # # # # # ##
// # # # # # # #
// #### ## ## ## ##
//
// *INDENT-OM*
std::vector<Move> Rook::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> moveList;
const int directions[4][2] = {
{-1, 0}, // Up
@ -141,14 +200,12 @@ std::vector<Move> Rook::getLegalMoves(const Square &from, const Board &board) co
{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) {
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
if(!target) {
moveList.push_back({from, targetSquare});
} else if(target && target->getColour() != this->getColour()) {
@ -163,22 +220,113 @@ std::vector<Move> Rook::getLegalMoves(const Square &from, const Board &board) co
return moveList;
}
std::vector<Move> Queen::getLegalMoves(const Square &from, const Board &board) const {
// *INDENT-OFF*
// ## # ## ## ## ## # ##
// # # # # # # # # # #
// # # # # ### ### # #
// # # # # # # # #
// ### ## # ### ### ### ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Queen::getLegalMoves(const Square &from, 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;
}
std::vector<Move> Knight::getLegalMoves(const Square &from, const Board &board) const {
// *INDENT-OFF*
// ## # ## #
// # # #
// # ## # ## ## ## # ### ####
// # # # # # # # # # #
// ## # # # # # # # #
// # # # # # # # # # # #
// ## ## ### ## ##### ### ### ## ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Knight::getLegalMoves(const Square &from, 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;
}
std::vector<Move> Bishop::getLegalMoves(const Square &from, const Board &board) const {
// *INDENT-OFF*
// ## # ##
// # #
// ### ## ### ### ## # ##
// # # # # # # # # # #
// # # # ## # # # # # #
// # # # # # # # # # #
// #### ##### ### ### ## ## ###
// #
// ###
// *INDENT-ON*
std::vector<Move> Bishop::getLegalMoves(const Square &from, 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;
}
std::vector<Move> Pawn::getLegalMoves(const Square &from, const Board &board) const {
// *INDENT-OFF*
//
// # ## ## # # ## # ##
// # # # # # # # #
// # # ### # # # # #
// # # # # # # # #
// ### ## # # # ### ##
// #
// ###
// *INDENT-ON*
std::vector<Move> Pawn::getLegalMoves(const Square &from, Board &board) const {
std::vector<Move> moveList;
const int directions[2][4][2] = {
{
@ -202,13 +350,11 @@ std::vector<Move> Pawn::getLegalMoves(const Square &from, const Board &board) co
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
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
if(dir[0] == -2 && !this->checkIfMoved()) {
// then 2 is potentially legal
if(!target && !(board.boardGrid[r + 1][f])) // check both squares for pieces of any colour
if(!target && board.isSquareEmpty(Square{static_cast<Rank>(r + 1), static_cast<File>(f)})) // check both squares for pieces of any colour
moveList.push_back({from, targetSquare});
else
continue;
@ -231,13 +377,11 @@ std::vector<Move> Pawn::getLegalMoves(const Square &from, const Board &board) co
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
const auto& target = board.boardGrid[r][f];
auto ra = static_cast<Rank>(r);
auto fi = static_cast<File>(f);
Square targetSquare = {ra, fi};
Square targetSquare{static_cast<Rank>(r), static_cast<File>(f)};
const Piece *target = board.getPieceAt(targetSquare);
if(dir[0] == 2 && !this->checkIfMoved()) {
// then 2 is potentially legal
if(!target && !(board.boardGrid[r - 1][f]))
if(!target && board.isSquareEmpty(Square{static_cast<Rank>(r + 1), static_cast<File>(f)}))
moveList.push_back({from, targetSquare});
else
continue;

172
Piece.hpp
View file

@ -1,172 +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
#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
doxygen-awesome-css Submodule

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

169
inc/Board.hpp Normal file
View file

@ -0,0 +1,169 @@
// © 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

235
inc/Piece.hpp Normal file
View file

@ -0,0 +1,235 @@
// © 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 "Board.hpp"
#include "Piece.hpp"
#include "NeoPixel.hpp"
#include "inc/Board.hpp"
#include "inc/Piece.hpp"
#include "inc/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 A all digital
ANSELBCLR = 0xFFFF; // port B 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,6 +179,7 @@ extern "C" int main(void) {
initInterrupts();
Board gameBoard;
NeoPixel boardLights(64);
gameBoard.setupInitialPosition();
while(1) {
}
}
@ -191,7 +192,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

@ -1,692 +0,0 @@
<?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,9 +4,8 @@ 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) {