diff options
-rw-r--r-- | .gitignore | 9 | ||||
-rw-r--r-- | Makefile | 15 | ||||
-rwxr-xr-x | competition.py | 353 | ||||
-rwxr-xr-x | fullcomp.sh | 36 | ||||
-rwxr-xr-x | fullcompMT.sh | 93 | ||||
-rwxr-xr-x | fullcompstats.py | 42 | ||||
-rwxr-xr-x | gluon.cc | 45 | ||||
-rwxr-xr-x | higgs.cc | 117 | ||||
-rwxr-xr-x | higgs.h | 31 | ||||
-rwxr-xr-x | neutrino.cc | 86 | ||||
-rw-r--r-- | randino.cpp | 169 | ||||
-rw-r--r-- | viewcompetition.cpp | 111 |
12 files changed, 1107 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2800b41 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +competitions/ +playerlogs/ + +gluon +neutrino +randino + +*.o + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4476c41 --- /dev/null +++ b/Makefile @@ -0,0 +1,15 @@ +.PHONY: all + +all: neutrino randino gluon + +neutrino: neutrino.cc higgs.o + g++ -Wall -std=c++11 -O2 -o neutrino neutrino.cc higgs.o + +gluon: gluon.cc higgs.o + g++ -Wall -std=c++11 -O2 -o gluon gluon.cc higgs.o + +randino: randino.cpp + g++ -Wall -std=c++11 -O2 -o randino randino.cpp + +higgs.o: higgs.cc + g++ -Wall -std=c++11 -O2 -c -o higgs.o higgs.cc diff --git a/competition.py b/competition.py new file mode 100755 index 0000000..ab72d20 --- /dev/null +++ b/competition.py @@ -0,0 +1,353 @@ +#!/usr/bin/env python3 +""" +Usage: ./competition.py [options] [competitionfile] + +The <competitionfile> should contain two lines, which are the two commands to +execute as players. + +The script writes a competitionlog to competitions/game_p1_vs_p2.txt (with p1 +and p2 replaced by their respective commands). + +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 +""" + +import os,sys,subprocess,shlex,re,time + +S=5 +PNONE=0 +PP1=1 +PP2=2 +PNEU=3 + +#Function definitions + +class Board: + def __init__(self): + self._neuidx=S*(S//2)+S//2 + self._grid=[0]*(S*S) + self._grid[self._neuidx]=PNEU + for i in range(S): + self._grid[i]=PP1 + self._grid[S*(S-1)+i]=PP2 + + def move(self,at,to): + if at<0 or at>=S*S: raise Exception("Invalid at") + if to<0 or to>=S*S: raise Exception("Invalid to") + if self._grid[at]==PNONE: raise Exception("Nothing to move") + if self._grid[to]!=PNONE: raise Exception("Place taken") + self._grid[to]=self._grid[at] + self._grid[at]=PNONE + if self._grid[to]==PNEU: + self._neuidx=to + + def undomove(self,at,to): + self._grid[at]=self._grid[to] + self._grid[to]=PNONE + if self._grid[at]==PNEU: + self._neuidx=at + + def get(self,idx): return self._grid[idx] + + def neu(self): return self._neuidx + + def pr(self): + print("+"+"-+"*S) + for y in range(S): + print("|",end="") + for x in range(S): + print(self._grid[S*y+x],end=(" " if x<S-1 else "|")) + print("") + print("+"+"-+"*S) + + +INDEXDELTAS=[(0,-1),(1,-1),(1,0),(1,1),(0,1),(-1,1),(-1,0),(-1,-1)] +def indexAfterSlide(board,idx,dir): + x,y=idx%S,idx//S + dx,dy=INDEXDELTAS[dir] + while True: + x2,y2=x+dx,y+dy + if x2<0 or x2>=S or y2<0 or y2>=S or board.get(S*y2+x2)!=PNONE: + return S*y+x + x,y=x2,y2 + +def parsemove(line): + match=re.match(r"^([0-7]|-1) ([0-9]+) ([0-7])$",line) + if not match: return False + try: return [int(match.group(i)) for i in range(1,4)] #neudir, from, dir + except: return False + +def isvalid(board,player,move): + if move[1]<0 or move[1]>=S*S: return False + if board.get(move[1])!=[PP1,PP2][player-1]: return False + if move[0]==-1 and not isFirstMove: return False + try: + if move[0]!=-1: + oldneu=board.neu() + newneuidx=indexAfterSlide(board,oldneu,move[0]) + if newneuidx==oldneu: return False + board.move(board.neu(),newneuidx) + newidx=indexAfterSlide(board,move[1],move[2]) + if newidx==move[1]: + if move[0]!=-1: board.undomove(oldneu,newneuidx) + return False + board.move(move[1],newidx) + except Exception as e: + return False + board.undomove(move[1],newidx) + if move[0]!=-1: board.undomove(oldneu,newneuidx) + return True + +def movestr(mv):return " ".join([str(e) for e in mv]) + +def haswon(board,lastplayer): + if board.neu()<S: return 1 + if board.neu()>=S*(S-1): return 2 + for dir in range(8): + newidx=indexAfterSlide(board,board.neu(),dir) + if newidx!=board.neu(): return 0 + return lastplayer + +#Getting entries and flags + +fname="" +quiet=False +viewcompetition=False +complog=True +if len(sys.argv)==1: #no args + fname="competition.txt" +else: + for arg in sys.argv[1:]: #skip script name + if len(arg)>1 and arg[0]=="-": + for c in arg[1:]: #skip "-" + if c=="C": + complog=False + elif c=="h": + print(__doc__) + sys.exit(0) + elif c=="q": quiet=True + elif c=="v": viewcompetition=True + else: + print("Unrecognised flag '"+c+"'.") + print(__doc__) + sys.exit(1) + elif fname=="": + fname=arg + else: + print("Unrecognised argument '"+arg+"'; the competition file name was already given as '"+fname+"'.") + sys.exit(1) + +if fname=="-": + if not quiet: print("Getting entries from stdin.") + p1fname="" + p2fname="" + while p1fname=="": p1fname=input().strip() + while p2fname=="": p2fname=input().strip() +else: + if fname=="": fname="competition.txt" + if not quiet: print("Getting entries from file '"+fname+"'.") + try: + f=open(fname,mode="r") + except: + print("Could not open file '"+fname+"'.") + sys.exit(1) + + p1fname=f.readline().strip() + if p1fname=="": + print("Too few lines in file."); + sys.exit(1) + p2fname=f.readline().strip() + if p2fname=="": + print("Too few lines in file."); + sys.exit(1) + f.close() + +#Set up player logs + +if not os.path.exists("playerlogs"): + try: + os.mkdir("playerlogs") + except: + print("Error: could not create log directory 'playerlogs'.") + sys.exit(1) +elif not os.path.isdir("playerlogs"): + #Apparently, there's a file named "playerlogs". Bastard. + print("Error: an existing file prohibits creation of log directory '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") +except: + print("Error: could not open log file '"+logfname+"'.") + sys.exit(1) + +#Start programs + +if not quiet: + print("Running this competition with:") + print("P1 (X): '"+p1fname+"'") + print("P2 (O): '"+p2fname+"'") + +try: + p1proc=subprocess.Popen(shlex.split(p1fname),stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=p1errlog,bufsize=1,shell=True) #line-buffered +except Exception as e: + print("Could not execute command '"+p1fname+"'.") + raise e +(p1in,p1out)=(p1proc.stdin,p1proc.stdout) + +try: + p2proc=subprocess.Popen(shlex.split(p2fname),stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=p2errlog,bufsize=1,shell=True) #line-buffered +except Exception as e: + print("Could not execute command '"+p2fname+"'.") + raise e +(p2in,p2out)=(p2proc.stdin,p2proc.stdout) + +#Set up competition log + +if not os.path.exists("competitions"): + try: + os.mkdir("competitions") + except: + print("Error: could not create log directory 'competitions'.") + sys.exit(1) +elif not os.path.isdir("competitions"): + #Apparently, there's a file named "competitions". Bastard. + print("Error: an existing file prohibits creation of log directory '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" + logfile=open(logfname,mode="w") + logfile.write("P1: "+p1fname+"\nP2: "+p2fname+"\n") +except: + print("Error: could not open log file '"+logfname+"'.") + sys.exit(1) + +#Start competition + +board=Board() +nummoves=0 +endgame=False + +isFirstMove=True + +p1totaltime=0 +p2totaltime=0 + +p1in.write(b"go\n"); +try: + p1in.flush() +except IOError as e: + if e.errno==os.errno.EINVAL: + print("Program P1 quit prematurely.") + try: p2proc.terminate() + except: pass + sys.exit(1) + else: raise e +p2in.write(b"nogo\n"); +try: + p2in.flush() +except IOError as e: + if e.errno==os.errno.EINVAL: + print("Program P2 quit prematurely.") + try: p1proc.terminate() + except: pass + sys.exit(1) + else: raise e +while True: + for (pAin,pAout,pBin,pBout,player) in [(p1in,p1out,p2in,p2out,1),(p2in,p2out,p1in,p1out,2)]: + while True: + line=pAout.readline().decode("ascii").strip() + if len(line)>0: + break + time.sleep(0.1) + timeoutfail=False + if player==1: + p1totaltime+=0.1 + if p1totaltime>=50: + timeoutfail=True + else: + p2totaltime+=0.1 + if p2totaltime>=50: + timeoutfail=True + if timeoutfail: + print("P"+str(player)+" timed out!") + try: p1proc.terminate() + except: pass + try: p2proc.terminate() + except: pass + sys.exit(1) + move=parsemove(line) + if move==False or not isvalid(board,player,move): + print("move =",move,"player =",player) + print("P"+str(player)+" made an invalid move: '"+line+"'.") + endgame=True + break + if not isFirstMove: + newidx=indexAfterSlide(board,board.neu(),move[0]) + #print("moving",board.neu(),newidx) + board.move(board.neu(),newidx) + newidx=indexAfterSlide(board,move[1],move[2]) + board.move(move[1],newidx) + + if not quiet: + print("P"+str(player)+": "+movestr(move)+" ",end="") + sys.stdout.flush() + + won=haswon(board,player) + + if not won: #writing the move to the next player if it was a winning move is _quite_ useless. + pBin.write((movestr(move)+"\n").encode("ascii")) + try: + pBin.flush() + except IOError as e: + if e.errno==os.errno.EINVAL: + print("Program P"+str(3-player)+" quit prematurely.") + try: + if player==1: p2proc.terminate() + else: p1proc.terminate() + except: pass + sys.exit(1) + else: raise e + if complog: + logfile.write("P"+str(player)+": "+movestr(move)+"\n") + + nummoves+=1 + if won!=0: + if not quiet: + print("") + board.pr() + print("") + print("P"+str(won)+" has won this game!") + if complog: + logfile.write("P"+str(won)+" won\n") + endgame=True + break + if not quiet: + print("") + board.pr() + print("") + isFirstMove=False + if endgame: + break + +#Clean up + +if complog: + logfile.close() +p1errlog.close() +p2errlog.close() + +try: p1proc.terminate() +except: pass +try: p2proc.terminate() +except: pass + +if viewcompetition: + os.system("."+os.path.sep+"viewcompetition "+logfname) diff --git a/fullcomp.sh b/fullcomp.sh new file mode 100755 index 0000000..c588bd5 --- /dev/null +++ b/fullcomp.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +BINARIES="./stttfirst ./stttrandom ./stttrecur ./stttswag" + +if [[ ! -e competitions ]]; then + mkdir competitions || exit 1 +fi + +find competitions -type f -delete + +for p1 in $BINARIES; do + for p2 in $BINARIES; do + if [[ $p1 == $p2 ]]; then + continue + fi + printf "%s\n%s\n" $p1 $p2 >competition.txt + ./competition.py $@ + status=$? + if [[ $status != 0 ]]; then + echo "$p1 - $p2 : ERROR $status (0-0)" + continue + fi + p1pretty=$(echo "$p1" | sed 's/[^a-zA-Z0-9 ]//g') + p2pretty=$(echo "$p2" | sed 's/[^a-zA-Z0-9 ]//g') + complogfile="competitions/game_${p1pretty}_vs_${p2pretty}.txt" + lastline=$(tail -n1 $complogfile) + if [[ "$lastline" == "P1 won" ]]; then + echo "$p1 - $p2 : WIN - LOSS (3-1)" + elif [[ "$lastline" == "P2 won" ]]; then + echo "$p1 - $p2 : LOSS - WIN (1-3)" + elif [[ "$lastline" == "Tie" ]]; then + echo "$p1 - $p1 : TIE (1-1)" + fi + done +done + +./fullcompstats.py diff --git a/fullcompMT.sh b/fullcompMT.sh new file mode 100755 index 0000000..5214f25 --- /dev/null +++ b/fullcompMT.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash +BINARIES="./stttfirst ./stttrandom ./stttrecur ./stttswag" + +if [[ ! -e competitions ]]; then + mkdir competitions || exit 1 +fi +if [[ ! -e competitionstubs ]]; then + mkdir competitionstubs || exit 1 +fi + +find competitions/ -type f -delete +find competitionstubs/ -type f -delete + +FIFONAME=fullcompMT_output_fifo.fifo +[[ -e $FIFONAME ]] && rm $FIFONAME +mkfifo fullcompMT_output_fifo.fifo + +tail -F $FIFONAME & +TAILPID=$! + +trap "rm $FIFONAME; kill $TAILPID; ./fullcompstats.py" EXIT + + +DATE_FMT="%Y-%m-%d %H:%M:%S" + + + +#SOURCE: competition.sh, by Wilmer van der Gaast +# Don't count the number of logical cores/threads. Although a competition +# finishes slightly faster when using all (hyper)threads, it's only a 10-20% +# improvement instead of the ~100% you'd expect. You just get threads tied +# up waiting for execution units very often. Nice when testing, but it ruins +# the time limits/etc. +if [ -z "$num_cores" ] && [ -e /proc/cpuinfo ]; then + num_cores=$(grep ^'core id\b' /proc/cpuinfo | sort | uniq | wc -l) +fi + +if [ -z "$num_cores" ] || [ "$num_cores" -lt "1" ]; then + # OS X, src: + # http://stackoverflow.com/questions/1715580/how-to-discover-number-of-cores-on-mac-os-x + # http://www.opensource.apple.com/source/xnu/xnu-792.13.8/libkern/libkern/sysctl.h + num_cores=$(sysctl -n hw.physicalcpu || echo 0) +fi + +if [ -z "$num_cores" ] || [ "$num_cores" -lt "1" ]; then + num_cores=2 + echo "Couldn't figure out number of cores, will guess $num_cores." +else + echo "Number of cores (w/o Hyper-Threading): $num_cores." +fi + + + +if [[ isatty ]]; then + function green { + printf '\x1B[33m%s\x1B[0m' $1 + } +else + function green { + printf '%s' $1 + } +fi + + + +for p1 in $BINARIES; do + for p2 in $BINARIES; do + [[ $p1 == $p2 ]] && continue + p1pretty=$(echo "$p1" | sed 's/[^a-zA-Z0-9 ]//g') + p2pretty=$(echo "$p2" | sed 's/[^a-zA-Z0-9 ]//g') + COMPFILE="competitionstubs/game_${p1pretty}_vs_${p2pretty}.sh" + cat >"$COMPFILE" << EOF +#!/usr/bin/env bash +printf "%s\n%s\n" $p1 $p2 | ./competition.py -q - +status=$? +if [[ \$status != 0 ]]; then + echo \$(date +"$DATE_FMT") "$p1 - $p2 : ERROR $status (0-0)" >$FIFONAME + exit 1 +fi +lastline=\$(tail -n1 "competitions/game_${p1pretty}_vs_${p2pretty}.txt") +if [[ "\$lastline" == "P1 won" ]]; then + echo \$(date +"$DATE_FMT") $(green "$p1") "- $p2 : WIN - LOSS (3-1)" >$FIFONAME +elif [[ "\$lastline" == "P2 won" ]]; then + echo \$(date +"$DATE_FMT") "$p1 -" $(green $p2) ": LOSS - WIN (1-3)" >$FIFONAME +elif [[ "\$lastline" == "Tie" ]]; then + echo \$(date +"$DATE_FMT") "$p1" $(green -) "$p2 : TIE (1-1)" >$FIFONAME +fi +EOF + chmod +x $COMPFILE + done +done + +find competitionstubs -type f -name 'game_*' | xargs -P$num_cores -n1 -- bash diff --git a/fullcompstats.py b/fullcompstats.py new file mode 100755 index 0000000..38e713f --- /dev/null +++ b/fullcompstats.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +from os import listdir +from os.path import isfile,join +from re import match +from sys import exit +files=[fnm for fnm in listdir("competitions") if isfile(join("competitions",fnm)) and fnm[:5]=="game_"] +scores=dict() +playernames=[] +for fname in files: + f=open(join("competitions",fname)) + lines=f.readlines() + p1name=lines[0][4:].strip() + p2name=lines[1][4:].strip() + result=lines[-1].strip() + if not match(r"P. won|Tie",result): + print("(Unterminated log file "+fname+")") + continue #both get 0 score + try: + playernames.index(p1name) + except: + playernames.append(p1name) + scores[p1name]=0 + try: + playernames.index(p2name) + except: + playernames.append(p2name) + scores[p2name]=0 + if result=="Tie": + scores[p1name]+=1 + scores[p2name]+=1 + elif result=="P1 won": + scores[p1name]+=3 + scores[p2name]+=1 + elif result=="P2 won": + scores[p1name]+=1 + scores[p2name]+=3 +scores=sorted(scores.items(),key=lambda item:-item[1]) #sort reverse on scores +maxplayerlen=max(6,max([len(sc[0]) for sc in scores]))+1 +print("PLAYER "+" "*(maxplayerlen-7)+"| SCORE") +print("-"*maxplayerlen+"+------") +for score in scores: + print(score[0]+" "*(maxplayerlen-len(score[0]))+"| "+str(score[1])) diff --git a/gluon.cc b/gluon.cc new file mode 100755 index 0000000..86b78bd --- /dev/null +++ b/gluon.cc @@ -0,0 +1,45 @@ +#include <iostream>
+#include <vector>
+#include <climits>
+#include <cstdlib>
+#include <ctime>
+#include "higgs.h"
+
+using namespace std;
+
+Move importMove() {
+ Move move;
+ cin >> move.ndir >> move.p >> move.dir;
+ return move;
+}
+
+void exportMove( Move move ) {
+ cout << move.ndir << " " << move.p << " " << move.dir << endl;
+}
+
+int main() {
+ Board board;
+ Move move;
+ string input;
+ srand( time( NULL ) );
+
+ cin >> input;
+ if( input == "go" ) {
+ //board.print();
+ move.ndir = -1;
+ move.p = S-1;
+ move.dir = 4;
+ board.doMove( move );
+ exportMove( move );
+ }
+ while( 1 ) {
+ //board.print();
+ board.doMove( importMove() );
+
+ //board.print();
+ vector<Move> move_list = board.generateMoves();
+ move = move_list[ rand() % move_list.size() ];
+ board.doMove( move );
+ exportMove( move );
+ }
+}
\ No newline at end of file diff --git a/higgs.cc b/higgs.cc new file mode 100755 index 0000000..237346a --- /dev/null +++ b/higgs.cc @@ -0,0 +1,117 @@ +#include <iostream>
+#include <vector>
+#include <climits>
+#include "higgs.h"
+
+using namespace std;
+
+int getIndex(int x, int y) {
+ return x + y*S;
+}
+
+int getX(int i) {
+ return i % S;
+}
+
+int getY(int i) {
+ return i / S;
+}
+
+void Board::doMove( Move move ) {
+ if( move.ndir != -1 ) {
+ int new_neutron = pushPiece( neutron, move.ndir );
+ square[new_neutron] = -1;
+ square[neutron] = 0;
+ neutron = new_neutron;
+ }
+ int new_proton = pushPiece( move.p, move.dir );
+ square[new_proton] = square[move.p];
+ square[move.p] = 0;
+ proton[square[new_proton] - 1] = new_proton;
+ move_count++;
+}
+
+void Board::undoMove( Move move, int n ) {
+ int new_proton = pushPiece( move.p, move.dir, true );
+ square[move.p] = square[new_proton];
+ square[new_proton] = 0;
+ proton[square[move.p]-1] = move.p;
+ if( move.ndir != -1 ) {
+ square[neutron] = 0;
+ square[n] = -1;
+ neutron = n;
+ }
+ move_count--;
+}
+
+vector<Move> Board::generateMoves() {
+ vector<Move> move_list;
+ Move move;
+ int n;
+ for( move.ndir = 0; move.ndir < 8; move.ndir++ ) {
+ n = pushPiece( neutron, move.ndir );
+ if( n != neutron ) {
+ square[n] = -1;
+ square[neutron] = 0;
+ for( int i = 0; i < S; i++ ) {
+ move.p = proton[i+S*(move_count % 2)];
+ for( move.dir = 0; move.dir < 8; move.dir++ ) {
+ if( pushPiece( move.p, move.dir ) != move.p )
+ move_list.push_back( move );
+ }
+ }
+ square[neutron] = -1;
+ square[n] = 0;
+ }
+ }
+ return move_list;
+}
+
+int Board::neutronWin() {
+ return ( getY(neutron) == 0 ) - ( getY(neutron) == S-1 );
+}
+
+int Board::pushPiece( int p, int d, bool e ) {
+ int dx = ( d > 0 && d < 4 ) - ( d > 4 && d < 8 );
+ int dy = ( d > 2 && d < 6 ) - ( d > 6 || d < 2 );
+ int x = getX( p );
+ int y = getY( p );
+ do {
+ x += dx;
+ y += dy;
+ } while( x >= 0 && x < S && y >= 0 && y < S && square[getIndex(x,y)] == 0 );
+ if( !e ) {
+ x -= dx;
+ y -= dy;
+ }
+ return getIndex(x,y);
+}
+
+void Board::print() {
+ for( int i = 0; i < SS; i++ ) {
+ if( i % S == 0 )
+ cerr << "|";
+ if( square[i] == 0 )
+ cerr << " .";
+ else if( square[i] == -1 )
+ cerr << " N";
+ else if( square[i] <= S )
+ cerr << " +";
+ else
+ cerr << " -";
+ if( i % S == S-1 )
+ cerr << " |\n";
+ }
+}
+
+Board::Board() {
+ for( int x = 0; x < S; x++ ) {
+ square[proton[x] = getIndex(x,0)] = x + 1;
+ square[proton[S+x] = getIndex(x,S-1)] = S + 1 + x;
+ }
+ for( int i = S; i < (S-1)*S; i++ )
+ square[i] = 0;
+ neutron = getIndex( S / 2, S / 2);
+ square[neutron] = -1;
+ move_count = 0;
+}
@@ -0,0 +1,31 @@ +#include <vector>
+#include <climits>
+
+#define S 5
+#define SS 25
+
+int getIndex(int x, int y);
+int getX(int i);
+int getY(int i);
+
+struct Move {
+ int ndir;
+ int p;
+ int dir;
+};
+
+class Board {
+public:
+ int square[SS];
+ int proton[2*S];
+ int neutron;
+ int move_count;
+public:
+ void doMove( Move move );
+ void undoMove( Move move, int n );
+ std::vector<Move> generateMoves();
+ int neutronWin();
+ int pushPiece( int p, int d, bool e = false );
+ void print();
+ Board();
+};
diff --git a/neutrino.cc b/neutrino.cc new file mode 100755 index 0000000..2d8edac --- /dev/null +++ b/neutrino.cc @@ -0,0 +1,86 @@ +#include <iostream>
+#include <vector>
+#include <climits>
+#include "higgs.h"
+
+using namespace std;
+
+
+int evaluate( const Board& board ) {
+ int score = 0;
+ for( int i = 0; i < S; ++i ) {
+ score += getY( board.proton[i] )*getY( board.proton[i] );
+ score -= (S - 1 - getY( board.proton[i+S] ))*(S-1-getY( board.proton[i+S] ));
+ }
+ score += S*(getY( board.neutron ) - S/2);
+ return (board.move_count % 2 == 0) ? score : -score;
+}
+
+int minimax( Board& board, Move& best_move, int depth, int alpha = INT_MIN/2, int beta = INT_MAX/2 ) {
+ if( board.neutronWin() != 0 ) {
+ if( board.neutronWin()*(2*( board.move_count % 2 ) - 1 ) > 0 )
+ return INT_MIN/2;
+ else
+ return INT_MAX/2;
+ } else if( depth == 0 )
+ return evaluate( board );
+ else {
+ int global_score = INT_MIN;
+ int local_score;
+ int prev_neutron;
+ Move best_move_recursive;
+ vector<Move> move_list = board.generateMoves();
+ if( move_list.size() == 0 )
+ return INT_MAX/2;
+ for( Move& move : move_list ) {
+ prev_neutron = board.neutron;
+ board.doMove( move );
+ local_score = -minimax( board, best_move_recursive, depth-1, -beta, -alpha );
+ board.undoMove( move, prev_neutron );
+ if( local_score > global_score ) {
+ global_score = local_score;
+ best_move = move;
+ }
+ if( local_score > alpha )
+ alpha = local_score;
+ if( beta <= alpha )
+ break;
+ }
+ return global_score;
+ }
+}
+
+Move importMove() {
+ Move move;
+ cin >> move.ndir >> move.p >> move.dir;
+ return move;
+}
+
+void exportMove( Move move ) {
+ cout << move.ndir << " " << move.p << " " << move.dir << endl;
+}
+
+int main() {
+ Board board;
+ Move move;
+ string input;
+
+ cin >> input;
+ if( input == "go" ) {
+ //board.print();
+ move.ndir = -1;
+ move.p = S-1;
+ move.dir = 4;
+ board.doMove( move );
+ exportMove( move );
+ }
+ while( 1 ) {
+ //board.print();
+ board.doMove( importMove() );
+
+ //board.print();
+ minimax( board, move, 5 );
+ board.doMove( move );
+ exportMove( move );
+ }
+}
\ No newline at end of file diff --git a/randino.cpp b/randino.cpp new file mode 100644 index 0000000..e9b5abb --- /dev/null +++ b/randino.cpp @@ -0,0 +1,169 @@ +#include <iostream> +#include <fstream> +#include <sstream> +#include <vector> +#include <sys/time.h> + +#define S (5) + +using namespace std; + +int index_deltas[8][2]={{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}}; + +class Move{ +public: + int neudir,from,dir; + string str(void){ + stringstream ss; + ss<<neudir<<' '<<from<<' '<<dir; + return ss.str(); + } +}; + +class Board{ +public: + int grid[S*S]; + int neuidx; + Board(void):neuidx(0){ + memset(grid,0,S*S*sizeof(int)); + grid[S*(S/2)+S/2]=3; + for(int i=0;i<S;i++){ + grid[i]=1; + grid[S*(S-1)+i]=2; + } + } + int moved(int at,int dir){ + int x=at%S,y=at/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||grid[S*y2+x2]!=0)return S*y+x; + x=x2; + y=y2; + } + } + bool move(int at,int dir){ + int newat=moved(at,dir); + if(newat==at)return false; + grid[newat]=grid[at]; + grid[at]=0; + if(grid[newat]==3)neuidx=newat; + return true; + } + void undomove(int at,int dir){ + int movedidx=moved(at,dir); + movedidx+=S*index_deltas[dir][1]+index_deltas[dir][0]; + grid[at]=grid[movedidx]; + grid[movedidx]=0; + if(grid[at]==3)neuidx=at; + } + bool isvalid(Move mv){ + int oldneuidx=neuidx; + if(!move(oldneuidx,mv.neudir)){ + undomove(oldneuidx,mv.neudir); + return false; + } + if(!move(mv.from,mv.dir)){ + undomove(mv.from,mv.dir); + undomove(oldneuidx,mv.neudir); + return false; + } + undomove(mv.from,mv.dir); + undomove(oldneuidx,mv.neudir); + return true; + } +}; + + +Move calculate_move(Board &bd){ + vector<Move> poss; + Move m; + int nd,fr,d; + int newneu,newidx; + for(nd=0;nd<8;nd++){ + newneu=bd.moved(bd.neuidx,nd); + if(newneu==bd.neuidx)continue; + for(fr=0;fr<S*S;fr++){ + if(bd.grid[fr]!=1)continue; + for(d=0;d<8;d++){ + newidx=bd.moved(fr,d); + if(newidx==fr)continue; + m.neudir=nd; + m.from=fr; + m.dir=d; + poss.push_back(m); + } + } + } + return poss[rand()%poss.size()]; +} + + +bool should_flip_board=false; + +inline int flip_index(int idx){ + return S*(S-1-idx/S)+S-1-idx%S; +} +inline int flip_dir(int dir){ + return (dir+4)%8; +} + +Move protocol_get_move(void){ + Move m; + cin>>m.neudir>>m.from>>m.dir; + if(should_flip_board){ + m.from=flip_index(m.from); + m.dir=flip_dir(m.dir); + } + return m; +} + +void protocol_put_move(Move m){ + if(should_flip_board){ + cout<<m.neudir<<' '<<flip_index(m.from)<<' '<<flip_dir(m.dir)<<endl; + } else { + cout<<m.neudir<<' '<<m.from<<' '<<m.dir<<endl; + } +} + +int main(void){ + Board bd; + Move mv; + string line; + struct timeval tv; + gettimeofday(&tv,NULL); + cerr<<"seed="<<(1000000*tv.tv_sec+tv.tv_usec)<<endl; + srand(1000000*tv.tv_sec+tv.tv_usec); + getline(cin,line); + if(line=="go"){ + should_flip_board=false; + mv.neudir=-1; mv.from=0; mv.dir=4; + protocol_put_move(mv); + } else { + if(line!="nogo")cerr<<"no0b "<<line<<" not in (go,nogo)"<<endl; + should_flip_board=true; + mv=protocol_get_move(); + bd.move(mv.from,mv.dir); + mv=calculate_move(bd); + if(!bd.isvalid(mv)){ + cerr<<"calculate_move gave invalid move "<<mv.str()<<endl; + return 1; + } + bd.move(bd.neuidx,mv.neudir); + bd.move(mv.from,mv.dir); + protocol_put_move(mv); + } + while(true){ + mv=protocol_get_move(); + bd.move(mv.from,mv.dir); + mv=calculate_move(bd); + if(!bd.isvalid(mv)){ + cerr<<"calculate_move gave invalid move "<<mv.str()<<endl; + return 1; + } + bd.move(bd.neuidx,mv.neudir); + bd.move(mv.from,mv.dir); + protocol_put_move(mv); + } + return 0; +} diff --git a/viewcompetition.cpp b/viewcompetition.cpp new file mode 100644 index 0000000..40ba715 --- /dev/null +++ b/viewcompetition.cpp @@ -0,0 +1,111 @@ +#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) + +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; + } +} + +int main(int argc,char **argv){ + if(argc==1){ + cout<<"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; + return 1; + } + ifstream in(argv[1]); + if(!in.good()){ + cout<<"Cannot open file '"<<argv[1]<<"'."<<endl; + return 1; + } + string p1name,p2name; + int player,x,y; + char c; + 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; + if(!in.good()){ + cout<<"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.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'); + } else if(c==' '){ + cout<<"\x1B[17;1HThe victor is player "<<player<<"!"<<endl; + in.close(); + dosleep(1500); + return 0; + } else { + cout<<"\x1B[17;1HError in log file format."<<endl; + return 1; + } + } else if(c=='T'){ + cout<<"\x1B[17;1HThe game resulted in a tie."<<endl; + in.close(); + dosleep(1500); + return 0; + } + } + cout<<"\x1B[17;1HLog file ended prematurely."<<endl; + return 1; +} |