2020-10-22 19:23:09 +02:00
package rps
2020-10-22 19:52:33 +02:00
import kotlin.random.Random
2020-10-22 19:23:09 +02:00
fun main ( ) {
2020-10-22 19:52:33 +02:00
println ( playGame ( 100 ) )
2020-10-22 19:23:09 +02:00
}
2020-10-22 19:32:38 +02:00
/ * *
* A possible move in a game of rock - paper - scissors .
*
* [ strongAgainst ] is a function for lazy evaluation because otherwise we can ’ t access SCISSORS before it ’ s been defined .
* If the game needs to be expanded ( e . g . the somewhat common “ rock , paper , scissors , salamander , spock ” ) ,
* this argument could be a List < Move > instead .
* /
enum class Move ( val strongAgainst : ( ) -> Move ) {
ROCK ( { SCISSORS } ) ,
PAPER ( { ROCK } ) ,
SCISSORS ( { PAPER } )
2020-10-22 19:23:09 +02:00
}
// purposely not calling this Result to avoid confusion with kotlin.Result and similar
enum class Outcome {
WIN ,
DRAW ,
LOSS
}
2020-10-22 19:41:03 +02:00
// Named Triple for readability
data class GameSummary ( val wins : Int , val draws : Int , val losses : Int )
2020-10-22 19:23:09 +02:00
/** Determine the [Outcome] of [first] vs [second] from the perspective of [first]. */
2020-10-22 19:32:38 +02:00
fun determineOutcome ( first : Move , second : Move ) : Outcome = when {
first . strongAgainst ( ) == second -> Outcome . WIN
first == second -> Outcome . DRAW
else -> Outcome . LOSS
2020-10-22 19:41:03 +02:00
}
2020-10-22 19:43:08 +02:00
// Note: This would be slightly more efficient (but a lot less elegant) with an imperative loop and three mutable integers.
2020-10-22 19:52:33 +02:00
fun List < Outcome > . calculateGameSummary ( ) = GameSummary (
wins = count { it == Outcome . WIN } ,
draws = count { it == Outcome . DRAW } ,
losses = count { it == Outcome . LOSS } ,
2020-10-22 19:43:08 +02:00
)
2020-10-22 19:52:33 +02:00
fun playGame ( turns : Int ) : GameSummary = generateSequence { randomMove ( ) }
. take ( turns )
. map { determineOutcome ( it , Move . ROCK ) }
. toList ( )
. calculateGameSummary ( )
fun randomMove ( ) : Move = Move . values ( ) . let { allMoves ->
allMoves [ Random . nextInt ( allMoves . size ) ]
}