A fog-of-war and friction chess variant — two players, real-time, in the browser. Standard chess rules are broken in deliberate and instructive ways.
- Screenshots
- What This Is
- Game Mechanics
- The Clausewitz Connection
- MIT LL EduCATE Curriculum
- Local Setup
- Watching Games
- Contributing
- License
Screenshots coming — run the server locally and grab one from
/playand/spectator.
Clausewitzian Chess is a two-player, browser-based chess variant originally built at MIT Lincoln Laboratory for the DARPA CASCADE program. It is not a polished game — it is an engineering research prototype that uses chess as a substrate for exploring concepts from military theory and complex systems.
The core idea: chess is a perfect-information game with deterministic outcomes. Real-world decision-making under conflict is none of those things. This variant removes the comfortable certainties one at a time.
What changes from standard chess:
- You can only see pieces within your visibility range
- One piece type per turn is randomly blocked from moving
- Each player picks their starting pieces and layout from a point budget
- Each player gets a secret, randomly assigned victory condition — and the game is non-zero-sum
What does not change:
- The board, the piece movement rules, and the turn structure are standard chess
- The game uses pseudo-legal moves — check is not enforced, and kings are captured like any other piece. This is intentional: it prevents check status from leaking information about hidden board state and keeps game-over conditions explicit
This codebase is a full rewrite of the original prototype: React 19 frontend, TypeScript game logic, Express 5 / Socket.io 4.x / MongoDB 7.x backend.
You cannot see the entire board. Each of your pieces has a view range (Chebyshev distance — the square neighborhood around the piece). Opponent pieces outside any of your pieces' view ranges are hidden — they do not appear on the board at all.
Default ranges: pawns see 2 squares away, all other pieces see 1 square away. Both players can configure these values before the game starts.
Additional visibility modifiers:
- Jamming — some pieces can reduce the effective sight range of nearby enemy observers
- Threat reveal — a piece can be configured to become visible when it is attacking one of your pieces (or when one of your pieces can capture it), regardless of range
When you move a sliding piece (rook, bishop, queen) through fog, you might run into a hidden enemy piece. The game does not snap back — the piece advances to the square just in front of the blocker instead. You learn something about the board by running into it.
Each turn, one piece type is randomly selected as the friction piece. All of your pieces of that type are blocked from moving that turn. You can still pick them up, drag them across the board, and release them — the move is rejected at the drop point. This is a deliberate design choice: the disruption happens at the moment of commitment, not before it.
The friction piece for the current turn and the next turn are shown below the board. You can configure whether to display these indicators.
Friction models the inability to execute an order as desired: lost communications, coordination failures, unexpected contingencies. Playtesting found this to be the most immediately frustrating mechanic — which was taken as a sign that it was working.
Before the game starts, both players build their army. Each player has a point budget (default 42) and places pieces on their back two ranks. Piece costs are standard chess material values: pawn = 1, knight = 3, bishop = 3, rook = 5, queen = 9, king = 2.
You must place at least one king. Blank boards default to the standard chess starting arrangement.
This replaces the fixed starting position and models composition — players design their force before deploying it. Setup happens in real time; a chat channel is available during this phase.
Each player is randomly assigned one of four secret victory conditions at game start. You do not know your opponent's condition. The game is non-zero-sum: both players can win, both can lose, or outcomes can differ.
| Condition | Win Criteria |
|---|---|
| King Capture | Physically capture the opponent's king |
| Three Check | Put the opponent's king in check 3 or more times |
| Most Material | Capture more total material value than your opponent when the game ends |
| Most Pieces | Capture more total pieces (by count) than your opponent when the game ends |
The game ends when the turn limit is reached (default 20 turns) or either player resigns. Kings are captured like any other piece — if both players draw King Capture, the turn limit is removed entirely and the game runs until one king falls.
Score values are tracked and optionally shared with your opponent during play. The victory condition itself is never revealed until the game ends.
The game is named after Carl von Clausewitz, the Prussian general whose 1832 treatise On War remains a foundational text in military theory. Clausewitz described three conditions that separate real conflict from idealized models:
Fog of war — hidden or uncertain information about friendly and adversary forces
Friction — the gap between intended and executed action
Chance — the unpredictable element present in all conflict
The DARPA CASCADE program (Complex Adaptive System Composition and Design Environment) that funded this work was interested in modeling systems-of-systems behavior — large, interdependent systems where actors have incomplete information, imperfect execution, and conflicting goals. Earlier CASCADE wargames assumed perfect communications, instantaneous order execution, and complete world-state knowledge.
Clausewitzian Chess was built to remove those assumptions and make the consequences playable.
From the original research findings: players held capable pieces in reserve under fog uncertainty (mirroring how military operations hold critical assets until area security is established), adapted strategies when friction blocked planned moves, and behaved differently based on their secret victory condition — including attempting to deduce and disrupt the opponent's condition from their move patterns.
This game is used in MIT Lincoln Laboratory's EduCATE (Education through Computation, Algorithms, and Technology in Engineering) program, which teaches systems-of-systems reasoning to students in the top high school / early college range.
The game is a classroom tool, not a competitive platform. The concepts it embeds — operating under uncertainty, adapting plans when execution fails, reasoning about an adversary with different objectives — are transferable to engineering, logistics, and policy contexts.
How it works in the classroom:
Students play the game first, then analyze what happened. The mechanics surface naturally: Why did you move that piece into fog? What did you do when friction blocked your rook? Did you ever figure out your opponent's victory condition?
The game produces experiences that are easy to discuss and hard to manufacture in a lecture hall.
This codebase is the platform that runs it. Students contribute code as part of the curriculum — see Contributing below.
Prerequisites:
- Node.js 20 or newer
- MongoDB running locally (7.x recommended)
Step 1 — Clone and install dependencies:
git clone https://github.com/jakurucar/Clausewitzian_Chess.git
cd Clausewitzian_Chess
npm installStep 2 — Configure environment variables:
cp .env.example .envOpen .env and fill in your MongoDB credentials. At minimum you need DB_USER and DB_PASS. All variables are documented in .env.example, including optional settings for port, CORS, TLS, and proxy.
Step 3 — Set up MongoDB:
MongoDB must be running before the server starts. For local development:
# Ubuntu/Debian
sudo apt install mongodb
sudo systemctl start mongodb
# macOS (Homebrew)
brew install mongodb-community
brew services start mongodb-community
# Windows
# See: https://www.mongodb.com/docs/manual/tutorial/install-mongodb-on-windows/Then create the database user. Connect to the Mongo shell and run:
use dcchess;
db.createUser({
user: "mongouser",
pwd: "mongopass",
roles: [{ role: "readWrite", db: "dcchess" }]
});Use credentials that match what you put in .env. Full details in database/README.md.
Step 4 — Start the server:
npm start # runs node app.jsThe server starts at http://localhost:3000.
Open two browser tabs (or two browsers) and log in with different usernames to play a game against yourself.
Running tests:
npm test # unit tests (Vitest)
npm run build:e2e # build with test mode enabled (required before E2E)
npm run test:e2e # Playwright E2E suite
npm run test:e2e:headed # headed mode (for drag-capture and replay tests)Navigate to /spectator while the server is running to watch live games. Active games appear as cards — click any card to follow that game in real time. The spectator view updates on every move and cleans up automatically when the game ends.
No login required to spectate.
This codebase is used in the EduCATE curriculum, which means students submit PRs as part of their coursework. Here is what that process looks like.
Before you start:
Read the code you are changing. The game logic lives in src/game/ (TypeScript modules). The server is app.js (CommonJS). The React frontend is src/. If you are not sure where something lives, docs/codebase-inventory.md is a good starting point.
Workflow:
- Fork the repository on GitHub
- Create a branch from
master— name it after the thing you are doing, e.g.fix/friction-displayorfeat/move-history-panel - Make your changes. Run
npm run lintandnpm run formatbefore committing - Run the test suite:
npm test. If you are adding a feature, add tests for it - Open a pull request against
masteron the upstream repo
What to expect in review:
PRs are reviewed by the maintainer (JK). Expect feedback on correctness, test coverage, and whether the change preserves the Socket.io event contracts that the game relies on. Event names and payloads are stable — do not rename or restructure them without flagging it explicitly in the PR description.
What is in scope:
- Bug fixes
- UI/UX improvements to the React frontend
- New game features (discuss in an issue first if the scope is large)
- Test coverage improvements
- Documentation
What is out of scope:
- Changes to the Socket.io event contracts without discussion
- Modifications to
public/lib/(the vendored legacy library directory — these files are being phased out, not maintained) - Anything that removes or weakens the fog, friction, or victory condition mechanics — these are load-bearing
Code conventions:
- Backend (
app.js): CommonJS — userequire, notimport - Game logic (
src/game/,src/lib/): TypeScript with strict mode - Frontend (
src/): ESM / Vite - Comments: only when explaining a non-obvious constraint or design choice, not what the code does
BSD 3-Clause — Copyright (c) 2019, MIT Lincoln Laboratory / DARPA.
This material is based upon work supported by the Defense Advanced Research Projects Agency under Air Force Contract No. FA8702-15-D-0001. Any opinions, findings, conclusions, or recommendations expressed in this material are those of the author(s) and do not necessarily reflect the views of the Defense Advanced Research Projects Agency. DISTRIBUTION STATEMENT A — Approved for public release. Distribution is unlimited.