mirror of
https://github.com/averel10/crypto_clash.git
synced 2026-03-12 19:08:11 +01:00
fix game and add playbook
This commit is contained in:
528
docs/minusOne-example-gameplay.md
Normal file
528
docs/minusOne-example-gameplay.md
Normal file
@@ -0,0 +1,528 @@
|
||||
# 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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:**
|
||||
|
||||
```javascript
|
||||
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:
|
||||
|
||||
```javascript
|
||||
resolveTimeout(1); // Call this to win by default
|
||||
```
|
||||
Reference in New Issue
Block a user