# To run this script # open a Command Prompt or PowerShell in "C:\Program Files (x86)\gnubg>" # and run ".\gnubg-cli.exe --python=D:\MuratMutantChecker1stWorstM.py" # or run .\gnubg-cli.exe then type ">"+[ENTER] to get in Python interpreter # and run "exec(open('D:\MuratMutantChecker1stWorstM.py').read())" # replace "D:\" with the path to the script file on your computer import math import sys experiment = 'MuratMutantChecker1stWorstM' # used in filenames to save games and matches # mutant doubles, takes and drops according to double/take points # based on the 5 stages of a game # mutant also always makes 2nd best move gamestages = [0, 7, 19, 37, 49] # 1-6=6 7-18=12 19-36=18 37-48=12 49-54=6 cubepoints = [0.55, 0.60, 0.65, 0.70, 0.75] takepoints = [0.15, 0.20, 0.25, 0.30, 0.35] beaverpoints = [0.35, 0.40, 0.45, 0.50, 0.55] toogoodpoint = 0.85 session = games = game = movecount = snum = gnum = cycle = power = seed = 0 opoints = xpoints = zpoints = wonroll = autocube = cubeyes = takeyes = beaveryes = 0 cubepoint = takepoint = beaverpoint = 0 session = int(input('Enter beginning game: ')) # i.e. 0, 1000, 2000, etc. #games = int(input('Enter games to run: ')) # games in filenames will start with session+1 #saveall = input('Save individual games? y/n: ') #matchlog = input('Save matches to logfile? y/n: ') #gameslog = input('Save games to logfile? y/n: ') #seed = int(input('Enter RNG seed: ')) seed = 340000 + session if seed > 0 : gnubg.command('set seed ' + str(seed)) games = 1000 matchlog = gameslog = 'y' if matchlog == 'y' : matchfile = open('D:\\' + experiment + 'Session.txt', 'a') if gameslog == 'y' : gamesfile = open('D:\\' + experiment + str(int(session)).zfill(6) + '.txt', 'a') def getpos() : global posinfo, dice, player, resigned, doubled, gamestate posinfo = gnubg.posinfo() dice = posinfo['dice'] player = posinfo['turn'] resigned = posinfo['resigned'] doubled = posinfo['doubled'] gamestate = posinfo['gamestate'] # 0=no game, 1=playing, 2=over, 3=resigned, 4=dropped def getcube() : global cubeinfo, cubeowner, cubevalue, beaver cubeinfo = gnubg.cubeinfo() cubeowner = cubeinfo['cubeowner'] # 0=bot, 1=mutant, -1=centerd cubevalue = cubeinfo['cube'] beaver = cubeinfo['beavers'] def getwin() : global cubeless, win cubeless = gnubg.evaluate() win = cubeless[0] # cubeless win% # win = cubeless[5] # cubeless equity def geteval() : global evalinfo, toogood evalinfo = gnubg.cfevaluate() toogood = evalinfo[4] def makemove(): global board, allmoves, pickmove, convmove, move, movecount gnubg.command('roll') movecount = movecount + 1 # used in filenames and/or to determine game stages posinfo = gnubg.posinfo() dice = posinfo['dice'] # to fix gnubg bug, need this again to check if mutant danced if dice != (0, 0): # mutant can move, proceed allmoves = gnubg.hint() if movecount < 3 : pickmove = allmoves['hint'][-1]['move'] else : pickmove = allmoves['hint'][0]['move'] board = gnubg.board() convmove = gnubg.parsemove(pickmove) move = gnubg.movetupletostring(convmove, board) gnubg.command(move) def errorend(error) : print(error) input('Enter to exit') sys.exit() while game < games : # loop to run number of games entered above game = game + 1 gnubg.command('new game') getpos() wonroll = 0 if dice != (0, 0) : # mutant won the opening roll wonroll = 1 movecount = -1 # adjust move count since bot auto-moves after mutant's turn else : movecount = 0 wonroll = 0 gamestate = 1 cycle = cubevalue = points = winfactor = 0 while gamestate == 1 : # main game loop getpos() movecount = movecount + 1 # always increment as bot auto-rolls and auto-moves if gamestate > 1 : break if resigned > 0 : gnubg.command('agree') movecount = movecount - 1 # don't count them as moves break getcube() if cubevalue == 2048 and beaver == 1 : # when bot beavers, cubeinfo is not current cubevalue = 4096 print('beavering cubeowner ', cubeowner) input('contine \a') # just to know when this happens if cubevalue == 4096 : cubevalue = 2 gnubg.command('set cube value 2') cycle = cycle + 1 input('cube cycled \a') if cubeowner == 0 and doubled ==0 : # mutant has no cube access, just move if beaver > 0 : input('Not doubled but beavered! \a') # this should never happen makemove() continue for i in reversed(range(5)) : if movecount >= gamestages[i] : cubepoint = cubepoints[i] takepoint = takepoints[i] beaverpoint = beaverpoints[i] break getwin() cubeyes = takeyes = beaveryes = cubelow = 0 if doubled == 1 : # reverse GWC win = 1 - win if win > cubepoint : # mutant's GWC > cubepoint cubeyes = 1 if win > toogoodpoint : # too good cubeyes = 0 if win > takepoint : # mutant's GWC > takepoint takeyes = 1 if win > beaverpoint : # mutant's GWC > cubepoint beaveryes = 1 if cubeowner == 1 and beaver == 2 : # respond to bot's raccoon movecount = movecount -1 # don't count cube actions as moves if win == 1 : input('win 100\a') # this should never happen if win == 0 : input('win 0\a') # this should never happen if cubeyes : # in case bot beavers with GWC <= mutant's cubepoint gnubg.command('take') # bot racconed low, so take input('bot racconed low, take \a') continue elif takeyes : gnubg.command('take') # bot racconed < mutant's takepoint, so take # input('take bot raccon \a') continue else : gnubg.command('drop') # mutant drops with GWC <= takepoint # input('drop bot raccoon \a') break if cubeowner == 0 and beaver == 1 : # respond to bot's beaver movecount = movecount -1 # don't count cube actions as moves if cubeyes : input('bot beavered low \a') # can this happen? if cubevalue == 4096 : input('bot beavered, cube 4096 \a' ) # this should not happen if cubevalue == 2048 : input('bot beavered, cube 2048 \a') # this should not happen gnubg.command('beaver') # mutant always raccoons since it doubled with GWC > cubepoint # input('raccoon bot beaver \a') continue if cubeowner < 1 and doubled == 1 : # respond to bot's double movecount = movecount -1 # don't count cube actions as moves if beaveryes : gnubg.command('beaver') # mutant beavers with GWC > cubepoint # input('beaver bot double \a') continue elif takeyes : gnubg.command('take') # mutant takes with GWC > takepoint # input('take bot double \a') continue else : gnubg.command('drop') # mutant drops with GWC <= takepoint # input('drop bot double \a') break if cubeyes : # at this point mutant can initiate a cube action if movecount > 0 : # can double after opening roll movecount = movecount -1 # don't count cube actions as moves gnubg.command('double') # mutant doubles with GWC > cubepoint # input('regular double \a') continue makemove() # game ended, build game filename and save getcube() gameinfo = gnubg.match(analysis=0, boards=0, statistics=1, verbose=0)['games'][-1] gnum = '_G' + str(session + game).zfill(5) # game number winner = "_" + gameinfo['info']['winner'] # O or X won points = gameinfo['info']['points-won'] # points won integer winfactor = points / cubevalue if winfactor == 3 : wintype = '_W3' # won backgammon elif winfactor == 2 : wintype = '_W2' # won gammon elif winfactor == 1 : wintype = '_W1' # won normal else : errorend('invalid multiplier') # this should never happen if cycle > 0 : # calculate effective cube value power = math.log(cubevalue, 2) + (cycle * 11) # 2^12 = 4096 cubevalue = int(math.pow(2, power)) cval = '_C' + str(cubevalue).zfill(6) # cube value formatted points = int(cubevalue * winfactor) # effective points won if winner == '_O' : # to fix gnubg bug, players reversed winner = '_X' xpoints = xpoints + points elif winner == '_X' : winner = '_O' opoints = opoints + points else : errorend('invalid winner') # this should never happen points = str(points).zfill(6) # points won formatted autocube = autocube + wonroll if gameinfo['game'][-1]['action'] == 'resign' : endtype = '_R' # resigned elif gameinfo['game'][-1]['action'] == 'drop' : endtype = '_D' # dropped elif gameinfo['game'][-1]['action'] == 'move' : endtype = '_F' # finished else : errorend('invalid how game ended') # this should never happen lastacted = gameinfo['game'][-1]['player'] # player who made last action if lastacted == 'O' : # fix gnubg bug, players reversed lastacted = 'X' elif lastacted == 'X' : lastacted = 'O' else : errorend('invalid last player') # this should never happen if lastacted == 'X' : movecount = movecount - 1 # it wasn't subtracted for mutant in game loop, do it now mcnt = '_M' + str(movecount).zfill(3) # number of moves in game for both players if wonroll == 1 : mcnt = mcnt + '_W' # flag games when mutant won opening roll cubeskill = round(gameinfo['stats']['O']['cube']['error-skill'], 4) # cube error for mutant cubeskill = '_ES' + str(int(cubeskill * 1000)).zfill(6) # formatted without decimal cubecost = round(gameinfo['stats']['O']['cube']['error-cost'], 4) # cube error for mutant cubecost = '_EC' + str(int(cubecost * 1000)).zfill(6) # formatted without decimal filename = experiment + gnum + winner + points + cubeskill + cubecost + cval + wintype + endtype + lastacted + mcnt if gameslog == 'y' : gamesfile.write(filename + '\n') # filename = 'save game E:\\' + filename + '.sgf' # if saveall == 'y': gnubg.command(filename) # session ended, build match filename and save snum = '_S' + str(session).zfill(5) # session begin number + games in session opoints = '_O' + str(opoints).zfill(8) # O's total points won xpoints = '_X' + str(xpoints).zfill(8) # X's total points won autocube = '_A' + str(autocube).zfill(3) # count for mutant's opening roll wins (no cube) gameinfo = gnubg.match(analysis=0, boards=0, statistics=1, verbose=0)['stats'] cubecount = gameinfo['O']['cube']['total-cube'] # total cube actions for mutant cubecount = '_CC' + str(cubecount).zfill(6) # formatted without decimal cubeskill = round(gameinfo['O']['cube']['error-skill'], 4) # total cube error for mutant cubeskill = '_ES' + str(int(cubeskill * 10000)).zfill(8) # formatted without decimal cubecost = round(gameinfo['O']['cube']['error-cost'], 4) # total cube error for mutant cubecost = '_EC' + str(int(cubecost * 10000)).zfill(8) # formatted without decimal diceseed = '_DS' + str(int(seed)).zfill(8) filename = experiment + snum + gnum + opoints + xpoints + cubecount + cubeskill + cubecost + diceseed + autocube if matchlog == 'y' : matchfile.write(filename + '\n') filename = 'save match D:\\' + filename + '.sgf' gnubg.command(filename) gamesfile.close() matchfile.close() print('session ended \a') # sounds bell to alert that it's done # all prefixes starting with an "_" are unique single characters # to use in wild-card filename searches within a directory # in order to select certain games, i.e. *_W3* to select games ended in a backgammon # prefixes used: _G, _O, _X, _C, _W, _R, _D, _DS, _F, _M, _S, _CC, _ES, _EC _A, _W