Force-move Games: Rock Paper Scissors
This package contains a sample implementation of a rock-paper-scissors (RPS) game.
The package defines two objects:
RockPaperScissorsStateextends the core
Statecontract, defining the attributes needed to describe a "move".
validTransitionfunction, which outlines the rules that players have to follow during gameplay.
The real-world game involves two players simultaneously picking a move. In our force-move game implementation, we will use a commit-reveal strategy to simulate this, where one player commits to a value beforehand and then only reveals their choice once the other player's choice is known.
In our implementation, each round of the game will pass through four different
We describe below how a client could control the flow of states that could be exchanged during a round of rock-paper-scissors played between Alice and Bob.
In each state
bBal represent Alice and Bob's current balances in the game respectively.
The dotted lines in the above figure represent the resolution of the game if it were to conclude from the given state -- that is, what the game rules considers a fair payout to each player.
The states we show in the diagram are slightly simplified. In particular, we omit the framework attributes implemented by the core state contract. The client's game library should automatically take care of these -- if they aren't updated correctly, the other player could enforce the game rules with the rules contained in the on-chain smart-contract.
The game requires some setup, as outlined in the simple adjudicator's readme.
For simplicty we assume that we start in a position where Bob has just signed and sent
state0A to Alice as
// In Alice's client, Alice holds message0B, which satisfies:;;;;
It could be that Alice and Bob have just entered the game from the setup phase, which we'll cover later, or they might have just finished a previous round.
Alics kicks off a round by moving to a
In doing this, she chooses a
stake that they're each going to contribute and
adjusts their totals accordingly.
She also provides the
preCommit, which she calculates by hashing her
rock, with a random string,
// In Alice's client:let move0B = RPS;let gameAttributes =positionType: RPSRoundProposedaBal: 4bBal: 3stake: 1preCommit:;let state1A = RPS;let message1A = StateWalletA;// Alice ---> message1A ----> Bob
Bob then decides whether to accept the round or not.
If he didn't want to accept, he would sign and send back the same
(apart from an increased
turnNum) as he sent in the beginning.
If he does want to accept, he signs the
RPS.RoundAccepted state, providing his
choice -- in this case
// In Bob's client:StateWalletB;let move1A = RPS;let gameAttributes =positionType: RPSRoundAcceptedaBal: 4bBal: 3stake: 1preCommit:bPlay: 'scissors';let state2B = RPS;let message2B = StateWalletB;// b ---> message2B ----> a
Notice that, even though Alice appears to be winning at this point, if Bob were to force-move Alice into responding to
message2B, and Alice fails to respond in time, Bob would take the stake.
This is the only fair distribution, as from the world's point of view -- ie. anyone but Alice -- this case is indistinguishable from Alice deliberately stalling, knowing that she's lost.
The next step is for Alice to reveal her value.
To do this she signs the
RPS.Reveal state, which reveals her choice.
She also provides the
salt used in the pre-commit, so that Bob can
verify that she hasn't changed her choice:
let move2B = RPS;let gameAttributes =positionType: RPSRevealaBal: 4bBal: 3stake: 1aPlay: 'rock'salt: 'xyz'preCommit:bPlay: 'scissors';let state3A = RPS;let message3A = StateWalletA;// Alice ---> message3A ----> Bob
Bob then completes the round by signing the
In doing this he updates the totals to reflect the fact that Alice won the last
// In Bob's client:StateWalletB;let move3A = RPS;let gameAttributes =positionType: RPSRestingaBal: 6bBal: 3;let state4B = RPS;let message4B = StateWalletB;// Bob ---> message4B ----> Alice
Now they are back in the
Resting state, Alice is free to propose another
round if she wishes.
Either play may communicate their wish to end the game at any point by moving to an
This is discussed in detail in the (to-be-released) whitepaper.