From: Sam Moore Date: Wed, 30 Nov 2011 04:36:18 +0000 (+0800) Subject: Modified Turn Response Protocol, added handling for SIGPIPE, changed placeholder... X-Git-Url: https://git.ucc.asn.au/?p=progcomp2012.git;a=commitdiff_plain;h=2ab27eb698cfd57977cc9cc25edcbfbeb3b1b1ee Modified Turn Response Protocol, added handling for SIGPIPE, changed placeholder images The "outcome" of a move is now listed as: TYPE [ATTACKER_RANK] [DEFENDER_RANK] Where ATTACKER_RANK and DEFENDER_RANK will be present if TYPE is one of: KILLS, DIES, BOTHDIE, and indicate the ranks of the pieces involved. This involved adding a class MovementResult, which stores the ranks of pieces in addition to an enum, replacing the enum Board::MovementResult The sample agent "forfax" was causing broken pipes, which caused the manager program to exit. I added a handler for SIGPIPE in manager/main.cpp to ensure that the manager program reports a DEFAULT victory to the other AI, and exits gracefully. However, I still don't know WHY forfax causes broken pipes, but hopefully its a problem with forfax and not with the manager program. I edited the images used by the graphical display to show the ordered ranks of the pieces, rather than some obscure characters. Unfortunately I have just realised that the enum used for Piece::Type stores ranks in the wrong order. In the actual game, LOWER numbers are better, in my enum, HIGHER numbers are better. To make things more confusing, I made the printed ATTACKER_RANK and DEFENDER_RANK correspond to the traditional numbering, not the enum numbering... --- diff --git a/manager/controller.cpp b/manager/controller.cpp index dad6e44..736663e 100644 --- a/manager/controller.cpp +++ b/manager/controller.cpp @@ -8,9 +8,10 @@ using namespace std; /** * Queries the AI program to setup its pieces + * @param opponentName - string containing the name/id of the opponent AI program * @returns the result of the response */ -Board::MovementResult Controller::Setup(const char * opponentName) +MovementResult Controller::Setup(const char * opponentName) { int y; switch (colour) @@ -48,12 +49,12 @@ Board::MovementResult Controller::Setup(const char * opponentName) if (!GetMessage(line, 2.5)) { fprintf(stderr, "Timeout on setup\n"); - return Board::BAD_RESPONSE; + return MovementResult::BAD_RESPONSE; } if ((int)(line.size()) != Board::theBoard.Width()) { fprintf(stderr, "Bad length of \"%s\" on setup\n", line.c_str()); - return Board::BAD_RESPONSE; + return MovementResult::BAD_RESPONSE; } for (int x = 0; x < (int)(line.size()); ++x) @@ -69,7 +70,7 @@ Board::MovementResult Controller::Setup(const char * opponentName) if (usedUnits[type] > Piece::maxUnits[(int)type]) { fprintf(stderr, "Too many units of type %c\n", Piece::tokens[(int)(type)]); - return Board::BAD_RESPONSE; + return MovementResult::BAD_RESPONSE; } Board::theBoard.AddPiece(x, y+ii, type, colour); @@ -79,10 +80,10 @@ Board::MovementResult Controller::Setup(const char * opponentName) if (usedUnits[(int)Piece::FLAG] <= 0) { - return Board::BAD_RESPONSE; //You need to include a flag! + return MovementResult::BAD_RESPONSE; //You need to include a flag! } - return Board::OK; + return MovementResult::OK; } @@ -90,11 +91,11 @@ Board::MovementResult Controller::Setup(const char * opponentName) * Queries the AI program to respond to a state of Board::theBoard * @returns The result of the response and/or move if made */ -Board::MovementResult Controller::MakeMove(string & buffer) +MovementResult Controller::MakeMove(string & buffer) { if (!Running()) - return Board::NO_MOVE; //AI has quit + return MovementResult::NO_MOVE; //AI has quit Board::theBoard.Print(output, colour); @@ -103,7 +104,7 @@ Board::MovementResult Controller::MakeMove(string & buffer) buffer.clear(); if (!GetMessage(buffer,2)) { - return Board::NO_MOVE; //AI did not respond. It will lose by default. + return MovementResult::NO_MOVE; //AI did not respond. It will lose by default. } int x; int y; string direction=""; @@ -133,29 +134,39 @@ Board::MovementResult Controller::MakeMove(string & buffer) else { fprintf(stderr, "BAD_RESPONSE \"%s\"\n", buffer.c_str()); - return Board::BAD_RESPONSE; //AI gave bogus direction - it will lose by default. + return MovementResult::BAD_RESPONSE; //AI gave bogus direction - it will lose by default. } int multiplier = 1; if (s.peek() != EOF) s >> multiplier; - Board::MovementResult moveResult = Board::theBoard.MovePiece(x, y, dir, multiplier, colour); - switch (moveResult) + MovementResult moveResult = Board::theBoard.MovePiece(x, y, dir, multiplier, colour); + + s.clear(); s.str(""); + + //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"; + switch (moveResult.type) { - case Board::OK: + case MovementResult::OK: buffer += " OK"; break; - case Board::VICTORY: + case MovementResult::VICTORY: buffer += " FLAG"; break; - case Board::KILLS: - buffer += " KILLS"; + case MovementResult::KILLS: + buffer += " KILLS "; + buffer += s.str(); + break; - case Board::DIES: - buffer += " DIES"; + case MovementResult::DIES: + buffer += " DIES "; + buffer += s.str(); break; - case Board::BOTH_DIE: - buffer += " BOTHDIE"; + case MovementResult::BOTH_DIE: + buffer += " BOTHDIE "; + buffer += s.str(); break; default: buffer += " ILLEGAL"; @@ -164,7 +175,7 @@ Board::MovementResult Controller::MakeMove(string & buffer) } if (!Board::LegalResult(moveResult)) - return Board::OK; //HACK - Legal results returned! + return MovementResult::OK; //HACK - Legal results returned! else return moveResult; diff --git a/manager/controller.h b/manager/controller.h index 0e2e5cc..1fac88d 100644 --- a/manager/controller.h +++ b/manager/controller.h @@ -15,9 +15,9 @@ class Controller : public Program Controller(const Piece::Colour & newColour, const char * executablePath) : Program(executablePath), colour(newColour) {} virtual ~Controller() {} - Board::MovementResult Setup(const char * opponentName); //Requests the AI program for the initial positioning of its pieces. + MovementResult Setup(const char * opponentName); //Requests the AI program for the initial positioning of its pieces. - Board::MovementResult MakeMove(std::string & buffer); //Queries the AI program for a response to the state of Board::theBoard + MovementResult MakeMove(std::string & buffer); //Queries the AI program for a response to the state of Board::theBoard const Piece::Colour colour; //Colour identifying the side of the AI program. diff --git a/manager/forfax b/manager/forfax new file mode 120000 index 0000000..a715b0f --- /dev/null +++ b/manager/forfax @@ -0,0 +1 @@ +../samples/forfax/forfax \ No newline at end of file diff --git a/manager/images/piece10.bmp b/manager/images/piece10.bmp index cfeda8a..cf77ed4 100644 Binary files a/manager/images/piece10.bmp and b/manager/images/piece10.bmp differ diff --git a/manager/images/piece11.bmp b/manager/images/piece11.bmp index f4ebeb2..b006d3d 100644 Binary files a/manager/images/piece11.bmp and b/manager/images/piece11.bmp differ diff --git a/manager/images/piece12.bmp b/manager/images/piece12.bmp index 6c9544e..8c67a48 100644 Binary files a/manager/images/piece12.bmp and b/manager/images/piece12.bmp differ diff --git a/manager/images/piece13.bmp b/manager/images/piece13.bmp index 0878912..f822c24 100644 Binary files a/manager/images/piece13.bmp and b/manager/images/piece13.bmp differ diff --git a/manager/images/piece2.bmp b/manager/images/piece2.bmp index ef4927b..0a11b11 100644 Binary files a/manager/images/piece2.bmp and b/manager/images/piece2.bmp differ diff --git a/manager/images/piece3.bmp b/manager/images/piece3.bmp index 4209648..40ca3f8 100644 Binary files a/manager/images/piece3.bmp and b/manager/images/piece3.bmp differ diff --git a/manager/images/piece4.bmp b/manager/images/piece4.bmp index 63161fb..0a27a46 100644 Binary files a/manager/images/piece4.bmp and b/manager/images/piece4.bmp differ diff --git a/manager/images/piece5.bmp b/manager/images/piece5.bmp index 9163c12..051bd43 100644 Binary files a/manager/images/piece5.bmp and b/manager/images/piece5.bmp differ diff --git a/manager/images/piece6.bmp b/manager/images/piece6.bmp index 321bf55..5ca389b 100644 Binary files a/manager/images/piece6.bmp and b/manager/images/piece6.bmp differ diff --git a/manager/images/piece7.bmp b/manager/images/piece7.bmp index e690190..aaf28a1 100644 Binary files a/manager/images/piece7.bmp and b/manager/images/piece7.bmp differ diff --git a/manager/images/piece8.bmp b/manager/images/piece8.bmp index 8ada911..b2ea5b7 100644 Binary files a/manager/images/piece8.bmp and b/manager/images/piece8.bmp differ diff --git a/manager/images/piece9.bmp b/manager/images/piece9.bmp index e22c4b6..e37e251 100644 Binary files a/manager/images/piece9.bmp and b/manager/images/piece9.bmp differ diff --git a/manager/main.cpp b/manager/main.cpp index 96569eb..4f203d9 100644 --- a/manager/main.cpp +++ b/manager/main.cpp @@ -18,8 +18,12 @@ using namespace std; Controller * red; Controller * blue; +Colour turn; void cleanup(); + +void BrokenPipe(int sig); + int main(int argc, char ** argv) { assert(argc == 3); @@ -39,17 +43,18 @@ int main(int argc, char ** argv) red = new Controller(Piece::RED, argv[1]); blue = new Controller(Piece::BLUE, argv[2]); atexit(cleanup); + signal(SIGPIPE, BrokenPipe); - Board::MovementResult redSetup = red->Setup(argv[2]); - Board::MovementResult blueSetup = blue->Setup(argv[1]); - if (redSetup != Board::OK) + MovementResult redSetup = red->Setup(argv[2]); + MovementResult blueSetup = blue->Setup(argv[1]); + if (redSetup != MovementResult::OK) { fprintf(stderr, "Blue wins by DEFAULT!\n"); red->SendMessage("ILLEGAL"); blue->SendMessage("DEFAULT"); exit(EXIT_SUCCESS); } - if (blueSetup != Board::OK) + if (blueSetup != MovementResult::OK) { fprintf(stderr, "Red wins by DEFAULT!\n"); red->SendMessage("DEFAULT"); @@ -57,7 +62,7 @@ int main(int argc, char ** argv) exit(EXIT_SUCCESS); } - Board::MovementResult result = Board::OK; + MovementResult result(MovementResult::OK); system("clear"); int count = 1; @@ -70,17 +75,17 @@ int main(int argc, char ** argv) string buffer; red->SendMessage("START"); - Colour turn = Piece::RED; + turn = Piece::RED; while (Board::LegalResult(result)) { - fprintf(stderr, "This is move %d...\n", count); - fprintf(stderr,"---RED's turn---\n"); + turn = Piece::RED; + fprintf(stderr, "%d RED: ", count); result = red->MakeMove(buffer); red->SendMessage(buffer); blue->SendMessage(buffer); - + fprintf(stderr, "%s\n", buffer.c_str()); if (!Board::LegalResult(result)) break; #ifdef GRAPHICS @@ -92,11 +97,13 @@ int main(int argc, char ** argv) exit(EXIT_SUCCESS); } #endif //GRAPHICS - fprintf(stderr,"---BLUE's turn---\n"); + turn = Piece::BLUE; + fprintf(stderr, "%d BLU: ", count); result = blue->MakeMove(buffer); blue->SendMessage(buffer); red->SendMessage(buffer); + fprintf(stderr, "%s\n", buffer.c_str()); if (!Board::LegalResult(result)) break; @@ -148,36 +155,36 @@ int main(int argc, char ** argv) fprintf(stderr,"Game ends on ERROR's turn - REASON: "); } - switch (result) + switch (result.type) { - case Board::NO_BOARD: + case MovementResult::NO_BOARD: fprintf(stderr,"Board does not exit?!\n"); break; - case Board::INVALID_POSITION: + case MovementResult::INVALID_POSITION: fprintf(stderr,"Coords outside board\n"); break; - case Board::NO_SELECTION: + case MovementResult::NO_SELECTION: fprintf(stderr,"Move does not select a piece\n"); break; - case Board::NOT_YOUR_UNIT: + case MovementResult::NOT_YOUR_UNIT: fprintf(stderr,"Selected piece belongs to other player\n"); break; - case Board::IMMOBILE_UNIT: + case MovementResult::IMMOBILE_UNIT: fprintf(stderr,"Selected piece is not mobile (FLAG or BOMB)\n"); break; - case Board::INVALID_DIRECTION: + case MovementResult::INVALID_DIRECTION: fprintf(stderr,"Selected unit cannot move that way\n"); break; - case Board::POSITION_FULL: + case MovementResult::POSITION_FULL: fprintf(stderr,"Attempted move into square occupied by allied piece\n"); break; - case Board::VICTORY: + case MovementResult::VICTORY: fprintf(stderr,"Captured the flag\n"); break; - case Board::BAD_RESPONSE: + case MovementResult::BAD_RESPONSE: fprintf(stderr,"Unintelligable response\n"); break; - case Board::NO_MOVE: + case MovementResult::NO_MOVE: fprintf(stderr,"Did not make a move (may have exited)\n"); break; } @@ -221,4 +228,24 @@ void cleanup() delete blue; } +void BrokenPipe(int sig) +{ + if (turn == Piece::RED) + { + fprintf(stderr,"Game ends on RED's turn - REASON: Broken pipe\n"); + blue->SendMessage("DEFAULT"); + } + else if (turn == Piece::BLUE) + { + fprintf(stderr,"Game ends on BLUE's turn - REASON: Broken pipe\n"); + red->SendMessage("DEFAULT"); + } + else + { + fprintf(stderr,"Game ends on ERROR's turn - REASON: Broken pipe\n"); + + } + exit(EXIT_SUCCESS); +} + #endif //GRAPHICS diff --git a/manager/movementresult.h b/manager/movementresult.h new file mode 100644 index 0000000..8df375c --- /dev/null +++ b/manager/movementresult.h @@ -0,0 +1,34 @@ +/** + * Contains declaration for MovementResult class + */ +#ifndef MOVERESULT_H +#define MOVERESULT_H + +class Board; +class Piece; + +/** + * Class used to indicate the result of a move in stratego + */ +class MovementResult +{ + public: + typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, BAD_RESPONSE, NO_MOVE} Type; + + MovementResult(const Type & result = OK, const Piece::Type & newAttackerRank = Piece::NOTHING, const Piece::Type & newDefenderRank = Piece::NOTHING) + : type(result), attackerRank(newAttackerRank), defenderRank(newDefenderRank) {} + MovementResult(const MovementResult & cpy) : type(cpy.type), attackerRank(cpy.attackerRank), defenderRank(cpy.defenderRank) {} + virtual ~MovementResult() {} + + + bool operator==(const Type & equType) const {return type == equType;} + bool operator!=(const Type & equType) const {return type != equType;} + + Type type; + Piece::Type attackerRank; + Piece::Type defenderRank; +}; + +#endif //MOVERESULT_H + +//EOF diff --git a/manager/program.cpp b/manager/program.cpp index ea5304c..8b4e4af 100644 --- a/manager/program.cpp +++ b/manager/program.cpp @@ -10,6 +10,7 @@ using namespace std; + /** * Constructor * @param executablePath - path to the program that will be run @@ -21,6 +22,8 @@ using namespace std; */ Program::Program(const char * executablePath) : input(NULL), output(NULL), pid(0) { + + int readPipe[2]; int writePipe[2]; assert(pipe(readPipe) == 0); assert(pipe(writePipe) == 0); @@ -88,6 +91,7 @@ Program::~Program() * Sends a message to the wrapped AI program * WARNING: Always prints a new line after the message (so don't include a new line) * This is because everything is always line buffered. + * @returns true if the message was successfully sent; false if it was not (ie: the process was not running!) */ bool Program::SendMessage(const char * print, ...) { @@ -97,12 +101,15 @@ bool Program::SendMessage(const char * print, ...) va_list ap; va_start(ap, print); - vfprintf(output, print, ap); - fprintf(output, "\n"); - + if (vfprintf(output, print, ap) < 0 || fprintf(output, "\n") < 0) + { + va_end(ap); + return false; + } + va_end(ap); - va_end(ap); + return true; } @@ -161,3 +168,5 @@ bool Program::Running() const } + + diff --git a/manager/program.h b/manager/program.h index 406d954..bddde0f 100644 --- a/manager/program.h +++ b/manager/program.h @@ -24,6 +24,8 @@ class Program bool Running() const; + + protected: FILE * input; //Stream used for sending information TO the process FILE * output; //Stream used for retrieving information FROM the process diff --git a/manager/stratego.cpp b/manager/stratego.cpp index 8ffad72..871d382 100644 --- a/manager/stratego.cpp +++ b/manager/stratego.cpp @@ -232,32 +232,32 @@ Piece * Board::GetPiece(int x, int y) * @param colour - Colour which the piece must match for the move to be valid * @returns A MovementResult which indicates the result of the move - OK is good, VICTORY means that a flag was captured, anything else is an error */ -Board::MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour) +MovementResult Board::MovePiece(int x, int y, const Direction & direction, int multiplier,const Piece::Colour & colour) { if (board == NULL) { - return NO_BOARD; + return MovementResult(MovementResult::NO_BOARD); } if (!(x >= 0 && x < width && y >= 0 && y < height)) { - return INVALID_POSITION; + return MovementResult(MovementResult::INVALID_POSITION); } Piece * target = board[x][y]; if (target == NULL) { - return NO_SELECTION; + return MovementResult(MovementResult::NO_SELECTION); } if (!(colour == Piece::NONE || target->colour == colour)) { - return NOT_YOUR_UNIT; + return MovementResult(MovementResult::NOT_YOUR_UNIT); } if (target->type == Piece::FLAG || target->type == Piece::BOMB || target->type == Piece::BOULDER) { - return IMMOBILE_UNIT; + return MovementResult(MovementResult::IMMOBILE_UNIT); } if (multiplier > 1 && target->type != Piece::SCOUT) { - return INVALID_DIRECTION; //Can only move a scout multiple times. + return MovementResult(MovementResult::INVALID_DIRECTION); //Can only move a scout multiple times. } int x2 = x; int y2 = y; @@ -280,11 +280,11 @@ Board::MovementResult Board::MovePiece(int x, int y, const Direction & direction } if (!(x2 >= 0 && x2 < width && y2 >= 0 && y2 < height)) { - return INVALID_DIRECTION; + return MovementResult(MovementResult::INVALID_DIRECTION); } if (ii < multiplier-1 && board[x2][y2] != NULL) { - return POSITION_FULL; + return MovementResult(MovementResult::POSITION_FULL); } } Piece * defender = board[x2][y2]; @@ -295,23 +295,27 @@ Board::MovementResult Board::MovePiece(int x, int y, const Direction & direction } else if (defender->colour != target->colour) { + Piece::Type defenderType = defender->type; + Piece::Type attackerType = target->type; + if (defender->colour == Piece::NONE) { - return POSITION_FULL; + return MovementResult(MovementResult::POSITION_FULL); } if (defender->type == Piece::FLAG) { winner = target->colour; - return VICTORY; + return MovementResult(MovementResult::VICTORY); } else if (defender->type == Piece::BOMB) { if (target->type == Piece::MINER) { + delete defender; board[x][y] = NULL; board[x2][y2] = target; - return KILLS; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); } else { @@ -319,7 +323,7 @@ Board::MovementResult Board::MovePiece(int x, int y, const Direction & direction delete target; board[x][y] = NULL; board[x2][y2] = NULL; - return BOTH_DIE; + return MovementResult(MovementResult::BOTH_DIE, attackerType, defenderType); } } else if (defender->type == Piece::MARSHAL && target->type == Piece::SPY) @@ -327,34 +331,34 @@ Board::MovementResult Board::MovePiece(int x, int y, const Direction & direction delete defender; board[x][y] = NULL; board[x2][y2] = target; - return KILLS; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); } else if (target->operator > (*defender)) { delete defender; board[x][y] = NULL; board[x2][y2] = target; - return KILLS; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); } else if (target->operator==(*defender) && rand() % 2 == 0) { delete defender; board[x][y] = NULL; board[x2][y2] = target; - return KILLS; + return MovementResult(MovementResult::KILLS, attackerType, defenderType); } else { delete target; board[x][y] = NULL; - return DIES; + return MovementResult(MovementResult::DIES, attackerType, defenderType); } } else { - return POSITION_FULL; + return MovementResult(MovementResult::POSITION_FULL); } - return OK; + return MovementResult(MovementResult::OK); } diff --git a/manager/stratego.h b/manager/stratego.h index 877af2d..25aa5cc 100644 --- a/manager/stratego.h +++ b/manager/stratego.h @@ -89,6 +89,8 @@ class Piece }; +#include "movementresult.h" + /** * A Stratego board */ @@ -112,12 +114,11 @@ class Board typedef enum {UP, DOWN, LEFT, RIGHT} Direction; - typedef enum {OK, DIES, KILLS, BOTH_DIE, NO_BOARD, INVALID_POSITION, NO_SELECTION, NOT_YOUR_UNIT, IMMOBILE_UNIT, INVALID_DIRECTION, POSITION_FULL, VICTORY, BAD_RESPONSE, NO_MOVE} MovementResult; //The possible results from a move - //WARNING: Some of the MovementResults are returned by the Controller class in "controller.h", in Controller::MakeMove + static bool LegalResult(const MovementResult & result) { - return (result == OK || result == DIES || result == KILLS || result == BOTH_DIE); + return (result == MovementResult::OK || result == MovementResult::DIES || result == MovementResult::KILLS || result == MovementResult::BOTH_DIE); } MovementResult MovePiece(int x, int y, const Direction & direction, int multiplier=1,const Piece::Colour & colour=Piece::NONE); //Move piece from position in direction diff --git a/samples/forfax/forfax.cpp b/samples/forfax/forfax.cpp index e27af9f..6fa0ba3 100644 --- a/samples/forfax/forfax.cpp +++ b/samples/forfax/forfax.cpp @@ -525,7 +525,7 @@ bool Forfax::MakeMove() bool Forfax::InterpretMove() { - int x; int y; string direction; string result; int multiplier = 1; + int x; int y; string direction; string result; int multiplier = 1; int attackerVal = (int)(Piece::BOMB); int defenderVal = (int)(Piece::BOMB); cerr << "Forfax " << strColour << " waiting for movement information...\n"; cin >> x; cin >> y; cin >> direction; cin >> result; @@ -536,6 +536,20 @@ bool Forfax::InterpretMove() s >> multiplier; result.clear(); cin >> result; + + if (cin.peek() != '\n') + { + cerr << "Forfax " << strColour << " reading ranks of pieces\n"; + s.clear(); s.str(result); + s >> attackerVal; + result.clear(); + cin >> result; + s.clear(); s.str(result); + s >> defenderVal; + result.clear(); + + cin >> result; + } } if (cin.get() != '\n') { @@ -544,6 +558,9 @@ bool Forfax::InterpretMove() return false; } + Piece::Type attackerRank = Piece::Type(Piece::BOMB - attackerVal); + Piece::Type defenderRank = Piece::Type(Piece::BOMB - defenderVal); + cerr << "Forfax " << strColour << " interpreting movement result of " << x << " " << y << " " << direction << " " << result << " ...\n"; diff --git a/samples/forfax/main.cpp b/samples/forfax/main.cpp index d0cea95..2b31fee 100644 --- a/samples/forfax/main.cpp +++ b/samples/forfax/main.cpp @@ -6,13 +6,15 @@ using namespace std; #include - +void quit(); Forfax forfax; int main(int argc, char ** argv) { setbuf(stdin, NULL); setbuf(stdout, NULL); + atexit(&quit); + if (!forfax.Setup()) exit(EXIT_SUCCESS); @@ -25,3 +27,8 @@ int main(int argc, char ** argv) } + +void quit() +{ + cerr << " Forfax quit\n"; +} diff --git a/web/index.html b/web/index.html index 25c2dae..7736907 100644 --- a/web/index.html +++ b/web/index.html @@ -84,11 +84,12 @@ OUTCOME Description OK The piece was successfully moved, nothing eventful happened FLAG The piece moved onto the opposing Flag; the game will end shortly - KILLS The piece landed on a square occupied by an enemy, and destroyed it, moving into the square - DIES The piece landed on a square occupied by an enemy, and was destroyed. The piece is removed from the board. - BOTHDIE The piece landed on a square occupied by an enemy, and both pieces were destroyed. + KILLS RANK1 RANK2 The piece landed on a square occupied by an enemy, and destroyed it, moving into the square + DIES RANK1 RANK2 The piece landed on a square occupied by an enemy, and was destroyed. The piece is removed from the board. + BOTHDIE RANK1 RANK2 The piece landed on a square occupied by an enemy, and both pieces were destroyed. ILLEGAL The moving player attempted to make an illegal move, and has hence lost the game. The game will end shortly. +

If printed, RANK1 and RANK2 indicate the ranks of the moved piece and the defending piece (the piece who occupied the destination square) respectively.

Additional Turns