Skip to content

Instantly share code, notes, and snippets.

@timyates
Last active December 29, 2015 00:19
Show Gist options
  • Save timyates/7585299 to your computer and use it in GitHub Desktop.
Save timyates/7585299 to your computer and use it in GitHub Desktop.
Rock Paper Scissors with groovy-stream v0.7.0-SNAPSHOT
@GrabResolver( name='so', root='https://oss.sonatype.org/content/repositories/snapshots/' )
@Grab( 'com.bloidonia:groovy-stream:0.7.0-SNAPSHOT' )
import groovy.stream.Stream
// A random number generator
Random rnd = new Random()
// A list of possible moves
List moves = [ 'rock', 'paper', 'scissors' ]
// A map showing whch moves beat which
Map beats = [ 'rock' : 'scissors',
'paper' : 'rock',
'scissors' : 'paper' ]
// A stream of random moves
def randomMove = Stream.from { rnd.nextInt( moves.size() ) }
.map { moves[ it ] }
// A player is a Stream of their name and a random move
def player = { String name ->
Stream.from { [ player: name ] }
.zip( randomMove ) { map, move ->
map << [ move: move ]
}
}
// A Closure that declares a winner between two moves
def winner = { move1, move2 ->
def ret = "$move1.player:$move1.move vs $move2.player:$move2.move :"
if( move1.move == move2.move ) { "$ret no one wins" }
else if( move2.move == beats[ move1.move ] ) { "$ret $move1.player wins" }
else { "$ret $move2.player wins" }
}
// Create a never-ending stream that gives us the winner of the two players
def judge = Stream.from( player( 'tim' ) )
.zipWithIndex( player( 'alice' ) ) { tim, alice, index ->
"Game ${index + 1} : ${winner( tim, alice )}"
}
// Play 10 games
judge.take( 10 ).each {
println it
}
@GrabResolver( name='so', root='https://oss.sonatype.org/content/repositories/snapshots/' )
@Grab( 'com.bloidonia:groovy-stream:0.7.0-SNAPSHOT' )
import groovy.stream.Stream
@groovy.transform.CompileStatic
class RPS {
enum Result { WIN, LOSE, DRAW }
enum Moves {
ROCK( SCISSORS ),
PAPER( ROCK ),
SCISSORS( PAPER )
Moves beats
Moves( Moves beats ) {
this.beats = beats
}
}
@groovy.transform.Immutable
class Move {
String player
Moves move
String toString() {
"$player:$move"
}
}
Random rnd = new Random()
Stream<Moves> moves() {
Stream.from { rnd.nextInt( Moves.values().length ) }
.map { Integer it -> Moves.values()[ it ] }
}
Stream<Move> player( String name ) {
Stream.from { name }
.zip( moves() ) { String pname, Moves move -> new Move( pname, move ) }
}
Stream<String> game( String p1, String p2 ) {
Stream.from( player( p1 ) )
.zipWithIndex( player( p2 ) ) { Move p1move, Move p2move, Integer index ->
message( index + 1, p1move, p2move )
}
}
String message( Integer index, Move m1, Move m2 ) {
"Game $index : $m1 vs $m2 : ${resultMessage( m1, m2, result( m1, m2 ) )}"
}
Result result( Move m1, Move m2 ) {
m1.move == m2.move ? Result.DRAW : m1.move.beats == m2.move ? Result.WIN : Result.LOSE
}
String resultMessage( Move m1, Move m2, Result r ) {
r == Result.DRAW ? 'draw' : r == Result.WIN ? "$m1.player wins" : "$m2.player wins"
}
}
new RPS().game( 'Tim', 'Alice' ).take( 10 ).each {
println it
}
@mperry
Copy link

mperry commented Nov 21, 2013

Nice work. Some small improvements to remove the imperative code:

  • remove the mutation of map using "<<" in the player function.
  • change the winner function to create a list of optional results which you then fold to get the winner.

@timyates
Copy link
Author

Cool, thanks @mperry, I added rps2.groovy, which I believe covers your concerns

And more directly mirrors your excellent version :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment