const express = require('express'); const socketio = require('socket.io'); const { v4: uuidv4 } = require('uuid'); const fs = require('fs'); const app = express(); const PORT = process.env.PORT || 3000; // Game state storage const rooms = Array(10).fill().map((_, i) => ({ id: `room${i}`, players: [], gameState: Array(6).fill().map(() => Array(7).fill(null)), currentPlayer: 0, moves: [] })); const hallOfFame = JSON.parse(fs.readFileSync('halloffame.json', 'utf8') || '{}'); app.use(express.static('public')); app.use(express.urlencoded({ extended: true })); app.get('/', (req, res) => { res.sendFile(__dirname + '/public/index.html'); }); app.get('/room:num', (req, res) => { res.sendFile(__dirname + '/public/room.html'); }); const server = app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); }); const io = socketio(server); io.on('connection', (socket) => { let currentRoom = null; let playerName = null; socket.on('askRooms', () => { io.emit('updateRooms', rooms); io.emit('updateHOF', hallOfFame); }); let stopGame = (room, roomId) => { console.log("Not enough players in room " + roomId + ", game stops."); room["gameState"] = Array(6).fill().map(() => Array(7).fill(null)); room["currentPlayer"] = 0; }; let startGame = (room, roomId) => { console.log("Two players on room " + roomId + ", game starting."); io.to(roomId).emit('startGame', { board: room.gameState, currentPlayer: room.currentPlayer }); }; let leaveRooms = () => { if (currentRoom) { let oldPlayercount = currentRoom.players.length; currentRoom.players = currentRoom.players.filter(p => p.id !== socket.id); let newPlayercount = currentRoom.players.length; if (oldPlayercount == 2 && newPlayercount < 2) { stopGame(currentRoom, currentRoom.id); } console.log("Player " + playerName + " leaved room " + currentRoom.id + "."); currentRoom = null; io.emit('updateRooms', rooms); } } socket.on('joinRoom', ({ name, roomId }) => { leaveRooms(); const room = rooms.find(r => r.id === roomId); if (!room || room.players.length >= 2) { socket.emit('error', 'Room is full or doesn\'t exist'); return; } playerName = name; currentRoom = room; console.log("Player " + name + " joined room " + roomId + "."); room.players.push({ id: socket.id, name }); socket.join(roomId); io.emit('updateRooms', rooms); if (room.players.length === 2) { startGame(room, roomId); } }); socket.on('move', (col) => { if (!currentRoom) return; const playerIndex = currentRoom.players.findIndex(p => p.id === socket.id); if (playerIndex !== currentRoom.currentPlayer) { console.log("Not " + playerName + "'s turn to play"); return; }; const row = findAvailableRow(currentRoom.gameState, col); if (row === -1) return; console.log("On room " + currentRoom.id + ", " + playerName + " played on column " + col + " at height" + row); currentRoom.gameState[row][col] = playerIndex; currentRoom.moves.push({ player: playerIndex, col }); const winner = checkWin(currentRoom.gameState, row, col); if (winner !== null) { console.log("In room "+currentRoom.id+", player "+playerName+" won"); hallOfFame[playerName] = (hallOfFame[playerName] || 0) + 1; fs.writeFileSync('halloffame.json', JSON.stringify(hallOfFame)); stopGame(currentRoom, currentRoom.id); socket.join(currentRoom.id); io.to(currentRoom.id).emit('stopGame', { board: currentRoom.gameState, winner: winner }); } else { currentRoom.currentPlayer = 1 - currentRoom.currentPlayer; socket.join(currentRoom.id); io.to(currentRoom.id).emit('updateGame', { board: currentRoom.gameState, currentPlayer: currentRoom.currentPlayer }); } }); socket.on('chatMessage', (message) => { if (!currentRoom) { return; } io.to(currentRoom.id).emit('message', { name: playerName, message }); }); socket.on('disconnect', () => { leaveRooms(); }); }); function findAvailableRow(board, col) { for (let row = 5; row >= 0; row--) { if (board[row][col] == null) return row; } return -1; } function checkWin(board, row, col) { const player = board[row][col]; if (player === null) return null; const ROWS = board.length; const COLS = board[0].length; const WINNING_LENGTH = 4; const directions = [ [0, 1], // horizontal → [1, 0], // vertical ↓ [1, 1], // diagonale descendante ↘ [1, -1] // diagonale montante ↗ ]; for (const [dx, dy] of directions) { let count = 1; for (let step = 1; step < WINNING_LENGTH; step++) { const newRow = row + step * dx; const newCol = col + step * dy; if ( newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS && board[newRow][newCol] === player ) { count++; } else { break; } } // Direction opposée for (let step = 1; step < WINNING_LENGTH; step++) { const newRow = row - step * dx; const newCol = col - step * dy; if ( newRow >= 0 && newRow < ROWS && newCol >= 0 && newCol < COLS && board[newRow][newCol] === player ) { count++; } else { break; } } if (count >= WINNING_LENGTH) { return player; } } return null; }