aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorzedarider <ymherklotz@gmail.com>2016-11-24 17:56:43 +0000
committerzedarider <ymherklotz@gmail.com>2016-11-24 17:56:43 +0000
commit44bcbd77f83baf64dc57ae8f816492194da7aa87 (patch)
treecdcb44db021536b203fa3951f6afe2eef33a7ad3
parentbea3f2ee3a313049c3513b3eedf5cb6519f19729 (diff)
parent95f75aa7aacf5e0e1ef11e8d200f84de44bd891f (diff)
downloadChessAI-44bcbd77f83baf64dc57ae8f816492194da7aa87.tar.gz
ChessAI-44bcbd77f83baf64dc57ae8f816492194da7aa87.zip
final changes from mac
-rw-r--r--Makefile4
-rwxr-xr-xbin/chess_aibin234216 -> 326304 bytes
-rw-r--r--include/chess_ai.hpp123
-rw-r--r--include/chess_tester.hpp89
-rw-r--r--src/chess_board.cpp134
-rw-r--r--src/chess_piece.cpp33
-rw-r--r--src/chess_tester.cpp125
-rw-r--r--src/main.cpp9
8 files changed, 418 insertions, 99 deletions
diff --git a/Makefile b/Makefile
index 1612948..ccca428 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,11 @@ TARGET := bin/chess_ai
SRCEXT := cpp
SOURCES := $(shell find $(SRCDIR) -type f -name "*.$(SRCEXT)")
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.o))
+<<<<<<< HEAD
CFLAGS := -g -Wall -Wextra -std=c++14
+=======
+CFLAGS := -g -Wall -Wextra -Wpedantic -std=c++14
+>>>>>>> 95f75aa7aacf5e0e1ef11e8d200f84de44bd891f
LIB :=
INC := -I include
diff --git a/bin/chess_ai b/bin/chess_ai
index a09b495..6114edc 100755
--- a/bin/chess_ai
+++ b/bin/chess_ai
Binary files differ
diff --git a/include/chess_ai.hpp b/include/chess_ai.hpp
index 2984d49..3a0d95b 100644
--- a/include/chess_ai.hpp
+++ b/include/chess_ai.hpp
@@ -9,13 +9,31 @@
namespace chess_ai {
+ // Describes the different types of chess pieces there are on the board
enum piece_type : unsigned;
+
+ // Describes the colour of the pieces
enum piece_colour : unsigned;
+
+ // just describes if the board is full or empty
enum board_state : unsigned;
+
+ // defines the errors that can happen when moving a piece
+ enum move_error : unsigned;
+
+ // The chess board that will be played on
class chess_board;
+
+ // Any chess piece in the game
class chess_piece;
- // Describes the different types of chess pieces there are on the board
+ // typedefs for iterators to access elements easier
+
+ typedef std::vector<std::vector<chess_ai::chess_piece>>::
+ iterator vector_iterator;
+
+ typedef std::vector<chess_ai::chess_piece>::iterator square_iterator;
+
enum piece_type : unsigned {
// A pawn can only move forward twice on the first move, otherwise only
// once. It only take pieces that are on the diagonals in front of it,
@@ -47,7 +65,6 @@ namespace chess_ai {
empty
};
- // Describes the colour of the pieces
enum piece_colour : unsigned {
// Looking at the board white will be at the bottom
white,
@@ -57,7 +74,6 @@ namespace chess_ai {
none
};
- // just describes if the board is full or empty
enum board_state : unsigned {
// The starting position of the board with all pieces in the right
// position
@@ -70,7 +86,24 @@ namespace chess_ai {
clear
};
- // The chess board that will be played on
+ enum move_error : unsigned {
+ // when king is in check there are limited possibilities
+ move_error_KingInCheckAfterMove,
+ // when there is a friendly piece in the way
+ move_error_FriendlyPieceOnDestination,
+ // when there is an enemy piece blocking the way
+ move_error_EnemyPieceOnDestination,
+ // illegal move for chose piece
+ move_error_IllegalMove,
+
+ // when the move is successful
+ move_Success,
+ // when a move leads to a check
+ move_Check,
+ // when a move leads to a checkmate
+ move_Checkmate,
+ };
+
class chess_board {
public:
@@ -79,7 +112,10 @@ namespace chess_ai {
// Create a chess board depending on the state
chess_board(board_state state);
-
+
+ // destructor to clean up the variables
+ ~chess_board();
+
// prints the current board state
void print_board();
@@ -92,28 +128,53 @@ namespace chess_ai {
// remove piece at a specific location only
void remove_piece(unsigned x, unsigned y);
-
- protected:
- void init_board_vector();
-
+ // move a piece according to the chess rules
+ move_error move_piece(chess_piece piece);
+
+ // move piece using only x and y (for pawns)
+ move_error move_piece(unsigned x, unsigned y);
+
+ // moves a piece to an x, y coordinate
+ move_error move_piece(chess_piece piece, unsigned x, unsigned y);
+
+ // move piece with x and y as original and final destination
+ move_error move_piece(unsigned orig_x, unsigned orig_y,
+ unsigned dest_x, unsigned dest_y);
+
+ // move piece and return a piece that has been captured
+ move_error move_piece(unsigned orig_x, unsigned orig_y,
+ unsigned dest_x, unsigned dest_y,
+ chess_piece& taken_piece);
+
+ // iterate through the list and return the pointer to change
+ square_iterator& iterate_board(square_iterator& it, unsigned x,
+ unsigned y);
+
+
private:
-
+
+ // initialises vector
+ void init_board_vector();
+
+ // moves the pawn and tests all the cases that it should.
+ move_error move_pawn(square_iterator it, square_iterator new_it,
+ chess_piece& taken_piece);
+
// The size of the chess board is a constant and hence defined by a
// preprocessed define statement.
- unsigned const SIZE = CHESS_BOARD_SIZE;
+ const unsigned SIZE;
// The actual board where the values of the pieces will be changed.
std::vector<std::vector<chess_piece>> grid;
};
- // Any chess piece in the game
class chess_piece {
friend class chess_board;
public:
-
- // Initialises the chess piece to an empty square on the board
- chess_piece();
+
+ // Initialises the chess piece to an empty square on the board
+ chess_piece() : type(empty), colour(none), x(0), y(0) {}
// Otherwise initialise the chess piece to a king or queen where the
// location is alreay known
@@ -123,6 +184,9 @@ namespace chess_ai {
chess_piece(piece_type type, piece_colour colour, unsigned x,
unsigned y);
+ // destructor to clean up the variables
+ ~chess_piece();
+
// Set the type of the chess_piece
void set_type(piece_type type);
@@ -138,32 +202,9 @@ namespace chess_ai {
// set the different values
void set(piece_type type, piece_colour colour, unsigned x, unsigned y);
- // overloading operators
-
- // so that we can make two copies of a point
- chess_piece& operator=(const chess_piece& piece) {
- if(this != &piece) {
- this->set(piece.type, piece.colour, piece.x, piece.y);
- }
- return *this;
- }
-
- // overload ++ operator for pawns
- chess_piece& operator++() {
- if(this->type == pawn) {
- if(this->colour == white) {
- --pawn->y;
- } else {
- ++pawn->y;
- }
- }
- return *this;
- }
-
// return a printable version of the square
std::string str();
-
- protected:
+
private:
// Type of the chess piece, eg. bishop or queen
@@ -171,10 +212,10 @@ namespace chess_ai {
// Colour of the chess piece
piece_colour colour;
-
+
// x location of the chess piece
unsigned x;
-
+
// y location of the chess piece
unsigned y;
};
diff --git a/include/chess_tester.hpp b/include/chess_tester.hpp
new file mode 100644
index 0000000..c0c2f1c
--- /dev/null
+++ b/include/chess_tester.hpp
@@ -0,0 +1,89 @@
+#ifndef CHESS_TESTER_HPP
+#define CHESS_TESTER_HPP
+
+#define CHESS_TEST_SIZE 7
+
+#include <string>
+#include <vector>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+#include <algorithm>
+#include <iostream>
+
+struct tested_pieces {
+ std::string piece_name;
+ int num_passed;
+ int num_failed;
+
+ friend bool operator==(const tested_pieces& tp1, const tested_pieces& tp2) {
+ if(tp1.piece_name == tp2.piece_name) {
+ return true;
+ }
+ return false;
+ }
+
+ friend bool operator<(const tested_pieces& tp1, const tested_pieces& tp2) {
+ if(tp1.piece_name < tp2.piece_name) {
+ return true;
+ }
+ return false;
+ }
+};
+
+class chess_tester {
+
+public:
+
+ // sets all the initial values for the tester
+ chess_tester();
+
+ // begins the test suite so that this class can record the results and
+ // analyse them
+ void chess_begin_test_suite();
+
+ // begins the test
+ int chess_begin_test(std::string test_name);
+
+ // records the result of the test
+ void chess_end_test(int test_id, bool passed);
+
+ // analyses the results and prints them out
+ void chess_end_test_suite();
+
+ // see if the test is acceptable
+ bool is_in_arr(const std::string& test_piece) const;
+
+ // see if test is in vector
+ bool is_in_vec(const tested_pieces& piece) const;
+
+private:
+
+ // checks if the test suite is running
+ bool ts_begin;
+
+ // list of pieces to test
+ const std::string chess_test_pieces[CHESS_TEST_SIZE] = {
+ "<INTERNAL>",
+ "PAWN",
+ "ROOK",
+ "KNIGHT",
+ "BISHOP",
+ "QUEEN",
+ "KING"
+ };
+
+ // vector that contains the tested pieces
+ std::vector<tested_pieces> test_piece;
+
+ // the test_id of the current instruction
+ int test_id;
+
+ // the test id of the test that has been started
+ int test_id_test;
+
+ // the current test that is being tested
+ std::string current_test;
+};
+
+#endif
diff --git a/src/chess_board.cpp b/src/chess_board.cpp
index 9a6848b..8b449ca 100644
--- a/src/chess_board.cpp
+++ b/src/chess_board.cpp
@@ -1,14 +1,10 @@
#include "../include/chess_ai.hpp"
-typedef std::vector<std::vector<chess_ai::chess_piece>>::
-iterator vector_iterator;
-typedef std::vector<chess_ai::chess_piece>::iterator square_iterator;
-
-chess_ai::chess_board::chess_board() {
+chess_ai::chess_board::chess_board() : SIZE(CHESS_BOARD_SIZE) {
init_board_vector();
}
-chess_ai::chess_board::chess_board(board_state state) {
+chess_ai::chess_board::chess_board(board_state state) : SIZE(CHESS_BOARD_SIZE) {
unsigned vec_index, sqr_index;
init_board_vector();
@@ -66,6 +62,8 @@ chess_ai::chess_board::chess_board(board_state state) {
}
}
+chess_ai::chess_board::~chess_board() {}
+
void chess_ai::chess_board::init_board_vector() {
for(unsigned i = 0; i < SIZE; ++i) {
std::vector<chess_ai::chess_piece> tmp_vec;
@@ -110,21 +108,74 @@ void chess_ai::chess_board::print_board() {
}
void chess_ai::chess_board::set_piece(chess_piece piece) {
- unsigned vec_index, sqr_index;
- for(vector_iterator it_vec = grid.begin(); it_vec != grid.end(); ++it_vec) {
- for(square_iterator it_sqr = (*it_vec).begin();
- it_sqr != (*it_vec).end(); ++it_sqr) {
- vec_index = it_vec - grid.begin();
- sqr_index = it_sqr - (*it_vec).begin();
-
- if(vec_index == piece.y && sqr_index == piece.x) {
- *it_sqr = piece;
- }
- }
- }
+ square_iterator it_sqr;
+ *iterate_board(it_sqr, piece.x, piece.y) = piece;
}
void chess_ai::chess_board::remove_piece(chess_piece piece) {
+ remove_piece(piece.x, piece.y);
+}
+
+void chess_ai::chess_board::remove_piece(unsigned x, unsigned y) {
+ square_iterator it_sqr;
+ *iterate_board(it_sqr, x, y) = chess_piece();
+}
+
+chess_ai::move_error chess_ai::chess_board::move_piece(chess_piece piece) {
+ return move_piece(piece.x, piece.y);
+}
+
+chess_ai::move_error chess_ai::chess_board::move_piece(unsigned x, unsigned y) {
+ square_iterator it;
+ iterate_board(it, x, y);
+
+ if(it->y < 7 && it->y > 0) {
+ if(it->colour == white)
+ return move_piece(x, y, x, y-1);
+ return move_piece(x, y, x, y+1);
+ }
+ return move_error_IllegalMove;
+}
+
+chess_ai::move_error chess_ai::chess_board::move_piece
+(chess_ai::chess_piece piece, unsigned x, unsigned y) {
+
+ return move_piece(piece.x, piece.y, x, y);
+}
+
+chess_ai::move_error chess_ai::chess_board::move_piece
+(unsigned orig_x, unsigned orig_y, unsigned dest_x, unsigned dest_y) {
+
+ chess_piece taken;
+ return move_piece(orig_x, orig_y, dest_x, dest_y, taken);
+}
+
+chess_ai::move_error chess_ai::chess_board::move_piece
+(unsigned orig_x, unsigned orig_y, unsigned dest_x, unsigned dest_y,
+ chess_piece& taken_piece) {
+
+ square_iterator it;
+ square_iterator new_it;
+
+ iterate_board(it, orig_x, orig_y);
+ iterate_board(new_it, dest_x, dest_y);
+
+ switch(it->type) {
+ case pawn:
+ return move_pawn(it, new_it, taken_piece);
+ case rook:
+ case knight:
+ case bishop:
+ case queen:
+ case king:
+ default:
+ return move_error_IllegalMove;
+ }
+}
+
+chess_ai::square_iterator& chess_ai::chess_board::iterate_board
+(square_iterator& it, unsigned x, unsigned y) {
+
unsigned vec_index, sqr_index;
for(vector_iterator it_vec = grid.begin(); it_vec != grid.end(); ++it_vec) {
for(square_iterator it_sqr = (*it_vec).begin();
@@ -132,26 +183,45 @@ void chess_ai::chess_board::remove_piece(chess_piece piece) {
vec_index = it_vec - grid.begin();
sqr_index = it_sqr - (*it_vec).begin();
- if(vec_index == piece.y && sqr_index == piece.x) {
- chess_piece empty_piece;
- *it_sqr = empty_piece;
+ if(vec_index == y && sqr_index == x) {
+ it = it_sqr;
+ return it;
}
}
}
+ return it;
}
-void chess_ai::chess_board::remove_piece(unsigned x, unsigned y) {
- unsigned vec_index, sqr_index;
- for(vector_iterator it_vec = grid.begin(); it_vec != grid.end(); ++it_vec) {
- for(square_iterator it_sqr = (*it_vec).begin();
- it_sqr != (*it_vec).end(); ++it_sqr) {
- vec_index = it_vec - grid.begin();
- sqr_index = it_sqr - (*it_vec).begin();
-
- if(vec_index == y && sqr_index == x) {
- chess_piece empty_piece;
- *it_sqr = empty_piece;
+chess_ai::move_error chess_ai::chess_board::move_pawn
+(square_iterator it, square_iterator new_it, chess_piece& taken_piece) {
+
+ chess_piece piece(it->type, it->colour, new_it->x, new_it->y);
+
+ if((new_it->y - it->y == 2 && it->y == 1) ||
+ ((int)new_it->y - (int)it->y == -2 && it->y == 6) ||
+ (new_it->y - it->y == 1 && piece.colour == black && it->y < 7) ||
+ ((int)new_it->y - (int)it->y == -1 && piece.colour == white &&
+ it->y > 0)) {
+ if(new_it->x == it->x) {
+ if(new_it->type == empty) {
+ remove_piece(it->x, it->y);
+ set_piece(piece);
+ return move_Success;
+ } else if(new_it->colour == it->colour) {
+ return move_error_FriendlyPieceOnDestination;
+ }
+ return move_error_EnemyPieceOnDestination;
+ } else if(new_it->x - it->x == 1 || (int)new_it->x - (int)it->x == -1) {
+ if(new_it->colour != it->colour && new_it->colour != none) {
+ taken_piece.set(new_it->type, new_it->colour, new_it->x,
+ new_it->y);
+ remove_piece(it->x, it->y);
+ set_piece(piece);
+ return move_Success;
+ } else if(new_it->colour == it->colour) {
+ return move_error_FriendlyPieceOnDestination;
}
}
}
+ return move_error_IllegalMove;
}
diff --git a/src/chess_piece.cpp b/src/chess_piece.cpp
index cd28ef8..83b664f 100644
--- a/src/chess_piece.cpp
+++ b/src/chess_piece.cpp
@@ -1,16 +1,8 @@
#include "../include/chess_ai.hpp"
-chess_ai::chess_piece::chess_piece() {
- type = empty;
- colour = none;
- x = -1;
- y = -1;
-}
-
-chess_ai::chess_piece::chess_piece(piece_type type, piece_colour colour) {
- this->type = type;
- this->colour = colour;
-
+chess_ai::chess_piece::chess_piece(piece_type type, piece_colour colour) :
+ type(type), colour(colour) {
+
if(colour == black) {
y = 0;
} else {
@@ -25,13 +17,10 @@ chess_ai::chess_piece::chess_piece(piece_type type, piece_colour colour) {
}
chess_ai::chess_piece::chess_piece(piece_type type, piece_colour colour,
- unsigned x, unsigned y) {
- this->type = type;
- this->colour = colour;
- this->x = x;
- this->y = y;
-
-}
+ unsigned x, unsigned y) :
+ type(type), colour(colour), x(x), y(y) {}
+
+chess_ai::chess_piece::~chess_piece() {}
void chess_ai::chess_piece::set_type(piece_type type) {
this->type = type;
@@ -49,6 +38,14 @@ void chess_ai::chess_piece::set_y(unsigned y) {
this->y = y;
}
+void chess_ai::chess_piece::set(piece_type type, piece_colour colour,
+ unsigned x, unsigned y) {
+ set_type(type);
+ set_colour(colour);
+ set_x(x);
+ set_y(y);
+}
+
std::string chess_ai::chess_piece::str() {
if(type == empty)
return " ";
diff --git a/src/chess_tester.cpp b/src/chess_tester.cpp
new file mode 100644
index 0000000..60f6ee0
--- /dev/null
+++ b/src/chess_tester.cpp
@@ -0,0 +1,125 @@
+#include "../include/chess_tester.hpp"
+
+chess_tester::chess_tester() : ts_begin(false) {
+ srand(time(NULL));
+
+ test_id = rand() % 0xffffffff;
+ test_id_test = test_id;
+
+}
+
+void chess_tester::chess_begin_test_suite() {
+ if(ts_begin) {
+ fprintf(stderr, "Error: already started test suite\n");
+ exit(1);
+ }
+
+ ts_begin = true;
+}
+
+int chess_tester::chess_begin_test(std::string test_name) {
+ if(!ts_begin) {
+ fprintf(stderr, "Error: the test suite hasn't been started yet\n");
+ exit(1);
+ }
+
+ if(!is_in_arr(test_name)) {
+ fprintf(stderr, "Error: the test name does not exist\n");
+ exit(1);
+ }
+
+ current_test = test_name;
+
+ test_id = rand() % 0xffffffff;
+ test_id_test = test_id;
+
+ return test_id;
+}
+
+void chess_tester::chess_end_test(int test_id, bool passed) {
+ if(test_id != test_id_test) {
+ fprintf(stderr , "Error: the test from before has not been ended\n");
+ exit(1);
+ }
+
+ tested_pieces tmp;
+ tmp.piece_name = current_test;
+
+ if(passed) {
+ tmp.num_passed = 1;
+ tmp.num_failed = 0;
+ } else {
+ tmp.num_passed = 0;
+ tmp.num_failed = 1;
+ }
+
+ if(test_piece.empty() || !is_in_vec(tmp)) {
+ test_piece.push_back(tmp);
+ } else {
+ for(unsigned i = 0; i < test_piece.size(); ++i) {
+ if(test_piece[i] == tmp) {
+ if(passed) {
+ test_piece[i].num_passed++;
+ } else {
+ test_piece[i].num_failed++;
+ }
+ }
+ }
+ }
+}
+
+void chess_tester::chess_end_test_suite() {
+ std::sort(test_piece.begin(), test_piece.end());
+
+ int pieces_passed = 0;
+ int pieces_partial = 0;
+ int pieces_fail = 0;
+
+ fprintf(stderr, "+-%10s-+-%5s-+-%6s-+-%8s-+\n", "----------", "-----",
+ "------", "--------");
+ fprintf(stderr, "| %10s | %5s | %6s | %8s |\n", "Piece ", "Total", "Passed",
+ "Passed %");
+ fprintf(stderr, "+-%10s-+-%5s-+-%6s-+-%8s-+\n", "----------", "-----",
+ "------", "--------");
+ for(unsigned i = 0; i < test_piece.size(); ++i) {
+ fprintf(stderr, "| %10s | %5d | %6d | %7.3f%% |\n",
+ test_piece[i].piece_name.c_str(), test_piece[i].num_passed +
+ test_piece[i].num_failed, test_piece[i].num_passed,
+ 100.0*(double)test_piece[i].num_passed /
+ (double)(test_piece[i].num_passed + test_piece[i].num_failed));
+
+ if(test_piece[i].num_passed == 0) {
+ pieces_fail++;
+ } else if(test_piece[i].num_failed == 0) {
+ pieces_passed++;
+ } else {
+ pieces_partial++;
+ }
+ }
+ fprintf(stderr, "+-%10s-+-%5s-+-%6s-+-%8s-+\n", "----------", "-----",
+ "------", "--------");
+
+ fprintf(stderr, "\nTotal pieces tested: %lu\n", test_piece.size());
+ fprintf(stderr, "Passed: %d\n", pieces_passed);
+ fprintf(stderr, "Partially working: %d\n", pieces_partial);
+ fprintf(stderr, "Failed: %d\n", pieces_fail);
+}
+
+bool chess_tester::is_in_arr(const std::string& test_piece) const {
+ for(unsigned i = 0; i < CHESS_TEST_SIZE; ++i) {
+ if(chess_test_pieces[i] == test_piece) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool chess_tester::is_in_vec(const tested_pieces& piece) const {
+ for(unsigned i = 0; i < test_piece.size(); ++i) {
+ if(test_piece[i] == piece) {
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/src/main.cpp b/src/main.cpp
index b41c919..def5cf0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -8,6 +8,7 @@
*/
#include "../include/chess_ai.hpp"
+#include "../include/chess_tester.hpp"
#include <iostream>
@@ -17,14 +18,6 @@ using namespace chess_ai;
int main(int argc, char** argv) {
(void)argc;
(void)argv;
-
- chess_board board(initial);
- board.print_board();
-
- chess_piece piece(rook, white, 5, 3);
- board.set_piece(piece);
-
- board.print_board();
return 0;
}