From 2ab27eb698cfd57977cc9cc25edcbfbeb3b1b1ee Mon Sep 17 00:00:00 2001 From: Sam Moore Date: Wed, 30 Nov 2011 12:36:18 +0800 Subject: [PATCH] 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... --- manager/controller.cpp | 53 +++++++++++++++++----------- manager/controller.h | 4 +-- manager/forfax | 1 + manager/images/piece10.bmp | Bin 1322 -> 1330 bytes manager/images/piece11.bmp | Bin 1354 -> 1298 bytes manager/images/piece12.bmp | Bin 1370 -> 1162 bytes manager/images/piece13.bmp | Bin 1374 -> 1114 bytes manager/images/piece2.bmp | Bin 1238 -> 1094 bytes manager/images/piece3.bmp | Bin 1306 -> 1414 bytes manager/images/piece4.bmp | Bin 1310 -> 1338 bytes manager/images/piece5.bmp | Bin 1258 -> 1370 bytes manager/images/piece6.bmp | Bin 1246 -> 1226 bytes manager/images/piece7.bmp | Bin 1342 -> 1382 bytes manager/images/piece8.bmp | Bin 1206 -> 1270 bytes manager/images/piece9.bmp | Bin 1282 -> 1214 bytes manager/main.cpp | 69 ++++++++++++++++++++++++++----------- manager/movementresult.h | 34 ++++++++++++++++++ manager/program.cpp | 17 ++++++--- manager/program.h | 2 ++ manager/stratego.cpp | 42 ++++++++++++---------- manager/stratego.h | 7 ++-- samples/forfax/forfax.cpp | 19 +++++++++- samples/forfax/main.cpp | 9 ++++- web/index.html | 7 ++-- 24 files changed, 189 insertions(+), 75 deletions(-) create mode 120000 manager/forfax create mode 100644 manager/movementresult.h 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 cfeda8a32d1e402e4ddd5bf8872a71fb1bfe0e39..cf77ed49ee52d4408c156a7a666200e1dcd4d674 100644 GIT binary patch literal 1330 zcmd6lOKVy|6vzKF$@RvYTyyiP-X?AH(j+Fajjes9wVIU(S&N8*8y9L6TnHk9f?vR$ zxbO=IE?l?}UFgQ=ce3}9P)Z!zW&UtxhVwgTICJLQ-8(sGauVQNIUPP4!J6jBD)6wb z+b_kV+I&9O*lae#WHLcMpNGw61IKX?MG+p42aQGp)9DmGpAQa)1MzqqR;v{zlL_s1 z8|88tu~-bl;Sh;L0@-X9g+c-0a2VBU6{FDzcDo&^R0_Rb4_>bqE|&|PP6vTN0D>T( zUaw;?7@*Z^A(zWRk|fBojApY5qtS?3t%hJQh*GJ9VzG!yrGj)i4W8%G@AoktkC99! zVK$p#Fc=UDh0yJG;rIIyjYg5lWMHvaKq-aW?M5UL(R=dJSF%ulswT>do=F*iC;cz~ ze*0tdr`xDswIKhK>+=_S@b#OZMl9erH!5&)9~oSAD|-Jyja!hfQA)3gV=2ERSIhYM z1+laE%E_tKM$Tjwmky5z;g1!}s_)><+jlBvaVo#wU&`qou`u%Yw8p+7W(MEdRswc5 q$S#8m>l>nIBAXI})0I`uz^~~a%Ow|K|Ug&!;(jf%|XDR$Kc3 literal 1322 zcmdUtO>0^~6o%h3_g+o!wI;RsFfq+%V^fo~CMM>qA_Npfg5biXisC{cuJsSN5kwF{ z5M8<#T&Nqtg^2o}%xDsV*FqLuq)pY1#wVPP7F2s|iH z=HQWujmP6D8;wR73qPtq=qOMxzngY!>x;9UhMddc7W6trlLd z7rkB&l}ZKSa2Sj+M59pz0s-W5Iiyl4h@yy0CIhF_iF`f}o6UwqB7xy>2#rRAVzCIf z+YP(jj#{k-v)K%tPKQ>jg;*?xP$+~>rvq7*5s$~w?RKFk3M5HFqtQSl5`o|EN4wod zzu$+?=Yz}TLZMJVI-N!`nMAYMM5$DQ!!ddF2N3;LuZa_{^qly|zv!R2;eyD1d2%Jw z(e=&kAEH$Qn>kkEC2ui diff --git a/manager/images/piece11.bmp b/manager/images/piece11.bmp index f4ebeb2c867a5a6b435191b45a9e3ba6e8292599..b006d3d6959103121fee30d248ae54aac5149ced 100644 GIT binary patch literal 1298 zcmd6lO>Y5F6o%h>4Q0^kw5Cd{`axAc^t%f?5^TD$vhWjh!#@yviG{?5#DYX(gOw%X z`#%x1G0 z#^W*4=``GKH*`83EEWsG;V>GF21cV10)YT{o`=upgTvu~!C*k8Qb97AL@*dcx7$Uj zRDvjq@OV6!PN$emCh+_H==b|56bfjyT4=Z1$Ye68)oKs~0UXDn*XyCv>7ZV(Bb7=a z9*-jyiy@oMA{vb%pU)!_iJ(|4VmKV4TrMLN3Slr9AdyI**=(X(t-@?J!|8M)m&+~A zyz4tr)!$zesv_xvSNb16+gpwKWbKsxxAza}+C4W}}74YX9 zIQ89YSOJrAKFfOVY%EAp=hSn1vX$Gd?ya11mp5|3hW_-L2wORIU0$&Qh5y_s`)nq1 zp~`Kic9wS#a;D1Zp>Ra$v6YDO2^IY*Z#0?r2|2JZyK+9I8cwU*(;H;0#us3@EBmkE PHUH}2ti{#q+v)fV%pO*> literal 1354 zcmdUuy^j)M5XPU`y@f^axbp)~J@r7;6Hynz4@5mhE+Ll)4I$JtR1zp@pn*U|LrEZn z5a=ifAyiQC5d!>AxVs!-5psC-2U>e_U{obwR+X7@b@iftT~x1Ac0k zb}nWlTPzkbo6qN%PN&G_a`1ROFc=KrI1UWMz~yqGTCKupG{WokqFgRxJRYOjY$6;E z!)~{uP$(dkN}*ILL8H;YVzHpp=|HE`As7rIkx0N~G9eHMfMr>9yIo8s6KJ(s*lacw zi$&Dyb%a78}VM>?H`!{LC>=fhwyK(E(BJRXN$uLsZbFq_S2G#bmd z`q#bq5IeM)|)6`@7k5dDCy_zdxc6PT`~A`tR|WfqZGPv7?ymT~``etkp{AS5f?KzD^fSygE$OcBv-$%y9q#C7 c7F_}eU6d?Sa<=?pdc24y`_bvg?BQmMl6&Kq_W6^ zH#^I>48!a^p1y)szKD0>+s6b|WI}?!^v+jtZCuxNLr_%}f*^ox+enfGVHhIIGQ@F= zJkP;7hhZ2nO%r8VB8nmuMFG$A;5ZH}%Yy5=NYk{fH~T=78rmi{AsX@h;Yf5kU%JO* z&e&F?U0-U7Go6-FzWH5lwGqzCV|I;@o&dLA%k$>6GVH0PUy#Ye( BCi?&Y literal 1370 zcmd6l&5xOJ5XZmsJnOA&wcFCFrCY_WcB@-jPhaSZR!gXZ8xa@8sV6r_iMw!j5Q#*P zkT{Sy5FuXvC*{$nr6j%du#?RECi9t@-()iG?-3Dri4btH^3HxKLCVK*1pJV1)VGSP zb-7&fY_V8iKA)pdC?FUNLZ{O~CX<0>S%^d;wA*c1tyb9WcI5MU42MJXdOc(^8K_h$ zOs7*c8Vx9wN+gp>7z_ps1_O-8W9apIxLhvOYBewngKoErbUKZ4xeTw@i&m=zv)K%d zMuXXGhJL>fkH>>*wTf^!jL~R>R4N6x+YN`q0gmI4NF*?sOi(J75RFC=kH^t$HW3H} zkj-YHP$(c4ixCQi(CKs_m&@UFI#DbZ5s5@lsZ?OGSdh!*;Pd%lGMP}X*Wvg3A(2R+ zR;yvN*$|7xHoLp-mJZ6FscE(OJy{)!ApeCMkH2U*&)09>E0+K3um0~1^x>nDHJ*PW z_vdxOE_ZU|GV*msDZSd`Z{E_oOH5-SYrOkEAK5kA N^ZnyKg*&{4?@!Z3Yt8@w diff --git a/manager/images/piece13.bmp b/manager/images/piece13.bmp index 0878912192750045445f6f1924eb4799133bac61..f822c241c48e20bcdb334d1cd8fda8e99caafe3b 100644 GIT binary patch literal 1114 zcmd6l$qfQA3`KutAwe|3k^6MOeHus)l);G#!kunHE3^#KP)>4-gf;aN4vyw{uN!n?{srZXa0XX_P)Wa6B+;j literal 1374 zcmdVaJ#!L47zgnGbA*=&0zwP|q7f8xAmZC$1O-GuWpD;4DN+Cfl_eAuq)3yYp`u_i zd;tauN}vOVBIG;8y~~S2j><-#ncdmh-|e%{?CxCb$DtBZ91^h4MtfI{ppoXW1^m=r zwiKHY+r`C&WasDSI6gi`I-Q1EtwyuiM5oh1C=^1uT!zo*!*aPqBocww>qVo{fI^`_ zx7)>VID|%{fz@h7JRZl<(Gh~dAoO}Y^7%Y6nGATIM>3g2EEYqdPyi8OFc@GuokFM6 zq1WqSG#WvvR3ewlp<1m%rBY!$9^>rn3=W3_?RFdeejlY$39VKOE|&}8a2N)I0rUAB zfj|JKr>CgZYA~5hSS%Lscs#J%?Z{@cs8lLAIXOYSUdLoIfz4)v+wDdokw7Yyg4t}w zY&L_@XoTPIM>HBmu~>v42$$#gulMXwW#V_$#K{DEEZ6bZuJ}rHu+294<`ui|teTzG z{IM_ZnZzx-VkLZnlH95b5(q?2@q;LRUUU6Jab1KALD6kwU-SE-e332$`m0e#?u zp^g5INZ_0SR;YabSM>S~$Gz2W@E1frmiwh&E5F`K&-a=09~!U7mk<(Zk$)QmiNMqoGrLlQ&)!ve$qKmkUOAdtW+j|k5}Di3l!(0?ETtN&mg e2gzdiA1sDUfPw-FAR3S*(ex8YpD=R7s22~a6t$g6JyY| zuVV*lt;wL>xM)vuCnVo+?%@ve_P)p<(Son9ysE1rjlw%`D2MkczS+W_YwRx(jV58F@YDUx`9Q0PN#d}_m#v(=>P41ceRTb zZf>`7DwoSD(N>=1zb@_O?D7}B8p786j9ujU9)TCv^E*@0_z@i!V($})WRV|a`1xk} XRmvU`rTWM3ZfLWA%HPTF_J7bP)#N?B diff --git a/manager/images/piece3.bmp b/manager/images/piece3.bmp index 4209648f0382661bfa3d6f5bd8a37906de070a43..40ca3f83243022110e8927558f78138512e5519c 100644 GIT binary patch literal 1414 zcmdUt-EY}p6vw}ws+CfEQC73fY^#^q46D7VcC~q%+GZ|XAw=RvA`&iKiG-F2NfUZe zH=R--EJ3F zs}&xP2gPC$d_Et+U=YX0$51E~Xf~Vhdc7D722iWj2m}IXG#U^Jg$RX05C{Y)m&@q) z`!E`fsMTs&IJj8G~ghr!5DwRSk7K2nOh0o`M-EK!FlR-M229L*sQmI6}UPqx& zz}eXuSS%LIW;5FDHhR4t^m;ww@i=rk9b_^YB9RE(Za1RQD2|Sfkj-XcFc{G3bRdyP zkjv#jr_*tIdWwUC12`NGoS&b=WHKRV6FUp~Z%QX%-@)1X6DPzjo9Cu=^R9(# z%B>qV3VoH&^KAp!*(Fr{PkTl}wm*NF>%S$|ao$cidH0@>4c`&X05E%sDeZVqOIsc?n$0UEt0L%f^o*;HUl8zDv*A zR;$&9EtgAFt5qZt2{@fj*laeq-EIVfL8MYC^m;wy^LeydEsRDZWV2ZaAyBW^(d~AT z%jIA)nJ^p<(P%U<9*he?+Zm#z=| z_|AyC$j9qIPl)f0xciQax1>z4lm9n=O};tAgQVvG4_xtj-}x`k&R_X>ak+>4{3oO( zAnD%x&rgqiFAi`ayi}jE=2jko#6_i)*n&qKHsZ}2+hANwEl3mm6ZA^-pY diff --git a/manager/images/piece4.bmp b/manager/images/piece4.bmp index 63161fb91013e20a3492aeecd04326842b39e3e4..0a27a46897b10c6084abcba4221d0368f6215d72 100644 GIT binary patch literal 1338 zcmd7QzmF0@6bJC{n*)KxMG((D&pYInQ_)r75Pt!3YC%CF4GAR$6(JD{{sCwRG!zsx zbc6;%2sE@Lgh2T5KjH2IYHrtPc`uor$$Z|M*}TlR?;#`92od0wSML2FnALq4fFIV~ z_$u!xW4qm|w%Kg3SS(N|6c7%F5sSs(^Z5{u$1xlZF`v&73|TBkW40Fu~^V* zwUEhV&}cN^a5&&}Ix(3{V6|E?olcQRB+%(}U^bgkEEdshHo+J}rBVUMap-ot==FN2 z*Xvj=mk2w;^Y86JK5$p9DwOS3OQVAZ92cjs#<#HjL%_5abVK$q=ZnvY|ZX=)1 zBNBVz-F_dTrPv>c?1Fhj7B5maydwnglII1e!su#&29gZZv6ghlDn!2 z`5_$Q|NM)E|ML({z58?YTJ-)((KuuLr%*U@NYHV{K3skb>=SgIUA((`ze~_}_LhQw zcj4IUzoOj@+Imr<)7NiK$fq8l@fURdlIPDPdZp|9B|TN(89i5MiG2V91uCnHS#*Pfe WJ0`Pb$2z_T9skGsJiNnOIR6A?Ctf`O literal 1310 zcmd6ly>CHL7{;G-d#M)fZPi6_dv9B#m6WH6N^M7 zgaQAPUKb_TN0$zLllPpH^Lw86e13j$3P`~bz%GvXSrVwEdC)*aJ-Es>cH#H?5s5@lE|-zZB(my@lZ{`zn z@bLH}kozTY@7m7qoXlLX*6$#<+qhjIH`}<4T$!$Cf;IJdft+7lZsrzZWw^7AoHY?W z#hjX_g4OzZa>7!S!MK4lN90&Ux|8V@toSuVdoZycYNP^kzC#m*a+ji1d;98%K+Yx8 PQnSo|`JeND_z(MU;Wk)} diff --git a/manager/images/piece5.bmp b/manager/images/piece5.bmp index 9163c1235ff19392b556aadd2ce18c94753db693..051bd432f840b8cd2a659ca080ea673bb0aba9ab 100644 GIT binary patch literal 1370 zcmd7QzmF0@6bJC{%&~}zf+w7!o{FBr33w_eAR->3fEFZ#@@NPR2|+5LfrN^Nf&@wu zAp8mqH3i`s2!vn%6S9j$lU<_ay=3NX<}+`1@^;+*O9p&g65w?6r2RbzWc)fLz)$&h z{Mf8;W4&JUwpy*QSS*muW?{G6;q`jqa5!KxnUKk3uv{*o)9G+^b%j=|1({5SP$-0Q zxr}^1k3b**N-2iJA)?VJ3WWl?-7Zq86r4^c+-^4%3I(RqDF%Z9lu9KckqGMbI*P?2 zYPA|zmW9jZLZ{O~yWNILr9wCy#(X|UsZ@f&V1UhL!)P=@I-Q1Etwz7!2g5M1SS+Yi zDo7@is8*}U<#GrHgJ?FJ@cDf3`~B$kdhmEWh{xlY&1Nv0&5+CGXfzrakH;_?jYuRC z(ChWETCIr1Vwg-O+umLGnTW=pQZ^?-JI3zHoh^)P3>w znA;$932}08PR_*rBhhl;AfLqDMm}($A$D;;C+|04IU!bYr)O{8vYL0qe6YugwmA|e)IXS+-x>m z!D_X_a=C=#ILPI4D3{Afr_-p_YG^bX&~+X2`5eV!5tT{>sZP17(Qk1?H2QLR>?sw!r)8CtCt27>_%!$7;;MkbR%v)M$a z(?K$sM4?bXB9TC;RDx~W$mjDI4u@{P2VY1S`?iS*g8tuQ6o3Et{PHdnoFB6k#)8p+ zyFlPCVJ@%qCUcWRBudXRXDs~qM4BOW{hlcF;4%~3e{)OPou^FXA@W}_b}ik1e!=N7 jDD{(5{`51sE54&+mHg8E9_*^1|AX~E{^$ND9^B{`9UevJ diff --git a/manager/images/piece6.bmp b/manager/images/piece6.bmp index 321bf557d21a756277fd6495e7321e0354eca1bd..5ca389b1fa7d5e8701303f37b7742f336d537718 100644 GIT binary patch literal 1226 zcmd6ly>fy;6ot=jgqRpeLVh7Xn1l=zFf@*pW05{DVPV5$Xm|o%z|J?Yv9N#{hY~E+ zcOomOOvW9GRGyi8_wIgo&)#CczLyOYTC!}hXm5j{$totse_CaHvh61FJl_zk*K3SM zBXql6^m;u=k_6kf;kqtN(?k#ih~pTYP6vy{0$~_pKA&Se9wSK-^!t4{j)N@AAc`V< z-$xWhuq+E{nnDl+c%FyZYzD(HFdPmsolc?aI##O{27>`6lL<6UE9N=+M7XNPCX^%c z53U$*dnev~nS9i8ReP`HRB7)Y;Q3RT=sN>0SGCt#PL-E>E|ceN1J|Fb+EXp3%40p3 z$wS$|_ouga_k4bJU7jm9eBQc{3LulqVma5cf{2%wY51> literal 1246 zcmd6l&1%9x6ot>7q=~Jut+7qp^d~m`vvnni574ay-Q+R4%_6ViLK1MHxDFU_W3q4= z&}Z;f?8Fwb8R({q95|Od^TFlJa6g@$jDvQ(wz!+WCRBLG#raqD#~=Kdd%xf31l#Qv zS(afu9>aBAwA*cLHXHc957RUu%QCv%F5);w5Cm`>2Zmu_Fc@Gs9K!QFbUGa@mrF>J zgfI-TUaz4j3RbHX(lmvpX|OB{^Z6XMZDTf@AxRQMQ3O?0q3b#(lL>mg9{T-0rqd}F ziv>ob(II2$3kg-kCMFR5JAZy5dVOoviIjK71oI!sRvA;DsK)aMc$04Ppbun;xmgZ= zNB81<7j$Vbc6CiRLS8$iv-7&%pa#c+_e=7TqE?Pis+ySRw}k}%S3usCiT|;m#U_@n F`v%h^LH+;$ diff --git a/manager/images/piece7.bmp b/manager/images/piece7.bmp index e69019073f57cc07d1de541fddb21f0f42beb541..aaf28a105c96d5c5b08104cc55801babf4ae235e 100644 GIT binary patch literal 1382 zcmdVZ&5Ke|7zXg?y*Xx%I!>0BHItd;*qDudm+6$1meoSHZWP3Y&_ZzQ%8e^QQBW76 z;Kq%JiV7}7XH@+7pX}aiQ;>I}Wxa4Nm-Bnx!?}lZonOOS;44hP0sE%=F$fZV9wOk| z_Ii9_XSlIit$155mzYc@=ytn^L?UoF9Ps=7NTpIZJv~Jr5P(D?K`OTt=hOfXCy3!C*ilk$}Zwfm|+!R;z{2=R>E{!D6w1 zQmKSmtwuZ^N3B*vp-_O`Zih;xLaWt6uh&B+lfisGht+C@)9FON-$y!~2E#BoIXOYS zUdL!OLbX~&yWNINCPS%If?lsjKA(p|p+K|QL?{$OI2^`!JO&X#qtReGog$mfA{vb% znM}fLHe)uMp;D>9WHQ0!a=~V^Ar_0R&+%V>vL7Z;zjjURscjT{Y0m1e-7Wt3$@AI8 zuO-m`{%HS@v3?NqflU|f?7d}Mo%D`dVAEfdodd`58=auPpqHF8ugE6kkBOf0{*0ar z`6HrT&e_}(AvX|NIDbe-Rv|YL-Dl?y&GdkaZR}rnoAh@Kckhw$K+u_MbX|Mn=HC7- zjyL-mHIas=bDX(CSO4g{mr3N}S<;T*Ws%pe;OfA-E3POyJ`hyYO`srw0!V16prNs*BZPv4777v? z3K|kx5)vvN;Su0}!pqDWO}um#`X%RPa({E~`OcY}xrv7lp(#v&mp>`DK{(R(aR7X0 zdff1xU2L~ojcqm?)a!MqstQ?_K}7I+y(kuoNG6jQ4u@E+R_Js(2!%qhSS%QgMlc$U zu-olOBobIImuNPdP!t8T*$fVc1O0v-v~8`J3&CX)%3N(Jln8uR%ai^T%9 zS`EQq5Z!JUHk%ESBq5znV>})sm&?KBa-rAjArJ__YPBMjN+FxgA|8*!?RLZG^P$mb zAR3J#7K>pp7{KH4pj0ZMP$-2<*Kdz`HNp8o3K^L6@e_S!LjLab{mv!}&<7z`-{@Vur3)c{ zrDOJ*R3X2`FNys7`I(RC#qmDweP$-Qe$G!4^e0J%OQNf%C%Zx-?vaTup6E6N{NXv7 zAMIwRxP|!-hzwe?(jRuCpA)HPp2qEb8ddOrl;CUXRC?c6mVltUvFc_dvC?J(eVLF{ck|dPN zWz1$Xlu9MYvW#}SjZUY7VzCHCQ6LBcy4^13^Esl?DC+e(D5Z$U^$3msEazEh5zd3}BZn>jrZ)=Yhx{PdX9PexanIX&{Q jYtDHs`Jq!y=yGd<9e&+-;IQYq>Q6p(tf@BlZ;yAsv-3|2 literal 1206 zcmds$J8pwO5QhI)U3Eoi^lO$X1;(%;&}X&S_F499U` znkIrEKv|ZsEDMUFpsFf(o(Emm;rl)e!$46K$g&J+nj%ROXqtw)u3_6YR8>Wu=UA`T z2*VJ9ARvk&xULJv7(`KoEX%vvzur;9Bigsk_=wnmKR!{8#qxQ%pg7@t$T`1Zw;Cmy z-`zh*V_ahAT^;p$KJvcu#kp{GoL^iX=Tzsgzi;{fC6}1oo$odr?tjM4#QlOHpG@hy Xo(QM?iXrdk`}mW5leTL5{b9dslXh})a1mDr!J(_G;NIQQDWh}n2ROJmIwekmp#RBU zO^YEh77B&Da1KWw&bjYBYJ9B5XtiQlW-p~Po zEEWq8Lat62*VJRQh1(+IF6yJDvF{&p65uC1h#F%_k9FG0Mj&)rYU4u zMwVr;EDM^Z!Eqc2f`BNBpzAv3^Er5)Z#^7*VoT{!XPdC??1=n{zm0ze_4of9pLRE# zwHCI{e|nZ0krzpN?c?_kkIn1Tz5ee+evs3f+hKmiT@THt^!(y-;CwdxY&6VyVY1&p m>!&B&@!tD2oF4tc>1epW9kNba``;kDy!&<=RrmiLaP9;TnG|S5b45aa1jvd#=Q#>*RIr!YcC6* zK?N70?_?8WC`9YF_J=bJ=R0TS%$XVelQLL{5+GvE!b>CYFZ}QVUjf@R(_`6uK3}le zY=-G{igLM(cs!0oA^};J5sgOCY&J2OOpr>YpzAtDqY;L~Avlf$Aq0&^1BPKh6h&k* z8RT*~jK^cJEQ@S5i@{)kYPE`by^ef7k5Z|GN~MBWEQVgM2TCcr-7bp7A{0e|BuQwu z+eoL=Xti4CbUNU99-5}1P$;0^?<1K^LJ$Nn3g(J4hg0ZEeUAzuz9;2*8Q|ugJ8~~m8hnV@0d5{9*Ebg7ZrAfG60*T^bmw1^ zqm5i57aRHU$*IN9&VzQCdwsfpV39*-n-$Il_#hQ__rzcFsmIIg`24Jmtq<$y&+m85 K>oouPf6zB)%}6@{ 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

-- 2.20.1