diff --git a/public/game.html b/public/game.html
index 03f4c2d..b95565a 100644
--- a/public/game.html
+++ b/public/game.html
@@ -17,10 +17,7 @@
@@ -44,6 +41,12 @@
const myColorEl = document.getElementById('myColor');
let socket = null;
let myColor = null;
+ // selection state for this client
+ let selectedSquare = null; // algebraic name like 'e2'
+ let selectedSquareEl = null;
+ let myPlayerId = playerId || null;
+ // track remote selections: { playerId: square }
+ const remoteSelections = {};
// safe logger: prefer on-page log if present, otherwise console
function log(...args){
@@ -84,15 +87,31 @@
}
if(data.boardState) renderBoardFromState(data.boardState);
});
- socket.on('move:moved', (data)=>{ log('move:moved', data); if(data.boardState) renderBoardFromState(data.boardState); });
socket.on('game:over', (data)=>{ log('game:over', data); if(data.boardState) renderBoardFromState(data.boardState); });
socket.on('game:started', (data)=>{ log('game:started', data); if(data.boardState) renderBoardFromState(data.boardState); });
+ // selection events broadcasted by other clients
+ socket.on('game:select', (data) => {
+ try{
+ const pid = data && data.playerId;
+ const square = data && data.square;
+ // ignore our own (some transports might echo)
+ if(pid === myPlayerId) return;
+ if(!pid) return;
+ if(!square){
+ // clear remote selection for that player
+ clearRemoteSelection(pid);
+ return;
+ }
+ setRemoteSelection(pid, square);
+ }catch(e){ console.warn('game:select handler error', e); }
+ });
socket.emit('room:join', { roomId, playerId }, (resp)=>{
if(resp && resp.error){ log('join error', resp); alert(resp.error); return; }
log('Rejoint room', resp);
// remember assigned id/color from server
if(resp.playerId){
+ myPlayerId = resp.playerId;
if(playerIdEl) playerIdEl.textContent = resp.playerId;
}
if(resp.color){
@@ -109,26 +128,59 @@
connectAndJoin();
- // show markers for legal moves when clicking any square (any piece color)
- function clearLegalMarkers(){
- const prev = boardEl.querySelectorAll('.move-marker');
- prev.forEach(p=>p.remove());
+ // movement UI removed: legalMoves and move markers are disabled
+
+ // selection helpers (client-side)
+ function clearSelection(emit = true){
+ if(selectedSquareEl){
+ selectedSquareEl.classList.remove('selected');
+ }
+ selectedSquare = null;
+ selectedSquareEl = null;
+ const fromEl = document.getElementById('from');
+ if(fromEl) fromEl.value = '';
+ // notify others that we cleared selection
+ if(emit && socket && myPlayerId){
+ socket.emit('game:select', { roomId, square: null }, ()=>{});
+ }
}
- function showLegalMoves(moves){
- clearLegalMarkers();
- (moves||[]).forEach(m => {
- const to = m.to || (m.move && m.move.to);
- if(!to) return;
- const target = boardEl.querySelector(`.square[data-square="${to}"]`);
- if(!target) return;
- const marker = document.createElement('div');
- marker.className = 'move-marker';
- // store metadata if needed later
- marker.dataset.from = m.from || '';
- marker.dataset.to = to;
- target.appendChild(marker);
- });
+ function setSelection(squareName, emit = true){
+ if(!squareName) return clearSelection(emit);
+ if(selectedSquareEl) selectedSquareEl.classList.remove('selected');
+ const sqEl = boardEl.querySelector(`.square[data-square="${squareName}"]`);
+ if(!sqEl){ selectedSquare = null; selectedSquareEl = null; return; }
+ selectedSquare = squareName;
+ selectedSquareEl = sqEl;
+ sqEl.classList.add('selected');
+ const fromEl = document.getElementById('from');
+ if(fromEl) fromEl.value = squareName;
+ // notify others of our selection
+ if(emit && socket && myPlayerId){
+ socket.emit('game:select', { roomId, square: squareName }, ()=>{});
+ }
+ }
+
+ // remote selection helpers: mark a square as selected by another player
+ function setRemoteSelection(playerId, squareName){
+ // clear previous for that player
+ clearRemoteSelection(playerId);
+ const sqEl = boardEl.querySelector(`.square[data-square="${squareName}"]`);
+ if(!sqEl) return;
+ remoteSelections[playerId] = squareName;
+ sqEl.classList.add('selected-remote');
+ sqEl.dataset.selectedBy = playerId;
+ }
+
+ function clearRemoteSelection(playerId){
+ const prev = remoteSelections[playerId];
+ if(!prev) return;
+ const prevEl = boardEl.querySelector(`.square[data-square="${prev}"]`);
+ if(prevEl){
+ prevEl.classList.remove('selected-remote');
+ delete prevEl.dataset.selectedBy;
+ }
+ delete remoteSelections[playerId];
}
if(boardEl){
@@ -137,32 +189,20 @@
if(!sqEl) return;
const square = sqEl.getAttribute('data-square');
if(!square) return;
- if(socket){
- socket.emit('game:legalMoves', { roomId, square }, (resp)=>{
- if(resp && resp.error){ log('legalMoves error', resp); clearLegalMarkers(); return; }
- log('legalMoves for', square, resp.moves || resp);
- showLegalMoves(resp.moves || []);
- });
+
+ // clicked a piece -> select it (no legal moves requested)
+ const pieceImg = ev.target.closest && ev.target.closest('img.piece');
+ if(pieceImg){
+ setSelection(square);
+ return;
}
+
+ // default: clicked empty square -> clear selection
+ clearSelection();
});
}
- const moveBtn = document.getElementById('move');
- if(moveBtn){
- moveBtn.addEventListener('click', ()=>{
- if(!socket){ alert('non connecté'); return; }
- const fromEl = document.getElementById('from');
- const toEl = document.getElementById('to');
- const promoEl = document.getElementById('promo');
- const from = fromEl ? fromEl.value.trim() : '';
- const to = toEl ? toEl.value.trim() : '';
- const promotion = promoEl ? promoEl.value.trim() || undefined : undefined;
- socket.emit('game:move', { roomId, from, to, promotion }, (resp)=>{
- if(resp && resp.error) { log('move error', resp); alert(resp.error); return; }
- log('move accepted', resp);
- });
- });
- }
+ // move button removed
// Board rendering using provided SVG assets and `boardState` JSON.
const pieceSetPath = '/assets/chess-pieces/chess_maestro_bw';
@@ -187,6 +227,17 @@
img.className = 'piece';
sqEl.appendChild(img);
});
+
+ // re-apply selection if the previously selected square still exists
+ if(selectedSquare){
+ // re-apply local selection without re-emitting
+ setSelection(selectedSquare, false);
+ }
+ // re-apply remote selections
+ Object.entries(remoteSelections).forEach(([pid, sq]) => {
+ const el = boardEl.querySelector(`.square[data-square="${sq}"]`);
+ if(el) el.classList.add('selected-remote');
+ });
}
// build grid with independent square elements and data-square attributes
diff --git a/public/styles/style.css b/public/styles/style.css
index 3ae6f1e..4616fde 100644
--- a/public/styles/style.css
+++ b/public/styles/style.css
@@ -49,12 +49,23 @@ a:hover{text-decoration:underline}
/* marker shown on target squares for legal moves */
.square{position:relative}
-.square .move-marker{
- position:absolute;
- left:50%;top:50%;transform:translate(-50%,-50%);
- width:18%;height:18%;border-radius:50%;pointer-events:none;background:rgba(96,165,250,0.95);
- box-shadow:0 2px 6px rgba(2,6,23,0.6);z-index:3
+/* move markers removed */
+
+/* highlighted/selected square when a player selects a piece */
+.square.selected{
+ outline: 3px solid rgba(245,158,11,0.95); /* amber */
+ box-shadow: inset 0 0 0 3px rgba(245,158,11,0.08), 0 8px 24px rgba(245,158,11,0.06);
+ z-index: 4;
}
+.square.selected .piece{transform: scale(1.06); transition: transform 140ms ease}
+
+/* remote selection (other player's selection) */
+.square.selected-remote{
+ outline: 3px solid rgba(59,130,246,0.95); /* blue */
+ box-shadow: inset 0 0 0 3px rgba(59,130,246,0.06), 0 6px 16px rgba(59,130,246,0.04);
+ z-index: 3;
+}
+.square.selected-remote .piece{transform: scale(1.02); transition: transform 140ms ease}
/* basic checkerboard coloring */
.square.light{background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));}
diff --git a/server.js b/server.js
index 5fdf259..9998197 100644
--- a/server.js
+++ b/server.js
@@ -200,16 +200,16 @@ io.on('connection', (socket) => {
});
// delegates to `computeLegalMoves` which is a stub you should implement.
- socket.on('game:legalMoves', ({ roomId, square }, cb) => {
+ // legalMoves API removed (movement UI disabled)
+
+ // propagate selection made by one client to the other clients in the same room
+ socket.on('game:select', ({ roomId, square }, cb) => {
const room = rooms.get(roomId);
- if (!room) return cb && cb({ error: 'room not found' });
- try{
- const moves = computeLegalMoves(room, square) || [];
- return cb && cb({ ok: true, moves });
- }catch(e){
- console.error('game:legalMoves error', e);
- return cb && cb({ error: 'invalid square', moves: [] });
- }
+ if(!room) return cb && cb({ error: 'room not found' });
+ const playerId = socket.data.playerId || null;
+ // broadcast to other sockets in the room (exclude sender)
+ socket.to(roomId).emit('game:select', { playerId, square });
+ cb && cb({ ok: true });
});
// Simple cards API via sockets: list/play