# zai_mix_history_v3

 Author zdg Submission date 2011-10-22 16:24:31.706775 Rating 7067 Matches played 1222 Win rate 73.4

Use rpsrunner.py to play unranked matches on your computer.

## Source code:

``````# mixes the strategies that try to play in the opponent's shoes

# --------------------- initialization -----------------------------
if not input:
import random, math
import itertools, operator, collections

R, P, S = 0, 1, 2
RPS = [R, P, S]
T, W, L = R, P, S
PAYOFFS = [T, W, L]
to_win = [W, T, L]
convert = {'R':R, 'P':P, 'S':S, R:'R', P:'P', S:'S'}
subh = [[T, L, W], [W, T, L], [L, W, T]]
addh = [[R, P, S], [P, S, R], [S, R, P]]
POWER3 = [3 ** n for n in xrange(10)]

def empty_vec(n):
return [0.0] * n

def uniform_vec(n):
return [1.0 / n] * n

def mix_scores(u, v, d):
e = 1.0 - d
for i in xrange(len(u)):
u[i] = u[i] * d + v[i] * e

def predictability(u, sqrt=math.sqrt):
uniform = 1.0 / len(u)
acc = 0.0
for x in u:
acc += (x - uniform) ** 2
return sqrt(acc)

def normalize(u):
factor = 1.0 / sum(u)
for i in xrange(len(u)):
u[i] *= factor

def pick_weighted(v):
u = random.random()
acc = 0.0
for i, p in enumerate(v):
acc += p
if u <= acc:
return (i, p)

# def score_counts(counts):
# score = 0
# for s in PAYOFFS:
# score += counts[s] * s
# return score

# mixes multiple strategies
class Mixer(object):
def __init__(self, decay_function, dropswitch, *bots):
self.bots = bots
self.bot_num = len(self.bots)
self.decay_function = decay_function
self.dropswitch = dropswitch
self.next_hands = [None] * self.bot_num
self.scores = [None] * self.bot_num

def update(self):
# update scores
op_last_hand = op_hands[-1]
for i in xrange(self.bot_num):
last_hand = self.next_hands[i]
if last_hand is None:
continue
payoff = [last_hand[ties[op_last_hand]], last_hand[beats[op_last_hand]], last_hand[loses[op_last_hand]]]
if payoff[L] > payoff[W] and self.dropswitch:
self.scores[i] = None
else:
if self.scores[i] is None:
self.scores[i] = uniform_vec(3)
mix_scores(self.scores[i], payoff, self.decay_function(len(op_hands)))

# compute next hand
next_hand = empty_vec(3)
for i in xrange(self.bot_num):
bot_next_hand = self.bots[i].next_hand
self.next_hands[i] = bot_next_hand
if bot_next_hand is None:
continue
curr_score = self.scores[i]
if curr_score is None:
continue
nonrandomness = predictability(curr_score)
# nonrandomness = 1.0
for s in PAYOFFS:
pscore = curr_score[s] * nonrandomness
for h in RPS:
if sum(next_hand) <= 0.1:
self.next_hand = pick_weighted(uniform_vec(3))[0]
else:
normalize(next_hand)
self.next_hand = pick_weighted(next_hand)[0]

class History(object):
def __init__(self, order, offset, *handss):
self.order = order
self.offset = offset
self.handss = handss
self.handss_num = len(handss)
self.all = []
self.counts = collections.defaultdict(list)

def update(self):
# update the all list
last_hands = [self.handss[i][-1] for i in xrange(self.handss_num)]
code = 0
for i in xrange(self.handss_num):
code += last_hands[i] * POWER3[i]
self.all.append(code)
hands_len = len(self.all)

# update for the previous hand
for order in xrange(min(self.order, hands_len - 1)):
index = tuple(self.all[-order-2:-1])
self.counts[index].append(code)

# setup the next one and predict
prediction = [0] * 3
for order in xrange(min(self.order, hands_len)):
index = tuple(self.all[-order-1:])
past = self.counts[index]
if past:
mine, ops = self.decode3(past[-1])
if subh[mine][ops] == W:
prediction[mine] = 1.0
if sum(prediction) < 0.01:
self.next_hand = None
else:
normalize(prediction)
offsetted = [0.0] * 3
self.next_hand = offsetted

def decode3(self, code):
hands = []
for i in xrange(self.handss_num):
hands.append(code % 3)
code /= 3
return hands

class ConstantBot(object):
def __init__(self, op_moves, my_moves, offset):
self.op_moves = op_moves
self.my_moves = my_moves
self.offset = offset
next_hand_p = [0.0] * 3
self.next_hand = next_hand_p

def update(self):
pass

class BeatLastBot(object):
def __init__(self, op_moves, my_moves, offset):
self.op_moves = op_moves
self.my_moves = my_moves
self.offset = offset

def update(self):
next_hand_p = [0.0] * 3
self.next_hand = next_hand_p

op_hands = []
my_hands = []
payoffs = []

output = convert[random.choice(RPS)]
# --------------------- turn -----------------------------
else:
last_input, last_output = convert[input], convert[output]
my_hands.append(last_output)
op_hands.append(last_input)
payoffs.append(subh[last_output][last_input])
hands_played = len(op_hands)

# bot initialization after first turn
if hands_played == 1:
# constantbot = ConstantBot(op_hands, my_hands, T)
# constantbot2 = ConstantBot(my_hands, op_hands, W)
beatlastbot = BeatLastBot(op_hands, my_hands, T)
beatlastbot2 = BeatLastBot(my_hands, op_hands, W)
hist = History(5, T, my_hands, op_hands)
hist2 = History(5, W, op_hands, my_hands)

mixer = Mixer(lambda x:0.9, False, beatlastbot, beatlastbot2, hist, hist2)

# constantbot.update()
# constantbot2.update()
beatlastbot.update()
beatlastbot2.update()
hist.update()
hist2.update()
mixer.update()

output = convert[mixer.next_hand]``````