A URL-based Prisoner's Dilemma game built with the configurable correspondence games framework.
Try it out at Prisoner's Dilemma
- ✅ Config-driven: Powered by YAML configuration
- ✅ URL-based gameplay: Share links to play asynchronously
- ✅ Framework components: Uses DynamicChoiceBoard and DynamicPayoffMatrix
- ✅ 5 rounds: Classic iterated prisoner's dilemma
- ✅ Classic payoffs: Temptation (5), Reward (3), Punishment (1), Sucker's payoff (0)
# Install dependencies
npm install
# Start dev server
npm run devOpen http://localhost:5174/dilemma/
- Player 1 starts the game and makes their choice (Stay Silent or Talk)
- Copy the URL and send it to Player 2
- Player 2 opens the URL and makes their choice
- Results are revealed and totals are updated
- Repeat for 5 rounds
- Winner is determined by highest total score
The game is defined in games/configs/prisoners-dilemma.yaml:
metadata:
id: prisoners-dilemma
name: "Prisoner's Dilemma"
version: "1.0.0"
choices:
- id: silent
label: "Stay Silent"
description: "Cooperate with the other player by staying silent"
icon: "🤐"
- id: talk
label: "Talk"
description: "Betray the other player by talking to the authorities"
icon: "🗣️"
# 4 payoff rules (2×2 combinations)
# Classic prisoner's dilemma payoffs:
# Both silent: (3, 3) - Reward for mutual cooperation
# Silent/Talk: (0, 5) - Sucker's payoff / Temptation to defect
# Talk/Silent: (5, 0) - Temptation to defect / Sucker's payoff
# Both talk: (1, 1) - Punishment for mutual defectionThe Prisoner's Dilemma is a classic game theory scenario that demonstrates why rational individuals might not cooperate, even when cooperation benefits both.
Payoff Structure:
- Both Stay Silent (3, 3): Best collective outcome - moderate sentences
- Both Talk (1, 1): Worst collective outcome - harsh sentences
- One Talks, One Silent (5, 0): Betrayer goes free (5), silent one gets maximum sentence (0)
The Dilemma: Talking is always better individually (dominant strategy), but both talking is worse than both staying silent!
Renders choice buttons dynamically based on config:
- Adapts to any number of choices
- Shows icons and descriptions
- Applies theme colors
Displays payoff outcomes:
- Color-coded scores (green=positive, red=negative)
- Shows all possible combinations
- Outcome text for each scenario
- PayoffEngine: Calculates scores from config rules
- TurnEngine: Manages round progression and alternation
dilemma/
├── src/
│ ├── App.tsx # Main game logic
│ ├── main.tsx # React entry point
│ ├── framework/ # Configurable framework
│ │ ├── core/
│ │ │ ├── config/ # YAML loader & validation
│ │ │ ├── schemas/ # Zod schemas
│ │ │ └── engine/ # Game logic engines
│ │ ├── components/ # Dynamic UI components
│ │ ├── hooks/ # React hooks
│ │ └── storage/ # Encryption utilities
│ └── shared/
│ └── utils/
│ └── constants.ts # Game secret
│
├── games/configs/
│ └── prisoners-dilemma.yaml
│
├── package.json
├── vite.config.ts
└── tsconfig.json
npm run dev # Start dev server (port 5174)
npm run build # Build for production
npm run preview # Preview production build
npm run type-check # TypeScript validationSimply run:
npm run deployThis will:
- Build the project
- Push the
dist/folder to thegh-pagesbranch - GitHub Pages will automatically serve from that branch
First-time setup: Make sure GitHub Pages is enabled in your repo settings and set to deploy from the gh-pages branch.
-
Build the project:
npm run build
-
Push the
dist/directory to thegh-pagesbranch:git subtree push --prefix dist origin gh-pages
Note: The vite.config.ts is already configured with the correct base path: /dilemma/
Edit games/configs/prisoners-dilemma.yaml:
progression:
totalRounds: 10 # Change to any numberTo adjust the payoff values (e.g., make cooperation more rewarding):
- Edit the
payoffRulessection in the YAML config - Adjust the
outcomevalues for each scenario - Framework handles the rest automatically!
ui:
primaryColor: "#3b82f6" # Blue theme
secondaryColor: "#8b5cf6" # Purple accentThis game demonstrates the configurable framework's capabilities:
- No hardcoded game logic - everything from YAML
- Dynamic UI generation - adapts to config
- Type-safe - Zod validation at runtime
- Reusable - same components work for any game
In iterated prisoner's dilemma (multiple rounds):
- Tit-for-Tat: Start silent, then copy opponent's last move
- Always Defect: Always talk (dominant strategy in single round)
- Always Cooperate: Always stay silent (risky but builds trust)
- Forgiving Tit-for-Tat: Occasionally forgive betrayals
- Rock Paper Scissors - 3 choices, 3 rounds
- Create your own game using this framework!
MIT
Built with the Correspondence Games Framework