Files
crypto_clash/docs/minusOne-example-gameplay.md
2025-12-16 12:25:44 +01:00

12 KiB

Example Gameplay: Rock-Paper-Scissors Minus One

This document provides a step-by-step playbook for two players (Alice and Bob) to play the "Minus One" variant. Follow along to understand the exact order of operations and function calls.

Quick Reference

Move Encoding

  • 1 = Rock
  • 2 = Paper
  • 3 = Scissors

Game Flow

1. Registration (both players)
2. Initial Commit (both players)
3. First Reveal (both players)
4. Withdrawal Commit (both players)
5. Withdrawal Reveal (both players)
6. Get Outcome (either player)

Hash Generation Tool

🔗 https://emn178.github.io/online-tools/keccak_256.html

  • Input Type: UTF-8
  • Output Type: Hex
  • Format: <move>-<password> (e.g., 1-mypass for Rock)

Game Rules

  1. Each player commits 2 different moves (e.g., Rock + Paper)
  2. Both players reveal their 2 moves
  3. Each player secretly withdraws 1 move (commits which index: 1 or 2)
  4. Both players reveal which move they withdrew
  5. The remaining move for each player battles to determine winner

Example Game Scenario

Players:

  • 👩 Alice (will choose Rock + Paper, keep Rock)
  • 👨 Bob (will choose Rock + Scissors, keep Scissors)

Expected Winner: Alice (Rock beats Scissors)

Minimum Bet: 0.01 ETH (10000000000000000 wei)


🎮 PHASE 1: REGISTRATION

Goal: Both players join the game with their nicknames and bets

Step 1.1: Alice Registers (Player 1)

Function: register(uint gameId, string memory name)

Alice's Input:

gameId: 0  (creates new game)
name: "Alice"
value: 0.01 ETH

Smart Contract Call:

register(0, "Alice");
// Send 0.01 ETH with transaction

Returns: (1, 1)

  • Position: Player 1
  • Game ID: 1

Alice is now registered as Player 1 in Game 1


Step 1.2: Bob Registers (Player 2)

Function: register(uint gameId, string memory name)

Bob's Input:

gameId: 1  (joins Alice's game)
name: "Bob"
value: 0.01 ETH  (must match Alice's bet!)

Smart Contract Call:

register(1, "Bob");
// Send 0.01 ETH with transaction

Returns: (2, 1)

  • Position: Player 2
  • Game ID: 1

Bob is now registered as Player 2 Game automatically advances to InitialCommit phase


🎮 PHASE 2: INITIAL COMMIT

Goal: Both players commit their 2 encrypted moves (hashes)

Step 2.1: Alice Prepares Her Hashes (Off-chain)

Alice's Strategy:

  • Move 1: Rock (1)
  • Move 2: Paper (2)

Generate Hash for Move 1 (Rock):

  1. Go to: https://emn178.github.io/online-tools/keccak_256.html
  2. Input: 1-alicepass1 (UTF-8)
  3. Output: 0x7364263d5fc729b4709129564a2c516f2eb40f55d8704860e46f597c91b6b264

Generate Hash for Move 2 (Paper):

  1. Input: 2-alicepass2 (UTF-8)
  2. Output: 0xc9ad7a6c99b3f5af24991d9c66c0cc2b731869f4b7399653f0820f99e34d45ef

💾 Alice must save these:

  • Cleartext for reveal: 1-alicepass1 and 2-alicepass2
  • Hashes for commit: 0x7364... and 0xc9ad...

Step 2.2: Alice Commits

Function: commitInitialMoves(uint gameId, bytes32 hash1, bytes32 hash2)

Alice's Input:

gameId: 1
hash1: 0x7364263d5fc729b4709129564a2c516f2eb40f55d8704860e46f597c91b6b264
hash2: 0xc9ad7a6c99b3f5af24991d9c66c0cc2b731869f4b7399653f0820f99e34d45ef

Smart Contract Call:

commitInitialMoves(
  1,
  "0x7364263d5fc729b4709129564a2c516f2eb40f55d8704860e46f597c91b6b264",
  "0xc9ad7a6c99b3f5af24991d9c66c0cc2b731869f4b7399653f0820f99e34d45ef"
);

Returns: true

Alice has committed her two moves


Step 2.3: Bob Prepares His Hashes (Off-chain)

Bob's Strategy:

  • Move 1: Rock (1)
  • Move 2: Scissors (3)

Generate Hash for Move 1 (Rock):

  1. Go to: https://emn178.github.io/online-tools/keccak_256.html
  2. Input: 1-bobsecret1 (UTF-8)
  3. Output: 0x16864f12ec74b4fac1cd9fd5b0db1959e4df91cf55e9180cc13cdf20a134af16

Generate Hash for Move 2 (Scissors):

  1. Input: 3-bobsecret2 (UTF-8)
  2. Output: 0x86d1def3d3f9bed5f2de22161040c10c75dcb52f263f3c3ec08cdc8ba10d2103

💾 Bob must save these:

  • Cleartext for reveal: 1-bobsecret1 and 3-bobsecret2
  • Hashes for commit: 0x1686... and 0x86d1...

Step 2.4: Bob Commits

Function: commitInitialMoves(uint gameId, bytes32 hash1, bytes32 hash2)

Bob's Input:

gameId: 1
hash1: 0x16864f12ec74b4fac1cd9fd5b0db1959e4df91cf55e9180cc13cdf20a134af16
hash2: 0x86d1def3d3f9bed5f2de22161040c10c75dcb52f263f3c3ec08cdc8ba10d2103

Smart Contract Call:

commitInitialMoves(
  1,
  "0x16864f12ec74b4fac1cd9fd5b0db1959e4df91cf55e9180cc13cdf20a134af16",
  "0x86d1def3d3f9bed5f2de22161040c10c75dcb52f263f3c3ec08cdc8ba10d2103"
);

Returns: true

Bob has committed his two moves Game automatically advances to FirstReveal phase


🎮 PHASE 3: FIRST REVEAL

Goal: Both players reveal their original cleartext strings to prove their moves

Step 3.1: Alice Reveals

Function: revealInitialMoves(uint gameId, string memory clear1, string memory clear2)

Alice's Input:

gameId: 1
clear1: "1-alicepass1"  (the exact string she hashed)
clear2: "2-alicepass2"  (the exact string she hashed)

Smart Contract Call:

revealInitialMoves(1, "1-alicepass1", "2-alicepass2");

Returns: (Rock, Paper) (enum values for moves 1 and 3)

Alice's moves are now public:

  • Move 1: Rock
  • Move 2: Paper

Step 3.2: Bob Reveals

Function: revealInitialMoves(uint gameId, string memory clear1, string memory clear2)

Bob's Input:

gameId: 1
clear1: "1-bobsecret1"  (the exact string he hashed)
clear2: "3-bobsecret2"  (the exact string he hashed)

Smart Contract Call:

revealInitialMoves(1, "1-bobsecret1", "3-bobsecret2");

Returns: (Rock, Scissors) (enum values for moves 1 and 3)

Bob's moves are now public:

  • Move 1: Rock
  • Move 2: Scissors

Current Game State:

  • Alice has: Rock (move 1) and Paper (move 2)
  • Bob has: Rock (move 1) and Scissors (move 2)

Game automatically advances to WithdrawalCommit phase


🎮 PHASE 4: WITHDRAWAL COMMIT

Goal: Both players secretly commit which move to withdraw (1 or 2)

Step 4.1: Alice Prepares Withdrawal Hash (Off-chain)

Alice's Decision:

  • She wants to keep Rock (move 1)
  • So she will withdraw move index 2 (Paper)

Generate Withdrawal Hash:

  1. Go to: https://emn178.github.io/online-tools/keccak_256.html
  2. Input: 2-alicewith (UTF-8) ← Note: "2" is the index to withdraw
  3. Output: 0x7c9ff59a4d298766d9480c130f6ed67c06f135a1c2f45326583593bb9c2e6363

💾 Alice must save:

  • Cleartext: 2-alicewith
  • Hash: 0x9a3f...

Step 4.2: Alice Commits Withdrawal

Function: commitWithdraw(uint gameId, bytes32 wHash)

Alice's Input:

gameId: 1
wHash: 0x7c9ff59a4d298766d9480c130f6ed67c06f135a1c2f45326583593bb9c2e6363

Smart Contract Call:

commitWithdraw(
  1,
  "0x7c9ff59a4d298766d9480c130f6ed67c06f135a1c2f45326583593bb9c2e6363"
);

Returns: true

Alice has secretly committed to withdraw move 2


Step 4.3: Bob Prepares Withdrawal Hash (Off-chain)

Bob's Decision:

  • He wants to keep Scissors (move 2)
  • So he will withdraw move index 1 (Rock)

Generate Withdrawal Hash:

  1. Go to: https://emn178.github.io/online-tools/keccak_256.html
  2. Input: 1-bobwith (UTF-8) ← Note: "1" is the index to withdraw
  3. Output: 0x29e944e8859972eb35622d3149120d878d7931aaa9ac2e213d0b321ee564b7dc

💾 Bob must save:

  • Cleartext: 1-bobwith
  • Hash: 0x29e9...

Step 4.4: Bob Commits Withdrawal

Function: commitWithdraw(uint gameId, bytes32 wHash)

Bob's Input:

gameId: 1
wHash: 0x29e944e8859972eb35622d3149120d878d7931aaa9ac2e213d0b321ee564b7dc

Smart Contract Call:

commitWithdraw(
  1,
  "0x29e944e8859972eb35622d3149120d878d7931aaa9ac2e213d0b321ee564b7dc"
);

Returns: true

Bob has secretly committed to withdraw move 1 Game automatically advances to WithdrawalReveal phase


🎮 PHASE 5: WITHDRAWAL REVEAL

Goal: Both players reveal which move they withdrew

Step 5.1: Alice Reveals Withdrawal

Function: withdrawMove(uint gameId, string memory clear)

Alice's Input:

gameId: 1
clear: "2-alicewith"  (the exact string she hashed for withdrawal)

Smart Contract Call:

withdrawMove(1, "2-alicewith");

Returns: 2

Alice withdrew move 2 (Paper) Alice keeps: Rock (move 1)


Step 5.2: Bob Reveals Withdrawal

Function: withdrawMove(uint gameId, string memory clear)

Bob's Input:

gameId: 1
clear: "1-bobwith"  (the exact string he hashed for withdrawal)

Smart Contract Call:

withdrawMove(1, "1-bobwith");

Returns: 1

Bob withdrew move 1 (Rock) Bob keeps: Scissors (move 2)

Final Battle:

  • Alice's final move: Rock
  • Bob's final move: Scissors
  • Winner: Alice! (Rock beats Scissors)

Game automatically determines outcome and advances to Done phase


🎮 PHASE 6: GET OUTCOME

Goal: Either player calls to finalize and receive payout

Step 6.1: Get Outcome (Either Player Can Call)

Function: getOutcome(uint gameId)

Input:

gameId: 1

Smart Contract Call:

getOutcome(1);

Returns: Outcomes.A (Alice wins)

What Happens:

  1. Contract calculates winner: Rock beats Scissors
  2. Alice receives 0.02 ETH (both players' bets)
  3. Game is marked inactive
  4. Contract balance reduced by payout

Game Complete! Alice won and received 0.02 ETH


📊 Summary Table

Step Who Acts Function Key Inputs Result
1.1 Alice register(0, "Alice") gameId=0, name="Alice", value=0.01 ETH Player 1 in Game 1
1.2 Bob register(1, "Bob") gameId=1, name="Bob", value=0.01 ETH Player 2 in Game 1
2.1 Alice commitInitialMoves(1, hash1, hash2) Hashes of "1-alicepass1" and "2-alicepass2" Committed
2.2 Bob commitInitialMoves(1, hash1, hash2) Hashes of "1-bobsecret1" and "3-bobsecret2" Committed
3.1 Alice revealInitialMoves(1, clear1, clear2) "1-alicepass1", "2-alicepass2" Reveals Rock + Paper
3.2 Bob revealInitialMoves(1, clear1, clear2) "1-bobsecret1", "3-bobsecret2" Reveals Rock + Scissors
4.1 Alice commitWithdraw(1, wHash) Hash of "2-alicewith" Committed withdrawal
4.2 Bob commitWithdraw(1, wHash) Hash of "1-bobwith" Committed withdrawal
5.1 Alice withdrawMove(1, clear) "2-alicewith" Withdrew Paper, keeps Rock
5.2 Bob withdrawMove(1, clear) "1-bobwith" Withdrew Rock, keeps Scissors
6.1 Either getOutcome(1) gameId=1 Alice wins, gets 0.02 ETH

⚠️ Important Notes

Must Save These Strings!

  • Initial moves cleartext: You need them in Phase 3
  • Withdrawal cleartext: You need it in Phase 5
  • If you lose these strings, you cannot reveal and will timeout!

Order Matters

  • Either player can act first within each phase
  • Game won't advance until both players complete the current phase
  • You have 10 minutes per phase (commit or reveal)

Common Mistakes

Using different strings in reveal than in commit → "Hash mismatch"
Committing same move twice (e.g., Rock + Rock) → "Moves must differ"
Second player betting different amount → "Bet must match initial"
Withdrawing index 0 or 3 → "Index must be 1 or 2"
Losing your cleartext strings → Cannot reveal, will timeout

Timeout Protection

If your opponent doesn't act within 10 minutes:

resolveTimeout(1); // Call this to win by default