iocane3

This program has been disqualified.


AuthorSean
Submission date2017-04-06 08:00:16.848568
Rating6974
Matches played140
Win rate71.43

Source code:

if input == "":

    import collections
    import math
    import random

    gamma = random.gammavariate
    sqrt = math.sqrt
    log = math.log
    exp = math.exp
    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")

    def log_add(a, b):
        if a > b:
            a, b = b, a
        return a + log(1+exp(b-a))

    log_half = log(0.5)

    def log_mean(a, b):
        return log_add(a, b) + log_half

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

    class CTW:
        def __init__(self):
            self.counts = [0.5] * 3
            self.children = None
            self.p_self = 0
            self.p_children = 0
            self.p = 0
        def update(self, h):
            s = h[-1]
            i = len(h) - 2
            d = 0
            self.update_helper(s, h, i, d)
        def update_helper(self, x, h, i, d):
            p_cond = log(self.counts[x] / sum(self.counts))
            self.p_self += p_cond
            self.counts[x] += 1
            if i < 0 or d >= 10:
                self.p = self.p_self
                return
            if self.children is None:
                self.children = tuple(CTW() for _ in range(3))
                self.p_children = self.p_self
            child = self.children[h[i]]
            self.p_children -= child.p
            child.update_helper(x, h, i - 1, d + 1)                 
            self.p_children += child.p
            self.p = log_mean(self.p_self, self.p_children)
        def predict(self, h):
            i = len(h) - 1
            d = 0
            p = [exp(self.predict_helper(m, h, i, d) - self.p) for m in moves]
            scores = [p[bad_against[m]] - p[good_against[m]] for m in moves]
            s = max(scores)
            return random.choice([m for m in moves if scores[m] == s])
        def predict_helper(self, m, h, i, d):
            p_cond = log(self.counts[m] / sum(self.counts))
            p_self = self.p_self + p_cond
            if i < 0 or d >= 10:
                return p_self
            if self.children is None:
                return p_self
            child = self.children[h[i]] 
            p_children = self.p_children - child.p
            p_children += child.predict_helper(m, h, i - 1, d + 1)                 
            return log_mean(p_self, p_children)

    class Markov:
        def __init__(self):
            self.seen = None
            self.children = None
        def update(self, h):
            s = h[-1]
            i = len(h) - 2
            d = 0
            while d < 10:
                self.seen = s
                if self.children is None:
                    self.children = tuple(Markov() for _ in range(3))
                if i < 0:
                    return
                self = self.children[h[i]]
                i -= 1
                d += 1
        def predict(self, h):
            i = len(h) - 1
            while self.seen is not None:
                seen = self.seen
                self = self.children[h[i]]
                i -= 1
            return seen

    class Frequency:
        def __init__(self, k=1):
            self.k=k
            self.counts = [0, 0, 0]
        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 Meta:
        def __init__(self, predictor):
            self.predictor = predictor    
            self.prediction = None
            self.counts = [[0 for _ in range(3)] for _ in range(3)]
        def update(self, h):
            s = h[-1]
            if self.prediction is not None:
                for i, counts in enumerate(self.counts):
                    m = (self.prediction + i) % 3
                    if m == good_against[s]:
                        counts[2] += 1
                    elif m == bad_against[s]:
                        counts[0] += 1
                    else:
                        counts[1] += 1
            self.predictor.update(h)
        def predictions(self, h):
            self.prediction = self.predictor.predict(h)
            for i, counts in enumerate(self.counts):
                p = belief(counts)
                yield ((self.prediction + i) % 3, p[2] - p[0])

    class Random:
        def __init__(self):
            pass
        def update(self, h):
            pass
        def predictions(self, h):
            return [(random.choice(moves), 0)]

    class PredictionBlender:
        def __init__(self, predictors):
            self.predictors = predictors
        def update(self, h):
            for predictor in self.predictors:
                predictor.update(h)
        def predict(self, h):
            predictions = [p for predictor in self.predictors for p in predictor.predictions(h)] 
            best_score = float('-inf')
            for m, score in predictions:
                if score > best_score:
                    move = m
                    best_score = score
            return move

    predictors = [
        Meta(Markov()),
        Meta(Frequency()),
        Meta(Frequency(k=0.99)),
        Meta(Frequency(k=0.9)),
        Meta(Frequency(k=0.8)),
        Meta(Frequency(k=0.5)),
        Meta(CTW()),
        Random()
    ]
    model = PredictionBlender(predictors)
    history = []
    output = random.choice(name)
else:
    us = index[output]
    them = index[input] 
    history.append(them)
    model.update(history)
    history.append(us)
    output = name[model.predict(history)]