aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rwxr-xr-xcompetition.py34
-rw-r--r--viewcompetition.cpp125
-rw-r--r--viewcompetition.css76
-rw-r--r--viewcompetition.js255
5 files changed, 416 insertions, 77 deletions
diff --git a/.gitignore b/.gitignore
index ccdaa2a..321bcea 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,13 @@
competitions/
playerlogs/
+gamevisuals/
gluon
neutrino
randino
photon
+viewcompetition
+
*.o
diff --git a/competition.py b/competition.py
index ab72d20..2582288 100755
--- a/competition.py
+++ b/competition.py
@@ -12,7 +12,7 @@ Options:
-C Do not write a Competition log
-h Help. What you're looking at
-q Quiet. Don't print so much
- -v View the competition afterwards using ./viewcompetition
+ -V Do not view the competition, so don't write an html file
"""
import os,sys,subprocess,shlex,re,time
@@ -115,7 +115,7 @@ def haswon(board,lastplayer):
fname=""
quiet=False
-viewcompetition=False
+viewcompetition=True
complog=True
if len(sys.argv)==1: #no args
fname="competition.txt"
@@ -129,7 +129,7 @@ else:
print(__doc__)
sys.exit(0)
elif c=="q": quiet=True
- elif c=="v": viewcompetition=True
+ elif c=="V": viewcompetition=False
else:
print("Unrecognised flag '"+c+"'.")
print(__doc__)
@@ -179,12 +179,12 @@ elif not os.path.isdir("playerlogs"):
sys.exit(1)
try:
- logfname="playerlogs/"+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+"_white_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+".txt"
- p1errlog=open(logfname,mode="w")
- logfname="playerlogs/"+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+"_black_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+".txt"
- p2errlog=open(logfname,mode="w")
+ plogfname="playerlogs"+os.path.sep+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+"_white_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+".txt"
+ p1errlog=open(plogfname,mode="w")
+ plogfname="playerlogs"+os.path.sep+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+"_black_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+".txt"
+ p2errlog=open(plogfname,mode="w")
except:
- print("Error: could not open log file '"+logfname+"'.")
+ print("Error: could not open log file '"+plogfname+"'.")
sys.exit(1)
#Start programs
@@ -222,7 +222,7 @@ elif not os.path.isdir("competitions"):
sys.exit(1)
try:
- logfname="competitions/game_"+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+"_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+".txt"
+ logfname="competitions"+os.path.sep+"game_"+re.sub(r"[^a-zA-Z0-9 ]","",p1fname)+"_vs_"+re.sub(r"[^a-zA-Z0-9 ]","",p2fname)+".txt"
logfile=open(logfname,mode="w")
logfile.write("P1: "+p1fname+"\nP2: "+p2fname+"\n")
except:
@@ -299,6 +299,8 @@ while True:
if not quiet:
print("P"+str(player)+": "+movestr(move)+" ",end="")
sys.stdout.flush()
+ if complog:
+ logfile.write("P"+str(player)+": "+movestr(move)+"\n")
won=haswon(board,player)
@@ -315,8 +317,6 @@ while True:
except: pass
sys.exit(1)
else: raise e
- if complog:
- logfile.write("P"+str(player)+": "+movestr(move)+"\n")
nummoves+=1
if won!=0:
@@ -350,4 +350,14 @@ try: p2proc.terminate()
except: pass
if viewcompetition:
- os.system("."+os.path.sep+"viewcompetition "+logfname)
+ if not os.path.exists("gamevisuals"):
+ try:
+ os.mkdir("gamevisuals")
+ except:
+ print("Error: could not create log directory 'gamevisuals'.")
+ sys.exit(1)
+ elif not os.path.isdir("gamevisuals"):
+ #Apparently, there's a file named "gamevisuals". Bastard.
+ print("Error: an existing file prohibits creation of log directory 'gamevisuals'.")
+ sys.exit(1)
+ os.system("."+os.path.sep+"viewcompetition "+logfname+" >gamevisuals"+os.path.sep+logfname[logfname.index(os.path.sep)+1:]+".html")
diff --git a/viewcompetition.cpp b/viewcompetition.cpp
index 40ba715..3f15c29 100644
--- a/viewcompetition.cpp
+++ b/viewcompetition.cpp
@@ -1,111 +1,106 @@
#include <iostream>
#include <fstream>
-#include <limits>
-#include <cstdint>
-#include <cassert>
-#ifdef _WIN32
-#include <windows.h>
-#else
-#include <unistd.h>
-#endif
-
-#define SYMBOLFOR(p) ((p)==P1?'X':(p)==P2?'O':(p)==PNONE?'.':'?')
-
-#define PNONE (0)
-#define P1 (1)
-#define P2 (2)
+#include <vector>
+#include <sstream>
using namespace std;
-uint8_t board[81]={PNONE};
-
-void dosleep(int ms){
-#ifdef _WIN32
- Sleep(ms);
-#else
- usleep(ms*1e3);
-#endif
-}
-
-void printboard(void){
- int x,y;
- cout<<"+-------+-------+-------+"<<endl;
- for(y=0;y<9;y++){
- cout<<"| ";
- for(x=0;x<9;x++){
- cout<<SYMBOLFOR(board[9*y+x])<<' ';
- if(x%3==2)cout<<"| ";
- }
- cout<<endl;
- if(y%3==2)cout<<"+-------+-------+-------+"<<endl;
+struct Move{
+ int neudir,from,dir;
+ string str(void){
+ stringstream ss;
+ ss<<neudir<<' '<<from<<' '<<dir;
+ return ss.str();
}
-}
+ string json(void){
+ stringstream ss;
+ ss<<'['<<neudir<<','<<from<<','<<dir<<']';
+ return ss.str();
+ }
+};
+
+const char *html_string[5]={
+"<!DOCTYPE html>\n\
+<html>\n\
+<head>\n\
+<meta charset=\"utf-8\">\n\
+<title>Game</title>\n\
+<script>\n\
+var S=" , ";\n\
+var PLAYERS=[" , "];\n\
+var MOVES=[" , "null];MOVES.pop();\n\
+var WINNER=" , ";\n\
+</script>\n\
+<script src=\"../viewcompetition.js\"></script>\n\
+<link rel=\"stylesheet\" type=\"text/css\" href=\"../viewcompetition.css\">\n\
+</head>\n\
+<body>\n\
+<h1 id=\"header\"></h1>\n\
+<table id=\"bgtab\"><tbody id=\"bgtbody\"></tbody></table><br>\n\
+<input type=\"button\" id=\"prevmovebtn\" onclick=\"prevmove()\" value=\"&larr;\">\n\
+<input type=\"button\" id=\"nextmovebtn\" onclick=\"nextmove()\" value=\"&rarr;\"><br>\n\
+<div id=\"movelist\" style=\"margin-top:30px\"></div>\n\
+<div id=\"status\" style=\"margin-top:50px\"></div>\n\
+</body>\n\
+</html>\n"};
int main(int argc,char **argv){
if(argc==1){
- cout<<"Pass the file name of the competition log as a command-line parameter."<<endl;
+ cerr<<"Pass the file name of the competition log as a command-line parameter."<<endl;
return 1;
} else if(argc>2){
- cout<<"Multiple command-line arguments were passed."<<endl;
+ cerr<<"Multiple command-line arguments were passed."<<endl;
return 1;
}
ifstream in(argv[1]);
if(!in.good()){
- cout<<"Cannot open file '"<<argv[1]<<"'."<<endl;
+ cerr<<"Cannot open file '"<<argv[1]<<"'."<<endl;
return 1;
}
string p1name,p2name;
- int player,x,y;
+ int player;
char c;
+ Move mv;
+ cout<<html_string[0];
+ cout<<5;
+ cout<<html_string[1];
in.get(); in.get(); in.get(); in.get(); //"P1: "
getline(in,p1name);
in.get(); in.get(); in.get(); in.get(); //"P2: "
getline(in,p2name);
- cout<<"\x1B[2J\x1B[1;1HCompetition between:\n"
- "P1 (X): "<<p1name<<"\n"
- "P2 (O): "<<p2name<<endl;
+ cout<<'"'<<p1name<<"\",\""<<p2name<<"\"";
+ cout<<html_string[2];
if(!in.good()){
- cout<<"Error in log file format."<<endl;
+ cerr<<"Error in log file format."<<endl;
return 1;
}
- cout<<"\x1B[4;27HPress enter to play next move"<<flush;
- cout<<"\x1B[4;1H"<<flush;
- printboard();
while(in.good()){
c=in.get(); //"P" for a move line or a win line, "T" for a tie line
if(c=='P'){
player=in.get()-'0';
c=in.get(); //":" for a move line, " " for a win line
if(c==':'){
- in.get();
- x=in.get()-'0';
- in.get(); //" "
- y=in.get()-'0';
+ in>>mv.neudir>>mv.from>>mv.dir;
in.ignore(numeric_limits<streamsize>::max(),'\n');
- board[9*y+x]=player;
- cout<<"\x1B["<<(5+y/3+y)<<';'<<(3+x/3*2+x*2)<<'H'<<SYMBOLFOR(player)
- <<"\x1B[5;27H"<<SYMBOLFOR(player)<<": "<<x<<' '<<y
- <<"\x1B[7;27H"<<SYMBOLFOR(haswonsmall(0))<<SYMBOLFOR(haswonsmall(1))<<SYMBOLFOR(haswonsmall(2))
- <<"\x1B[8;27H"<<SYMBOLFOR(haswonsmall(3))<<SYMBOLFOR(haswonsmall(4))<<SYMBOLFOR(haswonsmall(5))
- <<"\x1B[9;27H"<<SYMBOLFOR(haswonsmall(6))<<SYMBOLFOR(haswonsmall(7))<<SYMBOLFOR(haswonsmall(8))<<flush;
- c=cin.get();
- if(c!='\n')cin.ignore(numeric_limits<streamsize>::max(),'\n');
+ cout<<mv.json()<<',';
} else if(c==' '){
- cout<<"\x1B[17;1HThe victor is player "<<player<<"!"<<endl;
+ cout<<html_string[3];
+ cout<<player;
+ cout<<html_string[4]<<flush;
in.close();
- dosleep(1500);
return 0;
} else {
- cout<<"\x1B[17;1HError in log file format."<<endl;
+ cerr<<"Error in log file format."<<endl;
return 1;
}
} else if(c=='T'){
- cout<<"\x1B[17;1HThe game resulted in a tie."<<endl;
+ cout<<html_string[3];
+ cout<<-1;
+ cout<<html_string[4]<<flush;
in.close();
- dosleep(1500);
return 0;
}
}
- cout<<"\x1B[17;1HLog file ended prematurely."<<endl;
+ cerr<<"Log file ended prematurely."<<endl;
return 1;
}
diff --git a/viewcompetition.css b/viewcompetition.css
new file mode 100644
index 0000000..0fc53f5
--- /dev/null
+++ b/viewcompetition.css
@@ -0,0 +1,76 @@
+body{
+ font-family:Georgia,Times,Serif;
+ font-size:15px;
+}
+
+table#bgtab{
+ border-spacing:4px;
+}
+td.bgcell{
+ width:80px;
+ height:80px;
+ border:3px #ddd solid;
+ border-radius:12px;
+ transition:background-color 0.6s ease 0.2s, box-shadow 0.6s ease 0.2s, -webkit-box-shadow 0.6s ease 0.2s;
+
+ text-align:right;
+ vertical-align:bottom;
+ font-size:14px;
+}
+td.bgcell.win{
+ background-color:#8f8;
+ box-shadow:inset 0 0 6px #6e6;
+ -webkit-box-shadow:inset 0 0 6px #6e6;
+}
+div.fgcell{
+ position:absolute;
+ width:82px;
+ height:82px;
+ border:3px rgba(0,0,0,0) solid;
+ text-align:center;
+ transition:left 0.6s ease 0s, top 0.6s ease 0s;
+}
+
+div.fgcell > div{
+ height:75%;
+ margin:10px;
+ border-radius:30px;
+}
+
+h1#header{
+ letter-spacing:0.5px;
+}
+span.celltypeclr{
+ border-radius:5px;
+ padding:4px;
+}
+
+div#status{
+ font-size:16px;
+ font-weight:bold;
+}
+
+div.fgcell.celltype_1 > div{background-color:#ddd;}
+span.celltypeclr_1 {background-color:#ddd;}
+div.fgcell.celltype_2 > div{background-color:#2a2a2a;}
+span.celltypeclr_2 {background-color:#2a2a2a;color:#eee;}
+div.fgcell.celltype_3 > div{background-color:#11e;}
+
+div#movelist{
+ border:1px black solid;
+ width:500px;
+}
+div#movelist table{
+ border-spacing:0;
+ width:100%;
+}
+div#movelist tr:first-child{
+ font-weight:bold;
+ background-color:#ccc;
+}
+div#movelist tr:first-child > td{
+ border-bottom:1px black solid;
+}
+div#movelist tr:nth-child(odd){background-color:#e4e4e4;}
+div#movelist tr:nth-child(even){background-color:#fff;}
+div#movelist tr:nth-child(n+2):hover{background-color:#bbf;cursor:pointer;}
diff --git a/viewcompetition.js b/viewcompetition.js
new file mode 100644
index 0000000..ab05c3c
--- /dev/null
+++ b/viewcompetition.js
@@ -0,0 +1,255 @@
+var moveidx=0;
+var neuidxhist=[];
+
+var board=Array.apply(null,new Array(S*S)).map(function(){return 0;});
+var fgcells=board.map(function(){return null;});
+var neuidx;
+
+var canclick=false;
+
+function init(){
+ var tr,td,y,x,e,span,
+ movelisttbody,
+ header=document.getElementById("header"),
+ status=document.getElementById("status"),
+ movelist=document.getElementById("movelist"),
+ bgtbody=document.getElementById("bgtbody");
+
+ document.title="Game: "+PLAYERS[0]+" vs "+PLAYERS[1];
+
+ header.appendChild(document.createTextNode("Game: "));
+ span=document.createElement("span");
+ span.classList.add("celltypeclr"); span.classList.add("celltypeclr_1");
+ span.appendChild(document.createTextNode(PLAYERS[0]));
+ header.appendChild(span);
+ header.appendChild(document.createTextNode(" vs "));
+ span=document.createElement("span");
+ span.classList.add("celltypeclr"); span.classList.add("celltypeclr_2");
+ span.appendChild(document.createTextNode(PLAYERS[1]));
+ header.appendChild(span);
+
+ status.appendChild(document.createTextNode("Game won by "));
+ span=document.createElement("span");
+ span.classList.add("celltypeclr"); span.classList.add("celltypeclr_"+WINNER);
+ span.appendChild(document.createTextNode(PLAYERS[WINNER-1]));
+ status.appendChild(span);
+ status.appendChild(document.createTextNode("."));
+
+
+ e=document.createElement("table");
+ movelisttbody=document.createElement("tbody");
+ tr=document.createElement("tr");
+ td=document.createElement("td"); td.innerHTML="Player"; tr.appendChild(td);
+ td=document.createElement("td"); td.innerHTML="Neutron"; tr.appendChild(td);
+ td=document.createElement("td"); td.innerHTML="Stone"; tr.appendChild(td);
+ movelisttbody.appendChild(tr);
+ e.appendChild(movelisttbody);
+ movelist.appendChild(e);
+
+ tr=document.createElement("tr");
+ td=document.createElement("td");
+ td.setAttribute("colspan","3");
+ td.innerHTML="&nbsp;";
+ tr.appendChild(td);
+ tr.addEventListener("click",function(ev){
+ if(moveidx==0)return;
+ while(moveidx>0)prevmove(true);
+ });
+ movelisttbody.appendChild(tr);
+
+ MOVES.forEach(function(mv,i){
+ var tr,td;
+ tr=document.createElement("tr");
+
+ td=document.createElement("td");
+ td.innerHTML=i%2+1;
+ tr.appendChild(td);
+
+ td=document.createElement("td");
+ if(mv[0]==-1)td.innerHTML="&nbsp;";
+ else td.innerHTML=arrowfor(mv[0]);
+ tr.appendChild(td);
+
+ td=document.createElement("td");
+ td.innerHTML=mv[1]+": "+arrowfor(mv[2]);
+ tr.appendChild(td);
+
+ tr.addEventListener("click",(function(target){return function(ev){
+ if(moveidx==target)return;
+ while(moveidx<target)nextmove(true);
+ while(moveidx>target)prevmove(true);
+ };})(i+1));
+
+ movelisttbody.appendChild(tr);
+ });
+
+
+ for(y=0;y<S;y++){
+ tr=document.createElement("tr");
+ for(x=0;x<S;x++){
+ td=document.createElement("td");
+ td.classList.add("bgcell");
+ td.innerHTML=S*y+x;
+ tr.appendChild(td);
+ }
+ bgtbody.appendChild(tr);
+ }
+ for(x=0;x<S;x++){
+ board[x]=1;
+ e=makefgcell(x,1);
+ fgcells[x]=e;
+ document.body.appendChild(e);
+
+ board[S*(S-1)+x]=2;
+ e=makefgcell(S*(S-1)+x,2);
+ fgcells[S*(S-1)+x]=e;
+ document.body.appendChild(e);
+ }
+ neuidx=S*~~(S/2)+~~(S/2);
+ board[neuidx]=3;
+ e=makefgcell(neuidx,3);
+ fgcells[neuidx]=e;
+ document.body.appendChild(e);
+
+ setnextenabled(true);
+ setprevenabled(false);
+ canclick=true;
+}
+
+function arrowfor(dir){
+ return "&#x"+[2191,2197,2192,2198,2193,2199,2190,2196][dir]+";";
+}
+
+function bgcell(idx){
+ return document.getElementById("bgtbody").children[idx/S|0].children[idx%S];
+}
+function fgcellposition(idx){
+ var rect=bgcell(idx).getBoundingClientRect();
+ return [rect.left,rect.top+document.documentElement.scrollTop];
+}
+function movefgcell(e,idx){
+ var pos=fgcellposition(idx);
+ e.style.left=pos[0]+"px";
+ e.style.top=pos[1]+"px";
+ e.cell_index=idx;
+}
+function makefgcell(idx,type){ //type in [1,2,3]
+ var pos=fgcellposition(idx),
+ e=document.createElement("div");
+ e.classList.add("fgcell");
+ e.classList.add("celltype_"+type);
+ e.style="left:"+pos[0]+"px;top:"+pos[1]+"px;";
+ e.cell_index=idx;
+ e.appendChild(document.createElement("div"));
+ return e;
+}
+
+var index_deltas=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]];
+function indexafterslide(from,dir,overshoot){
+ var x=from%S,y=~~(from/S),x2,y2;
+ while(true){
+ x2=x+index_deltas[dir][0];
+ y2=y+index_deltas[dir][1];
+ if(x2<0||x2>=S||y2<0||y2>=S||board[S*y2+x2]!=0){
+ if(overshoot)return S*y2+x2;
+ else return S*y+x;
+ }
+ x=x2;
+ y=y2;
+ }
+}
+
+function setnextenabled(en){
+ document.getElementById("nextmovebtn").disabled=!en;
+}
+function setprevenabled(en){
+ document.getElementById("prevmovebtn").disabled=!en;
+}
+
+function displaycurrentmove(){
+
+}
+
+function nextmove(notimeout){
+ var newidx;
+ if(moveidx==MOVES.length||!canclick)return false;
+
+ if(MOVES[moveidx][0]!=-1){
+ neuidxhist.push(neuidx);
+ newidx=indexafterslide(neuidx,MOVES[moveidx][0]);
+ movefgcell(fgcells[neuidx],newidx);
+ board[newidx]=board[neuidx];
+ board[neuidx]=0;
+ fgcells[newidx]=fgcells[neuidx];
+ fgcells[neuidx]=null;
+ neuidx=newidx;
+
+ if(moveidx==MOVES.length-1)bgcell(neuidx).classList.add("win");
+ }
+
+ newidx=indexafterslide(MOVES[moveidx][1],MOVES[moveidx][2]);
+ if(MOVES[moveidx][0]!=-1&&!notimeout){
+ setTimeout(
+ (function(e,idx){return function(){
+ movefgcell(e,idx);
+ canclick=true;
+ };})(fgcells[MOVES[moveidx][1]],newidx),
+ 500
+ );
+ canclick=false;
+ } else {
+ movefgcell(fgcells[MOVES[moveidx][1]],newidx);
+ }
+ board[newidx]=board[MOVES[moveidx][1]];
+ board[MOVES[moveidx][1]]=0;
+ fgcells[newidx]=fgcells[MOVES[moveidx][1]];
+ fgcells[MOVES[moveidx][1]]=null;
+
+ moveidx++;
+ setprevenabled(true);
+ if(moveidx==MOVES.length)setnextenabled(false);
+ return true;
+}
+function prevmove(notimeout){
+ var item,oldneuidx,newidx,winGlowIdxToRemove=null;
+ if(moveidx==0||!canclick)return false;
+ moveidx--;
+
+ if(MOVES[moveidx][0]!=-1&&moveidx==MOVES.length-1)winGlowIdxToRemove=neuidx;
+
+ newidx=indexafterslide(MOVES[moveidx][1],MOVES[moveidx][2],true);
+ board[MOVES[moveidx][1]]=board[newidx];
+ board[newidx]=0;
+ fgcells[MOVES[moveidx][1]]=fgcells[newidx];
+ fgcells[newidx]=null;
+ movefgcell(fgcells[MOVES[moveidx][1]],MOVES[moveidx][1]);
+
+ if(MOVES[moveidx][0]!=-1){
+ oldneuidx=neuidxhist.pop();
+ board[oldneuidx]=board[neuidx];
+ board[neuidx]=0;
+ fgcells[oldneuidx]=fgcells[neuidx];
+ fgcells[neuidx]=null;
+ if(notimeout){
+ movefgcell(fgcells[oldneuidx],oldneuidx);
+ if(winGlowIdxToRemove!=null)bgcell(winGlowIdxToRemove).classList.remove("win");
+ } else {
+ setTimeout(
+ (function(e,idx){return function(){
+ movefgcell(e,idx);
+ canclick=true;
+ if(winGlowIdxToRemove!=null)bgcell(winGlowIdxToRemove).classList.remove("win");
+ };})(fgcells[oldneuidx],oldneuidx),
+ 500
+ );
+ canclick=false;
+ }
+ neuidx=oldneuidx;
+ }
+
+ setnextenabled(true);
+ if(moveidx==0)setprevenabled(false);
+ return true;
+}
+
+window.addEventListener("load",init,false);