Rock-paper-scissors
In this task, the goal is to implement the classic children's game Rock Paper Scissors, as well as a simple predictive AI player.
Rock Paper Scissors has two players. Each player chooses one of rock, paper or scissors, without knowing the other player's choice. The winner is decided by a set of rules:
- Rock beats scissors
- Scissors beat paper
- Paper beats rock.
If both players choose the same thing, there is no winner for that round.
For this task's AI player, keep track of the player's choice frequency, and use that choice frequency to make a weighted random choice to beat the player's likely choice.
Ada
<lang Ada>with Ada.Text_IO; with Ada.Numerics.Float_Random;
procedure Rock_Paper_Scissors is
package Rand renames Ada.Numerics.Float_Random; Gen: Rand.Generator;
type Choice is (Rock, Paper, Scissors);
Cnt: array (Choice) of Natural := (1, 1, 1); -- pretend that each of R., P., and S., has been played once by the human
function Computer_Choice return Choice is Random_Number: Natural := Integer(Rand.Random(Gen) * (Float(Cnt(Rock)) + Float(Cnt(Paper)) + Float(Cnt(Scissors)))); begin if Random_Number < Cnt(Rock) then -- guess the human will choose Rock return Paper; elsif Random_Number - Cnt(Rock) < Cnt(Paper) then -- guess the human will choose Paper return Scissors; else -- guess the human will choose Scissors return Rock; end if; end Computer_Choice;
Finish_The_Game: exception;
function Human_Choice return Choice is Done: Boolean := False; T: constant String := "enter ""r"" for Rock, ""p"" for Paper, or ""s"" for Scissors""!"; U: constant String := "or enter ""q"" to Quit the game"; Result: Choice; begin Ada.Text_IO.Put_Line(T); Ada.Text_IO.Put_Line(U); while not Done loop Done := True; declare S: String := Ada.Text_IO.Get_Line; begin if S="r" or S="R" then Result := Rock; elsif S="p" or S = "P" then Result := Paper; elsif S="s" or S="S" then Result := Scissors; elsif S="q" or S="Q" then raise Finish_The_Game; else Done := False; end if; end; end loop; return Result; end Human_Choice;
type Result is (Human_Wins, Draw, Computer_Wins);
function "<" (X, Y: Choice) return Boolean is -- X < Y if X looses against Y begin case X is when Rock => return (Y = Paper); when Paper => return (Y = Scissors); when Scissors => return (Y = Rock); end case; end "<";
Score: array(Result) of Natural := (0, 0, 0);
C,H: Choice;
Res: Result;
begin
-- play the game loop C := Computer_Choice; -- the computer makes its choice first H := Human_Choice; -- now ask the player for his/her choice Cnt(H) := Cnt(H) + 1; -- update the counts for the AI if C < H then Res := Human_Wins; elsif H < C then Res := Computer_Wins; else Res := Draw; end if; Ada.Text_IO.Put_Line("COMPUTER'S CHOICE: " & Choice'Image(C) & " RESULT: " & Result'Image(Res)); Ada.Text_IO.New_Line; Score(Res) := Score(Res) + 1; end loop;
exception
when Finish_The_Game => Ada.Text_IO.New_Line; for R in Score'Range loop Ada.Text_IO.Put_Line(Result'Image(R) & Natural'Image(Score(R))); end loop;
end Rock_Paper_Scissors;</lang>
First and last few lines of the output of a game, where the human did permanently choose Rock:
./rock_paper_scissors enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: SCISSORS RESULT: HUMAN_WINS enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: ROCK RESULT: DRAW enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: SCISSORS RESULT: HUMAN_WINS enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: ROCK RESULT: DRAW [...] enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: ROCK RESULT: DRAW enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game r COMPUTER'S CHOICE: PAPER RESULT: COMPUTER_WINS enter "r" for Rock, "p" for Paper, or "s" for Scissors"! or enter "q" to Quit the game q HUMAN_WINS 2 DRAW 5 COMPUTER_WINS 21
Python
<lang python>#!/usr/bin/python from random import randint, random from operator import add from functools import reduce from bisect import bisect_left
WHATBEATS = { 'paper' : 'scissors',
'scissors' : 'rock', 'rock' : 'paper' }
ORDER = ('rock', 'paper', 'scissors')
CHOICEFREQUENCY = {}
def probChoice(choices, probabilities):
scalefactor = reduce(add, probabilities) prob_accumulator = 0 accumulator = [] for p in probabilities: prob_accumulator += float(p) / scalefactor accumulator.append(prob_accumulator) r = random() bsct = bisect_left(accumulator, r) chc = choices[bsct] return chc
def checkWinner(a, b):
global WHATBEATS
abeater = WHATBEATS[a] bbeater = WHATBEATS[b]
if b == abeater: return b elif a == bbeater: return a
return None
def sanitizeChoice(a):
# Drop it to lower-case return a.lower()
def registerPlayerChoice(choice):
global CHOICEFREQUENCY if choice in CHOICEFREQUENCY: CHOICEFREQUENCY[choice] += 1 else: CHOICEFREQUENCY[choice] = 1
def getRandomChoice():
global WHATBEATS global ORDER global CHOICEFREQUENCY if len(CHOICEFREQUENCY.keys()) == 0: return ORDER[randint(0,len(ORDER)-1)] choices = CHOICEFREQUENCY.keys() probabilities = CHOICEFREQUENCY.values() return WHATBEATS[probChoice(choices, probabilities)]
while True:
choice = raw_input() choice = sanitizeChoice(choice) if not choice in ORDER: continue
compChoice = getRandomChoice() print "Computer picked", compChoice,
# Don't register the player choice until after the computer has made # its choice. registerPlayerChoice(choice)
winner = checkWinner(choice, compChoice)
if winner == None: winner = "nobody"
print winner, "wins!"