Commit 7518ec8d authored by Sam Moore's avatar Sam Moore

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.
parent 8571bc0c
#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
No preview for this file type
......@@ -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];
......@@ -45,6 +48,8 @@ Piece::Piece(const Piece & cpy) : x(cpy.x), y(cpy.y), colour(cpy.colour), type_i
* @param choose_types - Indicates whether Board should setup the 2nd types of pieces; default false
*/
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<Piece::Type, int> 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<Piece::Type, int> & 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<Piece*> & 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,9 +268,11 @@ void Board::Update_move(int x1, int y1, int x2, int y2)
else
black_king = NULL;
}
if ((IsClone() && s2.piece == parent->grid[x2][y2].piece) == false)
{
delete s2.piece;
}
}
s1.piece->x = s2.x;
s1.piece->y = s2.y;
......@@ -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<Piece*> & 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<Piece*> & v = pieces(s.piece->colour);
v[s.piece->piece_index] = s.piece;
}
}
\ No newline at end of file
......@@ -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<Piece*> & 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,34 +80,56 @@ 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<Piece*> & pieces(const Piece::Colour & colour) {return ((colour == Piece::WHITE) ? white : black);}
// helper; return map of unidentified 2nd types for given colour
std::map<Piece::Type, int> & 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<Square*> & v); // get allowed moves for piece
void Get_moves(Piece * p, std::vector<Square*> & 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<Piece*> white;
std::vector<Piece*> black;
// The number of pieces with each 2nd type that are still unidentified
std::map<Piece::Type, int> white_unknown;
std::map<Piece::Type, int> 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<Square*> & v);
......
#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
../c++/agent.cpp
\ No newline at end of file
../c++/agent.h
\ No newline at end of file
/**
* silverfish : A Sample agent for UCC::Progcomp2013
* @file main.cpp
* @purpose The main function
*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#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
}
../c++/qchess.cpp
\ No newline at end of file
../c++/qchess.h
\ No newline at end of file
#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<Piece::Type, double> & 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
#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<Piece::Type, double> & new_values);
virtual ~Silver() {}
virtual Square & Select();
virtual Square & Move();
std::map<Piece::Type, double> values;
};
#endif //_SILVERFISH_H
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment