CTWMetaOnly

This program has been disqualified.


AuthorSean
Submission date2016-02-20 19:46:56.557990
Rating5945
Matches played115
Win rate59.13

Source code:

if input == "":

    import array
    import math
    import collections
    import random

    log = math.log
    exp = math.exp
    third = 1/3.0
    log_half = log(0.5)
    log_third = log(third)
    log_sixth = log(1/6.0)
    log2 = log(2.0)
    log3 = log(3.0)
    log5 = log(5.0)
    log7 = log(7.0)
    R, P, S = 0, 1, 2
    strategies = ((R, P, S), (P, S, R), (S, R, P))
    index = {"R": 0, "P": 1, "S": 2}
    name = ("R", "P", "S")
    beat = (1, 2, 0)

    def log_add(x, y):
        if y > x:
            x, y = y, x
        d = y - x
        if d < -60:
            return x
        return x + log(1.0 + exp(d))

    def laplace_smoothing(counts, n, x):
        return (counts[x] + 1.0) / (n + len(counts))

    def update_meta_counts(counts, meta_counts, x):
        if x >= 3:
            o = 3
            x -= 3
        else:
            o = 0
        y = 0
        z = -1
        for y1 in xrange(3):
            z1 = counts[o + y1]
            if z1 > z:
                z = z1
                y = y1
        for j, s in enumerate(strategies):
            if s[y] == x:
                meta_counts[o + j] += 1

    def generate_probs(counts, meta_counts, x):
        if x >= 3:
            x -= 3
        p = 0
        m0 = sum(1 for y in counts if y)
        n0 = sum(counts)
        m1 = sum(1 for y in meta_counts if y)
        n1 = sum(meta_counts)
        for q, s in enumerate(strategies):
            for k, y in enumerate(s):
                if y == x:
                    p += laplace_smoothing(meta_counts, n1, q) * \
                         laplace_smoothing(counts, n0, k)
        return p

    class ContextTree:
        def __init__(self, n):
            self.log_p_kt = 0.0
            self.log_p = 0.0
            self.counts = array.array('i',(0 for _ in xrange(n)))
            self.meta_counts = array.array('i',(0 for _ in xrange(n)))
            self.total = 0
            self.children = None
        def update(self, history, i=0):
            x = history[i]
            if i and (x >= 3):
                x -= 3
            p = generate_probs(self.counts, self.meta_counts, x)
            self.log_p_kt += log(p)
            update_meta_counts(self.counts, self.meta_counts, x)
            self.total += 1
            self.counts[x] += 1
            if self.total == 1 or i >= len(history) - 1 or i >= 16:
                self.log_p = self.log_p_kt
                return
            if self.children is None:
                self.children = [None for _ in xrange(len(self.counts))]
            if self.children[x] is None:
                self.children[x] = ContextTree(3)
            self.children[x].update(history, i + 1)
            log_p_children = 0
            for child in self.children:
                if child is not None:
                    log_p_children += child.log_p
            self.log_p = log_add(self.log_p_kt, log_p_children) + log_half
        def predict(self, history, i=0):
            x = history[i]
            if i and x >= 3:
                x -= 3
            p = generate_probs(self.counts, self.meta_counts, x)
            log_p_kt = self.log_p_kt + log(p)
            if self.total == 0 or i >= len(history) - 1 or i >= 16:
                return log_p_kt
            log_p_children = 0
            if self.children is not None:
                for y, child in enumerate(self.children):
                    if child is not None:
                        if y == x:
                            log_p_children += child.predict(history, i + 1)
                        else:
                            log_p_children += child.log_p
                    elif y == x:
                        if len(self.counts) == 3:
                            log_p_children += log_sixth
                        else:
                            log_p_children += log_third
            return log_add(log_p_kt, log_p_children) + log_half
    both = ContextTree(6)
    history = collections.deque([])
    output = random.choice(name)
    pred = None
else:
    i = index[input]
    j = index[output]
    history.appendleft(i)
    both.update(history)
    history.appendleft(3 + j)
    both.update(history)
    ps = [0.0, 0.0, 0.0]
    uniform_log_p = -(len(history) +  1) * log3
    for i1, _ in enumerate(ps):
        history.appendleft(i1)
        a = both.predict(history)
        a = log_add(a, uniform_log_p)
        ps[i1] = a - log2
        history.popleft()
    t = log_add(log_add(ps[0], ps[1]), ps[2])
    scores = [0, 0, 0]
    for _ in xrange(3):
        r = t + log(random.random())
        for k, log_p in enumerate(ps):
            if k == 0:
                x = log_p
            else:
                x = log_add(x, log_p)
            if r <= x:
                break
        a = beat[k]
        b = beat[a]
        scores[a] += 1
        scores[b] -= 1
    m = max(scores)
    output = name[random.choice([k for k, x in enumerate(scores) if x == m])]