Author | Emmanuel Harish Menon |
Submission date | 2019-05-31 21:10:18.249648 |
Rating | 4561 |
Matches played | 229 |
Win rate | 46.72 |
Use rpsrunner.py to play unranked matches on your computer.
'''
Program Name: IocainePowder_SubmissionCode[v1].py
Written By: Emmanuel Harish Menon
Last Updated: 7:09 AM on 1/6/19
Explanation:
Iocaine Powder was originally conceived by Dan Egnor for the First International RoShamBo Programming Competition. This is program is merely my interpretation of the explanation he provided on his website.
'''
#import modules
import random
import operator
#output
output = ""
#counts number of plays
playCounter = {"R": 0, "P": 0, "S": 0}
#counts wins for each predictive algorithm
winTypeCounter = {"random": 0, "freq2": 0, "freq5": 0, "freq10": 0, "freq100": 0, "freq1000": 0, "history2": 0, "history5": 0, "history10": 0, "history100": 0, "history1000": 0}
#stores meta strategy names, makes it easier to iterate through stat dictionary
metaStratList = ["naive", "secondGuess", "thirdGuess", "oppNaive", "oppSecondGuess", "oppThirdGuess"]
#stores stats for each predictive algorithm's meta strategy (I'm almost certain there is a better way to do this)
randomStats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freqStats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freq2Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freq5Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freq10Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freq100Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
freq1000Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
history2Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
history5Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
history10Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
history100Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
history1000Stats = {"naive": 0, "secondGuess": 0, "thirdGuess": 0, "oppNaive": 0, "oppSecondGuess": 0, "oppThirdGuess": 0}
#list of moves to play to win
winningMoves = {"R": "P", "P": "S", "S": "R"}
#list of choices
choices = ["R", "P", "S"]
#stores opponents move history
oppMoveHistory = []
#stores bot's move history
myMoveHistory = []
#counts number of plays
numPlays = 1
#returns the key of the largest value in dictionary
def returnDictMax(dictionary):
return max(dictionary.items(), key=operator.itemgetter(1))[0]
#metastrategy, origin is used to determine which of the dictionaries the program should use to pick its strategy
def metaStrategy(oppPick, origin = ""):
#metastrategy
def naive():
return winningMoves[oppPick]
def secondGuess():
return winningMoves[winningMoves[naive()]]
def thirdGuess():
return winningMoves[winningMoves[secondGuess()]]
def oppNaive():
return winningMoves[naive()]
def oppSecondGuess():
return winningMoves[secondGuess()]
def oppThirdGuess():
return winningMoves[thirdGuess()]
#returns a winning value
def decisionMaker(dictMax):
if dictMax == "naive":
return naive()
elif dictMax == "secondGuess":
return secondGuess()
elif dictMax == "thirdGuess":
return thirdGuess()
elif dictMax == "oppNaive":
return oppNaive()
elif dictMax == "oppSecondGuess":
return oppSecondGuess()
elif dictMax == "oppThirdGuess":
return oppThirdGuess()
#this just simplifies the code below
def picker(dictMax):
if dictMax != 0:
pick = decisionMaker(dictMax)
else:
pick = choices[random.randint(0, 2)]
return pick
#if the function is being run from the randomGuesser() function
if origin == "random":
dictMax = returnDictMax(randomStats)
pick = picker(dictMax)
return pick
#if the function is being run from the freqAnalysis(2) function
elif origin == "freq2":
dictMax = returnDictMax(freq2Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the freqAnalysis(5) function
elif origin == "freq5":
dictMax = returnDictMax(freq5Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the freqAnalysis(10) function
elif origin == "freq10":
dictMax = returnDictMax(freq10Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the freqAnalysis(100) function
elif origin == "freq100":
dictMax = returnDictMax(freq100Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the freqAnalysis(1000) function
elif origin == "freq1000":
dictMax = returnDictMax(freq1000Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the historyMatcher(2) function
elif origin == "history2":
dictMax = returnDictMax(history2Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the historyMatcher(5) function
elif origin == "history5":
dictMax = returnDictMax(history5Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the historyMatcher(10) function
elif origin == "history10":
dictMax = returnDictMax(history10Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the historyMatcher(100) function
elif origin == "history100":
dictMax = returnDictMax(history100Stats)
pick = picker(dictMax)
return pick
#if the function is being run from the historyMatcher(1000) function
elif origin == "history1000":
dictMax = returnDictMax(history1000Stats)
pick = picker(dictMax)
return pick
#this is the origin value when we are updating the stats in the table
elif origin == "test":
return [winChecker(naive(), oppMoveHistory[-1]), winChecker(secondGuess(), oppMoveHistory[-1]), winChecker(thirdGuess(), oppMoveHistory[-1]), winChecker(oppNaive(), oppMoveHistory[-1]), winChecker(oppSecondGuess(), oppMoveHistory[-1]), winChecker(oppThirdGuess(), oppMoveHistory[-1])]
#the returnVal var is used so that the function can determine whether or not to return the predicted opponent's pick or the move that beats it
def randomGuesser(returnVal = "winning move"):
oppPick = choices[random.randint(0,2)]
if returnVal == "winning move":
return metaStrategy(oppPick, "random")
elif returnVal == "predicted move":
return oppPick
#does frequency analysis within a specified range
def freqAnalysis(searchRange, returnVal = "winning move"):
#stores number of each play within range
dictPlaysInRange = {"R": 0, "P": 0, "S": 0}
#stores a separate list to oppMoveHistory
tempList = oppMoveHistory[-searchRange:]
#updates dict
for pick in tempList:
dictPlaysInRange[pick] += 1
#returns max
oppPick = returnDictMax(dictPlaysInRange)
if returnVal == "winning move":
return metaStrategy(oppPick, "freq"+str(searchRange))
elif returnVal == "predicted move":
return oppPick
#searchRange is the range that the function will search in and checkSequence is a number which tells the function how many moves it wants to compare to
def historyMatcher(checkSequence, searchRange = len(oppMoveHistory), returnVal = "winning move"):
#list that needs to be found
checkList = oppMoveHistory[-checkSequence:]
searchList = oppMoveHistory[-searchRange:-checkSequence]
arrLength = len(searchList)
oppPick = ""
#runs as long as the array is longer than the list that needs to be found
while (arrLength >= checkSequence):
check = searchList[-checkSequence-1:-1]
#if it is found, break out of the while loop
if check == checkList:
oppPick = searchList[-1]
break
#remove last element from list
searchList.pop()
#reset arrLength
arrLength = len(searchList)
#if nothing has been found, random (still debating whether to include or not)
if oppPick == "":
oppPick = choices[random.randint(0, 2)]
if returnVal == "winning move":
return metaStrategy(oppPick, "history"+str(checkSequence))
elif returnVal == "predicted move":
return oppPick
#updates relevant dict stats
def metaStratUpdater(winList, dictionaryName):
for index, item in enumerate(winList):
if item == "W":
dictionaryName[metaStratList[index]] += 1
elif item == "L":
dictionaryName[metaStratList[index]] -= 1
#used to check for wins, losses and draws
def winChecker(output, _input):
if output == _input:
return "D"
elif winningMoves[_input] == output:
return "W"
elif winningMoves[output] == _input:
return "L"
stratFunctionList = [randomGuesser, freqAnalysis, historyMatcher]
#if the previous input is not empty
if input is not "":
#add the opponents previous move to the list and increment the relevant value in the dictionary
oppMoveHistory.append(input)
lenOfList = len(oppMoveHistory)
#updates win/lose/draw results for each
for function in stratFunctionList:
if function is randomGuesser:
#the move var is just the predicted move
move = function()
winList = metaStrategy(function("predicted move"), origin = "test")
#check to see if that move would have won
moveResult = winChecker(move, input)
if moveResult == "W":
winTypeCounter["random"] += 1
metaStratUpdater(winList, randomStats)
elif moveResult == "L":
winTypeCounter["random"] -= 1
metaStratUpdater(winList, randomStats)
elif function is freqAnalysis:
if lenOfList > 2:
move = function(2)
moveResult = winChecker(move, input)
winList = metaStrategy(function(2, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["freq2"] += 1
elif moveResult == "L":
winTypeCounter["freq2"] -= 1
metaStratUpdater(winList, freq2Stats)
if lenOfList > 5:
move = function(5)
moveResult = winChecker(move, input)
winList = metaStrategy(function(5, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["freq5"] += 1
elif moveResult == "L":
winTypeCounter["freq5"] -= 1
metaStratUpdater(winList, freq5Stats)
if lenOfList > 10:
move = function(10)
moveResult = winChecker(move, input)
winList = metaStrategy(function(10, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["freq10"] += 1
elif moveResult == "L":
winTypeCounter["freq10"] -= 1
metaStratUpdater(winList, freq10Stats)
if lenOfList > 100:
move = function(100)
moveResult = winChecker(move, input)
winList = metaStrategy(function(100, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["freq100"] += 1
elif moveResult == "L":
winTypeCounter["freq100"] -= 1
metaStratUpdater(winList, freq100Stats)
if lenOfList > 1000:
move = function(1000)
moveResult = winChecker(move, input)
winList = metaStrategy(function(1000, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["freq1000"] += 1
elif moveResult == "L":
winTypeCounter["freq1000"] -= 1
metaStratUpdater(winList, freq1000Stats)
elif function is historyMatcher:
if lenOfList > 4:
move = function(2)
moveResult = winChecker(move, input)
winList = metaStrategy(function(2, lenOfList, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["history2"] += 1
elif moveResult == "L":
winTypeCounter["history2"] -= 1
metaStratUpdater(winList, history2Stats)
if lenOfList > 10:
move = function(5)
moveResult = winChecker(move, input)
winList = metaStrategy(function(5, lenOfList, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["history5"] += 1
elif moveResult == "L":
winTypeCounter["history5"] -= 1
metaStratUpdater(winList, history5Stats)
if lenOfList > 20:
move = function(10)
moveResult = winChecker(move, input)
winList = metaStrategy(function(10, lenOfList, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["history10"] += 1
elif moveResult == "L":
winTypeCounter["history10"] -= 1
metaStratUpdater(winList, history10Stats)
if lenOfList > 200:
move = function(100)
moveResult = winChecker(move, input)
winList = metaStrategy(function(100, lenOfList, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["history100"] += 1
elif moveResult == "L":
winTypeCounter["history100"] -= 1
metaStratUpdater(winList, history100Stats)
if lenOfList > 2000:
move = function(1000)
moveResult = winChecker(move, input)
winList = metaStrategy(function(1000, lenOfList, returnVal = "predicted move"), origin = "test")
if moveResult == "W":
winTypeCounter["history1000"] += 1
elif moveResult == "L":
winTypeCounter["history1000"] -= 1
metaStratUpdater(winList, history1000Stats)
playCounter[input] += 1
#first move is random
if len(oppMoveHistory) == 0:
output = choices[random.randint(0, 2)]
else:
#the strategy that has the highest score is picked, if there is no "highest score" then random
dictMax = returnDictMax(winTypeCounter)
if winTypeCounter[dictMax] <= 0 or dictMax == "random":
output = randomGuesser()
elif dictMax == "freq2":
output = freqAnalysis(2)
elif dictMax == "freq5":
output = freqAnalysis(5)
elif dictMax == "freq10":
output = freqAnalysis(10)
elif dictMax == "freq100":
output = freqAnalysis(100)
elif dictMax == "freq1000":
output = freqAnalysis(1000)
elif dictMax == "history2":
output = historyMatcher(2)
elif dictMax == "history5":
output = historyMatcher(5)
elif dictMax == "history10":
output = historyMatcher(10)
elif dictMax == "history100":
output = historyMatcher(100)
elif dictMax == "history1000":
output = historyMatcher(1000)
#not currently doing anything with this variable but...
myMoveHistory.append(output)
numPlays += 1