neural12e02a

Authorclawsoon
Submission date2017-12-31 19:42:44.472080
Rating7743
Matches played316
Win rate74.37

Use rpsrunner.py to play unranked matches on your computer.

Source code:

# Neural net without numpy.  A wee bit on the slow side.  Learning rate = 1.0.

if input:
    output = rps.play(input)

else:

    import random, math
    from itertools import imap
    from operator import mul

    class RPS:

        letter2move = {
            'R': [1,0,0],
            'P': [0,1,0],
            'S': [0,0,1],
        }

        training = {
            'R': [0.02, 0.97, 0.01],
            'P': [0.01, 0.02, 0.97],
            'S': [0.97, 0.01, 0.02],
        }

        def __init__(self, memory_length=12):

            nn_input_size = memory_length*2*3
            self.moves = [0] * nn_input_size
            layer_sizes = [nn_input_size, nn_input_size / 2, 3]
            self.nn = NN(layer_sizes)
            self.turn = 0


        def play(self, their_last_letter=None):
            if their_last_letter:
                their_last_move = self.letter2move[their_last_letter]
                self.nn.train(self.training[their_last_letter])
                self.moves = self.my_last_move + their_last_move + self.moves[:-6]

            my_inclinations = self.nn.query(self.moves)
            my_letter = self.choose(my_inclinations)
            self.my_last_move = self.letter2move[my_letter]

            self.turn += 1

            return my_letter


        def choose(self, inclinations):
            total = sum(inclinations)
            cut = random.uniform(0, total)
            if cut < inclinations[0]:
                return 'R'
            elif cut < (inclinations[0] + inclinations[1]):
                return 'P'
            else:
                return 'S'


    class NN:
        def __init__(self, layer_sizes):
            self.weights = []
            self.weight_dimensions = []
            for n_before, n_after in zip(layer_sizes[:-1], layer_sizes[1:]):
                std_dev = n_after**-.5
                weights = [[random.gauss(0.0, std_dev) for x in xrange(n_before)] for y in xrange(n_after)]
                self.weights.append(weights)
                self.weight_dimensions.append((n_after, n_before))

        def train(self, targets):
            errors = [t-l for t,l in zip(targets, self.layers[-1])]
            #errors = list(imap(sub, targets, self.layers[-1]))

            for i in xrange(len(self.weights)-1, -1, -1):
                weights = self.weights[i]
                dimensions = self.weight_dimensions[i]
                after = self.layers[i+1]
                before = self.layers[i]

                new_errors = []
                for j in xrange(dimensions[1]):
                    column = [row[j] for row in weights]
                    new_errors.append(sum(imap(mul, errors, column)))

                for n_after in xrange(dimensions[0]):
                    after_total = after[n_after]
                    after_slope = after_total * (1.0 - after_total)
                    after_contrib = after_slope * errors[n_after]
                    weights[n_after] = [weights[n_after][n_before] + before[n_before] * after_contrib for n_before in xrange(dimensions[1])]

                errors = new_errors


        def query(self, inputs):
            current = inputs
            self.layers = [current]
            for weights in self.weights:
                current = [1.0 / (1.0 + math.exp(-sum(imap(mul, current, row)))) for row in weights]
                self.layers.append(current)
            return current


    rps = RPS(6)
    output = rps.play()