Commit 7f7bc054 authored by Sam Moore's avatar Sam Moore

Fixed segfault in manager program

Caused by the Program base class attempting to write EOF to programs
which had already exited. This caused a SIGPIPE signal.

The SIGPIPE handler function Game::HandleBrokenPipe then attempted to log the
event by calling Game::theGame->logMessage

However, since the program was exiting, DestroyGame had been called
and Game::theGame was in the process of being deleted.

Fixed by removing the fputc(output, EOF) line in Program::~Program.

It is ironic that this only became an issue since I modified the sample
AI to actually obey the protocol and exit as soon as "QUIT" is recieved...
parent 17a20de4
......@@ -117,8 +117,10 @@ MovementResult Controller::MakeMove(string & buffer)
}
else
{
//fprintf(stderr, "BAD_RESPONSE \"%s\"\n", buffer.c_str());
return MovementResult::BAD_RESPONSE; //Player gave bogus direction - it will lose by default.
if (Game::theGame->allowIllegalMoves)
return MovementResult::OK;
else
return MovementResult::BAD_RESPONSE; //Player gave bogus direction - it will lose by default.
}
int multiplier = 1;
......@@ -158,10 +160,15 @@ MovementResult Controller::MakeMove(string & buffer)
}
if (!Board::LegalResult(moveResult))
{
if (Game::theGame->allowIllegalMoves)
{
return MovementResult::OK; //HACK - Illegal results returned as legal! (Move not made)
}
else if (this->HumanController()) //Cut human controllers some slack and let them try again...
{
//Yes, checking type of object is "not the C++ way"
......
......@@ -205,6 +205,11 @@ void Game::Wait(double wait)
void Game::HandleBrokenPipe(int sig)
{
if (theGame == NULL)
{
fprintf(stderr, "ERROR - Recieved SIGPIPE during game exit!\n");
exit(EXIT_FAILURE);
}
if (theGame->turn == Piece::RED)
{
theGame->logMessage("Game ends on RED's turn - REASON: ");
......
......@@ -88,7 +88,7 @@ Piece::Colour SetupGame(int argc, char ** argv)
printBoard = !printBoard;
break;
case 'i':
allowIllegal = !allowIllegal;
allowIllegal = true;
break;
case 'o':
......
......@@ -81,7 +81,7 @@ Program::~Program()
{
if (Running()) //Check if the process created is still running...
{
fputc(EOF, output); //If it was, tell it to stop with EOF
//fputc(EOF, output); //If it was, tell it to stop with EOF
TimerThread timer(2); //Wait for 2 seconds
timer.Start();
......
#Makefile for the sample AI programs for UCC progcomp 2012
CPP = g++ -Wall -pedantic -lSDL -lGL -g
dummy : dummy.o
$(CPP) -o dummy dummy.o
clean :
rm -f dummy.o
rm -f dummy
#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <cassert>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
/**
* A suitably terrible program which combines C style IO with C++ style IO
* Enjoy!
* Mwuhahaha
*/
int main(int argc, char ** argv)
{
setbuf(stdout, NULL);
setbuf(stdin, NULL);
srand(time(NULL));
//Read in the colour, and choose a layout
int width = 14; int height = 14;
string colour; string opponent;
cin >> colour; cin >> opponent; cin >> width; cin >> height;
fgetc(stdin);
//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 == 10 && height == 10); //Can't deal with other sized boards
if (colour == "RED")
{
fprintf(stdout, "FB8sB479B8\n");
fprintf(stdout, "BB31555583\n");
fprintf(stdout, "6724898974\n");
fprintf(stdout, "967B669999\n");
}
else if (colour == "BLUE")
{
fprintf(stdout, "967B669999\n");
fprintf(stdout, "6724898974\n");
fprintf(stdout, "BB31555583\n");
fprintf(stdout, "FB8sB479B8\n");
}
else
{
return 1;
}
char board[width][height];
vector<pair<int, int> > choices;
int myPid = (int)(getpid());
while (true)
{
//fprintf(stderr, "%s [%d] looping\n", argv[0], myPid);
choices.clear();
//fprintf(stderr, "%s Waiting for status line...\n", colour.c_str());
char c = fgetc(stdin);
while (c != '\n')
{
//fprintf(stderr,"%c",c);
c = fgetc(stdin);
}
//fprintf(stderr, "%s Got status, waiting for board line...\n", colour.c_str());
//Read in board
for (int y=0; y < height; ++y)
{
for (int x=0; x < width; ++x)
{
board[x][y] = fgetc(stdin);
if (board[x][y] == EOF)
exit(EXIT_SUCCESS);
if (board[x][y] != '.' && board[x][y] != '*' && board[x][y] != '#' && board[x][y] != '+')
{
choices.push_back(pair<int, int>(x, y));
}
}
assert(fgetc(stdin) == '\n');
}
int dir = 0; int startDir = 0; int choice = rand() % choices.size(); int startChoice = choice;
int x1 = 0; int y1 = 0;
do
{
pair<int,int> pear = choices[choice];
x1 = pear.first;
y1 = pear.second;
//fprintf(stderr,"Trying unit at %d %d...\n", x1, y1);
if (board[x1][y1] == 'B' || board[x1][y1] == 'F')
{
choice = (choice+1) % choices.size();
continue;
}
int x2 = x1;
int y2 = y1;
dir = rand() % 4; startDir = dir; int lastDir = dir;
bool okay = false;
while (!okay)
{
//fprintf(stderr," Trying direction %d...\n", dir);
x2 = x1; y2 = y1;
switch (dir)
{
case 0:
--y2;
break;
case 1:
++y2;
break;
case 2:
--x2;
break;
case 3:
++x2;
break;
}
okay = !(x2 < 0 || y2 < 0 || x2 >= width || y2 >= height || (board[x2][y2] != '.' && board[x2][y2] != '*' && board[x2][y2] != '#'));
if (!okay)
{
dir = (dir+1) % 4;
if (dir == startDir)
break;
}
}
choice = (choice+1) % choices.size();
if (dir != startDir)
break;
}
while (choice != startChoice);
string direction="";
switch (dir)
{
case 0:
direction = "UP";
break;
case 1:
direction = "DOWN";
break;
case 2:
direction = "LEFT";
break;
case 3:
direction = "RIGHT";
break;
}
printf("%d %d %s\n", x1, y1, direction.c_str());
//fprintf(stderr,"%s Made move, waiting for confirmation line\n", colour.c_str());
while (fgetc(stdin) != '\n'); //Read in result line
//fprintf(stderr, "%s Done turn\n", colour.c_str());
//fprintf(stderr,"%s - %d %d %s\n",colour.c_str(), x1, y1, direction.c_str() );
//fprintf(stderr, "%s [%d] computed move\n", argv[0], myPid);
}
}
#Makefile for Forfax
CPP = g++ -Wall -pedantic -lSDL -lGL -g
OBJ = main.o forfax.o
BIN = forfax
$(BIN) : $(OBJ)
$(CPP) -o $(BIN) $(OBJ)
%.o : %.cpp %.h
$(CPP) -c $<
clean :
$(RM) $(BIN) $(OBJ) $(LINKOBJ)
clean_full: #cleans up all backup files
$(RM) $(BIN) $(OBJ) $(LINKOBJ)
$(RM) *.*~
$(RM) *~
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
#include <iostream> //For debug
#include <cassert> //For debug
class Board; //Forward declaration used by class Piece
/**
* Class to represent a piece on the board
*/
class Piece
{
public:
typedef enum {ERROR=14,BOMB=13,MARSHAL=12, GENERAL=11, COLONEL=10, MAJOR=9, CAPTAIN=8, LIEUTENANT=7, SERGEANT=6, MINER=5, SCOUT=4, SPY=3, FLAG=2,BOULDER=1, NOTHING=0} Type; //Type basically defines how strong the piece is
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 Type & fixedRank);
virtual ~Piece() {}
void SetCoords(int newX, int newY) {x = newX; y = newY;}
void GetCoords(int & storeX, int & storeY) const {storeX = x; storeY = y;}
const Colour & GetColour() const {return colour;}
static char tokens[]; //The tokens used to identify various pieces
static int maxUnits[]; //The maximum allowed number of units of each 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; //The minimum possible rank of the piece
Type maxRank; //The maximum possible rank of the piece
int lastMove;
int lastx; int lasty;
};
/**
* Class to represent a board
*/
class Board
{
public:
Board(int width, int height);
virtual ~Board();
std::vector<Piece*> & GetPieces(const Piece::Colour & colour) {return colour == Piece::RED ? red : blue;} //retrieve array of pieces
Piece * Get(int x, int y) const; //Retrieve single piece
Piece * GetClosest(int x, int y, const Piece::Colour & search = Piece::BOTH) const; //Retrieve closest piece of specified colour to the point
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;}
typedef enum {UP=0, DOWN=1, LEFT=2, RIGHT=3, NONE=4} Direction;
static Direction StrToDir(const std::string & str);
static void DirToStr(const Direction & dir, std::string & buffer);
static void MoveInDirection(int & x, int & y, const Direction & dir, int multiplier = 1);
static Direction DirectionBetween(int x1, int y1, int x2, int y2);
static int NumberOfMoves(int x1, int y1, int x2, int y2);
static int redUnits[];
static int blueUnits[];
bool ForgetPiece(Piece * forget); //removes piece from the red and blue vectors
private:
friend class Forfax;
int width;
int height;
Piece ** * board;
std::vector<Piece*> red; //Store all red pieces
std::vector<Piece*> blue; //Store all blue pieces
};
/**
* Class to manage the Forfax AI
*/
class Forfax
{
public:
Forfax();
virtual ~Forfax();
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 CombatScore(int x, int y, Piece * attacker) const; //Calculate total worth of combat at a point
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:
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
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) : piece(newPiece), dir(newDir)
{
score = forfax.MovementScore(piece, dir);
}
MovementChoice(const MovementChoice & cpy) : piece(cpy.piece), dir(cpy.dir), score(cpy.score)
{
}
bool operator<(const MovementChoice & a) const {return score < a.score;}
bool operator>(const MovementChoice & a) const {return score > a.score;}
bool operator<=(const MovementChoice & a) const {return score <= a.score;}
bool operator>=(const MovementChoice & a) const {return score >= a.score;}
bool operator==(const MovementChoice & a) const {return score == a.score;}
bool operator!=(const MovementChoice & a) const {return score != a.score;}
Piece * piece;
Board::Direction dir;
double score;
};
#endif //FORFAX_H
//EOF
/**
* "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>
#include "forfax.h"
using namespace std;
#include <stdio.h>
/**
* 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);
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;
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";
exit(EXIT_SUCCESS);
return 0;
}
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