Rock, Paper, Scissors, Lizard, Spock II: Wrath Of Neo4j
/ 2 min read
Found this post helpful?
Buy me a coffeeTable of Contents
In my previous post, I wrote a C# game engine for the game Rock, Paper, Scissors, Lizard, Spock. I kept looking at the image describing the game and it began to look familiar. Where have I seen this before?
Oh yeah… Neo4J and it’s amazingly descriptive UI. Could I develop a graph and query the result of any match? Let’s see if we can.
Setup
We first need to build the graph. We need to be more descriptive than the original image when describing the nodes and their relationships. We have 5 nodes: Rock, Paper, Scissors, Lizard, Spock. The relationships are Win, Lose, and Tie. This is what our Neo4J Cypher script will look like.
// Create a nodeCREATE (Rock:Throw {name: "Rock"})CREATE (Paper:Throw {name: "Paper"})CREATE (Scissors:Throw {name: "Scissors"})CREATE (Lizard:Throw {name: "Lizard" })CREATE (Spock:Throw {name: "Spock"})
CREATE (Rock)-[:Win]->(Scissors), (Rock)-[:Win]->(Lizard), (Rock)-[:Lose]->(Paper), (Rock)-[:Lose]->(Spock), (Paper)-[:Win]->(Rock), (Paper)-[:Win]->(Spock), (Paper)-[:Lose]->(Scissors), (Paper)-[:Lose]->(Lizard), (Scissors)-[:Win]->(Paper), (Scissors)-[:Win]->(Lizard), (Scissors)-[:Lose]->(Spock), (Scissors)-[:Lose]->(Rock), (Lizard)-[:Win]->(Spock), (Lizard)-[:Win]->(Paper), (Lizard)-[:Lose]->(Scissors), (Lizard)-[:Lose]->(Rock), (Spock)-[:Win]->(Scissors), (Spock)-[:Win]->(Rock), (Spock)-[:Lose]->(Paper), (Spock)-[:Lose]->(Lizard), (Rock)-[:Tie]->(Rock), (Scissors)-[:Tie]->(Scissors), (Paper)-[:Tie]->(Paper), (Lizard)-[:Tie]->(Lizard), (Spock)-[:Tie]->(Spock)I really do love the descriptive nature of Cypher. It is really awesome. When we execute this script we get this result.
Playing The Game
To play the game we need to know which nodes we are traveling from and then understand the relationship between them. This is what the query looks like. In our example we just pick the two throws by name: Rock and Paper.
// QueryMatch (from:Throw {name:"Rock"}), (to:Throw {name:"Paper"}), path = (from)-[result]->(to) return type(result) as ResultThis is what we get when we execute this query. Crap, we lost!
What about Rock versus Scissors?
// QueryMatch (from:Throw {name:"Rock"}), (to:Throw {name:"Scissors"}), path = (from)-[result]->(to) return type(result) as Result
Yay, we won! What about ties?
// QueryMatch (from:Throw {name:"Rock"}), (to:Throw {name:"Rock"}), path = (from)-[result]->(to) return type(result) as Result
Hey, at least we survive to play another game.
Conclusion
This is a really interesting use case for a graph database, and it is really fun to explore how to get a game engine running in a few lines of cypher script. It is worth comparing my C# implementation to this one and seeing which is you prefer, I know I would lean towards this post’s solution since this can support multiple players in a single game while my C# solution is limited to two.