skip to content
Khalid Abuhakmeh

Rock, Paper, Scissors, Lizard, Spock II: Wrath Of Neo4j

Model the rules of Rock, Paper, Scissors, Lizard, Spock as a graph in Neo4j and use Cypher queries as a game engine.

2 min read

Written in 2014. APIs and package versions may have moved on since, so check the code against the .NET version you're targeting.

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?

Rules Neo4j

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 node
CREATE (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.

// Query
Match (from:Throw {name:"Rock"}), (to:Throw {name:"Paper"}), path = (from)-[result]->(to) return type(result) as Result

This is what we get when we execute this query. Crap, we lost!

Query 1

What about Rock versus Scissors?

// Query
Match (from:Throw {name:"Rock"}), (to:Throw {name:"Scissors"}), path = (from)-[result]->(to) return type(result) as Result
Win

Yay, we won! What about ties?

// Query
Match (from:Throw {name:"Rock"}), (to:Throw {name:"Rock"}), path = (from)-[result]->(to) return type(result) as Result
iIe

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.

Comments

Related Posts