Improving C++ API
authorSam Moore <matches@ucc.asn.au>
Fri, 22 Mar 2013 04:53:43 +0000 (12:53 +0800)
committerSam Moore <matches@ucc.asn.au>
Fri, 22 Mar 2013 04:53:43 +0000 (12:53 +0800)
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.

13 files changed:
agents/c++/Makefile [new file with mode: 0644]
agents/c++/agent++
agents/c++/qchess.cpp
agents/c++/qchess.h
agents/silverfish/Makefile [new file with mode: 0644]
agents/silverfish/agent.cpp [new symlink]
agents/silverfish/agent.h [new symlink]
agents/silverfish/main.cpp [new file with mode: 0644]
agents/silverfish/qchess.cpp [new symlink]
agents/silverfish/qchess.h [new symlink]
agents/silverfish/silver [new file with mode: 0755]
agents/silverfish/silverfish.cpp [new file with mode: 0644]
agents/silverfish/silverfish.h [new file with mode: 0644]

diff --git a/agents/c++/Makefile b/agents/c++/Makefile
new file mode 100644 (file)
index 0000000..760d975
--- /dev/null
@@ -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
index b4d3540..956a644 100755 (executable)
Binary files a/agents/c++/agent++ and b/agents/c++/agent++ differ
index fbca352..f908756 100644 (file)
@@ -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<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,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<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
index b2b499a..40b09f1 100644 (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,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<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);
diff --git a/agents/silverfish/Makefile b/agents/silverfish/Makefile
new file mode 100644 (file)
index 0000000..e2c4927
--- /dev/null
@@ -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 (symlink)
index 0000000..9851ddc
--- /dev/null
@@ -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 (symlink)
index 0000000..8fbe3b6
--- /dev/null
@@ -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 (file)
index 0000000..7d24493
--- /dev/null
@@ -0,0 +1,38 @@
+/**
+ * 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
+}
diff --git a/agents/silverfish/qchess.cpp b/agents/silverfish/qchess.cpp
new file mode 120000 (symlink)
index 0000000..a770972
--- /dev/null
@@ -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 (symlink)
index 0000000..c020ad2
--- /dev/null
@@ -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 (executable)
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 (file)
index 0000000..20eb9e9
--- /dev/null
@@ -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<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
diff --git a/agents/silverfish/silverfish.h b/agents/silverfish/silverfish.h
new file mode 100644 (file)
index 0000000..dc5b26a
--- /dev/null
@@ -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<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

UCC git Repository :: git.ucc.asn.au