Commit 041c37d1 authored by Sam Moore's avatar Sam Moore
Browse files

Mostly messing with "forfax" AI

It would be nice to have an AI that doesn't segfault.

Currently segfault caused by Board::ForgetPiece.
valgrind outputs a lot of wierd crap about std::vector and uninitialised values
Uninitialised values created by std::vector::push_back()
All I am pushing is a simple pointer (Piece*), so I don't know WHY uninitialised values happen...
The std::list used in MakeMove is somehow using the same memory as the std::vectors of the board, which is causing invalid reads
Stupid, stupid stdlib.

I think that once that is fixed, forfax is pretty much done. I'd like to see how well it plays, but... segfaults.

I also fixed dummy to take into account the modified turn protocol which prints piece ranks. dummy just reads them and ignores them.

I plan to make the manager program more useful
	- Enable human players
	- Add command line arguments for things like timeouts, graphics on/off etc
	- Read a game from a file (so that games can be viewed after they are run)
I need to go through the manager program carefully and make sure that the way AI programs quit actually works
Ideally the AI program has a short period to exit gracefully before it is killed
I think for some reason the AI program always just gets killed.

At some point I need to setup a VM for this. I should probably do that.

I also might change minor things like the tokens (from random characters to digits + a few characters) and the internal ordering of the enum Piece::Type
parent 2ab27eb6
......@@ -146,7 +146,7 @@ MovementResult Controller::MakeMove(string & buffer)
//I stored the ranks in the wrong order; rank 1 is the marshal, 2 is the general etc...
//So I am reversing them in the output... great work
s << (Piece::BOMB - moveResult.attackerRank) << " " << (Piece::BOMB - moveResult.defenderRank) << "\n";
s << (Piece::BOMB - moveResult.attackerRank) << " " << (Piece::BOMB - moveResult.defenderRank);
switch (moveResult.type)
{
case MovementResult::OK:
......@@ -174,9 +174,9 @@ MovementResult Controller::MakeMove(string & buffer)
}
if (!Board::LegalResult(moveResult))
return MovementResult::OK; //HACK - Legal results returned!
else
//if (!Board::LegalResult(moveResult))
// return MovementResult::OK; //HACK - Legal results returned!
//else
return moveResult;
}
......
../samples/dummy
\ No newline at end of file
../samples/forfax/forfax
\ No newline at end of file
......@@ -28,18 +28,20 @@ int main(int argc, char ** argv)
{
assert(argc == 3);
for (int y = 5; y < 9; ++y)
for (int y = 4; y < 6; ++y)
{
for (int x = 3; x < 5; ++x)
for (int x = 2; x < 4; ++x)
{
theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
}
for (int x = 9; x < 11; ++x)
for (int x = 6; x < 8; ++x)
{
theBoard.AddPiece(x,y,Piece::BOULDER, Piece::NONE);
}
}
red = new Controller(Piece::RED, argv[1]);
blue = new Controller(Piece::BLUE, argv[2]);
atexit(cleanup);
......@@ -90,7 +92,7 @@ int main(int argc, char ** argv)
break;
#ifdef GRAPHICS
Board::theBoard.Draw();
if (CheckForQuitWhilstWaiting(0.2))
if (CheckForQuitWhilstWaiting(0.5))
{
red->SendMessage("QUIT");
blue->SendMessage("QUIT");
......@@ -112,7 +114,7 @@ int main(int argc, char ** argv)
#ifdef GRAPHICS
Board::theBoard.Draw();
if (CheckForQuitWhilstWaiting(0.2))
if (CheckForQuitWhilstWaiting(0.5))
{
red->SendMessage("QUIT");
blue->SendMessage("QUIT");
......@@ -130,12 +132,14 @@ int main(int argc, char ** argv)
printf("Final board state\n");
#ifdef GRAPHICS
Board::theBoard.Draw();
if (CheckForQuitWhilstWaiting(4))
{
red->SendMessage("QUIT");
blue->SendMessage("QUIT");
exit(EXIT_SUCCESS);
}
#else
Board::theBoard.Print(stderr);
#endif //GRAPHICS
......@@ -244,6 +248,16 @@ void BrokenPipe(int sig)
{
fprintf(stderr,"Game ends on ERROR's turn - REASON: Broken pipe\n");
}
Board::theBoard.Draw();
while (true)
{
if (CheckForQuitWhilstWaiting(4000))
{
red->SendMessage("QUIT");
blue->SendMessage("QUIT");
exit(EXIT_SUCCESS);
}
}
exit(EXIT_SUCCESS);
}
......
......@@ -7,7 +7,7 @@ using namespace std;
/**
* Static variables
*/
Board Board::theBoard(14,14);
Board Board::theBoard(10,10);
//nothing, boulder, flag, spy, scout, miner, sergeant, lietenant, captain, major, colonel, general, marshal, bomb, error
char Piece::tokens[] = {'.','+','F','y','s','n','S','L','c','m','C','G','M','B','?'};
int Piece::maxUnits[] = {0,0,1,1,8,5,4,4,4,3,2,1,1,6,0};
......
......@@ -5,6 +5,8 @@ CPP = g++ -Wall -pedantic -lSDL -lGL -g
dummy : dummy.o
$(CPP) -o dummy dummy.o
clean :
$(RM) $(BIN) $(OBJ) $(LINKOBJ)
......
......@@ -30,20 +30,20 @@ int main(int argc, char ** argv)
//fprintf(stderr, "Colour is \"%s\", width and height are (%d, %d), opponent is \"%s\"\n", colour.c_str(), width, height, opponent.c_str());
assert(width == 14 && height == 14); //Can't deal with other sized boards
assert(width == 10 && height == 10); //Can't deal with other sized boards
if (colour == "RED")
{
fprintf(stdout, "FB..........B.\n");
fprintf(stdout, "BBCM....cccc.C\n");
fprintf(stdout, "LSGmnsBmSsnsSm\n");
fprintf(stdout, "sLSBLnLssssnyn\n");
fprintf(stdout, "FBnyBmSsBn\n");
fprintf(stdout, "BBCMccccnC\n");
fprintf(stdout, "LSGmnsnsSm\n");
fprintf(stdout, "sLSBLLssss\n");
}
else if (colour == "BLUE")
{
fprintf(stdout, "sLSBLnLssssnyn\n");
fprintf(stdout, "LSGmnsBmSsnsSm\n");
fprintf(stdout, "BBCM....cccc.C\n");
fprintf(stdout, "FB..........B.\n");
fprintf(stdout, "sLSBLLssss\n");
fprintf(stdout, "LSGmnsnsSm\n");
fprintf(stdout, "BBCMccccnC\n");
fprintf(stdout, "FBnyBmSsBn\n");
}
else
{
......@@ -63,10 +63,12 @@ int main(int argc, char ** argv)
//fprintf(stderr, "%s [%d] looping\n", argv[0], myPid);
choices.clear();
// fprintf(stderr, "%s Waiting for status line...\n", colour.c_str());
while (fgetc(stdin) != '\n')
//fprintf(stderr, "%s Waiting for status line...\n", colour.c_str());
char c = fgetc(stdin);
while (c != '\n')
{
//fprintf(stderr,".");
//fprintf(stderr,"%c",c);
c = fgetc(stdin);
}
//fprintf(stderr, "%s Got status, waiting for board line...\n", colour.c_str());
......
This diff is collapsed.
/**
* "forfax", a sample Stratego AI for the UCC Programming Competition 2012
* Declarations for classes Piece, Board and Forfax, Declaration/Implementation of helper class MovementChoice
* @author Sam Moore (matches) [SZM]
* @website http://matches.ucc.asn.au/stratego
* @email [email protected] or [email protected]
* @git git.ucc.asn.au/progcomp2012.git
*/
#ifndef FORFAX_H
#define FORFAX_H
#include <vector> //Uses C++ std::vectors to store pieces
#include <string> //Uses C++ std::string
/**
* Header for the sample Stratego AI "forfax"
* @author Sam Moore 2011
*/
class Board;
#include <iostream> //For debug
#include <cassert> //For debug
class Board; //Forward declaration used by class Piece
/**
* Class to represent a piece on the board
*/
......@@ -18,7 +29,7 @@ class Piece
typedef enum {RED=0, BLUE=1, NONE, BOTH} Colour; //Used for the allegiance of the pieces - terrain counts as NONE.
Piece(int newX, int newY,const Colour & newColour);
Piece(int newX, int newY,const Colour & newColour, const Colour & rankKnownBy, const Type & fixedRank);
Piece(int newX, int newY,const Colour & newColour, const Type & fixedRank);
virtual ~Piece() {}
void SetCoords(int newX, int newY) {x = newX; y = newY;}
......@@ -30,12 +41,18 @@ class Piece
static Type GetType(char fromToken); //Retrieves the type of a piece given its character token
static Colour Opposite(const Colour & colour) {return colour == RED ? BLUE : RED;}
bool Mobile() const
{
if (minRank == maxRank)
return (minRank != Piece::FLAG && minRank != Piece::BOMB);
else
return true;
}
int x; int y;
const Colour colour; //The colour of the piece
Type minRank[2]; //The minimum possible rank of the piece, according to each colour
Type maxRank[2]; //The maximum possible rank of the piece, according to each colour
Type minRank; //The minimum possible rank of the piece
Type maxRank; //The maximum possible rank of the piece
int lastMove;
......@@ -57,6 +74,8 @@ class Board
Piece * Get(int x, int y) const; //Retrieve single piece
Piece * Set(int x, int y, Piece * newPiece); //Add piece to board
bool ValidPosition(int x, int y) const {return (x > 0 && x < width && y > 0 && y < height);}
int Width() const {return width;}
int Height() const {return height;}
......@@ -89,39 +108,52 @@ class Board
};
/**
* Small class to manage the Forfax AI
* Class to manage the Forfax AI
*/
class Forfax
{
public:
Forfax();
virtual ~Forfax();
bool Setup(); //Waits for input to determine colour and board size, and then responds with setup
bool MakeMove(); //Should be called each turn - determines Forfax's move
double CombatSuccessChance(Piece * attacker, Piece * defender, const Piece::Colour & accordingTo) const;
double MovementBaseScore(Piece * move, const Board::Direction & dir, const Piece::Colour & accordingTo) const;
double MovementTotalScore(Piece * move, const Board::Direction & dir, const Piece::Colour & accordingTo) const;
typedef enum {OK, NO_NEWLINE, EXPECTED_ATTACKER, UNEXPECTED_DEFENDER, NO_ATTACKER, NO_DEFENDER, COLOUR_MISMATCH, INVALID_QUERY, BOARD_ERROR, VICTORY} Status;
Status Setup(); //Waits for input to determine colour and board size, and then responds with setup
Status MakeMove(); //Should be called each turn - determines Forfax's move
//Move score functions
double MovementScore(Piece * move, const Board::Direction & dir) const; //Calculate total score
double CombatSuccessChance(Piece * attacker, Piece * defender) const; //Calculate chance of success in combat
double IntrinsicWorth(int x, int y) const; //How much a given point on the board is worth
double VictoryScore(Piece * attacker, Piece * defender) const; //How much killing the defender is worth
double DefeatScore(Piece * attacker, Piece * defender) const; //How much losing is worth
void PrintBoard(std::ostream & out);
protected:
bool MakeFirstMove(); //Should only be called on the first turn
bool InterpretMove();
Status MakeFirstMove(); //Should only be called on the first turn
Status InterpretMove();
private:
Board * board; //Forfax stores the state on a board
Piece::Colour colour; //Forfax needs to know his colour
std::string strColour; //String of colour
int turnNumber; //Forfax needs to know what turn number it is
int remainingUnits[14][2][2]; //Known remaining units, accessed by (type, colour, accordingTo)
static int remainingUnits[2][15]; //Known remaining units, accessed by [colour][type]
};
/**
* Helper class used to store various moves in the board, and their associated scores
*/
class MovementChoice
{
public:
MovementChoice(Piece * newPiece, const Board::Direction & newDir, const Forfax & forfax, const Piece::Colour & accordingTo) : piece(newPiece), dir(newDir)
MovementChoice(Piece * newPiece, const Board::Direction & newDir, const Forfax & forfax) : piece(newPiece), dir(newDir)
{
score = forfax.MovementBaseScore(piece, dir, accordingTo);
score = forfax.MovementScore(piece, dir);
}
MovementChoice(const MovementChoice & cpy) : piece(cpy.piece), dir(cpy.dir), score(cpy.score)
......@@ -143,14 +175,6 @@ class MovementChoice
};
class MovementTotalChoice : public MovementChoice
{
public:
MovementTotalChoice(Piece * newPiece, const Board::Direction & newDir, const Forfax & forfax, const Piece::Colour & accordingTo) : MovementChoice(newPiece, newDir, forfax, accordingTo)
{
score = score/(forfax.MovementTotalScore(piece, dir, Piece::Opposite(accordingTo)));
}
};
#endif //FORFAX_H
......
/**
* "forfax", a sample Stratego AI for the UCC Programming Competition 2012
* The main function for the "forfax" AI program
* @author Sam Moore (matches) [SZM]
* @website http://matches.ucc.asn.au/stratego
* @email [email protected] or [email protected]
* @git git.ucc.asn.au/progcomp2012.git
*/
#include <cstdlib>
#include <iostream>
......@@ -6,21 +15,73 @@
using namespace std;
#include <stdio.h>
void quit();
/**
* The AI
*/
Forfax forfax;
/**
* The main function
* @param argc the number of arguments
* @param argv the arguments
* @returns exit code 0 for success, something else for error
* Do I really need to tell you this?
*/
int main(int argc, char ** argv)
{
setbuf(stdin, NULL);
setbuf(stdout, NULL);
atexit(&quit);
if (!forfax.Setup())
exit(EXIT_SUCCESS);
Forfax::Status move = forfax.Setup();
while (move == Forfax::OK)
{
move = forfax.MakeMove();
}
while (forfax.MakeMove());
switch (move)
{
case Forfax::OK:
cerr << argv[0] << " Error - Should never see this!\n";
break;
case Forfax::NO_NEWLINE:
cerr << argv[0] << " Error - Expected a new line!\n";
break;
case Forfax::EXPECTED_ATTACKER:
cerr << argv[0] << " Error - Attacking piece does not exist on board!\n";
break;
case Forfax::UNEXPECTED_DEFENDER:
cerr << argv[0] << " Error - Unexpected defending piece on board!\n";
break;
case Forfax::NO_ATTACKER:
cerr << argv[0] << " Error - Couldn't find attacker in list of pieces!\n";
break;
case Forfax::NO_DEFENDER:
cerr << argv[0] << " Error - Couldn't find defender in list of pieces!\n";
break;
case Forfax::COLOUR_MISMATCH:
cerr << argv[0] << " Error - Colour of attacker and defender are the same!\n";
break;
case Forfax::INVALID_QUERY:
cerr << argv[0] << " Error - Query did not make sense\n";
break;
case Forfax::VICTORY:
cerr << argv[0] << " Game end - VICTORY!\n";
break;
case Forfax::BOARD_ERROR:
cerr << argv[0] << " Error - An error occurred with the board!\n";
break;
}
cerr << "Final board state:\n";
forfax.PrintBoard(cerr);
cerr << "Forfax is now exiting!\n";
cerr << "Forfax threw a hissy fit, and exited!\n";
exit(EXIT_SUCCESS);
return 0;
......@@ -28,7 +89,4 @@ int main(int argc, char ** argv)
}
void quit()
{
cerr << " Forfax quit\n";
}
Supports Markdown
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