Rock-paper-scissors: Difference between revisions

Content added Content deleted
(I refactored the Scala code, it is more functional, more testable)
Line 3,717: Line 3,717:
My move: 'paper
My move: 'paper
You lost</pre>
You lost</pre>

Here's another code: (I refactored the above code, it is more functional, more testable )
<lang Scala>object RockPaperScissors extends App {
def beats = Map(
'rock -> Set('lizard, 'scissors),
'paper -> Set('rock, 'spock),
'scissors -> Set('paper, 'lizard),
'lizard -> Set('spock, 'paper),
'spock -> Set('scissors, 'rock)
)
// init with uniform probabilities
def initPlayed = beats.mapValues(_ => 1)
def input = Symbol(readLine(s"""Your move (${beats.keys mkString ", "}): """))
def random(max: Int) = scala.util.Random.nextInt(max)
def display(text: String) = print(text)

def weighted(todo: Iterator[(Symbol,Int)], rand: Int, accum: Int = 0): Symbol = todo.next match {
case (s, i) if rand <= (accum + i) => s
case (_, i) => weighted(todo, rand, accum + i)
}

def calcMyMove(random: Int => Int, played: Map[Symbol,Int]) = {
weighted(played.toIterator, 1 + random(played.values.sum)) match {
// choose an opponent that would beat the player's anticipated move
case h => beats.find{case (s, l) => l contains h}.getOrElse(beats.head)._1
}
}

case class Result(text: String, won: Int, lost: Int, drew: Int) {
override def toString = s"$text. Won: $won, Lost: $lost, Drew: $drew"
}

def getResult(userWeapon: Symbol, myMove: Symbol, result: Result) = {
(userWeapon, myMove) match {
case (userWeapon, myMove) if beats(userWeapon) contains myMove =>
result.copy(text = "You won", won = result.won + 1)
case (userWeapon, myMove) if beats(myMove) contains userWeapon =>
result.copy(text = "You lost", lost = result.lost + 1)
case _ => result.copy(text = "We drew", drew = result.drew + 1)
}
}

def play(input: => Symbol, display: String => Unit, random: Int => Int)
(played: Map[Symbol,Int], result: Result): Result = {
val userWeapon = input
if (userWeapon != Symbol("")) {
val newResult = if (beats contains userWeapon) {
val myMove = calcMyMove(random, played)
display(s" My move: $myMove\n ")
getResult(userWeapon, myMove, result)
} else {
result.copy(text = " Unknown weapon, try again")
}
display(newResult + "\n")
play(input, display, random)(played get userWeapon match {
case None => played
case Some(count) => played.updated(userWeapon, count + 1)
}, newResult)
}
result
}

override def main(args: Array[String]): Unit =
play(input, display, random)(initPlayed, Result("Start", 0, 0, 0))
}</lang>
{{out}}
<pre>
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): rock
My move: 'rock
We drew. Won: 0, Lost: 0, Drew: 1
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): spock
My move: 'spock
We drew. Won: 0, Lost: 0, Drew: 2
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): lizard
My move: 'spock
You won. Won: 1, Lost: 0, Drew: 2
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): scissors
My move: 'spock
You lost. Won: 1, Lost: 1, Drew: 2
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): scissors
My move: 'spock
You lost. Won: 1, Lost: 2, Drew: 2
Your move ('spock, 'rock, 'lizard, 'paper, 'scissors): spock
My move: 'rock
You won. Won: 2, Lost: 2, Drew: 2</pre>


=={{header|Seed7}}==
=={{header|Seed7}}==