From 6264573c8537fda9df1b35a74019eabcc3ee8899 Mon Sep 17 00:00:00 2001 From: tomsmeding Date: Sun, 26 Apr 2015 20:21:51 +0200 Subject: Initial --- .gitignore | 9 ++ Makefile | 15 +++ competition.py | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fullcomp.sh | 36 ++++++ fullcompMT.sh | 93 ++++++++++++++ fullcompstats.py | 42 +++++++ gluon.cc | 45 +++++++ higgs.cc | 117 +++++++++++++++++ higgs.h | 31 +++++ neutrino.cc | 86 +++++++++++++ randino.cpp | 169 +++++++++++++++++++++++++ viewcompetition.cpp | 111 +++++++++++++++++ 12 files changed, 1107 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100755 competition.py create mode 100755 fullcomp.sh create mode 100755 fullcompMT.sh create mode 100755 fullcompstats.py create mode 100755 gluon.cc create mode 100755 higgs.cc create mode 100755 higgs.h create mode 100755 neutrino.cc create mode 100644 randino.cpp create mode 100644 viewcompetition.cpp 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 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 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*(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 +#include +#include +#include +#include +#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_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 +#include +#include +#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 Board::generateMoves() { + vector 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; +} diff --git a/higgs.h b/higgs.h new file mode 100755 index 0000000..c201955 --- /dev/null +++ b/higgs.h @@ -0,0 +1,31 @@ +#include +#include + +#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 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 +#include +#include +#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_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 +#include +#include +#include +#include + +#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<=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 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>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< +#include +#include +#include +#include +#ifdef _WIN32 +#include +#else +#include +#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<<"+-------+-------+-------+"<2){ + cout<<"Multiple command-line arguments were passed."<::max(),'\n'); + board[9*y+x]=player; + cout<<"\x1B["<<(5+y/3+y)<<';'<<(3+x/3*2+x*2)<<'H'<::max(),'\n'); + } else if(c==' '){ + cout<<"\x1B[17;1HThe victor is player "<