| Author | aluizio_chris | 
| Submission date | 2016-12-29 17:28:08.189627 | 
| Rating | 6017 | 
| Matches played | 399 | 
| Win rate | 63.66 | 
Use rpsrunner.py to play unranked matches on your computer.
import random
from random import randint
class RAM:
    def __init__(self, addressSize, entrySize, addressing, decay=None, up=None):
        self.addressing = addressing
        self.decay = decay
        self.up = up
        self.ram = {}
        self.address = [ randint(0, entrySize-1) for x in range(addressSize) ]
    def _addressToIndex(self, entry):
        binCode = []
        for i in self.address:
            binCode.append(entry[i])
        return self.addressing(binCode)
    def _acumulateRam(self, index):
        if index not in self.ram:
            self.ram[index] = 0
        self.ram[index] += 1
    def _getValue(self, index):
        if index not in self.ram:
            return 0
        else:
            return self.ram[index]
    def train(self, entry, negative=False):
        index = self._addressToIndex(entry)
        if not negative:
            if self.up is None:
                self._acumulateRam(index)
            else:
                self.up(entry=entry, ram=self.ram, address=self.address, index=index)
        else:
            self.decay(entry=entry, ram=self.ram, address=self.address, index=index)
    def classify(self, entry):
        index = self._addressToIndex(entry)
        return self._getValue(index)
class Discriminator:
    def __init__(self, name, entrySize, addressSize, addressing, numberOfRAMS=None, decay=None, up=None):
        if numberOfRAMS is None:
            numberOfRAMS = int(entrySize/addressSize)
        self.rams = [ RAM(addressSize, entrySize, addressing, decay=decay, up=up) for x in range(numberOfRAMS) ]
    def train(self, entry, negative=False):
        for ram in self.rams:
            ram.train(entry, negative)
    def classify(self, entry):
        return [ ram.classify(entry) for ram in self.rams ]
class Addressing:
    def __call__(self, binCode): # binCode is a list of values of selected points of entry
        index = 0
        for i,e in enumerate(binCode):
            if e > 0:
                index += pow(2,i)
        return index
class WiSARD:
    def __init__(self,
            addressSize = 3,
            numberOfRAMS = None,
            bleachingActivated = True,
            seed = random.randint(0, 1000000),
            sizeOfEntry = None,
            classes = [],
            verbose = True,
            addressing = Addressing(),
            makeBleaching = None,
            decay = None,
            up = None):
        self.seed = seed
        self.decay = decay
        self.up = up
        random.seed(seed)
        if addressSize < 3:
            self.addressSize = 3
        else:
            self.addressSize = addressSize
        self.numberOfRAMS = numberOfRAMS
        self.discriminators = {}
        self.bleachingActivated = bleachingActivated
        self.addressing = addressing
        if makeBleaching is None:
            self.makeBleaching = self._makeBleaching
        else:
            self.makeBleaching = makeBleaching
        if sizeOfEntry is not None:
            for aclass in classes:
                self.discriminators[aclass] = Discriminator(
                    aclass, sizeOfEntry, self.addressSize,
                    self.addressing, self.numberOfRAMS, decay=self.decay, up=self.up)
    def _makeBleaching(self, discriminatorsoutput):
        bleaching = 0
        ambiguity = True
        biggestVote = 2
        while ambiguity and biggestVote > 1:
            bleaching += 1
            biggestVote = None
            ambiguity = False
            for key in discriminatorsoutput:
                discriminator = discriminatorsoutput[key]
                limit = lambda x: 1 if x >= bleaching else 0
                discriminator[1] = sum(map(limit, discriminator[0]))
                if biggestVote is None or discriminator[1] > biggestVote:
                    biggestVote = discriminator[1]
                    ambiguity = False
                elif discriminator[1] == biggestVote:
                    ambiguity = True
            if self.bleachingActivated:
                break
        return discriminatorsoutput
    def train(self, entries, classes):
        sizeOfEntry = len(entries[0])
        for i,entry in enumerate(entries):
            aclass = str(classes[i])
            if aclass not in self.discriminators:
                self.discriminators[aclass] = Discriminator(
                    aclass, sizeOfEntry, self.addressSize,
                    self.addressing, self.numberOfRAMS, decay=self.decay, up= self.up)
            self.discriminators[aclass].train(entry)
            if self.decay is not None:
                for key in self.discriminators:
                    if key != aclass:
                        self.discriminators[key].train(entry, negative=True)
    def classifyEntry(self, entry):
        discriminatorsoutput = {}
        for keyClass in self.discriminators:
            discriminatorsoutput[keyClass] = [self.discriminators[keyClass].classify(entry),0]
        discriminatorsoutput = self.makeBleaching(discriminatorsoutput)
        calc = lambda key: (key, float(discriminatorsoutput[key][1])/len(discriminatorsoutput[key][0]))
        classes = list(map(calc,discriminatorsoutput))
        classes.sort(key=lambda x: x[1], reverse=True)
        return classes
    def classify(self, entries):
        output=[]
        for i,entry in enumerate(entries):
            aclass = self.classifyEntry(entry)[0][0]
            output.append((entry, aclass))
        return output
class Decay:
    def __call__(self, **kwargs):
        if kwargs['index'] in kwargs['ram']:
            value = kwargs['ram'][kwargs['index']]
            kwargs['ram'][kwargs['index']] = 0.5*value - 0.1
class Up:
    def __call__(self, **kwargs):
        if kwargs['index'] not in kwargs['ram']:
            kwargs['ram'][kwargs['index']] = 1
        else:
            value = kwargs['ram'][kwargs['index']]
            kwargs['ram'][kwargs['index']] = 0.5*value + 1
class MakeBleaching:
    def __call__(self, discriminatorsoutput):
        for key in discriminatorsoutput:
            ramsoutput = discriminatorsoutput[key][0]
            discriminatorsoutput[key][1] = sum(ramsoutput)
        return discriminatorsoutput
def get_x(history, target):
    x = []
    
    if(type(target) == type('')):
        target = char2num[target]
    for i in history:
        if(i == target):
            x.append(1)
        else:
            x.append(0)
    return x
def get_x_two_code(history, target=''):
    x = []
    
    for i in history:
        if(i == "R"):
            x.extend([1,0])
        elif(i == "P"):
            x.extend([0,1])
        else:
            x.extend([1,1])
    return x
def get_x_three_code(history, target=''):
    x = []
    
    for i in history:
        if(i == "R"):
            x.extend([1,0,0])
        elif(i == "P"):
            x.extend([0,1,0])
        else:
            x.extend([0,0,1])
    return x
if input == "":
    turn = 0
    history = []
    last_prediction = ''
    chutes = 0
    duvidas = 0
    certezas = 0
    win = 0
    # hyperparameters
    history_size = 16
    min_random_turns = 200
    final_random_turns = 0
    address_size=4
    get_x_function=get_x
    # ****************
    wisard_is_rock = WiSARD(addressSize=address_size,classes=['R', 'PS'],up=Up(),decay=Decay(),verbose=False,makeBleaching=MakeBleaching())
    wisard_is_paper = WiSARD(addressSize=address_size,classes=['P', 'RS'],up=Up(),decay=Decay(),verbose=False,makeBleaching=MakeBleaching())
    wisard_is_scissor = WiSARD(addressSize=address_size,classes=['S', 'RP'],up=Up(),decay=Decay(),verbose=False,makeBleaching=MakeBleaching())
    char2num = {"R":0, "P":1, "S":2}
    num2char = {0:"R", 1:"P", 2:"S"}
    defeated_by = {"R":"P", "P":"S", "S":"R"}
    prediction = random.choice(["R","P","S"])
    output = defeated_by[prediction]
elif len(history) < history_size or turn < min_random_turns or turn > 1000 - final_random_turns:
    prediction = random.choice(["R","P","S"])
    output = defeated_by[prediction]
    history.append(char2num[input])
    if(len(history) > history_size) : history.pop(0)
else:
    x_R = get_x_function(history, "R")
    x_P = get_x_function(history, "P")
    x_S = get_x_function(history, "S")
    # training
    if(input == "R"):
        wisard_is_rock.train([x_R], ["R"])
        wisard_is_paper.train([x_P], ["RS"])
        wisard_is_scissor.train([x_S], ["RP"])
    elif(input == "P"):
        wisard_is_paper.train([x_P], ["P"])
        wisard_is_rock.train([x_R], ["PS"])
        wisard_is_scissor.train([x_S], ["RP"])
    else:
        wisard_is_scissor.train([x_S], ["S"])
        wisard_is_rock.train([x_R], ["PS"])
        wisard_is_paper.train([x_P], ["RS"])
    # updating history
    history.append(char2num[input])
    history.pop(0)
    x_R = get_x_function(history, "R")
    x_P = get_x_function(history, "P")
    x_S = get_x_function(history, "S")
    # classifying
    result_R = wisard_is_rock.classifyEntry(x_R)
    result_P = wisard_is_paper.classifyEntry(x_P)
    result_S = wisard_is_scissor.classifyEntry(x_S)
    # print(str(result_R) + str(result_P) + str(result_S))
    possibilities = ['R','P','S']
    if(result_R[0][0] == 'PS' and result_R[0][1] >= 0.5):
        possibilities.remove('R')
    if(result_P[0][0] == 'RS' and result_P[0][1] >= 0.5):
        possibilities.remove('P')
    if(result_S[0][0] == 'RP' and result_S[0][1] >= 0.5):
        possibilities.remove('S')
    if(len(possibilities) > 0 and win/float(turn) > 0.2):
        if(len(possibilities) == 1) : certezas += 1
        elif(len(possibilities) == 2) : duvidas += 1
        else : chutes += 1
        prediction = random.choice(possibilities)
    else:
        chutes += 1
        prediction = random.choice(["R","P","S"])
    output = defeated_by[prediction]
if(input != '' and last_prediction != '' and last_prediction == input):
    win += 1
last_prediction = prediction
turn += 1