IocaneBayes2

AuthorSean
Submission date2018-08-31 07:18:56.956360
Rating7712
Matches played262
Win rate74.81

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

Source code:

if input == "":

    import collections
    import math
    import random

    gamma = random.gammavariate
    sqrt = math.sqrt
    log = math.log
    moves = R, P, S = 0, 1, 2
    index = {"R": R, "P": P, "S": S}
    good_against = (P, S, R)
    bad_against = (S, R, P)
    name = ("R", "P", "S")
    third = 1. / 3
    hash_codes = [random.randint(0, 0xFFFFFFFF) for _ in range(40)]

    def belief(counts):
        counts = [random.gammavariate(n, 1) for n in counts]
        t = sum(counts)
        return [n / t for n in counts]

    class MarkovPredictor:
        def __init__(self):
            self.table = {}
        def update(self, h):
            hash_code = 0
            s = h[-1]
            bound = min(11, len(h))
            for d in range(2, bound):
                c = h[-d]
                hash_code ^= hash_codes[3 * d + c]
                self.table[hash_code] = s
        def predict(self, h):
            seen = 0
            hash_code = 0
            bound = min(11, len(h)+1)
            for d in range(2, bound):
                c = h[-(d-1)]
                hash_code ^= hash_codes[3 * d + c]
                if hash_code in self.table:
                    seen = self.table[hash_code]
                else:
                    break
            return seen

    class FrequencyPredictor:
        def __init__(self, k=1):
            self.k=k
            self.counts = [third] * 3
        def update(self, h):
            self.counts[h[-1]] += 1
            for i, _ in enumerate(self.counts):
                self.counts[i] *= self.k
        def predict(self, h):
            p = belief(self.counts)
            scores = [p[bad_against[m]] - p[good_against[m]] for m in moves]
            return scores.index(max(scores))

    class MetaPredictor:
        def __init__(self, predictor):
            self.predictor = predictor()
            self.self_predictor = predictor()
            self.prediction = None
            self.self_prediction = None
            self.counts = [[third] * 3 for _ in range(6)]
        def update(self, h0, h1):
            s = h0[-1]
            if self.prediction is not None:
                p = self.prediction
                for i, counts in enumerate(self.counts):
                    if i == 3:
                        p = self.self_prediction
                    m = (p + i) % 3
                    counts[(s - m) % 3] += 1
            self.predictor.update(h0)
            self.self_predictor.update(h1)
        def predictions(self, h0, h1):
            self.prediction = self.predictor.predict(h0)
            self.self_prediction = self.self_predictor.predict(h1)
            p = self.prediction
            for i, counts in enumerate(self.counts):
                if i == 3:
                    p = self.self_prediction
                m = (p + i) % 3
                n = [0] * 3
                for d in range(3):
                    n[(m + d) % 3] = counts[d]
                yield n

    class RandomPredictor:
        def __init__(self):
            pass
        def update(self, h0, h1):
            pass
        def predictions(self, h0, h1):
            yield [third] * 3

    class PredictionBlender:
        def __init__(self, predictors):
            self.predictors = predictors
            self.counts = None
            self.predictions = None
        def update(self, h0, h1):
            s = h0[-1]
            if self.predictions is not None:
                for i, counts in enumerate(self.predictions):
                    self.counts[i] += counts[s]
            for predictor in self.predictors:
                predictor.update(h0, h1)
        def predict(self, h0, h1):
            self.predictions = []
            for predictor in self.predictors:
                for counts in predictor.predictions(h0, h1):
                    self.predictions.append(counts)
            if self.counts is None:
                n = len(self.predictions)
                self.counts = [0.5] * n
            random_predictions = [belief(counts) for counts in self.predictions]
            weights = belief(self.counts)
            p = [0] * 3
            for q, w in zip(random_predictions, weights):
                for i in range(3):
                    p[i] += w * q[i]
            scores = [p[bad_against[m]] - p[good_against[m]] for m in moves]
            return scores.index(max(scores))

    predictors = [
        MetaPredictor(MarkovPredictor),
        MetaPredictor(FrequencyPredictor),
        MetaPredictor(lambda: FrequencyPredictor(k=0.99)),
        MetaPredictor(lambda: FrequencyPredictor(k=0.9)),
        MetaPredictor(lambda: FrequencyPredictor(k=0.8)),
        MetaPredictor(lambda: FrequencyPredictor(k=0.5)),
        RandomPredictor()
    ]
    model = PredictionBlender(predictors)
    h0 = []
    h1 = []
    output = random.choice(name)
else:
    us = index[output]
    them = index[input] 
    h0.append(them)
    h1.append(us)
    model.update(h0, h1)
    h0.append(us)
    h1.append(them)
    output = name[model.predict(h0, h1)]