neuralevolution

This program has been disqualified.


Authorpyfex
Submission date2011-07-20 15:49:15.571996
Rating7029
Matches played228
Win rate70.61

Source code:

# See http://overview.cc/RockPaperScissors for more information about rock, paper, scissors
# Trying out a new approach. Use a neural network. The weights are adjusted using an 
# evolutionary technique.

if input == "":
    from collections import defaultdict
    import random
    import operator
    from itertools import izip
    split = {'R': [1, 0, 0], 'P': [0, 1, 0], 'S': [0, 0, 1], '':[0, 0, 0]}
    rps = ['R', 'P', 'S']
    beat = {'P': 'S', 'S': 'R', 'R': 'P'}
    cede = {'P': 'R', 'S': 'P', 'R': 'S'}
    score = {'RR': 0, 'PP': 0, 'SS': 0, 'PR': 1, 'RS': 1, 'SP': 1,'RP': -1, 'SR': -1, 'PS': -1,}
    hist = ""
    patterns = defaultdict(str)
    patterns2 = defaultdict(str)
    output = random.choice(rps)
    class Gene:
        def __init__(self, length, initrandom=True):
            self.length = length
            if initrandom:
                self.rockweight = [0] * (length+1)
                v = random.random()
                self.rockweight[random.randint(0,length-1)] = v
                self.rockweight[length] = v / 2
                self.paperweight = [0] * (length+1)
                v = random.random()
                self.paperweight[random.randint(0,length-1)] = v
                self.paperweight[length] = v / 2
                self.scissorsweight = [0] * (length+1)
                v = random.random()
                self.scissorsweight[random.randint(0,length-1)] = v
                self.scissorsweight[length] = v / 2
            else:
                self.rockweight = [0] * (length+1)
                self.paperweight = [0] * (length+1)
                self.scissorsweight = [0] * (length+1)
            self.performance = {'R': 1, 'P':1, 'S': 1}
            self.totalperformance = 1
            self.bestperformance = 0
            self.candidates = []

        def evaluate(self, neuroinp):
            candidates = []
            net = sum([i*w for i, w in izip(neuroinp, self.rockweight)])
            if net > self.rockweight[-1]:
                candidates.append('R')
            net = sum([i*w for i, w in izip(neuroinp, self.paperweight)])
            if net > self.paperweight[-1]:
                candidates.append('P')
            net = sum([i*w for i, w in izip(neuroinp, self.scissorsweight)])
            if net > self.scissorsweight[-1]:
                candidates.append('S')
            self.candidates = candidates
            return candidates

        def teach(self, hand):
            for h in rps:
                if (h == hand) == (h in self.candidates):
                    self.performance[h] += 1
                    self.totalperformance += 1
            self.bestperformance = max([self.performance[h] for h in rps])

        def crossover(self, other):
            new = Gene(self.length, initrandom=False)
            for h in rps:
                new.performance[h] = (self.performance[h] + other.performance[h]) / 2
            new.totalperformance = (self.totalperformance + other.totalperformance) / 2

            sep = self.performance['P'] / float(self.performance['P'] + other.performance['P'])
            if sep > 0.75:
                new.paperweight = self.paperweight[:]
            elif sep < 0.25:
                new.paperweight = other.paperweight[:]
            else:
                for i, (s, w) in enumerate(izip(self.paperweight, other.paperweight)):
                    new.paperweight[i] = (self.paperweight[i] + other.paperweight[i]) / 2

            sep = self.performance['R'] / float(self.performance['R'] + other.performance['R'])
            if sep > 0.75:
                new.rockweight = self.rockweight[:]
            elif sep < 0.25:
                new.rockweight = other.rockweight[:]
            else:
                for i, (s, w) in enumerate(izip(self.rockweight, other.rockweight)):
                    new.rockweight[i] = (self.rockweight[i] + other.rockweight[i]) / 2

            sep = self.performance['S'] / float(self.performance['S'] + other.performance['S'])
            if sep > 0.75:
                new.scissorsweight = self.scissorsweight[:]
            elif sep < 0.25:
                new.scissorsweight = other.scissorsweight[:]
            else:
                for i, (s, w) in enumerate(izip(self.scissorsweight, other.scissorsweight)):
                    new.scissorsweight[i] = (self.scissorsweight[i] + other.scissorsweight[i]) / 2
            return new

    genelength = 15
    genes = [Gene(genelength) for e in xrange(50)]
    g1 = Gene(genelength, initrandom=False)
    g1.rockweight =     [1, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0.5]
    g1.paperweight =    [0, 1, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0.5]
    g1.scissorsweight = [0, 0, 1,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0, 0, 0,  0.5]

    genes = [g1] + genes
    rnd = 0
    my = opp = my2 = opp2 = ''
else:
    for g in genes:
        g.teach(input)
    genes.sort(key=operator.attrgetter('totalperformance'), reverse=True)
    del genes[-1]
    del genes[-1]
    del genes[-1]
    del genes[-1]
    del genes[-1]

    for i in range(min(len(hist)/2,5), 0, -1):
        pattern = patterns[hist[-i*2:]]
        if pattern:
            for j in range(min(len(pattern)/2,5), 0, -1):
                patterns2[pattern[-2*j]] += output + input
        patterns[hist[-i*2:]] += output + input

    hist += output + input
    my = opp = my2 = opp2 = ''
    for i in range(min(len(hist)/2,5), 0, -1):
        pattern = patterns[hist[-2*i:]]
        if pattern:
            my, opp = pattern[-2:]
            for j in range(min(len(pattern)/2,5), 0, -1):
                pattern2 = patterns2[pattern[-2*j]]
                if pattern2:
                    my2, opp2 = pattern2[-2:]
                    break
            break

    neuroinp = split[opp] + split[my] + split[opp2] + split[my2] + split[input]
    a, b = random.sample(genes, 2)
    genes.append(a.crossover(b))
    a, b = random.sample(genes[:25], 2)
    genes.append(a.crossover(b))
    a, b = random.sample(genes[:5], 2)
    genes.append(a.crossover(b))
    a, b = random.sample(genes[:10], 2)
    genes.append(a.crossover(b))
    n = Gene(genelength)
    n.totalperformance = (a.totalperformance + b.totalperformance) / 2
    genes.append(n)

    for g in genes:
        g.evaluate(neuroinp)
    bestgene = genes[0]
    worstgene = genes[-1]
    candidates = bestgene.candidates
    
    if candidates == []:
        candidates = ['R', 'P', 'S']
    output = beat[random.choice(candidates)]