mag05

Authoraaasdf
Submission date2019-04-20 08:41:46.553765
Rating4944
Matches played241
Win rate47.3

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

Source code:

import random

# rock-paper-scissors (RPS game)
class RPSai:
	'''
	RPS class for the game
	Bayes strategy
	'''

	def __init__(self,k = 3):
		''' 
		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
		'''
		margin_prob = 0.05
		self.history = []
		self.k = k
		# probability distribution of the opponent's move through the whole game
		self.prob = {'R':margin_prob,'P':margin_prob,'S':margin_prob}
		self.kback_prob = {}

		# kback_prob initilization, non-zero initilization to avoid zero divisor

		for d4 in 'RPS':
			for d3 in 'RPS':
				for d2 in 'RPS':
					for d1 in 'RPS':
						backStr = d4+d3+d2+d1
						self.kback_prob[backStr] = margin_prob


	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