possibilité de jouer une partie
This commit is contained in:
parent
619c584572
commit
e64e96e61c
3 changed files with 95 additions and 6 deletions
|
|
@ -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 = '');
|
||||||
|
|
|
||||||
|
|
@ -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{
|
||||||
|
|
|
||||||
61
server.js
61
server.js
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue