diff options
author | zedarider <ymherklotz@gmail.com> | 2016-11-24 17:56:43 +0000 |
---|---|---|
committer | zedarider <ymherklotz@gmail.com> | 2016-11-24 17:56:43 +0000 |
commit | 44bcbd77f83baf64dc57ae8f816492194da7aa87 (patch) | |
tree | cdcb44db021536b203fa3951f6afe2eef33a7ad3 | |
parent | bea3f2ee3a313049c3513b3eedf5cb6519f19729 (diff) | |
parent | 95f75aa7aacf5e0e1ef11e8d200f84de44bd891f (diff) | |
download | ChessAI-44bcbd77f83baf64dc57ae8f816492194da7aa87.tar.gz ChessAI-44bcbd77f83baf64dc57ae8f816492194da7aa87.zip |
final changes from mac
-rw-r--r-- | Makefile | 4 | ||||
-rwxr-xr-x | bin/chess_ai | bin | 234216 -> 326304 bytes | |||
-rw-r--r-- | include/chess_ai.hpp | 123 | ||||
-rw-r--r-- | include/chess_tester.hpp | 89 | ||||
-rw-r--r-- | src/chess_board.cpp | 134 | ||||
-rw-r--r-- | src/chess_piece.cpp | 33 | ||||
-rw-r--r-- | src/chess_tester.cpp | 125 | ||||
-rw-r--r-- | src/main.cpp | 9 |
8 files changed, 418 insertions, 99 deletions
@@ -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 Binary files differindex a09b495..6114edc 100755 --- a/bin/chess_ai +++ b/bin/chess_ai 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; } |