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

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,17 +28,19 @@ 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]);
......@@ -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
......@@ -245,6 +249,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();
}
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;
while (forfax.MakeMove());
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 << "Forfax threw a hissy fit, and exited!\n";
cerr << "Final board state:\n";
forfax.PrintBoard(cerr);
cerr << "Forfax is now exiting!\n";
exit(EXIT_SUCCESS);
return 0;
......@@ -28,7 +89,4 @@ int main(int argc, char ** argv)
}
void quit()
{
cerr << " Forfax quit\n";
}
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