From 9ef456d10a5b33e34d04be257fdfeea8b8312659 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 6 Mar 2026 09:36:01 -0500 Subject: [PATCH] Add tracking of client placement of tiles This adds a new /place endpoint to be told where tiles are placed, and allows the server to send all placed tiles when a player reconnects. This means that a client refresh no longer clears the entire board, (which was really annoying). --- letterrip.js | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/letterrip.js b/letterrip.js index 24b7fd1..abeb975 100644 --- a/letterrip.js +++ b/letterrip.js @@ -32,6 +32,7 @@ class LetterRip extends Game { this.state = { bag: LetterRip.make_bag(), player_tiles: {}, + player_boards: {}, stuck: new Set(), finished: false, winner: null @@ -202,6 +203,39 @@ class LetterRip extends Game { response.json({ finished: false }); } + handle_place(request, response) { + const session_id = request.session.id; + + if (!this.state.player_tiles[session_id]) { + response.sendStatus(400); + return; + } + + const { tileIndex, r, c } = request.body; + + if (!this.state.player_boards[session_id]) { + this.state.player_boards[session_id] = {}; + } + + const board = this.state.player_boards[session_id]; + + /* Remove this tile from any previous position. */ + for (const key of Object.keys(board)) { + if (board[key].tileIndex === tileIndex) { + delete board[key]; + break; + } + } + + /* Place on the grid (r and c are null when returning to rack). */ + if (r !== null && c !== null) { + board[r + "," + c] = { tileIndex, letter: request.body.letter, + isBlank: request.body.isBlank || false }; + } + + response.sendStatus(200); + } + handle_events(request, response) { super.handle_events(request, response); @@ -215,6 +249,12 @@ class LetterRip extends Game { response.write(`event: tiles\ndata: ${data}\n\n`); } + /* Send this player's board layout for reconnect recovery. */ + const board = this.state.player_boards[session_id]; + if (board && Object.keys(board).length > 0) { + response.write(`event: board\ndata: ${JSON.stringify(board)}\n\n`); + } + /* Send current bag count. */ response.write(`event: dealt\ndata: ${JSON.stringify({ remaining: this.state.bag.length @@ -250,6 +290,10 @@ router.post('/stuck', (request, response) => { request.game.handle_stuck(request, response); }); +router.post('/place', (request, response) => { + request.game.handle_place(request, response); +}); + router.post('/complete', (request, response) => { request.game.handle_complete(request, response); }); -- 2.45.2