enum Colour { RED = 1, BLACK };
struct rbNode {
uint8_t key; // which is the square on the board
uint8_t colour;
rbNode *left, *right, *parent;
void* data;
};
rbNode* root;
void doInsert(uint8_t key, cBoard* square) {
rbNode* temp = makeNode(key, square);
root = rbInsert(temp, root);
postInsertFix(temp, root);
}
rbNode* makeNode(uint8_t key, cBoard* square) {
rbNode* temp = (rbNode*)malloc(sizeof(rbNode));
temp->key = key;
temp->left = temp->right = temp->parent = NULL;
temp->colour = RED;
temp->data = malloc(sizeof(cBoard));
memcpy(temp->data, square, sizeof(cBoard));
return temp;
}
rbNode* rbInsert(rbNode* node, rbNode* leaf) {
if (leaf == NULL) {
return node;
}
if (node->key == leaf->key) {
// could implement update here
return leaf;
}
if (node->key < leaf->key) {
leaf->left = rbInsert(node, leaf->left);
leaf->left->parent = leaf;
}
else if (node->key > leaf->key) {
leaf->right = rbInsert(node, leaf->right);
leaf->right->parent = leaf;
}
return leaf;
}
void postInsertFix(rbNode *&node, rbNode *&root) {
rbNode* grandMa = NULL;
rbNode* aunty = NULL;
while (node != root && node->parent->colour == RED) {
grandMa = node->parent->parent;
if (node->parent == grandMa->left) {
aunty = grandMa->right;
if (aunty && aunty->colour == RED) {
node->parent->colour = BLACK;
aunty->colour = BLACK;
grandMa->colour = RED;
node = grandMa;
}
else {
if (node == node->parent->right) {
node = node->parent;
rbRotateLeft(node, root);
}
node->parent->colour = BLACK;
grandMa->colour = RED;
rbRotateRight(grandMa, root);
}
}
else {
aunty = grandMa->left;
if (aunty && aunty->colour == RED) {
node->parent->colour = BLACK;
aunty->colour = BLACK;
grandMa->colour = RED;
node = grandMa;
}
else {
if (node == node->parent->left) {
node = node->parent;
rbRotateRight(node, root);
}
node->parent->colour = BLACK;
grandMa->colour = RED;
rbRotateLeft(grandMa, root);
}
}
}
root->colour = BLACK;
}
void rbSwap(uint8_t* a, uint8_t* b) {
// C++ has a swap template class but this version is C
// so good old xor swap does the job
*a = *a ^ *b;
*b = *a ^ *b;
*a = *b ^ *a;
}
void rbRotateLeft(rbNode* node, rbNode*& root) {
rbNode* child = node->right;
node->right = child->left;
if (child->left) {
child->left->parent = node;
}
child->parent = node->parent;
if (node == root) {
root = child;
}
else if (node == node->parent->left) {
node->parent->left = child;
}
else {
node->parent->right = child;
}
child->left = node;
node->parent = child;
}
void rbRotateRight(rbNode* node, rbNode*& root) {
rbNode* child = node->left;
node->left = child->right;
if (child->right != NULL) {
child->right->parent = node;
}
child->parent = node->parent;
if (node == root) {
root = child;
}
else if (node == node->parent->right) {
node->parent->right = child;
}
else {
node->parent->left = child;
}
child->right = node;
node->parent = child;
}
int rbHeight(rbNode* leaf) {
if (leaf) {
int subMax = rbMax(rbHeight(leaf->left), rbHeight(leaf->right));
if (leaf->colour == BLACK) { subMax++; }
return subMax;
}
return 0;
}
int rbMax(int a, int b) {
return (a <= b) ? b : a;
}
cBoard* rbSearch(uint8_t key, rbNode* leaf) {
if (leaf) {
if (leaf->key == key) {
return (cBoard*)leaf->data;
}
if (key < leaf->key) {
return rbSearch(key, leaf->left);
}
return rbSearch(key, leaf->right);
}
return NULL;
}
rbNode* rbFind(uint8_t key, rbNode* leaf) {
if (leaf) {
if (leaf->key == key) {
return leaf;
}
if (key < leaf->key) {
return rbFind(key, leaf->left);
}
return rbFind(key, leaf->right);
}
return NULL;
}
void rbDeleteTree(rbNode* leaf) {
if (leaf) {
rbDeleteTree(leaf->left);
rbDeleteTree(leaf->right);
free(leaf->data);
free(leaf);
}
}
void rbDoDelete(uint8_t key) {
rbNode* found = rbFind(key, root);
if (found) {
rbNode* del = rbPreDeleteFix(found, root);
// now zap whatever is no longer needed
free(del->data);
free(del);
}
}
rbNode* rbPreDeleteFix(rbNode* node, rbNode*& root) {
rbNode* nodeToDelete = node;
rbNode* child = NULL;
rbNode* parentNode = NULL;
if (nodeToDelete->left == NULL) { // node has one or no children
child = nodeToDelete->right; // which might be NULL
}
else {
if (nodeToDelete->right == NULL) // node has one child
child = nodeToDelete->left; // child is not NULL
else { // node has two children
nodeToDelete = rbMinimum(nodeToDelete->right);
// so we reset to the minimum key node
// from the right child (so next largest key)
child = nodeToDelete->right;
}
}
if (nodeToDelete != node) {
// if the nodeToDelete got changed above
node->left->parent = nodeToDelete;
nodeToDelete->left = node->left;
if (nodeToDelete != node->right) {
parentNode = nodeToDelete->parent;
if (child) {
child->parent = nodeToDelete->parent;
}
nodeToDelete->parent->left = child;
nodeToDelete->right = node->right;
node->right->parent = nodeToDelete;
}
else {
parentNode = nodeToDelete;
}
if (root == node) {
root = nodeToDelete;
}
else if (node->parent->left == node) {
node->parent->left = nodeToDelete;
}
else {
node->parent->right = nodeToDelete;
}
nodeToDelete->parent = node->parent;
rbSwap(&nodeToDelete->colour, &node->colour);// using xor swap
nodeToDelete = node;
// nodeToDelete now definately points to node to be deleted
}
else {
parentNode = nodeToDelete->parent;
if (child) {
child->parent = nodeToDelete->parent;
}
if (root == node) {
root = child;
}
else {
if (node->parent->left == node) {
node->parent->left = child;
}
else {
node->parent->right = child;
}
}
}
if (nodeToDelete->colour != RED) {
while (child != root && (child == NULL || child->colour == BLACK)) {
if (child == parentNode->left) {
rbNode* sisterNode = parentNode->right;
if (sisterNode->colour == RED) {
sisterNode->colour = BLACK;
parentNode->colour = RED;
rbRotateLeft(parentNode, root);
sisterNode = parentNode->right;
}
if ((sisterNode->left == NULL ||
sisterNode->left->colour == BLACK) &&
(sisterNode->right == NULL ||
sisterNode->right->colour == BLACK)) {
sisterNode->colour = RED;
child = parentNode;
parentNode = parentNode->parent;
}
else {
if (sisterNode->right == NULL ||
sisterNode->right->colour == BLACK) {
if (sisterNode->left) sisterNode->left->colour = BLACK;
sisterNode->colour = RED;
rbRotateRight(sisterNode, root);
sisterNode = parentNode->right;
}
sisterNode->colour = parentNode->colour;
parentNode->colour = BLACK;
if (sisterNode->right) {
sisterNode->right->colour = BLACK;
}
rbRotateLeft(parentNode, root);
break;
}
}
else { // same as above but the other way about
rbNode* sisterNode = parentNode->left;
if (sisterNode->colour == RED) {
sisterNode->colour = BLACK;
parentNode->colour = RED;
rbRotateRight(parentNode, root);
sisterNode = parentNode->left;
}
if ((sisterNode->right == NULL ||
sisterNode->right->colour == BLACK) &&
(sisterNode->left == NULL ||
sisterNode->left->colour == BLACK)) {
sisterNode->colour = RED;
child = parentNode;
parentNode = parentNode->parent;
}
else {
if (sisterNode->left == NULL ||
sisterNode->left->colour == BLACK) {
if (sisterNode->right) {
sisterNode->right->colour = BLACK;
}
sisterNode->colour = RED;
rbRotateLeft(sisterNode, root);
sisterNode = parentNode->left;
}
sisterNode->colour = parentNode->colour;
parentNode->colour = BLACK;
if (sisterNode->left) {
sisterNode->left->colour = BLACK;
}
rbRotateRight(parentNode, root);
break;
}
}
}
if (child) {
child->colour = BLACK;
}
}
return nodeToDelete;
}
rbNode* rbMaximum(rbNode* node) {
while (node->right) {
node = node->right;
}
return node;
}
rbNode* rbMinimum(rbNode* node) {
while (node->left) {
node = node->left;
}
return node;
}
void treeKeyPrint(rbNode* root) {
if (root) {
cout << "root: " << root->key << '\n';
if (root->left) {
cout << "root Left: " << root->left->key;
}
if (root->right) {
cout << "root Right: " << root->right->key;
}
cout << '\n';
}
}
void levelOrderHelper(rbNode* root)
{
if (root == NULL)
return;
queue<rbNode*> q;
q.push(root);
while (!q.empty())
{
rbNode *temp = q.front();
cout << temp->key << " ";
q.pop();
if (temp->left != NULL)
q.push(temp->left);
if (temp->right != NULL)
q.push(temp->right);
}
}
#include "stdafx.h"
#include "stdafx.h"
#include <stdint.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
using namespace std;
enum Players { WHT, BLK };
uint8_t nextMove = WHT;
enum Pieces { PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING };
char pNames[][7] = { "Pawn", "Rook", "Knight", "Bishop", "Queen", "King" };
char pSymbol[] = { 'P', 'R', 'N', 'B', 'Q', 'K' };
struct cBoard {
uint8_t player;
uint8_t piece;
};
typedef void(*ClBk)(uint8_t, struct cBoard*);
typedef void(*ClBkC)(uint8_t, uint8_t, cBoard*);
void displayBoard();
void doInsert(uint8_t, cBoard*);
rbNode* makeNode(uint8_t, cBoard*);
rbNode* rbInsert(rbNode*, rbNode*);
void postInsertFix(rbNode *&, rbNode *&);
void rbSwap(uint8_t*, uint8_t*);
void rbRotateLeft(rbNode*, rbNode *&);
void rbRotateRight(rbNode*, rbNode *&);
int rbHeight(rbNode*);
int rbMax(int a, int b);
cBoard* rbSearch(uint8_t, rbNode*);
rbNode* rbFind(uint8_t, rbNode*);
void rbDeleteTree(rbNode*);
rbNode* rbMaximum(rbNode*);
rbNode* rbMinimum(rbNode*);
rbNode* rbPreDeleteFix(rbNode*, rbNode*&);
void rbDoDelete(uint8_t);
void levelOrderHelper(rbNode*);
void treeKeyPrint(rbNode*);
void setupBoard();
void makeMove(uint8_t,uint8_t);
void castleMove(uint8_t, uint8_t, uint8_t, uint8_t);
void playGame();
int main()
{
setupBoard();
displayBoard();
playGame();
cin.get();
return 0;
}
void makeMove(uint8_t from, uint8_t to) {
cBoard* fSquare = rbSearch(from, root);
cBoard* tSquare = rbSearch(to, root);
if (fSquare) {
if (fSquare->player == nextMove) {
if (tSquare == NULL || tSquare->player != nextMove) {
// probably a valid move but you could write a lot more
// validation to check route is clear if not knight and
// distance allowed and from and to not the same etc.
if (tSquare) {
rbDoDelete(to);
}
doInsert(to, fSquare);
rbDoDelete(from);
}
else {
cout << "Target square invalid\n";
}
}
else {
cout << "Not your move\n";
}
}
nextMove = (nextMove == WHT) ? BLK : WHT; //whose move next
displayBoard();
}
// OK the castle move needs different validation so
// as this is not intended as a chess playing game demo
// this function is a bodge to allow the move
void castleMove(uint8_t f1, uint8_t f2, uint8_t t1, uint8_t t2) {
cBoard* f1Square = rbSearch(f1, root);
cBoard* f2Square = rbSearch(f2, root);
doInsert(t1, f1Square);
rbDoDelete(f1);
doInsert(t2, f2Square);
rbDoDelete(f2);
nextMove = (nextMove == WHT) ? BLK : WHT; //whose move next
displayBoard();
}
void playGame() {
uint8_t cOpt = 0;
uint8_t moves[][2] = { { 13,29 },{ 53,37 },{ 7,13 },{ 58,43 },{ 2,19 },{ 62,35 },
{ 13,23 },{ 52,44 },{ 12,20 },{ 63,46 },{ 3,39 },{ 59,45 },{ 23,40 },{ 0,0 },
{ 19,36 },{ 46,29 },{ 39,60 },{ 35,14 },{ 5,13 },{ 45,31 } };
uint8_t cstlmoves[][4] = { { 61,64,63,62 } };
for (int i = 0; i < sizeof(moves) / 2; i++) {
if (moves[i][0] == 0) {
castleMove(cstlmoves[cOpt][0], cstlmoves[cOpt][1], cstlmoves[cOpt][2], cstlmoves[cOpt][3]);
cOpt++; // max is 2 per game
}
else {
makeMove(moves[i][0], moves[i][1]);
}
}
cout << "Checkmate!\n";
}
void setupBoard() {
cBoard wSquare = { WHT, PAWN }, bSquare = { BLK, PAWN };
for (int i = 1; i < 9; i++) {
wSquare.piece = bSquare.piece = PAWN;
doInsert(i + 8, &wSquare);
doInsert(i + 48, &bSquare);
switch (i) {
case 1:
case 8:
wSquare.piece = bSquare.piece = ROOK;
break;
case 2:
case 7:
wSquare.piece = bSquare.piece = KNIGHT;
break;
case 3:
case 6:
wSquare.piece = bSquare.piece = BISHOP;
break;
case 4:
wSquare.piece = bSquare.piece = QUEEN;
break;
case 5:
wSquare.piece = bSquare.piece = KING;
break;
}
doInsert(i, &wSquare);
doInsert(i + 56, &bSquare);
}
}
void displayBoard() {
cBoard* square;
for (int i = 0; i < 8; i++) {
for (int j = 1; j < 9; j++) {
square = rbSearch(j + i * 8, root);
if (square) {
cout << (square->player == WHT ? pSymbol[square->piece] : (char)(pSymbol[square->piece] + 32));
}
else {
cout << ' ';
}
}
cout << '\n';
}
}
enum Players {WHT, BLK};
uint8_t nextMove = WHT;
enum Pieces {PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING};
char pNames[][7] = {"Pawn", "Rook", "Knight", "Bishop", "Queen", "King"};
char pSymbol[] = {'P', 'R', 'N', 'B', 'Q', 'K'};
struct cBoard{
uint8_t player;
uint8_t piece;
};
typedef void (*ClBk)(uint8_t, struct cBoard*);
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
void setup() {
Serial.begin(115200);
Serial << freeRam() << '\n';
setupBoard();
Serial << freeRam() << '\n';
displayBoard();
Serial << "Black Height: " << rbHeight(root) << '\n';
playGame();
Serial << "Black Height: " << rbHeight(root) << '\n';
rbIterate(root, printSquares);
rbDeleteTree(root);
Serial << freeRam() << '\n';
}
void printSquares(uint8_t key, cBoard* square) {
Serial << "Square " << key << ": Player: " << (square->player == WHT ? "White" : "Black") << " Piece: " << pNames[square->piece] << '\n';
}
void playGame() {
// This game was played between London and Athens in 1897
// London fell into a neat trap and lost to Athens in 10 moves each.
uint8_t moves[][2] = {{13,29},{53,37},{7,13},{58,43},{2,19},{62,35},
{13,23},{52,44},{12,20},{63,46},{3,39},{59,45},{23,40},{0,0},
{19,36},{46,29},{39,60},{35,14},{5,13},{45,31}};
uint8_t cstlmoves[][4] = {{61,64,63,62}};
for (int i = 0; i < sizeof(moves) / 2; i++) {
if(moves[i][0] == 0) {
// cludge to support castling (feel free to tweak and validate)
makeMove(64, 62);
makeMove(61, 63);
} else {
makeMove(moves[i][0], moves[i][1]);
}
nextMove = (nextMove == WHT)? BLK : WHT; //whose move next
displayBoard();
}
Serial << "Checkmate!\n";
}
void makeMove(uint8_t from, uint8_t to) {
cBoard* fSquare = rbSearch(from, root);
cBoard* tSquare = rbSearch(to, root);
if(fSquare) {
if(fSquare->player == nextMove) {
if(tSquare == NULL || tSquare->player != nextMove) {
// probably a valid move but you could write a lot more
// validation to check route is clear if not knight and
// distance allowed and from and to not the same etc.
if(tSquare) {
rbDoDelete(to);
}
rbDoInsert(to, fSquare);
rbDoDelete(from);
} else {
Serial << "Target square invalid\n";
}
} else {
Serial << "Not your move\n";
}
}
}
void setupBoard() {
cBoard wSquare = {WHT, PAWN}, bSquare = {BLK, PAWN};
for(int i = 1; i < 9; i++) {
wSquare.piece = bSquare.piece = PAWN;
rbDoInsert(i + 8, &wSquare);
rbDoInsert(i + 48, &bSquare);
switch(i) {
case 1:
case 8:
wSquare.piece = bSquare.piece = ROOK;
break;
case 2:
case 7:
wSquare.piece = bSquare.piece = KNIGHT;
break;
case 3:
case 6:
wSquare.piece = bSquare.piece = BISHOP;
break;
case 4:
wSquare.piece = bSquare.piece = QUEEN;
break;
case 5:
wSquare.piece = bSquare.piece = KING;
break;
}
rbDoInsert(i, &wSquare);
rbDoInsert(i + 56, &bSquare);
}
}
void displayBoard() {
cBoard* square;
for(int i = 0; i < 8; i++) {
for(int j = 1; j < 9; j++) {
square = rbSearch(j + i * 8, root);
if(square) {
Serial << (square->player == WHT ? pSymbol[square->piece] : (char)(pSymbol[square->piece]+32));
}else {
Serial << ' ';
}
}
Serial << '\n';
}
Serial << '\n';
}
#ifndef RedBlack_h
#define RedBlack_h
// std::swap is available in this context
//template <class T> inline void swap(T& a, T& b)
//{
// T c(a); a = b; b = c;
//};
template<typename T, typename K>
class RedBlack {
public:
using RBIter = bool(*)(K, T*);
RedBlack(bool = false);
~RedBlack();
bool deleteNode(K);
bool insertNode(K, T*);
int blackHeight();
int nodeCount(bool);
T* nodeSearch(K);
void iterate(RBIter);
void reverseIterate(RBIter);
private:
enum Colour { RED, BLACK };
struct rbNode {
K key;
uint8_t colour;
rbNode *left, *right, *parent;
void* data;
};
rbNode* root;
uint8_t tSize;
uint8_t nodeSize;
bool memoryError;
bool updateOK;
bool rbRepeat;
T* rbSearch(K, rbNode*);
int rbCount(bool, rbNode*);
rbNode* rbMinimum(rbNode*);
rbNode* rbMaximum(rbNode*);
int rbHeight(rbNode*);
int rbMax(int, int);
rbNode* rbFind(K, rbNode*);
void rbDeleteTree(rbNode*);
void rbRotateRight(rbNode*, rbNode*&);
void rbRotateLeft(rbNode*, rbNode*&);
rbNode* rbPreDeleteFix(rbNode*, rbNode*&);
void rbPostInsertFix(rbNode*, rbNode*&);
rbNode* rbInsert(rbNode*, rbNode*);
rbNode* rbMakeNode(K key, T* data);
void rbIterate(rbNode*, RBIter);
void rbRevIterate(rbNode*, RBIter);
};
// Constructot / destructor
template<typename T, typename K>
RedBlack<T, K>::RedBlack(bool noUpdates = false) {
root = NULL;
nodeSize = sizeof(rbNode);
tSize = sizeof(T);
updateOK = !noUpdates;
}
template<typename T, typename K>
RedBlack<T, K>::~RedBlack() {
rbDeleteTree(root);
}
template<typename T, typename K>
bool RedBlack<T, K>::insertNode(K key, T* data) {
memoryError = false;
rbNode* temp = rbMakeNode(key, data);
root = rbInsert(temp, root);
rbPostInsertFix(temp, root);
return memoryError;
}
template<typename T, typename K>
bool RedBlack<T, K>::deleteNode(K key) {
rbNode* found = rbFind(key, root);
if (found) {
rbNode* del = rbPreDeleteFix(found, root);
free(del->data);
free(del);
return true;
}
return false;
}
template<typename T, typename K>
T* RedBlack<T, K>::nodeSearch(K key) {
return rbSearch(key, root);
}
template<typename T, typename K>
void RedBlack<T, K>::iterate(RBIter callBack) {
rbRepeat = true;
rbIterate(root, callBack);
}
template<typename T, typename K>
void RedBlack<T, K>::reverseIterate(RBIter callBack) {
rbRepeat = true;
rbRevIterate(root, callBack);
}
template<typename T, typename K>
int RedBlack<T, K>::blackHeight() {
return rbHeight(root);
}
template<typename T, typename K>
int RedBlack<T, K>::nodeCount(bool blackOnly) {
return rbCount(blackOnly, root);
}
//private methods
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbMakeNode(K key, T* data) {
rbNode* temp = (rbNode*)malloc(nodeSize);
if (temp == NULL) {
memoryError = true;
}
temp->key = key;
temp->left = temp->right = temp->parent = NULL;
temp->colour = RED;
temp->data = malloc(tSize);
if (temp->data) {
memcpy(temp->data, data, tSize);
}
else {
memoryError = true;
}
return temp;
}
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbInsert(rbNode* node, rbNode* leaf) {
if (leaf == NULL) {
return node;
}
if (node->key == leaf->key) {
if (updateOK) {
memcpy(leaf->data, node->data, tSize);
free(node->data);
free(node);
}
else {
memoryError = true; // well sort of
}
return leaf;
}
if (node->key < leaf->key) {
leaf->left = rbInsert(node, leaf->left);
leaf->left->parent = leaf;
}
else if (node->key > leaf->key) {
leaf->right = rbInsert(node, leaf->right);
leaf->right->parent = leaf;
}
return leaf;
}
template<typename T, typename K>
void RedBlack<T, K>::rbPostInsertFix(rbNode* node, rbNode*& root) {
rbNode* grandMa = NULL;
rbNode* aunty = NULL;
while (node != root && node->parent->colour == RED) {
grandMa = node->parent->parent;
if (node->parent == grandMa->left) {
aunty = grandMa->right;
if (aunty && aunty->colour == RED) {
node->parent->colour = BLACK;
aunty->colour = BLACK;
grandMa->colour = RED;
node = grandMa;
}
else {
if (node == node->parent->right) {
node = node->parent;
rbRotateLeft(node, root);
}
node->parent->colour = BLACK;
grandMa->colour = RED;
rbRotateRight(grandMa, root);
}
}
else {
aunty = grandMa->left;
if (aunty && aunty->colour == RED) {
node->parent->colour = BLACK;
aunty->colour = BLACK;
grandMa->colour = RED;
node = grandMa;
}
else {
if (node == node->parent->left) {
node = node->parent;
rbRotateRight(node, root);
}
node->parent->colour = BLACK;
grandMa->colour = RED;
rbRotateLeft(grandMa, root);
}
}
}
root->colour = BLACK;
}
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbFind(K key, rbNode* leaf) {
if (leaf) {
if (leaf->key == key) {
return leaf;
}
if (key < leaf->key) {
return rbFind(key, leaf->left);
}
return rbFind(key, leaf->right);
}
return NULL;
}
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbPreDeleteFix(rbNode* node, rbNode*& root) {
rbNode* nodeToDelete = node;
rbNode* child = NULL;
rbNode* parentNode = NULL;
if (nodeToDelete->left == NULL) { // node has one or no children
child = nodeToDelete->right; // which might be NULL
}
else {
if (nodeToDelete->right == NULL) // node has one child
child = nodeToDelete->left; // child is not NULL
else { // node has two children
nodeToDelete = rbMinimum(nodeToDelete->right);
// so we reset to the minimum key node
// from the right child (so next largest key)
child = nodeToDelete->right;
}
}
if (nodeToDelete != node) {
// if the nodeToDelete got changed above
node->left->parent = nodeToDelete;
nodeToDelete->left = node->left;
if (nodeToDelete != node->right) {
parentNode = nodeToDelete->parent;
if (child) {
child->parent = nodeToDelete->parent;
}
nodeToDelete->parent->left = child;
nodeToDelete->right = node->right;
node->right->parent = nodeToDelete;
}
else {
parentNode = nodeToDelete;
}
if (root == node) {
root = nodeToDelete;
}
else if (node->parent->left == node) {
node->parent->left = nodeToDelete;
}
else {
node->parent->right = nodeToDelete;
}
nodeToDelete->parent = node->parent;
swap(nodeToDelete->colour, node->colour);
nodeToDelete = node;
// nodeToDelete now deinately points to node to be deleted
}
else {
parentNode = nodeToDelete->parent;
if (child) {
child->parent = nodeToDelete->parent;
}
if (root == node) {
root = child;
}
else {
if (node->parent->left == node) {
node->parent->left = child;
}
else {
node->parent->right = child;
}
}
}
if (nodeToDelete->colour != RED) {
while (child != root && (child == NULL || child->colour == BLACK)) {
if (child == parentNode->left) {
rbNode* sisterNode = parentNode->right;
if (sisterNode->colour == RED) {
sisterNode->colour = BLACK;
parentNode->colour = RED;
rbRotateLeft(parentNode, root);
sisterNode = parentNode->right;
}
if ((sisterNode->left == NULL ||
sisterNode->left->colour == BLACK) &&
(sisterNode->right == NULL ||
sisterNode->right->colour == BLACK)) {
sisterNode->colour = RED;
child = parentNode;
parentNode = parentNode->parent;
}
else {
if (sisterNode->right == NULL ||
sisterNode->right->colour == BLACK) {
if (sisterNode->left) sisterNode->left->colour = BLACK;
sisterNode->colour = RED;
rbRotateRight(sisterNode, root);
sisterNode = parentNode->right;
}
sisterNode->colour = parentNode->colour;
parentNode->colour = BLACK;
if (sisterNode->right) {
sisterNode->right->colour = BLACK;
}
rbRotateLeft(parentNode, root);
break;
}
}
else { // same as above but the other way about
rbNode* sisterNode = parentNode->left;
if (sisterNode->colour == RED) {
sisterNode->colour = BLACK;
parentNode->colour = RED;
rbRotateRight(parentNode, root);
sisterNode = parentNode->left;
}
if ((sisterNode->right == NULL ||
sisterNode->right->colour == BLACK) &&
(sisterNode->left == NULL ||
sisterNode->left->colour == BLACK)) {
sisterNode->colour = RED;
child = parentNode;
parentNode = parentNode->parent;
}
else {
if (sisterNode->left == NULL ||
sisterNode->left->colour == BLACK) {
if (sisterNode->right) {
sisterNode->right->colour = BLACK;
}
sisterNode->colour = RED;
rbRotateLeft(sisterNode, root);
sisterNode = parentNode->left;
}
sisterNode->colour = parentNode->colour;
parentNode->colour = BLACK;
if (sisterNode->left) {
sisterNode->left->colour = BLACK;
}
rbRotateRight(parentNode, root);
break;
}
}
}
if (child) {
child->colour = BLACK;
}
}
return nodeToDelete;
}
template<typename T, typename K>
void RedBlack<T, K>::rbRotateLeft(rbNode* node, rbNode*& root) {
rbNode* child = node->right;
node->right = child->left;
if (child->left) {
child->left->parent = node;
}
child->parent = node->parent;
if (node == root) {
root = child;
}
else if (node == node->parent->left) {
node->parent->left = child;
}
else {
node->parent->right = child;
}
child->left = node;
node->parent = child;
}
template<typename T, typename K>
void RedBlack<T, K>::rbRotateRight(rbNode* node, rbNode*& root) {
rbNode* child = node->left;
node->left = child->right;
if (child->right != 0) {
child->right->parent = node;
}
child->parent = node->parent;
if (node == root) {
root = child;
}
else if (node == node->parent->right) {
node->parent->right = child;
}
else {
node->parent->left = child;
}
child->right = node;
node->parent = child;
}
template<typename T, typename K>
T* RedBlack<T, K>::rbSearch(K key, rbNode* leaf) {
if (leaf) {
if (leaf->key == key) {
return (T*)leaf->data;
}
if (key < leaf->key) {
return rbSearch(key, leaf->left);
}
return rbSearch(key, leaf->right);
}
return NULL;
}
template<typename T, typename K>
void RedBlack<T, K>::rbIterate(rbNode* leaf, RBIter callBack) {
if (leaf && rbRepeat) {
rbIterate(leaf->left, callBack);
if (rbRepeat) {
rbRepeat = callBack(leaf->key, (T*)leaf->data);
rbIterate(leaf->right, callBack);
}
}
}
template<typename T, typename K>
void RedBlack<T, K>::rbRevIterate(rbNode* leaf, RBIter callBack) {
if (leaf && rbRepeat) {
rbRevIterate(leaf->right, callBack);
if (rbRepeat) {
rbRepeat = callBack(leaf->key, (T*)leaf->data);
rbRevIterate(leaf->left, callBack);
}
}
}
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbMinimum(rbNode* node) {
while (node->left) {
node = node->left;
}
return node;
}
template<typename T, typename K>
typename RedBlack<T, K>::rbNode* RedBlack<T, K>::rbMaximum(rbNode* node) {
while (node->right) {
node = node->right;
}
return node;
}
template<typename T, typename K>
int RedBlack<T, K>::rbHeight(rbNode* leaf) {
if (leaf) {
int subMax = rbMax(rbHeight(leaf->left), rbHeight(leaf->right));
if (leaf->colour == BLACK) { subMax++; }
return subMax;
}
return 0;
}
template<typename T, typename K>
int RedBlack<T, K>::rbMax(int a, int b) {
return (a <= b) ? b : a;
}
template<typename T, typename K>
int RedBlack<T, K>::rbCount(bool blackOnly, rbNode* leaf) {
if (leaf) {
int rVal = 1;
if (blackOnly && leaf->colour == RED) { rVal--; }
return rVal + rbCount(blackOnly, leaf->left) + rbCount(blackOnly, leaf->right);
}
return 0;
}
template<typename T, typename K>
void RedBlack<T, K>::rbDeleteTree(rbNode* leaf) {
if (leaf) {
rbDeleteTree(leaf->left);
rbDeleteTree(leaf->right);
free(leaf->data);
free(leaf);
}
}
#endif
#include "stdafx.h"
#include <stdint.h>
#include <stdlib.h>
#include "RedBlack.h"
#include <iostream>
using namespace std;
enum Players { WHT, BLK };
uint8_t nextMove = WHT;
enum Pieces { PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING };
char pNames[][7] = { "Pawn", "Rook", "Knight", "Bishop", "Queen", "King" };
char pSymbol[] = { 'P', 'R', 'N', 'B', 'Q', 'K' };
struct cBoard {
uint8_t player;
uint8_t piece;
};
bool printSquares(uint8_t, cBoard*);
void playGame();
void makeMove(uint8_t, uint8_t);
void setupBoard();
void displayBoard();
RedBlack<cBoard, uint8_t> rbTree(true);
int main()
{
setupBoard();
displayBoard();
playGame();
rbTree.iterate(printSquares);
cout << rbTree.nodeCount(false) << " Total nodes\n";
cout << rbTree.nodeCount(true) << " Black nodes\n";
cout << "Black Height: " << rbTree.blackHeight() << '\n';
rbTree.reverseIterate(printSquares);
cin.get();
return 0;
}
bool printSquares(uint8_t key, cBoard* square) {
// cast the uint8_t as otherwise it is treated as a char by cout
cout << "Square " << (int)key << ": Player: " << (square->player == WHT ? "White" : "Black") << " Piece: " << pNames[square->piece] << '\n';
return true;
}
void playGame() {
// This game was played between London and Athens in 1897
// London fell into a neat trap and lost to Athens in 10 moves each.
uint8_t moves[][2] = { { 13,29 },{ 53,37 },{ 7,13 },{ 58,43 },{ 2,19 },{ 62,35 },
{ 13,23 },{ 52,44 },{ 12,20 },{ 63,46 },{ 3,39 },{ 59,45 },{ 23,40 },{ 0,0 },
{ 19,36 },{ 46,29 },{ 39,60 },{ 35,14 },{ 5,13 },{ 45,31 } };
uint8_t cstlmoves[][4] = { { 61,64,63,62 } };
for (int i = 0; i < sizeof(moves) / 2; i++) {
if (moves[i][0] == 0) {
// cludge to support castling (feel free to tweak and validate)
makeMove(64, 62);
makeMove(61, 63);
}
else {
makeMove(moves[i][0], moves[i][1]);
}
nextMove = (nextMove == WHT) ? BLK : WHT; //whose move next
displayBoard();
}
cout << "Checkmate!\n";
}
void makeMove(uint8_t from, uint8_t to) {
cBoard* fSquare = rbTree.nodeSearch(from);
cBoard* tSquare = rbTree.nodeSearch(to);
if (fSquare) {
if (fSquare->player == nextMove) {
if (tSquare == NULL || tSquare->player != nextMove) {
// probably a valid move but you could write a lot more
// validation to check route is clear if not knight and
// distance allowed and from and to not the same etc.
if (tSquare) {
rbTree.deleteNode(to);
}
rbTree.insertNode(to, fSquare);
rbTree.deleteNode(from);
}
else {
cout << "Target square invalid\n";
}
}
else {
cout << "Not your move\n";
}
}
}
void setupBoard() {
cBoard wSquare = { WHT, PAWN }, bSquare = { BLK, PAWN };
for (int i = 1; i < 9; i++) {
wSquare.piece = bSquare.piece = PAWN;
rbTree.insertNode(i + 8, &wSquare);
rbTree.insertNode(i + 48, &bSquare);
switch (i) {
case 1:
case 8:
wSquare.piece = bSquare.piece = ROOK;
break;
case 2:
case 7:
wSquare.piece = bSquare.piece = KNIGHT;
break;
case 3:
case 6:
wSquare.piece = bSquare.piece = BISHOP;
break;
case 4:
wSquare.piece = bSquare.piece = QUEEN;
break;
case 5:
wSquare.piece = bSquare.piece = KING;
break;
}
rbTree.insertNode(i, &wSquare);
rbTree.insertNode(i + 56, &bSquare);
}
}
void displayBoard() {
cBoard* square;
for (int i = 0; i < 8; i++) {
for (int j = 1; j < 9; j++) {
square = rbTree.nodeSearch(j + i * 8);
if (square) {
cout << (square->player == WHT ? pSymbol[square->piece] : (char)(pSymbol[square->piece] + 32));
}
else {
cout << ' ';
}
}
cout << '\n';
}
cout << '\n';
}
#include "RedBlack.h"
enum Players {WHT, BLK};
uint8_t nextMove = WHT;
enum Pieces {PAWN, ROOK, KNIGHT, BISHOP, QUEEN, KING};
char pNames[][7] = {"Pawn", "Rook", "Knight", "Bishop", "Queen", "King"};
char pSymbol[] = {'P', 'R', 'N', 'B', 'Q', 'K'};
struct cBoard{
uint8_t player;
uint8_t piece;
};
RedBlack<cBoard, uint8_t> rbTree(true);
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
void setup() {
Serial.begin(115200);
setupBoard();
displayBoard();
playGame();
rbTree.iterate(printSquares);
Serial << rbTree.nodeCount(false) << " Total nodes\n";
Serial << rbTree.nodeCount(true) << " Black nodes\n";
Serial << "Black Height: " << rbTree.blackHeight() << '\n';
rbTree.reverseIterate(printSquares);
}
bool printSquares(uint8_t key, cBoard* square) {
Serial << "Square " << key << ": Player: " << (square->player == WHT ? "White" : "Black") << " Piece: " << pNames[square->piece] << '\n';
return true;
}
void playGame() {
// This game was played between London and Athens in 1897
// London fell into a neat trap and lost to Athens in 10 moves each.
uint8_t moves[][2] = {{13,29},{53,37},{7,13},{58,43},{2,19},{62,35},
{13,23},{52,44},{12,20},{63,46},{3,39},{59,45},{23,40},{0,0},
{19,36},{46,29},{39,60},{35,14},{5,13},{45,31}};
uint8_t cstlmoves[][4] = {{61,64,63,62}};
for (int i = 0; i < sizeof(moves) / 2; i++) {
if(moves[i][0] == 0) {
// cludge to support castling (feel free to tweak and validate)
makeMove(64, 62);
makeMove(61, 63);
} else {
makeMove(moves[i][0], moves[i][1]);
}
nextMove = (nextMove == WHT)? BLK : WHT; //whose move next
displayBoard();
}
Serial << "Checkmate!\n";
}
void makeMove(uint8_t from, uint8_t to) {
cBoard* fSquare = rbTree.nodeSearch(from);
cBoard* tSquare = rbTree.nodeSearch(to);
if(fSquare) {
if(fSquare->player == nextMove) {
if(tSquare == NULL || tSquare->player != nextMove) {
// probably a valid move but you could write a lot more
// validation to check route is clear if not knight and
// distance allowed and from and to not the same etc.
if(tSquare) {
rbTree.deleteNode(to);
}
rbTree.insertNode(to, fSquare);
rbTree.deleteNode(from);
} else {
Serial << "Target square invalid\n";
}
} else {
Serial << "Not your move\n";
}
}
}
void setupBoard() {
cBoard wSquare = {WHT, PAWN}, bSquare = {BLK, PAWN};
for(int i = 1; i < 9; i++) {
wSquare.piece = bSquare.piece = PAWN;
rbTree.insertNode(i + 8, &wSquare);
rbTree.insertNode(i + 48, &bSquare);
switch(i) {
case 1:
case 8:
wSquare.piece = bSquare.piece = ROOK;
break;
case 2:
case 7:
wSquare.piece = bSquare.piece = KNIGHT;
break;
case 3:
case 6:
wSquare.piece = bSquare.piece = BISHOP;
break;
case 4:
wSquare.piece = bSquare.piece = QUEEN;
break;
case 5:
wSquare.piece = bSquare.piece = KING;
break;
}
rbTree.insertNode(i, &wSquare);
rbTree.insertNode(i + 56, &bSquare);
}
}
void displayBoard() {
cBoard* square;
for(int i = 0; i < 8; i++) {
for(int j = 1; j < 9; j++) {
square = rbTree.nodeSearch(j + i * 8);
if(square) {
Serial << (square->player == WHT ? pSymbol[square->piece] : (char)(pSymbol[square->piece]+32));
}else {
Serial << ' ';
}
}
Serial << '\n';
}
Serial << '\n';
}
Read the chapter in my book C++ Data Structures with immediate download from Amazon