Iocane Powder

This program has been disqualified.


AuthorByron Knoll
Submission date2011-05-28 22:17:55.444040
Rating2809
Matches played388
Win rate28.09

Source code:

#!/usr/bin/env python
#
# Iocaine Powder
# Originally devised by Dan Egnor for the first annual RoShamBo
# programming competition.  Translated into python by David Bau.
# See http://ofb.net/~egnor/iocaine.html

import random

def beat(i):
  return (i + 1) % 3
def loseto(i):
  return (i - 1) % 3

def recall(age, hist):
  """Looking at the last 'age' points in 'hist', finds the
  last point with the longest similarity to the current point,
  returning 0 if none found."""
  end, length = 0, 0
  for past in xrange(1, min(age + 1, len(hist) - 1)):
    if length >= len(hist) - past: break
    for i in xrange(-1 - length, 0):
      if hist[i - past] != hist[i]: break
    else:
      for length in xrange(length + 1, len(hist) - past):
        if hist[-past - length - 1] != hist[-length - 1]: break
      else: length += 1
      end = len(hist) - past
  return end

class Stats:
  def __init__(self):
    self.sum = [[0, 0, 0]]
  def add(self, move, score):
    self.sum[-1][move] += score
  def advance(self):
    self.sum.append(self.sum[-1])
  def max(self, age, default, score):
    if age >= len(self.sum): diff = self.sum[-1]
    else: diff = [self.sum[-1][i] - self.sum[-1 - age][i] for i in xrange(3)]
    m = max(diff)
    if m > score: return diff.index(m), m
    return default, score

class Predictor:
  def __init__(self):
    self.stats = Stats()
    self.lastguess = -1
  def addguess(self, lastmove, guess):
    if lastmove != -1:
      diff = (lastmove - self.prediction) % 3
      self.stats.add(beat(diff), 1)
      self.stats.add(loseto(diff), -1)
      self.stats.advance()
    self.prediction = guess
  def bestguess(self, age, best):
    bestdiff = self.stats.max(age, (best[0] - self.prediction) % 3, best[1])
    return (bestdiff[0] + self.prediction) % 3, bestdiff[1]

ages = [5, 2, 1]

class Iocaine:
  def __init__(self):
    self.predictors = []
    self.predict_history = self.predictor((len(ages), 2, 3))
    self.predict_frequency = self.predictor((len(ages), 2))
    self.predict_fixed = self.predictor()
    self.predict_random = self.predictor()
    self.predict_meta = [Predictor() for a in xrange(len(ages))]
    self.stats = [Stats() for i in xrange(2)]
    self.histories = [[], [], []]
  def predictor(self, dims=None):
    if dims: return [self.predictor(dims[1:]) for i in xrange(dims[0])]
    self.predictors.append(Predictor())
    return self.predictors[-1]
  def move(self, them):
    if them != -1:
      self.histories[1].append(them)
      self.histories[2].append((self.histories[0][-1], them))
      for watch in xrange(2):
        self.stats[watch].add(self.histories[watch][-1], 1)
    rand = random.randrange(3)
    for a, age in enumerate(ages):
      best = [recall(age, hist) for hist in self.histories]
      for mimic in xrange(2):
        for watch, when in enumerate(best):
          if not when: move = rand
          else: move = self.histories[mimic][when]
          self.predict_history[a][mimic][watch].addguess(them, move)
        mostfreq, score = self.stats[mimic].max(age, rand, -1)
        self.predict_frequency[a][mimic].addguess(them, mostfreq)
    self.predict_random.addguess(them, rand)
    self.predict_fixed.addguess(them, 0)
           
    for meta, age in enumerate(ages):
      best = (-1, -1)
      for predictor in self.predictors:
        best = predictor.bestguess(age, best)
      self.predict_meta[meta].addguess(them, best[0])
 
    best = (-1, -1)
    for meta in xrange(len(ages)):
      best = self.predict_meta[meta].bestguess(age, best) 
    self.histories[0].append(best[0])
    return best[0]

moveArray = ["R", "P", "S"]
if input == "":
	iocaine = Iocaine()
	param = -1
elif input == "R":
	param = 0
elif input == "P":
	param = 1
elif input == "S":
	param = 2
output = moveArray[iocaine.move(param)]