#+AUTHOR: Tony
#+STARTUP: overview
* Guan Dan BTW
A real-time multiplayer web implementation of Guan Dan (掼蛋), a popular Chinese climbing card game for 4 players in 2v2 teams.
[[./assets/guandan.png]]
* Table of Contents :toc:
- [[#guan-dan-btw][Guan Dan BTW]]
- [[#features][Features]]
- [[#installation][Installation]]
- [[#usage][Usage]]
- [[#development][Development]]
- [[#project-structure][Project Structure]]
- [[#game-rules][Game Rules]]
- [[#future-plans][Future Plans]]
- [[#license][License]]
* Features
- Real-time multiplayer via WebSockets
- Room-based lobbies (create/join with room code)
- Full Guan Dan ruleset:
- Level system (2 through A)
- Wild cards (heart of current level)
- Bomb hierarchy (4-10 of a kind, straight flush, 4-joker)
- Tribute system between hands
- Bot players ("Fill with Bots" button for testing)
- Play log sidebar (track recent plays)
- Turn/play highlighting (visual feedback for whose turn and who just played)
* Installation
Requires Go 1.23+ and Node.js 18+.
#+begin_src sh
git clone https://github.com/tonybanters/guandanbtw
cd guandanbtw
nix develop
#+end_src
* Usage
Run both server and client:
#+begin_src sh
just dev # or: mprocs
#+end_src
Or run separately:
#+begin_src sh
cd server && air # go server with hot reload
cd client && npm run dev # vite dev server
#+end_src
Open =http://localhost:5173=, create a room, and share the room code with 3 friends. Use "Fill with Bots" to test without 4 players.
* Development
Using Nix (recommended):
#+begin_src sh
nix develop
#+end_src
Dev shell includes: go, gopls, air, nodejs, typescript, just, mprocs.
* Project Structure
#+begin_src
server/
├── main.go [Entry point, HTTP/WS server]
├── game/
│ ├── card.go [Card types, deck, ranking]
│ ├── combination.go [Valid play detection]
│ ├── bomb.go [Bomb hierarchy]
│ └── state.go [Game state machine]
├── room/
│ ├── hub.go [WebSocket hub, room management]
│ ├── room.go [Room logic, game flow]
│ └── client.go [Client connection handling]
└── protocol/
└── messages.go [JSON message types]
client/
├── src/
│ ├── App.tsx [Main app, state management]
│ ├── components/
│ │ ├── Card.tsx [Card component]
│ │ ├── Hand.tsx [Player hand]
│ │ ├── Table.tsx [Center play area]
│ │ ├── Lobby.tsx [Create/join room UI]
│ │ └── Game.tsx [Main game layout]
│ ├── hooks/
│ │ └── use_websocket.ts
│ └── game/
│ └── types.ts [Shared types]
└── package.json
#+end_src
* Game Rules
- 4 players, 2v2 teams (partners sit opposite)
- 2 decks + 4 jokers = 108 cards, 27 each
- Teams race to empty their hands
- Current level card ranks highest; heart of level is wild
- Valid plays: singles, pairs, triples, full houses, straights, tubes, plates
- Bombs beat everything (ranked by size, then straight flush, then 4-joker)
- Winners advance levels based on finish order
Full rules: [[https://www.pagat.com/climbing/guan_dan.html][pagat.com]]
* Future Plans
- Tribute UI on frontend
- Sound effects and better animations
- Card sorting options
- Spectator mode
- Mobile responsive layout
- Deployment (fly.io/railway)
* License
[[https://www.gnu.org/licenses/gpl-3.0.en.html][GPL v3]]