Last active
December 30, 2015 11:39
-
-
Save timyates/7823738 to your computer and use it in GitHub Desktop.
Reactive Rock Paper Scissors with Groovy and RxJava
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@Grab( 'com.netflix.rxjava:rxjava-groovy:0.15.1' ) | |
import groovy.transform.* | |
import rx.* | |
@CompileStatic | |
class RPSRX { | |
enum Result { | |
WIN, LOSE, DRAW | |
} | |
enum Move { | |
ROCK( SCISSORS ), | |
PAPER( ROCK ), | |
SCISSORS( PAPER ) | |
Move beats | |
Move( Move beats ) { | |
this.beats = beats | |
} | |
boolean beats( Move other ) { | |
other == beats | |
} | |
} | |
@Immutable | |
static class PlayerMove { | |
String player | |
Move move | |
String toString() { "$player:$move" } | |
} | |
final Random rnd = new Random() | |
private <T> Observable.OnSubscribeFunc<T> subscriptionBuilder( Closure<T> generator ) { | |
{ Observer<T> observer -> | |
boolean running = true | |
new Thread( { -> | |
while( running ) { | |
observer.onNext( generator() ) | |
} | |
observer.onCompleted(); | |
} ).start() | |
return { -> running = false } as Subscription | |
} | |
} | |
Observable<Integer> numbers() { | |
int n = 1 | |
Observable.create( subscriptionBuilder( { -> n++ } ) ) | |
} | |
Observable<Move> moves() { | |
Observable.create( subscriptionBuilder { | |
Move.values()[ rnd.nextInt( Move.values().length ) ] | |
} ) | |
} | |
Observable<PlayerMove> player( String name ) { | |
moves().map { Move it -> new PlayerMove( name, it ) } | |
} | |
String message( Integer index, PlayerMove m1, PlayerMove m2 ) { | |
"Game $index : $m1 vs $m2 : ${resultMessage( m1, m2, result( m1, m2 ) )}" | |
} | |
Result result( PlayerMove m1, PlayerMove m2 ) { | |
m1.move == m2.move ? Result.DRAW : m1.move.beats == m2.move ? Result.WIN : Result.LOSE | |
} | |
String resultMessage( PlayerMove m1, PlayerMove m2, Result r ) { | |
r == Result.DRAW ? 'draw' : r == Result.WIN ? "$m1.player wins" : "$m2.player wins" | |
} | |
Observable<String> game( String name1, String name2 ) { | |
Observable.zip( numbers(), player( name1 ), player( name2 ) ) { Integer n, PlayerMove a, PlayerMove b -> | |
message( n, a, b ) | |
} | |
} | |
} | |
new RPSRX().game( 'tim', 'alice' ).take( 10 ).subscribe { println it } |
@tednaleid Cool! Top tip :-) I hadn't noticed that in the rx-java deps, thanks! :-)
Rock Paper Scissors is my new Hello World ;-) Got my groovy-stream version, a Java 8 one, this one and next I might try project reactor ;-)
Doesn't seem to work anymore:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/Users/rgrinberg/reps/snippets/groovy/rx-rps.groovy: 34: [Static type checking] - Cannot return value of type groovy.lang.Closure <rx.Subscription> on method returning type rx.Observable$OnSubscribeFunc <T>
@ line 34, column 13.
{ Observer<T> observer ->
^
1 error
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fun reactive script! One thing I've noticed about the rx-java stuff is that it's maven dependency specifies that it wants groovy-all version "2.+". Grape's
Grab
annotation gets very sad when given ranges, especially on groovy-all. I've found that it speeds up my testing/script execution time a lot to also specify an explicit version of groovy so that grape doesn't try to resolve every valid version of groovy every time the script executes, by adding this after your first@Grab
:That speeds the execution time on my machine from about 20 seconds down to ~2 (without having to mess with ttl values in my ~/.groovy/grapeConfig.xml file).