From: Sam Moore Date: Fri, 22 Mar 2013 04:53:43 +0000 (+0800) Subject: Improving C++ API X-Git-Url: https://git.ucc.asn.au/?p=progcomp2013.git;a=commitdiff_plain;h=7518ec8d771e731d6ffbbe00b275b7e3c4b23301 Improving C++ API Changed the Piece and Board classes slightly so that I can make an efficient C++ agent. I plan to make SilverFish as good as I possibly can. Rather than writing 6 different mediocre sample agents like I did last year, I will just focus on this one. Technically I can't enter my own competition, so SilverFish is still just a sample agent. Anyway it still just defaults to random moves at the moment. --- diff --git a/agents/c++/Makefile b/agents/c++/Makefile new file mode 100644 index 0000000..760d975 --- /dev/null +++ b/agents/c++/Makefile @@ -0,0 +1,33 @@ +#Makefile for C++ agent +CXX = g++ -std=gnu++0x -Wall -Werror -pedantic -g +OBJ = qchess.o agent.o main.o +LIB = + +LINKOBJ = $(OBJ) + +RM = rm -f +BIN = agent++ + + + +$(BIN) : $(LINKOBJ) + $(CXX) -o $(BIN) $(LINKOBJ) + +%.o : %.cpp + $(CXX) -c $< + +no_main : $(OBJ) + +main.o : main.cpp + $(CXX) -c main.cpp + +clean : + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + +clean_full: #cleans up all backup files + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + $(RM) *.*~ + $(RM) *~ + + + \ No newline at end of file diff --git a/agents/c++/agent++ b/agents/c++/agent++ index b4d3540..956a644 100755 Binary files a/agents/c++/agent++ and b/agents/c++/agent++ differ diff --git a/agents/c++/qchess.cpp b/agents/c++/qchess.cpp index fbca352..f908756 100644 --- a/agents/c++/qchess.cpp +++ b/agents/c++/qchess.cpp @@ -9,24 +9,27 @@ using namespace std; + /** * @constructor * @param new_x, new_y - Position of piece * @param new_colour - Colour of piece * @param type1, type2 - Types of piece - * @param index - Index for initial type of piece + * @param new_type_index - Index for initial type of piece + * @param new_piece_index - Index for piece in a vector */ -Piece::Piece(int new_x, int new_y, const Piece::Colour & new_colour, const Piece::Type & type1, const Piece::Type & type2, int index) - : x(new_x), y(new_y), colour(new_colour), type_index(index), types(), current_type() +Piece::Piece(int new_x, int new_y, const Piece::Colour & new_colour, const Piece::Type & type1, const Piece::Type & type2, + int new_type_index, int new_piece_index) + : x(new_x), y(new_y), colour(new_colour), type_index(new_type_index), types(), current_type(), piece_index(new_piece_index) { types[0] = type1; types[1] = type2; - if (index < 0 || index >= 2) + if (type_index < 0 || type_index >= 2) { current_type = Piece::UNKNOWN; } else { - current_type = types[index]; + current_type = types[type_index]; } } @@ -34,7 +37,7 @@ Piece::Piece(int new_x, int new_y, const Piece::Colour & new_colour, const Piece * @constructor * @param cpy - Piece to copy construct from */ -Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_index(cpy.type_index) +Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_index(cpy.type_index), piece_index(cpy.piece_index) { types[0] = cpy.types[0]; types[1] = cpy.types[1]; @@ -44,7 +47,9 @@ Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_i * @constructor * @param choose_types - Indicates whether Board should setup the 2nd types of pieces; default false */ -Board::Board(bool choose_types) +Board::Board(bool choose_types) + : white(), black(), white_unknown(), black_unknown(), white_nUnknown(0), black_nUnknown(0), + white_king(NULL), black_king(NULL), parent(NULL) { // initialise all the Squares @@ -69,6 +74,14 @@ Board::Board(bool choose_types) freq[Piece::QUEEN] = 1; freq[Piece::PAWN] = 8; + if (!choose_types) + { + white_unknown = freq; + black_unknown = freq; + white_nUnknown = 15; + black_nUnknown = 15; + } + // for white and black... for (int i = 0; i < 2; ++i) { @@ -80,26 +93,25 @@ Board::Board(bool choose_types) int y = (i == 0) ? 1 : BOARD_HEIGHT-2; for (int x = 0; x < BOARD_WIDTH; ++x) { - Piece * p = new Piece(x, y, colours[i], Piece::PAWN, Piece::UNKNOWN); - v.push_back(p); + Piece::AddPiece(v, x, y, colours[i], Piece::PAWN, Piece::UNKNOWN); } // add other pieces y = (i == 0) ? 0 : BOARD_HEIGHT-1; - v.push_back(new Piece(0, y, colours[i], Piece::ROOK, Piece::UNKNOWN)); - v.push_back(new Piece(BOARD_WIDTH-1, y, colours[i], Piece::ROOK, Piece::UNKNOWN)); - v.push_back(new Piece(1, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN)); - v.push_back(new Piece(BOARD_WIDTH-2, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN)); - v.push_back(new Piece(2, y, colours[i], Piece::BISHOP, Piece::UNKNOWN)); - v.push_back(new Piece(BOARD_WIDTH-3, y, colours[i], Piece::BISHOP, Piece::UNKNOWN)); - v.push_back(new Piece(3, y, colours[i], Piece::QUEEN, Piece::UNKNOWN)); - - Piece * k = new Piece(4, y, colours[i], Piece::KING, Piece::KING, 1); + Piece::AddPiece(v, 0, y, colours[i], Piece::ROOK, Piece::UNKNOWN); + Piece::AddPiece(v, BOARD_WIDTH-1, y, colours[i], Piece::ROOK, Piece::UNKNOWN); + Piece::AddPiece(v, 1, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN); + Piece::AddPiece(v, BOARD_WIDTH-2, y, colours[i], Piece::KNIGHT, Piece::UNKNOWN); + Piece::AddPiece(v, 2, y, colours[i], Piece::BISHOP, Piece::UNKNOWN); + Piece::AddPiece(v, BOARD_WIDTH-3, y, colours[i], Piece::BISHOP, Piece::UNKNOWN); + Piece::AddPiece(v, 3, y, colours[i], Piece::QUEEN, Piece::UNKNOWN); + + Piece * k = Piece::AddPiece(v, 4, y, colours[i], Piece::KING, Piece::KING, 1); if (i == 0) white_king = k; else black_king = k; - v.push_back(k); + // add to board and choose second types if required map f(freq); @@ -133,10 +145,12 @@ Board::Board(bool choose_types) /** * @constructor - * @param cpy - Board to copy construct from; each Piece in the copy will be *copied* - * The Piece's in the copied Board may be altered without affecting the original + * @param cpy - Board to clone */ -Board::Board(const Board & cpy) +Board::Board(Board & cpy) +: white(cpy.white), black(cpy.black), white_unknown(cpy.white_unknown), black_unknown(cpy.black_unknown), + white_nUnknown(cpy.white_nUnknown), black_nUnknown(cpy.black_nUnknown), + white_king(cpy.white_king), black_king(cpy.black_king), parent(&cpy) { for (int x = 0; x < BOARD_WIDTH; ++x) { @@ -144,12 +158,7 @@ Board::Board(const Board & cpy) { grid[x][y].x = x; grid[x][y].y = y; - - if (cpy.grid[x][y].piece != NULL) - { - grid[x][y].piece = new Piece(*(cpy.grid[x][y].piece)); - pieces(grid[x][y].piece->colour).push_back(grid[x][y].piece); - } + grid[x][y].piece = cpy.grid[x][y].piece; } } } @@ -176,17 +185,43 @@ Board::~Board() * @purpose Update Piece that has been selected * @param x, y - Position of Piece to update * @param index - 0 or 1 - State the Piece "collapsed" into - * @param type - Type of the Piece + * @param type - Type of the Piece as a string */ void Board::Update_select(int x, int y, int index, const string & type) { - cerr << "Updating " << x << "," << y << " " << grid[x][y].piece << " " << index << " " << type << "\n"; + Board::Update_select(x, y, index, Piece::str2type(type)); +} + +/** + * @funct Update_select + * @purpose Update Piece that has been selected + * @param x, y - Position of Piece to update + * @param index - 0 or 1 - State the Piece "collapsed" into + * @param t - Type of the Piece + */ +void Board::Update_select(int x, int y, int index, const Piece::Type & t) +{ + cerr << "Updating " << x << "," << y << " " << grid[x][y].piece << " " << index << " " << t << "\n"; Square & s = grid[x][y]; + + Clone_copy(s); + assert(s.piece != NULL); assert(index >= 0 && index < 2); s.piece->type_index = index; - s.piece->types[index] = Piece::str2type(type); - s.piece->current_type = s.piece->types[index]; + + if (s.piece->types[index] == Piece::UNKNOWN) + { + map & m = unknown_types(s.piece->colour); + int n = (m[t]--); + if (n < 0) + throw Exception("Board::Update_select", "Too many pieces of type %s found", Piece::type2str(t)); + + nUnknown(s.piece->colour)--; + + } + s.piece->types[index] = t; + s.piece->current_type = t; } /** @@ -201,6 +236,12 @@ void Board::Update_move(int x1, int y1, int x2, int y2) { Square & s1 = grid[x1][y1]; Square & s2 = grid[x2][y2]; + + Clone_copy(s1); + + + + if (s2.piece != NULL) { vector & p = pieces(s2.piece->colour); @@ -214,6 +255,11 @@ void Board::Update_move(int x1, int y1, int x2, int y2) } ++i; } + while (i != p.end()) + { + (*i)->piece_index -= 1; + ++i; + } Piece * k = king(s2.piece->colour); if (k == s2.piece) { @@ -222,8 +268,10 @@ void Board::Update_move(int x1, int y1, int x2, int y2) else black_king = NULL; } - - delete s2.piece; + if ((IsClone() && s2.piece == parent->grid[x2][y2].piece) == false) + { + delete s2.piece; + } } s1.piece->x = s2.x; @@ -375,6 +423,36 @@ Piece::Type Piece::str2type(const string & str) return Piece::UNKNOWN; } +/** + * @funct type2str + * @purpose Convert Piece::Type to string + * @param t - The Types + * @returns a const char* + */ +const char * Piece::type2str(const Piece::Type & t) +{ + switch (t) + { + case PAWN: + return "pawn"; + case BISHOP: + return "bishop"; + case KNIGHT: + return "knight"; + case ROOK: + return "rook"; + case QUEEN: + return "queen"; + case UNKNOWN: + return "unknown"; + case KING: + return "king"; + default: + throw Exception("Piece::type2str", "Unknown type %d", (int)t); + return ""; + } +} + /** * @funct str2colour * @purpose Convert string to Piece::Colour @@ -392,4 +470,34 @@ Piece::Colour Piece::str2colour(const string & str) return Piece::BLACK; // should never get here } +/** + * @funct AddPiece + * @purpose Creates a new Piece and adds it to a vector + * @param v - The vector + * @params - All remaining parameters passed to Piece::Piece + * @returns Pointer to the new Piece + */ +Piece * Piece::AddPiece(vector & v, int x, int y, const Piece::Colour & colour, const Piece::Type & t1, const Piece::Type & t2, + int type_index) +{ + Piece * p = new Piece(x,y,colour,t1, t2,type_index, v.size()); + v.push_back(p); + return p; +} +/** + * @funct Clone_copy + * @purpose If necessary, copy the piece in the square + * @param s - The square + */ +void Board::Clone_copy(Square & s) +{ + if (s.piece == NULL || !IsClone()) return; + if (parent->grid[s.x][s.y].piece == s.piece) + { + s.piece = new Piece(*(s.piece)); + vector & v = pieces(s.piece->colour); + v[s.piece->piece_index] = s.piece; + } + +} \ No newline at end of file diff --git a/agents/c++/qchess.h b/agents/c++/qchess.h index b2b499a..40b09f1 100644 --- a/agents/c++/qchess.h +++ b/agents/c++/qchess.h @@ -32,8 +32,6 @@ class Piece typedef enum {PAWN, BISHOP, KNIGHT, ROOK, QUEEN, KING, UNKNOWN} Type; typedef enum {WHITE=0, BLACK=1} Colour; - Piece(int x, int y, const Colour & colour, const Type & type1, const Type & type2=UNKNOWN, int type_index = -1); // constructor - Piece(const Piece & cpy); // copy constructor virtual ~Piece() {} // destructor int x; int y; // position of the piece @@ -44,6 +42,18 @@ class Piece static Type str2type(const std::string & str); static Colour str2colour(const std::string & str); + static const char * type2str(const Type & t); + + static Piece * AddPiece(std::vector & v, int x, int y, const Colour & colour, const Type & type1, const Type & type2, int type_index=-1); + + private: + friend class Board; + Piece(int x, int y, const Colour & colour, const Type & type1, const Type & type2 + , int type_index, int new_piece_index); // constructor + Piece(const Piece & cpy); // copy constructor + + int piece_index; // index of the piece in Board's pieces vector + }; @@ -70,33 +80,55 @@ class Board { public: Board(bool choose_types = false); // constructor - Board(const Board & cpy); // copy constructor + Board(Board & parent); // clones a board, copy on write virtual ~Board(); // destructor // helper; return vector of pieces given player colour std::vector & pieces(const Piece::Colour & colour) {return ((colour == Piece::WHITE) ? white : black);} + // helper; return map of unidentified 2nd types for given colour + std::map & unknown_types(const Piece::Colour & colour) + { + return ((colour == Piece::WHITE) ? white_unknown : black_unknown); + } + + int & nUnknown(const Piece::Colour & colour) + { + return ((colour == Piece::WHITE) ? white_nUnknown : black_nUnknown); + } + // helper; return king given player colour Piece * king(const Piece::Colour & colour) {return ((colour == Piece::WHITE) ? white_king : black_king);} void Update_move(int x, int y, int x2, int y2); // move a piece void Update_select(int x, int y, int index, const std::string & type); // update a selected piece + void Update_select(int x, int y, int index, const Piece::Type & t); Square & square(int x, int y) {return grid[x][y];} // get square on board - void Get_moves(Piece * p, std::vector & v); // get allowed moves for piece + void Get_moves(Piece * p, std::vector & v); // get allowed moves for piece of known type // determine if position is on the board bool Valid_position(int x, int y) {return (x >= 0 && x <= BOARD_WIDTH-1 && y >= 0 && y <= BOARD_HEIGHT-1);} + + bool IsClone() const {return parent != NULL;} + void Clone_copy(Square & s); private: Square grid[BOARD_WIDTH][BOARD_HEIGHT]; - + // All pieces for each player std::vector white; std::vector black; + // The number of pieces with each 2nd type that are still unidentified + std::map white_unknown; + std::map black_unknown; + int white_nUnknown; + int black_nUnknown; Piece * white_king; Piece * black_king; + + Board * parent; // Add a move to the vector if it is valid void Move(Piece * p, int x, int y, std::vector & v); diff --git a/agents/silverfish/Makefile b/agents/silverfish/Makefile new file mode 100644 index 0000000..e2c4927 --- /dev/null +++ b/agents/silverfish/Makefile @@ -0,0 +1,33 @@ +#Makefile for SilverFish agent +CXX = g++ -std=gnu++0x -Wall -Werror -pedantic -g +OBJ = qchess.o agent.o silverfish.o main.o +LIB = + +LINKOBJ = $(OBJ) + +RM = rm -f +BIN = silver + + + +$(BIN) : $(LINKOBJ) + $(CXX) -o $(BIN) $(LINKOBJ) + +%.o : %.cpp + $(CXX) -c $< + +no_main : $(OBJ) + +main.o : main.cpp + $(CXX) -c main.cpp + +clean : + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + +clean_full: #cleans up all backup files + $(RM) $(BIN) $(OBJ) $(LINKOBJ) + $(RM) *.*~ + $(RM) *~ + + + \ No newline at end of file diff --git a/agents/silverfish/agent.cpp b/agents/silverfish/agent.cpp new file mode 120000 index 0000000..9851ddc --- /dev/null +++ b/agents/silverfish/agent.cpp @@ -0,0 +1 @@ +../c++/agent.cpp \ No newline at end of file diff --git a/agents/silverfish/agent.h b/agents/silverfish/agent.h new file mode 120000 index 0000000..8fbe3b6 --- /dev/null +++ b/agents/silverfish/agent.h @@ -0,0 +1 @@ +../c++/agent.h \ No newline at end of file diff --git a/agents/silverfish/main.cpp b/agents/silverfish/main.cpp new file mode 100644 index 0000000..7d24493 --- /dev/null +++ b/agents/silverfish/main.cpp @@ -0,0 +1,38 @@ +/** + * silverfish : A Sample agent for UCC::Progcomp2013 + * @file main.cpp + * @purpose The main function + */ +#include +#include +#include + +#include "silverfish.h" + +using namespace std; + +/** + * @funct main + * @purpose The main function; starts the agent + * @param argc - Number of arguments, unused + * @param argv - Argument string array, unused + */ +int main(int argc, char ** argv) +{ + srand(time(NULL)); // seed random number generator + + string colour; cin >> colour; // first read the colour of the agent + + try + { + Silver agent(colour); // create an agent using the colour + agent.Run(cin, cout); // run the agent (it will read from cin and output to cout) + } + catch (const Exception & e) + { + return 1; + } + + + return 0; // Don't use exit(3), because it causes memory leaks in the C++ stdlib +} diff --git a/agents/silverfish/qchess.cpp b/agents/silverfish/qchess.cpp new file mode 120000 index 0000000..a770972 --- /dev/null +++ b/agents/silverfish/qchess.cpp @@ -0,0 +1 @@ +../c++/qchess.cpp \ No newline at end of file diff --git a/agents/silverfish/qchess.h b/agents/silverfish/qchess.h new file mode 120000 index 0000000..c020ad2 --- /dev/null +++ b/agents/silverfish/qchess.h @@ -0,0 +1 @@ +../c++/qchess.h \ No newline at end of file diff --git a/agents/silverfish/silver b/agents/silverfish/silver new file mode 100755 index 0000000..88d49e3 Binary files /dev/null and b/agents/silverfish/silver differ diff --git a/agents/silverfish/silverfish.cpp b/agents/silverfish/silverfish.cpp new file mode 100644 index 0000000..20eb9e9 --- /dev/null +++ b/agents/silverfish/silverfish.cpp @@ -0,0 +1,30 @@ +#include "silverfish.h" + +using namespace std; + +Silver::Silver(const string & colour) : Agent(colour), values() +{ + values[Piece::PAWN] = 1; + values[Piece::BISHOP] = 3; + values[Piece::KNIGHT] = 3; + values[Piece::ROOK] = 5; + values[Piece::QUEEN] = 9; + values[Piece::KING] = 100; + values[Piece::UNKNOWN] = 1.5; +} + +Silver::Silver(const string & colour, const map & new_values) : Agent(colour), values(new_values) +{ + //TODO: Assert map is valid +} + +Square & Silver::Select() +{ + + return Agent::Select(); +} + +Square & Silver::Move() +{ + return Agent::Move(); +} \ No newline at end of file diff --git a/agents/silverfish/silverfish.h b/agents/silverfish/silverfish.h new file mode 100644 index 0000000..dc5b26a --- /dev/null +++ b/agents/silverfish/silverfish.h @@ -0,0 +1,20 @@ +#ifndef _SILVERFISH_H +#define _SILVERFISH_H + +#include "agent.h" + +class Silver : public Agent +{ + public: + Silver(const std::string & colour); + Silver(const std::string & colour, const std::map & new_values); + virtual ~Silver() {} + + virtual Square & Select(); + virtual Square & Move(); + + std::map values; +}; + + +#endif //_SILVERFISH_H \ No newline at end of file