Author | clawsoon |
Submission date | 2017-12-31 19:42:44.472080 |
Rating | 7743 |
Matches played | 316 |
Win rate | 74.37 |
Use rpsrunner.py to play unranked matches on your computer.
# 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()