Classroom link
Overview
In this lab you will take a working starter web app for the word game Ghost and turn it into:
1) A playable game with repeated rounds and scorekeeping
2) A two-human multiplayer mode where two browsers connect to the same server and play each other
The starter app already includes:
- A Bootstrap front end
- An Express/Node back end with API routes
- A large word list loader on the server (or a fallback)
- A placeholder computer move: the server replies with a random letter
Your work is to make the back end actually manage a full Ghost game and (in part 2) support two clients playing the same game.
Ghost rules (this version)
A fragment starts empty. Players alternate adding a single letter to the end of the fragment.
You lose the round if, after your move:
1) You complete a valid word of length ≥ N (N is configurable; default 4), OR
2) The fragment is not the prefix of any valid word (i.e., no dictionary word starts with that fragment)
Learning goals
- Practice JavaScript in a full-stack setting
- Understand client/server responsibilities
- Maintain state safely on the server across multiple requests
- Design clean JSON APIs
- Implement game logic using a word list + prefix checking
- Build a simple real-time multiplayer experience (2 clients)
Getting the starter running (Linux)
From the project directory:
- Install dependencies:
make install
- Start the dev server (auto-restarts on changes):
make dev
- Open in your browser:
http://localhost:4000
Optional: Install a larger dictionary
The server will try these sources in order:
1) server/words.txt
2) /usr/share/dict/words
3) server/words_sample.txt (small fallback)
If you want a large list and you have outbound internet from your environment:
make fetch-words
Part A — Make the server run repeated rounds and keep score (Human vs Computer)
What the starter currently does
- The server stores a single global fragment
- When you play a letter, it appends it
- Then the server appends a random letter
- It does a basic rule check to see if someone lost immediately
This is not a real “game session” yet: there is no scoring, no concept of rounds for a particular user, and no strategy.
Your tasks (Part A)
A1) Create a real game/session model on the server
You need a server-side data structure that can represent:
- Current fragment
- Whose turn it is
- Whether the round is over
- Score for human and computer (across rounds)
- Config value N (minimum word length)
Requirement: Your server must support playing multiple rounds without restarting the server.
Design hint (no code):
- You can keep an in-memory object keyed by a
gameId - The client can store the
gameIdand send it with each request - Or you can use cookies/sessions (optional; more advanced)
A2) Define clear API endpoints
You should end up with endpoints that support:
- Starting a new game (returns
gameId) - Starting a new round within an existing game
- Submitting a move
- Getting current state (fragment, score, status)
You may change the starter endpoints, but your UI must still function.
A3) Implement robust rule checking
After every move:
- Check if the fragment is a completed word of length ≥ N
- Check if the fragment is a valid prefix of at least one word
If a player loses:
- Update score
- Mark round complete
- Allow starting next round without resetting score
A4) Replace “random letter” with a computer strategy
You will design your own strategy. It does not need to be perfect, but it must:
- Only play a–z
- Avoid illegal moves when possible
- Prefer moves that increase the chance the human eventually loses
Technical requirement: Your strategy must use the dictionary and/or prefix logic on the server.
Examples of possible approaches (choose one):
- “Safe move”: choose a letter that keeps the fragment as a valid prefix
- “Look-ahead”: consider the next human move(s)
- “Parity strategy”: aim to force the opponent to complete a word (classic Ghost heuristic)
You should explain your strategy in your README.
Part B — Two-human multiplayer mode (two browsers)
Goal
Two browsers should be able to connect to the server, join the same game, and alternate turns.
Requirements
- The server must support at least one active 2-player game at a time (more is a bonus).
- Two clients must see the same fragment and score.
- The server must enforce turn-taking:
- If it’s Player 1’s turn, Player 2’s move is rejected (HTTP 400 or 409 with JSON error).
- The server must detect round end and update score correctly.
- The UI should show:
- Current fragment
- Whose turn it is
- Scoreboard
- Round result message when someone loses
Suggested architecture (no code)
- When a multiplayer game is created, it produces a
gameId. - A second client “joins” by entering the
gameId. - The server stores two player slots (P1 and P2).
- Each client identifies itself as P1 or P2 (token, random secret, or server-assigned id).
- Moves are validated against the current turn.
Polling is OK
You do NOT need WebSockets for Lab 1.
Your clients can update the UI by:
- polling a
/stateendpoint every ~500–1000ms, OR - refreshing state after each move and after “new round”
What to turn in
1) A working implementation of Part A (single human vs computer) with:
- repeated rounds
- scorekeeping
- non-random strategy
2) A working implementation of Part B (two humans) with:
- join-by-gameId (or equivalent)
- turn enforcement
- shared state visible to both clients
3) A short README that includes:
- how to run
- your API design (endpoint list + sample JSON fields)
- how your strategy works
- any limitations/known issues
Grading rubric (suggested)
Correctness (40%)
- Rule checks correct (word completion + invalid prefix)
- Turn order enforced
- Score updated correctly and persists across rounds
Server design (25%)
- Clear state model
- Clean endpoints and JSON responses
- Proper validation and error responses
Strategy quality (15%)
- Clearly described
- Better than random (uses dictionary/prefix checks)
- Doesn’t frequently self-destruct with illegal moves
Multiplayer (15%)
- Two clients share state reliably
- Join flow works
- UI reflects turn/score/round outcome
Code quality (5%)
- Reasonable structure
- Helpful comments
- No giant monolithic functions
Common pitfalls
- Forgetting to lowercase/validate input letters
- Confusing “prefix exists” with “word exists”
- Not enforcing turn order on the server
- Not resetting fragment correctly between rounds
- Using global variables for fragment/score (breaks multiple games)
Extension ideas (optional)
- Multiple concurrent games
- “Best of 5” match structure
- Timer per turn
- Display the completed losing word at end of round (if applicable)
- Host on a shared class server for cross-machine play
