diff --git a/game.js b/game.js index 3b5359f..e71dd09 100644 --- a/game.js +++ b/game.js @@ -12,7 +12,7 @@ import { updateElo, getAllSkins } from './init_database.js' -import {skins} from "./index.js"; +import {C4_COLS, C4_ROWS, skins} from "./index.js"; const messagesTimestamps = new Map(); @@ -309,4 +309,61 @@ export function randomSkinPrice(id=0) { const returnPrice = price() console.log(`#${id} :`, returnPrice) return returnPrice +} + +export function createConnect4Board() { + return Array(C4_ROWS).fill(null).map(() => Array(C4_COLS).fill(null)); +} + +export function checkConnect4Win(board, player) { + // Check horizontal + for (let r = 0; r < C4_ROWS; r++) { + for (let c = 0; c <= C4_COLS - 4; c++) { + if (board[r][c] === player && board[r][c+1] === player && board[r][c+2] === player && board[r][c+3] === player) { + return { win: true, pieces: [{row:r, col:c}, {row:r, col:c+1}, {row:r, col:c+2}, {row:r, col:c+3}] }; + } + } + } + + // Check vertical + for (let r = 0; r <= C4_ROWS - 4; r++) { + for (let c = 0; c < C4_COLS; c++) { + if (board[r][c] === player && board[r+1][c] === player && board[r+2][c] === player && board[r+3][c] === player) { + return { win: true, pieces: [{row:r, col:c}, {row:r+1, col:c}, {row:r+2, col:c}, {row:r+3, col:c}] }; + } + } + } + + // Check diagonal (down-right) + for (let r = 0; r <= C4_ROWS - 4; r++) { + for (let c = 0; c <= C4_COLS - 4; c++) { + if (board[r][c] === player && board[r+1][c+1] === player && board[r+2][c+2] === player && board[r+3][c+3] === player) { + return { win: true, pieces: [{row:r, col:c}, {row:r+1, col:c+1}, {row:r+2, col:c+2}, {row:r+3, col:c+3}] }; + } + } + } + + // Check diagonal (up-right) + for (let r = 3; r < C4_ROWS; r++) { + for (let c = 0; c <= C4_COLS - 4; c++) { + if (board[r][c] === player && board[r-1][c+1] === player && board[r-2][c+2] === player && board[r-3][c+3] === player) { + return { win: true, pieces: [{row:r, col:c}, {row:r-1, col:c+1}, {row:r-2, col:c+2}, {row:r-3, col:c+3}] }; + } + } + } + + return { win: false, pieces: [] }; +} + +export function checkConnect4Draw(board) { + return board[0].every(cell => cell !== null); +} + +export function formatConnect4BoardForDiscord(board) { + const symbols = { + 'R': '🔴', + 'Y': '🟡', + null: '⚪' + }; + return board.map(row => row.map(cell => symbols[cell]).join('')).join('\n'); } \ No newline at end of file diff --git a/index.js b/index.js index c2dc885..4027671 100644 --- a/index.js +++ b/index.js @@ -22,8 +22,8 @@ import { getNextActivePlayer, checkEndOfBettingRound, initialCards, checkRoomWinners, pruneOldLogs } from './utils.js'; import { - channelPointsHandler, - eloHandler, + channelPointsHandler, checkConnect4Draw, checkConnect4Win, createConnect4Board, + eloHandler, formatConnect4BoardForDiscord, pokerEloHandler, randomSkinPrice, slowmodesHandler @@ -4461,6 +4461,11 @@ const io = new Server(server, { let queue = [] let playingArray = [] +let connect4Queue = [] +let connect4PlayingArray = [] +export const C4_ROWS = 6 +export const C4_COLS = 7 + io.on('connection', (socket) => { socket.on('user-connected', async (user) => { @@ -4717,6 +4722,120 @@ io.on('connection', (socket) => { playingArray = playingArray.filter(obj => obj.p1.id !== e.playerId) }) + + socket.on('connect4queue', async (e) => { + console.log(`${e.playerId} in Connect 4 queue`); + + if (!connect4Queue.find(obj => obj === e.playerId)) { + connect4Queue.push(e.playerId); + } + + if (connect4Queue.length >= 2) { + const p1Id = connect4Queue[0]; + const p2Id = connect4Queue[1]; + const p1 = await client.users.fetch(p1Id); + const p2 = await client.users.fetch(p2Id); + let msgId; + + const board = createConnect4Board(); + const boardText = formatConnect4BoardForDiscord(board); + + try { + const guild = await client.guilds.fetch(process.env.GUILD_ID); + const generalChannel = guild.channels.cache.find(ch => ch.name === 'général' || ch.name === 'general'); + const embed = new EmbedBuilder() + .setTitle('Puissance 4') + .setDescription(`**🔴 ${p1.globalName}** vs **${p2.globalName} 🟡**\n\n${boardText}`) + .setColor('#5865f2') + .setTimestamp(new Date()); + const msg = await generalChannel.send({ embeds: [embed] }); + msgId = msg.id; + } catch (err) { + console.error("Error sending Connect 4 start message:", err); + } + + const lobby = { + p1: { id: p1Id, name: p1.globalName, val: 'R' }, + p2: { id: p2Id, name: p2.globalName, val: 'Y' }, + turn: p1Id, + board: board, + msgId: msgId, + gameOver: false, + winningPieces: [] + }; + + connect4PlayingArray.push(lobby); + connect4Queue.splice(0, 2); + } + + let names = []; + for (const n of connect4Queue) { + let name = await client.users.fetch(n); + names.push(name?.globalName); + } + io.emit('connect4queue', { allPlayers: connect4PlayingArray, queue: names }); + }); + + socket.on('connect4playing', async (e) => { + const lobby = connect4PlayingArray.find(l => (l.p1.id === e.playerId || l.p2.id === e.playerId) && !l.gameOver); + if (!lobby || lobby.turn !== e.playerId) return; + + const player = lobby.p1.id === e.playerId ? lobby.p1 : lobby.p2; + const col = e.col; + + // Drop the piece + let row; + for (row = C4_ROWS - 1; row >= 0; row--) { + if (lobby.board[row][col] === null) { + lobby.board[row][col] = player.val; + break; + } + } + + // Check for win + const winCheck = checkConnect4Win(lobby.board, player.val); + if (winCheck.win) { + lobby.gameOver = true; + lobby.winningPieces = winCheck.pieces; + await eloHandler(lobby.p1.id, lobby.p2.id, lobby.p1.id === player.id ? 1 : 0, lobby.p2.id === player.id ? 1 : 0, 'CONNECT4'); + io.emit('connect4gameOver', { game: lobby, winner: player.id }); + } + // Check for draw + else if (checkConnect4Draw(lobby.board)) { + lobby.gameOver = true; + await eloHandler(lobby.p1.id, lobby.p2.id, 0.5, 0.5, 'CONNECT4'); + io.emit('connect4gameOver', { game: lobby, winner: 'draw' }); + } + // Switch turns + else { + lobby.turn = lobby.p1.id === player.id ? lobby.p2.id : lobby.p1.id; + } + + // Update Discord message + try { + const guild = await client.guilds.fetch(process.env.GUILD_ID); + const generalChannel = guild.channels.cache.find(ch => ch.name === 'général' || ch.name === 'general'); + const message = await generalChannel.messages.fetch(lobby.msgId); + let description = `**🔴 ${lobby.p1.name}** vs **${lobby.p2.name} 🟡**\n\n${formatConnect4BoardForDiscord(lobby.board)}`; + if (lobby.gameOver) { + if(winCheck.win) { + description += `\n\n### Victoire de ${player.name}!`; + } else { + description += `\n\n### Match Nul!`; + } + } + const embed = new EmbedBuilder() + .setTitle('Puissance 4') + .setDescription(description) + .setColor(lobby.gameOver ? '#2ade2a' : '#5865f2') + .setTimestamp(new Date()); + await message.edit({ embeds: [embed] }); + } catch (err) { + console.error("Error updating Connect 4 message:", err); + } + + io.emit('connect4playing', { allPlayers: connect4PlayingArray }); + }); }); server.listen(PORT, () => {