This program has been disqualified.
Author | blue-tomato |
Submission date | 2015-07-08 07:50:49.846426 |
Rating | 8292 |
Matches played | 207 |
Win rate | 82.13 |
# author: blue-tomato (Matthew B. Smith)
# uses large pieces of code from:
# fltbot (author: Flight Odyssey), which in turn is a variation of dllu1 by dllu (modified constants)
# rps_cracker (author: Rekrul)
# Flight Odyssey suggests in the comments for fltbot: see also www.dllu.net/rps
# I chose to use these two submissions, because fltbot is based on rfind, while rps_cracker is based on
# the frequencies of sequences of various lengths. These two types of strategies perform fairly randomly
# against each other, so I hope that a bot that uses both should be more versatile than either. It is possible
# a future version of this program will contain predictive chunks from other rps bots.
# my unique contribution is in my style of meta-prediction. rather than producing 3 rotations of each strategy,
# and using a frequency predictor to select between them, I track a "meta-history" of how many rotations each
# selector has been off of the correct answer (the correct answer being the one that beats the input). I then
# use rfind on this meta-history to decide which rotation is ideal. Of course, I need to use a frequency-style
# predictor to decide between the various resulting meta-histories based on the different predictors.
# my chief concern is that rps-giant will exceed the 5 second match limit. If this happens I will have to submit
# a stream-lined version of this program.
# I have neglected to have a random fallback for this program. I may be conceited, but I currently believe this
# program is good enough compared to the current competition that a fallback is not currently needed.
# I have tested this program against the current top 5 on the leaderboard (fltbot by FlightOdyssey, NOOB MUHAMMED by
# PRO YUNUS, nervous scattershot by rspk, rps_cracker by Rekrul, and RVL V3 by Thatguy), and rps-giant consistently
# wins over 50 percent of matches against each.
import random
if input == '':
### setup - things for general use or used by meta predictors
beat = {'R':'P','P':'S','S':'R','X':'X'}
pnum = {'RR':'0','RP':'1','RS':'2','PR':'3','PP':'4','PS':'5','SR':'6','SP':'7','SS':'8'}
mpnum = {'AA':'0','AB':'1','AC':'2','BA':'3','BB':'4','BC':'5','CA':'6','CB':'7','CC':'8','XA':'a','XB':'b','XC':'c','AX':'d','BX':'e','CX':'f','XX':'x'}
mpnumi = {'0':'A','1':'A','2':'A','3':'B','4':'B','5':'B','6':'C','7':'C','8':'C','a':'X','b':'X','c':'X','d':'A','e':'B','f':'C','x':'X'}
mpnumo = {'0':'A','1':'B','2':'C','3':'A','4':'B','5':'C','6':'A','7':'B','8':'C','a':'A','b':'B','c':'C','d':'X','e':'X','f':'X','x':'X'}
mdec = {'A':{'R':'R','P':'P','S':'S','X':'X'},'B':{'R':'P','P':'S','S':'R','X':'X'},'C':{'R':'S','P':'R','S':'P','X':'X'}}
### setup for history
length = 0
hin = ''
hout = ''
hpair = ''
hinlengths = [8,15]
hinidx = [0,2]
hinsize = 2
houtlengths = [8,15]
houtidx = [4,6]
houtsize = 2
hpairlengths = [3,8,15]
hpairidx = [8,10,12]
hpairsize = 3
### setup for Rekrul's rps_cracker code (I could do this myself but man am I lazy)
SIZE = 4
WEIGHT_FACTOR = 7.
class HistoryNode(object):
def __init__(self, parent=None):
if parent is not None:
self.depth = parent.depth + 1
else:
self.depth = 0
self.children = {'RR': None, 'RS': None, 'RP': None, 'SR': None, 'SS': None,
'SP': None, 'PR': None, 'PS': None, 'PP': None}
self.distribution = {'RR': 0, 'RS': 0, 'RP': 0, 'SR': 0, 'SS': 0, 'SP': 0,
'PR': 0, 'PS': 0, 'PP': 0}
def new_move(self, input):
last_move = input[0:2]
if len(input) > 2:
if self.children[last_move] is None:
self.children[last_move] = HistoryNode(self)
self.children[last_move].new_move(input[2:])
else:
self.distribution[last_move] = self.distribution[last_move] * 0.975 + 1
def predict(self, input):
if len(input) > 0:
last_move = input[0:2]
if self.children[last_move] is not None:
return self.children[last_move].predict(input[2:])
else:
return None
else:
return self.distribution
class HistoryTree(object):
def __init__(self):
self.root = HistoryNode()
self.input = ''
def new_move(self, move):
self.input += move
if len(self.input) > SIZE * 2:
self.input = self.input[-SIZE * 2:]
for i in xrange(2, len(self.input) + 1, 2):
self.root.new_move(self.input[-i:])
def predict(self):
results = {'R':0, 'S':0, 'P':0}
for i in xrange(2, len(self.input) + 1, 2):
res = self.root.predict(self.input[-i:])
if res is not None:
for key in res:
results[key[1]] += res[key] * (WEIGHT_FACTOR ** i)
d = results
e = d.keys()
e.sort(cmp=lambda a, b: cmp(d[a], d[b]))
return e[-1]
def predict_i(self, i):
results = {'R':0, 'S':0, 'P':0}
for depth in xrange(i, -1, -1):
res = self.root.predict(self.input[-depth * 2:])
if res is not None:
break
if res is None:
return 'X'
else:
for key in res:
results[key[1]] += res[key]
d = results
e = d.keys()
e.sort(cmp=lambda a, b: cmp(d[a], d[b]))
return e[-1]
history_tree_me = HistoryTree()
history_tree_him = HistoryTree()
### setup for fltbot/dllu1 strange-predictor
centrifuge = {'RP':0,'PS':1,'SR':2,'PR':3,'SP':4,'RS':5,'RR':6,'PP':7,'SS':8}
centripete={'R':0,'P':1,'S':2}
flt_soma = [0.0]*9;
flt_rps = [1.0,1.0,1.0];
flt_revsoma = [0.0]*9;
flt_revrps = [1.0,1.0,1.0]
flt_a = "RPS"
### additional general setup
numpred = 28 # number of predictors (for convenience)
mh = ['']*numpred # meta-histories
choice = ['']*numpred # stores choice for output of basic predictors
mchoice = ['']*numpred # stores cchoice for meta-predictors that use meta-rfind technique
mscore = [0.0]*numpred # scores meta predictors
output = 'X'
else:
### create meta-history and score meta-predictors
for i in range(0,numpred):
# create meta history
mhoninput = 'X'
if choice[i] == beat[input]:
mhoninput = 'A'
elif choice[i] == input:
mhoninput = 'B'
elif choice[i] == beat[beat[input]]:
mhoninput = 'C'
mhonoutput = 'X'
if choice[i] == beat[output]:
mhonoutput = 'A'
elif choice[i] == output:
mhonoutput = 'B'
elif choice[i] == beat[beat[output]]:
mhonoutput = 'C'
mh[i] += mpnum[mhoninput+mhonoutput]
# score meta-predictors
# using scoring from rps_cracker
if mchoice[i] == beat[input]:
mscore[i] += 1.0
elif mchoice[i] == beat[beat[input]]:
mscore[i] -= 1.0
elif mchoice[i] == input:
mscore[i] -= 0.34
elif mchoice[i] == 'X':
mscore[i] -= 0.11333
mscore[i] *= 0.90
length += 1
hin += input
hout += output
hpair += pnum[input+output]
#########################################################################
### basic predictors ####################################################
#########################################################################
### predict based on input history
bhinloc = -1
hinloc = [-1]*hinsize
hinref = 0
for i in range(1,min(16,length)):
loc = hin[:-1].rfind(hin[-i:])
if loc != -1:
bhinloc = loc+i
if i == hinlengths[hinref]:
hinloc[hinref] = bhinloc
hinref += 1
else:
break
while hinref < hinsize:
hinloc[hinref] = bhinloc
hinref += 1
if bhinloc == -1:
for i in range(hinidx[0],hinidx[hinsize-1]+2):
choice[i] = 'X'
else:
for i in range(0,hinsize):
j = hinidx[i]
choice[j+0] = beat[hin[hinloc[i]]]
choice[j+1] = beat[beat[hout[hinloc[i]]]]
### predict based on output history
bhoutloc = -1
houtloc = [-1]*houtsize
houtref = 0
for i in range(1,min(16,length)):
loc = hout[:-1].rfind(hout[-i:])
if loc != -1:
bhoutloc = loc+i
if i == houtlengths[houtref]:
houtloc[houtref] = bhoutloc
houtref += 1
else:
break
while houtref < houtsize:
houtloc[houtref] = bhoutloc
houtref += 1
if bhoutloc == -1:
for i in range(houtidx[0],houtidx[houtsize-1]+2):
choice[i] = 'X'
else:
for i in range(0,houtsize):
j = houtidx[i]
choice[j+0] = beat[hin[houtloc[i]]]
choice[j+1] = beat[beat[hout[houtloc[i]]]]
### predict based on pairwise history
bhpairloc = -1
hpairloc = [-1]*hpairsize
hpairref = 0
for i in range(1,min(16,length)):
loc = hpair[:-1].rfind(hpair[-i:])
if loc != -1:
bhpairloc = loc+i
if i == hpairlengths[hpairref]:
hpairloc[hpairref] = bhpairloc
hpairref += 1
else:
break
while hpairref < hpairsize:
hpairloc[hpairref] = bhpairloc
hpairref += 1
if bhpairloc == -1:
for i in range(hpairidx[0],hpairidx[hpairsize-1]+2):
choice[i] = 'X'
else:
for i in range(0,hpairsize):
j = hpairidx[i]
choice[j+0] = beat[hin[hpairloc[i]]]
choice[j+1] = beat[beat[hout[hpairloc[i]]]]
### predict based on pairwise history with delay
### predictor taken from fltbot/dllu1
hpairdelayloc = -1
for i in range(2,min(9,length)):
loc = hpair[:-2].rfind(hpair[-i:-1])
if loc != -1:
hpairdelayloc = loc+i
else:
break
if hpairdelayloc == -1:
choice[14] = 'X'
choice[15] = 'X'
else:
choice[14] = beat[hin[hpairdelayloc]]
choice[15] = beat[beat[hout[hpairdelayloc]]]
### frequency of move-sequences predictor taken from rps_cracker
history_tree_me.new_move(output + input)
history_tree_him.new_move(input + output)
choice[16] = history_tree_me.predict()
choice[17] = history_tree_him.predict()
for j in xrange(SIZE):
choice[18+j*2] = history_tree_me.predict_i(j)
choice[19+j*2] = history_tree_him.predict_i(j)
### strange predictor taken from fltbot/dllu1. It appears many people have copied
### this predictor, so if I use it better it should help outperform them
flt_soma[centrifuge[input+output]] += 1.0;
flt_rps[centripete[input]] += 1.0;
flt_best = [0.0,0.0,0.0]
flt_best[0] = flt_soma[centrifuge[output+'R']]*flt_rps[0]
flt_best[1] = flt_soma[centrifuge[output+'P']]*flt_rps[1]
flt_best[2] = flt_soma[centrifuge[output+'S']]*flt_rps[2]
choice[26] = flt_a[flt_best.index(max(flt_best))]
flt_revsoma[centrifuge[output+input]] += 1.0
flt_revrps[centripete[output]] += 1.0
flt_revbest = [0.0,0.0,0.0]
flt_revbest[0] = flt_revsoma[centrifuge[input+'R']]*flt_revrps[0]
flt_revbest[1] = flt_revsoma[centrifuge[input+'P']]*flt_revrps[1]
flt_revbest[2] = flt_revsoma[centrifuge[input+'S']]*flt_revrps[2]
choice[27] = flt_a[flt_revbest.index(max(flt_revbest))]
#############################################################################
### meta predictors (using rfind) ###########################################
#############################################################################
for j in range(0,numpred):
mhloc = -1
for i in range(1,min(16,length)):
loc = mh[j][:-1].rfind(mh[j][-i:])
if loc != -1:
mhloc = loc+i
else:
break
mpred = mh[j][mhloc]
if mhloc == -1 or mpnumi[mpred] == 'X':
mchoice[j] = 'X'
else:
mchoice[j] = mdec[mpnumi[mpred]][choice[j]]
output = mchoice[mscore.index(max(mscore))]
if output == 'X':
output = random.choice('RPS')