possibilité de jouer une partie

This commit is contained in:
Didictateur 2025-11-22 15:38:07 +01:00
parent 619c584572
commit e64e96e61c
3 changed files with 95 additions and 6 deletions

View file

@ -50,6 +50,8 @@
const remoteSelections = {}; const remoteSelections = {};
// track remote moves: { playerId: [moves] } // track remote moves: { playerId: [moves] }
const remoteMoves = {}; const remoteMoves = {};
// current boardState cached locally
let currentBoardState = null;
// safe logger: prefer on-page log if present, otherwise console // safe logger: prefer on-page log if present, otherwise console
function log(...args){ function log(...args){
@ -134,6 +136,16 @@
}catch(e){ console.warn('game:select handler error', e); } }catch(e){ console.warn('game:select handler error', e); }
}); });
socket.on('move:moved', (data) => {
try{
log('recv move:moved', data && { from: data.from, to: data.to });
// clear any local selection (move completed) before re-render
clearSelection(false);
if(data && data.boardState) renderBoardFromState(data.boardState);
if(data && data.boardState) updateTurnBanner(data.boardState);
}catch(e){ console.warn('move:moved handler error', e); }
});
socket.emit('room:join', { roomId, playerId }, (resp)=>{ socket.emit('room:join', { roomId, playerId }, (resp)=>{
if(resp && resp.error){ log('join error', resp); alert(resp.error); return; } if(resp && resp.error){ log('join error', resp); alert(resp.error); return; }
log('Rejoint room', resp); log('Rejoint room', resp);
@ -296,6 +308,27 @@
const square = sqEl.getAttribute('data-square'); const square = sqEl.getAttribute('data-square');
if(!square) return; if(!square) return;
// If this square contains a move-marker (either clicked marker or square area), attempt the move.
// Prefer the actual clicked marker if present, otherwise look for a marker element inside the square.
const clickedMarker = ev.target.closest && ev.target.closest('.move-marker');
const marker = clickedMarker || sqEl.querySelector('.move-marker');
if(marker){
// ignore remote player's markers
const remoteBy = marker.dataset && marker.dataset.remoteBy;
if(remoteBy && remoteBy !== myPlayerId){ log('marker belongs to remote player, ignoring'); return; }
const to = marker.dataset && marker.dataset.to;
const from = marker.dataset && marker.dataset.from ? marker.dataset.from : selectedSquare;
if(!to || !from){ log('invalid marker metadata', { from, to }); return; }
// only allow if it's our turn
const myShort = (myColor && myColor[0]) || '';
if(!currentBoardState || currentBoardState.turn !== myShort){ log('not your turn'); return; }
socket.emit('game:move', { roomId, from, to }, (resp)=>{
if(resp && resp.error){ log('move error', resp); alert(resp.error); }
else { log('move sent', resp); }
});
return;
}
// clicked a piece -> select it (no legal moves requested) // clicked a piece -> select it (no legal moves requested)
const pieceImg = ev.target.closest && ev.target.closest('img.piece'); const pieceImg = ev.target.closest && ev.target.closest('img.piece');
if(pieceImg){ if(pieceImg){
@ -316,6 +349,8 @@
function renderBoardFromState(boardState){ function renderBoardFromState(boardState){
if(!boardState) return; if(!boardState) return;
// cache boardState for client-side checks (turn etc.)
currentBoardState = boardState;
// clear existing pieces but keep squares if present // clear existing pieces but keep squares if present
const squares = boardEl.querySelectorAll('.square'); const squares = boardEl.querySelectorAll('.square');
squares.forEach(s=> s.innerHTML = ''); squares.forEach(s=> s.innerHTML = '');

View file

@ -56,9 +56,10 @@ a:hover{text-decoration:underline}
.square .move-marker{ .square .move-marker{
position:absolute; position:absolute;
left:50%;top:50%;transform:translate(-50%,-50%); 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); width:18%;height:18%;border-radius:50%;pointer-events:auto;cursor:pointer;background:rgba(96,165,250,0.95);
box-shadow:0 2px 6px rgba(2,6,23,0.6);z-index:3; box-shadow:0 2px 6px rgba(2,6,23,0.6);z-index:3;transition:transform 120ms ease, opacity 120ms ease;
} }
.square .move-marker:hover{ transform:translate(-50%,-50%) scale(1.12); opacity:0.95 }
/* highlighted/selected square when a player selects a piece */ /* highlighted/selected square when a player selects a piece */
.square.selected{ .square.selected{

View file

@ -237,11 +237,64 @@ io.on('connection', (socket) => {
socket.on('game:move', ({ roomId, from, to, promotion }, cb) => { socket.on('game:move', ({ roomId, from, to, promotion }, cb) => {
const room = rooms.get(roomId); const room = rooms.get(roomId);
if (!room) return cb && cb({ error: 'room not found' }); if (!room) return cb && cb({ error: 'room not found' });
// Basic move handling: validate turn, validate piece ownership, validate target is one of computeLegalMoves,
// apply the move to room.boardState, handle captures, flip turn and broadcast the updated board.
try{
const senderId = socket.data.playerId;
if(!senderId) return cb && cb({ error: 'not joined' });
const roomPlayer = room.players.find(p => p.id === senderId);
if(!roomPlayer) return cb && cb({ error: 'player not in room' });
if(!room.boardState) return cb && cb({ error: 'no board state' });
// Move handling/validation is intentionally not implemented here. const board = room.boardState;
// Implement a function to validate & apply moves on the room.boardState and // determine player's color short form ('w'|'b')
// then emit 'move:moved' with move details and updated room.boardState. const playerColorShort = (roomPlayer.color && roomPlayer.color[0]) || null;
return cb && cb({ error: 'move handling not implemented on server; implement custom engine' }); if(!playerColorShort) return cb && cb({ error: 'invalid player color' });
// must be player's turn
if(board.turn !== playerColorShort) return cb && cb({ error: 'not your turn' });
// find piece at 'from'
const pieces = board.pieces || [];
const moving = pieces.find(p => p.square === from);
if(!moving) return cb && cb({ error: 'no piece at source' });
if(moving.color !== playerColorShort) return cb && cb({ error: 'not your piece' });
// validate that 'to' is among legal moves
const legal = computeLegalMoves(room, from) || [];
const ok = legal.some(m => m.to === to);
if(!ok) return cb && cb({ error: 'illegal move' });
// apply move: remove any piece on target (capture)
const targetIndex = pieces.findIndex(p => p.square === to);
if(targetIndex >= 0){
// remove captured piece
pieces.splice(targetIndex, 1);
}
// move the piece
moving.square = to;
// advance version and flip turn
board.version = (board.version || 0) + 1;
board.turn = (board.turn === 'w') ? 'b' : 'w';
// broadcast move and new board state
const moved = { playerId: senderId, from, to, boardState: board };
io.to(roomId).emit('move:moved', moved);
io.to(roomId).emit('room:update', {
boardState: board,
players: room.players.map(p => ({ id: p.id, color: p.color })),
status: room.status,
hostId: room.hostId,
size: room.size,
cards: Object.keys(room.cards || {})
});
return cb && cb({ ok: true, moved });
}catch(err){
console.error('game:move error', err);
return cb && cb({ error: 'server error' });
}
}); });
// Host can start the game explicitly // Host can start the game explicitly