Author | azure |
Submission date | 2019-04-20 07:13:06.994810 |
Rating | 4973 |
Matches played | 242 |
Win rate | 46.28 |
Use rpsrunner.py to play unranked matches on your computer.
import random
# rock-paper-scissors (RPS game)
class RPSai:
'''
RPS class for the game
Bayes strategy
'''
def __init__(self,k = 2):
'''
record history steps
k represents how far we look through the history
prob represents the opponents' history move probability
kback_prob represents P(I[n-1],I[n-2],...,I[n-k]|I[n]) where n is the last step, reflextive probability by Bayes
'''
self.history = []
self.k = k
# probability distribution of the opponent's move through the whole game
self.prob = {'R':0.1,'P':0.1,'S':0.1}
self.kback_prob = {}
# kback_prob initilization, non-zero initilization to avoid zero divisor
for d3 in 'RPS':
for d2 in 'RPS':
for d1 in 'RPS':
backStr = d3+d2+d1
self.kback_prob[backStr] = 0.1
def opponentMove(self,move):
'''
take opponent's move and store
'''
if move not in 'RPS':
print('ERROR')
self.history.append(move)
self.prob[move] += 1
def beatMove(self,move):
'''
return the move which will beat the opponent's move
R beats S, S beats P, P beats R
'''
if move not in 'RPS':
print('ERROR')
beat_dict = {'S':'R','P':'S','R':'P'}
return beat_dict[move]
def predictMove(self):
'''
return a prediction of the most likely move the opponent will make
in this e.g. return the move which occurs most frequently
'''
freq = {'S':0,'R':0,'P':0}
for i in self.history:
freq[i] += 1
max_freq = 0
max_move = 'S'
for move in 'SRP':
if freq[move] > max_freq:
max_move = move
max_freq = freq[move]
return max_move
def playMove(self):
'''
return the play which will beat the expected move (generated by predictMove),
the opponent will make
'''
best_move = self.beatMove(self.predictMove())
return self.beatMove(self.predictMove())
def probLastStep(self,move):
'''
return P(I[n]) based on the history list
'''
return self.prob[move] / (self.prob['R']+self.prob['P']+self.prob['S'])
def kbackUpdate(self,kstr):
'''
take the last k+1 character string to update the kprob list
'''
lastc = kstr[-1]
history_str = "".join(self.history)
self.kback_prob[kstr] = 1.0*history_str.count(kstr) / history_str.count(lastc)
def playMovePro(self):
'''
Bayes strategy to return the best move (adopted by the machine)
Core method of pattern recognition
'''
strategies = 'RPS'
# if online training examples are not enough, then random pick
if len(self.history) < self.k+1: # condition length control waiting to be revised
idx = random.randint(0,2)
return strategies[idx]
# take the last k+1 characters and remove the last one to form a prefix str
prefix_str = "".join(self.history[-self.k-1:-1])
self.kbackUpdate(prefix_str+self.history[-1])
# update the reflextive probability
# take P(I[n]) separately
r_prob = self.probLastStep('R')
p_prob = self.probLastStep('P')
s_prob = self.probLastStep('S')
# new prefix k character string for prediction
# reflextive probability by Bayes
new_prefix_str = "".join(self.history[-self.k:])
r_reflect_prob = self.kback_prob[new_prefix_str+'R']
p_reflect_prob = self.kback_prob[new_prefix_str+'P']
s_reflect_prob = self.kback_prob[new_prefix_str+'S']
# the prefix_str probability by Bayes
prefix_prob = r_prob * r_reflect_prob + p_prob * p_reflect_prob + s_prob * s_reflect_prob
r_final_prob = r_reflect_prob * r_prob / prefix_prob
p_final_prob = p_reflect_prob * p_prob / prefix_prob
s_final_prob = s_reflect_prob * s_prob / prefix_prob
# prediction probability distribution && argmax operation
predict_prob = [r_final_prob, p_final_prob, s_final_prob]
predict_next = strategies[predict_prob.index(max(predict_prob))]
return self.beatMove(predict_next)
if input == "":
comp = RPSai()
output = "R"
else:
# print comp.history
cpuMove = comp.playMovePro()
comp.opponentMove(input)
output = cpuMove