Skip to content

Multiplayer Rock, Paper, Scissors

Determine the winner (or remaining players) after several rounds of multiplayer Rock, Paper, Scissors.

Players stand in a circle and all throw at once. If rock, paper, and scissors are all thrown, it is a stalemate, and they rethrow. If only two throws are present, all players with the losing throw are eliminated. The following function decides which throws from a set of set of throws in a single round should be eliminated.

The actions of players are decided in advance; e.g. for two rounds of three-player RPS, the players and actions are represented as:

scheme
(define players '("alice" "bob" "charlie"))
(define strategies '((r p) (r r) (s p)))

where Alice throws Rock in the first round, then Paper in the second. Charlie never gets to throw his second pick (Paper), as he will be eliminated after one round. Alice is the only remaining player after the two rounds. The result should be '("alice").

You will need to keep track of the players and their actions. In each round, figure out which throws should be eliminated, then filter out the corresponding players and their strategies. Create two helper functions: one that creates a boolean "mask" of all the winners of a single round, and one that performs the filtering.

Racket

Throws will be represented as the symbols 'r, 'p and 's.

scheme
#lang racket
(provide rps)

(define (game-finished? strats) (or (null? strats) (ormap null? strats)))
(define (strats-current strats) (map car strats))
(define (strats-future strats) (map cdr strats))

(define (rps players strategies)
  (if (game-finished? strategies)
    players
    (let* ((current (strats-current strategies))
           (future (strats-future strategies)))
        ; Implement me!
      )
)

You can use the remove-duplicates function to remove duplicate throws and sort with symbol<? to order throws.

Your file is to be called rps.rkt and must provide the function rps.

Examples

Alice wins in the second round. Charlie loses immediately.

scheme
(define players '("alice" "bob" "charlie"))
(define strategies '((r p) (r r) (s p)))

(rps players strategies); '("alice")

Charlie loses because rock beats scissors (single round).

scheme
(define players '("alice" "bob" "charlie"))
(define strategies '((r) (r) (s)))

(rps players strategies); '("alice" "bob")

First two rounds are stalemates (stalemate, stalemate, win).

scheme
(define players '("alice" "bob" "charlie"))
(define strategies '((r p r) (p s r) (s r p)))

(rps players strategies) ; '("charlie")
Details
scheme
#lang racket

(provide rps)

(define players '("alice" "bob" "charlie"))
(define strategies '((r p) (r r) (s p)))

(define (game-finished? strats) (andmap null? strats))
(define (strats-current strats) (map car strats))
(define (strats-future strats) (map cdr strats))

(define (view xs bools)
  (for/list ((x xs) (b bools) #:when b) x))

(define (eliminated-throw throws)
  (match (remove-duplicates (sort throws symbol<?))
    ('(p r) 'r)
    ('(p s) 'p)
    ('(r s) 's)
    (_ '())))

(define (rps-survivors throws)
  (let* ((elim (eliminated-throw throws)))
    (map (curry (compose not equal?) elim) throws)))

(define (rps players strategies)
  (if (game-finished? strategies)
      players
      (let* ((current (strats-current strategies))
             (future (strats-future strategies))
             (mask (rps-survivors current)))
        (rps (view players mask) (view future mask)))))

Haskell

For simplicity, throws will be represented as the characters 'r', 'p' and 's'. Your task is to be called RPS.hs and must export the rps function.

haskell
module RPS (rps) where
import Data.List

isFinished xs = null xs || any null xs

currentStrategies = map head

futureStrategies = map tail

rps :: [String] -> [[Char]] -> [String]
rps players strategies | isFinished strategies = players
rps players strategies =
    let current = currentStrategies strategies
        future = futureStrategies strategies
    in [] -- Implement me !

You can use the nub function to remove duplicate throws and sort to order the throws.

Examples

Alice wins in the second round. Charlie loses immediately.

haskell
players = ["alice", "bob", "charlie"]
strategies = [['r', 'p'], ['r', 'r'], ['s', 'p']]

rps players strategies -- ["alice"]

Charlie loses because rock beats scissors (single round).

haskell
players = ["alice", "bob", "charlie"]
strategies = [['r'], ['r'], ['s']]

rps players strategies -- ["alice", "bob"]

First two rounds are stalemates (stalemate, stalemate, win).

haskell
players = ["alice", "bob", "charlie"]
strategies = [['r', 'p', 'r'], ['p', 's', 'r'], ['s', 'r', 'p']]

rps players strategies -- ["charlie"]
Details
haskell
module Task4 (rps) where
import Data.List

isFinished xs = null xs || any null xs

currentStrategies = map head

futureStrategies = map tail

view xs bs = map fst $ filter snd $ zip xs bs

eliminated throws =
    let e = elim $ sort $ nub throws
    in map (/= e) throws
    where
        elim ['p', 'r'] = 'r'
        elim ['p', 's'] = 'p'
        elim ['r', 's'] = 's'
        elim _ = ' '

rps :: [String] -> [[Char]] -> [String]
rps players strategies | isFinished strategies = players
rps players strategies =
    let current = currentStrategies strategies
        future = futureStrategies strategies
        mask = eliminated current
    in rps (view players mask) (view future mask)