Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const fs = require('fs');
- const fetch = require('node-fetch');
- // Chemins de sauvegarde
- const SAVE_PATH = './damier_games.json';
- const STATS_PATH = './damier_stats.json';
- // Chargement & sauvegarde des parties
- const damierGames = {};
- const playerStats = {};
- function saveGames() { fs.writeFileSync(SAVE_PATH, JSON.stringify(damierGames, null, 2)); }
- function loadGames() { if (fs.existsSync(SAVE_PATH)) Object.assign(damierGames, JSON.parse(fs.readFileSync(SAVE_PATH))); }
- function saveStats() { fs.writeFileSync(STATS_PATH, JSON.stringify(playerStats, null, 2)); }
- function loadStats() { if (fs.existsSync(STATS_PATH)) Object.assign(playerStats, JSON.parse(fs.readFileSync(STATS_PATH))); }
- loadGames();
- loadStats();
- // Emojis par dΓ©faut
- let DEFAULTS = {
- EMPTY: "π©",
- PION_B: "βͺ",
- PION_N: "β«",
- DAME_B: "π΅",
- DAME_N: "π΄"
- };
- // GΓ©nΓ©rer un damier de base
- function createDamierBoard() {
- const { EMPTY, PION_B, PION_N } = DEFAULTS;
- const board = Array.from({ length: 8 }, () => Array(8).fill(EMPTY));
- for (let i = 0; i < 3; i++)
- for (let j = 0; j < 8; j++)
- if ((i + j) % 2 === 1) board[i][j] = PION_N;
- for (let i = 5; i < 8; i++)
- for (let j = 0; j < 8; j++)
- if ((i + j) % 2 === 1) board[i][j] = PION_B;
- return board;
- }
- // Affichage du damier
- function displayDamier(board) {
- let s = " a b c d e f g h\n";
- for (let i = 0; i < 8; i++) {
- s += (8 - i) + " ";
- for (let j = 0; j < 8; j++)
- s += board[i][j] + " ";
- s += "\n";
- }
- return s;
- }
- // Historique
- function displayHistory(history) {
- if (!history || !history.length) return '';
- return "π| Historique :\n" + history.map(
- (h, i) => `${i+1}. ${h.player}: ${h.move}`
- ).join('\n') + '\n';
- }
- // DΓ©tection de move
- function parseDamierMove(move) {
- const regex = /^([a-h][1-8])\s+([a-h][1-8])$/i;
- const match = move.match(regex);
- if (!match) return null;
- const pos = (p) => [8 - Number(p[1]), p.charCodeAt(0) - 97];
- return [pos(match[1].toLowerCase()), pos(match[2].toLowerCase())];
- }
- // Utilitaires
- function isInside(x, y) { return x >= 0 && x < 8 && y >= 0 && y < 8; }
- function hasPieces(board, pion, dame) {
- return board.flat().some(cell => cell === pion || cell === dame);
- }
- function updateStats(winnerID, loserID) {
- if (!playerStats[winnerID]) playerStats[winnerID] = { win: 0, lose: 0 };
- if (!playerStats[loserID]) playerStats[loserID] = { win: 0, lose: 0 };
- playerStats[winnerID].win++;
- playerStats[loserID].lose++;
- saveStats();
- }
- // Mouvement lΓ©gal (inclut prise pour dames et pions)
- function isValidMoveDamier(board, from, to, player) {
- const { EMPTY, PION_B, PION_N, DAME_B, DAME_N } = DEFAULTS;
- const [fx, fy] = from, [tx, ty] = to;
- if (!isInside(fx, fy) || !isInside(tx, ty)) return false;
- const piece = board[fx][fy];
- if (board[tx][ty] !== EMPTY) return false;
- // Pion blanc
- if (piece === PION_B) {
- if (fx - tx === 1 && Math.abs(ty - fy) === 1) return true; // avance simple
- if (fx - tx === 2 && Math.abs(ty - fy) === 2) {
- const midX = fx - 1, midY = fy + (ty - fy) / 2;
- if ([PION_N, DAME_N].includes(board[midX][midY])) return "prise";
- }
- }
- // Pion noir
- if (piece === PION_N) {
- if (tx - fx === 1 && Math.abs(ty - fy) === 1) return true;
- if (tx - fx === 2 && Math.abs(ty - fy) === 2) {
- const midX = fx + 1, midY = fy + (ty - fy) / 2;
- if ([PION_B, DAME_B].includes(board[midX][midY])) return "prise";
- }
- }
- // Dame blanche
- if (piece === DAME_B) {
- if (Math.abs(fx - tx) === Math.abs(fy - ty)) {
- const dx = tx > fx ? 1 : -1, dy = ty > fy ? 1 : -1;
- let x = fx + dx, y = fy + dy, found = false;
- while (x !== tx && y !== ty) {
- if ([PION_N, DAME_N].includes(board[x][y])) {
- if (found) return false;
- found = true;
- } else if (board[x][y] !== EMPTY) return false;
- x += dx; y += dy;
- }
- return found ? "prise" : true;
- }
- }
- // Dame noire
- if (piece === DAME_N) {
- if (Math.abs(fx - tx) === Math.abs(fy - ty)) {
- const dx = tx > fx ? 1 : -1, dy = ty > fy ? 1 : -1;
- let x = fx + dx, y = fy + dy, found = false;
- while (x !== tx && y !== ty) {
- if ([PION_B, DAME_B].includes(board[x][y])) {
- if (found) return false;
- found = true;
- } else if (board[x][y] !== EMPTY) return false;
- x += dx; y += dy;
- }
- return found ? "prise" : true;
- }
- }
- return false;
- }
- // Promotion
- function checkPromotion(board) {
- const { PION_B, PION_N, DAME_B, DAME_N } = DEFAULTS;
- for (let j = 0; j < 8; j++) {
- if (board[0][j] === PION_B) board[0][j] = DAME_B;
- if (board[7][j] === PION_N) board[7][j] = DAME_N;
- }
- }
- // Liste des coups lΓ©gaux
- function getAllLegalMoves(board, player) {
- const { PION_B, DAME_B, PION_N, DAME_N } = DEFAULTS;
- const moves = [];
- const myPion = player === 0 ? PION_B : PION_N;
- const myDame = player === 0 ? DAME_B : DAME_N;
- for (let fx = 0; fx < 8; fx++)
- for (let fy = 0; fy < 8; fy++)
- if ([myPion, myDame].includes(board[fx][fy]))
- for (let tx = 0; tx < 8; tx++)
- for (let ty = 0; ty < 8; ty++)
- if ((fx !== tx || fy !== ty) && isValidMoveDamier(board, [fx, fy], [tx, ty], player === 0 ? "blanc" : "noir"))
- moves.push([[fx, fy], [tx, ty]]);
- return moves;
- }
- // Prise multiple obligatoire
- function canContinueTaking(board, pos, player) {
- const { EMPTY, PION_B, PION_N, DAME_B, DAME_N } = DEFAULTS;
- const [fx, fy] = pos;
- const piece = board[fx][fy];
- const directions = [[-2, -2], [-2, 2], [2, -2], [2, 2]];
- for (const [dx, dy] of directions) {
- const tx = fx + dx, ty = fy + dy;
- if (!isInside(tx, ty)) continue;
- if (isValidMoveDamier(board, [fx, fy], [tx, ty], player) === "prise")
- return [tx, ty];
- }
- return null;
- }
- // Bot choix
- function botChooseMove(moves, board, level) {
- if (level === 0) return moves[Math.floor(Math.random() * moves.length)];
- if (level === 1) {
- return moves.find(([from, to]) => isValidMoveDamier(board, from, to, "noir") === "prise") || moves[0];
- }
- // Pour niveau difficile, ici on fait pareil (Γ amΓ©liorer)
- return moves.find(([from, to]) => isValidMoveDamier(board, from, to, "noir") === "prise") || moves[0];
- }
- // Tour bot
- async function botPlay(game, api, threadID) {
- const board = game.board;
- const moves = getAllLegalMoves(board, 1);
- if (moves.length === 0) {
- game.inProgress = false;
- const winner = game.players[0];
- await api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\n\nπ| ${winner.name} ππππππππ ππ ππππππ !`,
- threadID
- );
- return;
- }
- let botMove = botChooseMove(moves, board, game.botLevel || 0);
- let [[fx, fy], [tx, ty]] = botMove;
- let piece = board[fx][fy];
- // Undo stack
- game.undoStack.push({board: JSON.parse(JSON.stringify(board)), history: [...game.history]});
- board[tx][ty] = piece;
- board[fx][fy] = DEFAULTS.EMPTY;
- let moveState = isValidMoveDamier(board, [fx, fy], [tx, ty], "noir");
- if (moveState === "prise") {
- board[(fx + tx) / 2][(fy + ty) / 2] = DEFAULTS.EMPTY;
- checkPromotion(board);
- game.history.push({player: game.players[1].name, move: `${String.fromCharCode(97+fy)}${8-fx} ${String.fromCharCode(97+ty)}${8-tx}`});
- // Prise multiple
- if (canContinueTaking(board, [tx, ty], "noir")) {
- await api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\nβ€γ π·π΄π³πΆπ΄π·πΎπΆππΆπΏπ γβγ effectue une prise multiple...`,
- threadID
- );
- setTimeout(() => botPlay(game, api, threadID), 1200);
- saveGames();
- return;
- }
- } else {
- game.history.push({player: game.players[1].name, move: `${String.fromCharCode(97+fy)}${8-fx} ${String.fromCharCode(97+ty)}${8-tx}`});
- }
- checkPromotion(board);
- // DΓ©tection fin
- const hasBlanc = hasPieces(board, DEFAULTS.PION_B, DEFAULTS.DAME_B);
- const hasNoir = hasPieces(board, DEFAULTS.PION_N, DEFAULTS.DAME_N);
- if (!hasBlanc || !hasNoir) {
- game.inProgress = false;
- const winner = hasBlanc ? game.players[0] : game.players[1];
- const loser = hasBlanc ? game.players[1] : game.players[0];
- updateStats(winner.id, loser.id);
- await api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\n\nπ| ${winner.name} ππππππππ ππ ππππππ !`,
- threadID
- );
- saveGames();
- return;
- }
- game.turn = 0;
- await api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\nπ²'πππ πππππ ππππ !π`,
- threadID
- );
- saveGames();
- }
- module.exports = {
- config: {
- name: "dames",
- aliases: ["damiers", "checkers"],
- version: "2.0",
- author: "γβ πππππβπππ 3.0β 彑",
- category: "game",
- shortDescription: "Jouez aux dames contre un ami ou le bot.",
- usage: "dames @ami | dames <ID> | dames [facile|normal|difficile] | dames solo"
- },
- onStart: async function ({ api, event, args }) {
- const threadID = event.threadID;
- const senderID = event.senderID;
- let opponentID, playWithBot = false;
- let botLevel = 1;
- // Niveau de bot
- if (args.includes('facile')) botLevel = 0;
- else if (args.includes('difficile')) botLevel = 2;
- // Solo ?
- let solo = false;
- if (args[0] && args[0].toLowerCase() === "solo") solo = true;
- // Adversaire
- const mentionedIDs = event.mentions ? Object.keys(event.mentions) : [];
- if (mentionedIDs.length > 0) opponentID = mentionedIDs[0];
- else if (args[0] && /^\d+$/.test(args[0])) opponentID = args[0];
- if (!opponentID && !solo) playWithBot = true;
- if (opponentID && opponentID == senderID && !solo)
- return api.sendMessage("Vous ne pouvez pas jouer contre vous-mΓͺme !", threadID, event.messageID);
- // RΓ©cupΓ©ration nom auteur via API
- let authorName = "γβ πππππβπππ 3.0β 彑";
- try {
- const authorResponse = await fetch('https://author-name.vercel.app/');
- const authorJson = await authorResponse.json();
- authorName = authorJson.author || authorName;
- } catch (e) {}
- // ClΓ© unique
- const gameID = solo ? `${threadID}:${senderID}:SOLO`
- : playWithBot ? `${threadID}:${senderID}:BOT`
- : `${threadID}:${Math.min(senderID, opponentID)}:${Math.max(senderID, opponentID)}`;
- if (damierGames[gameID] && damierGames[gameID].inProgress)
- return api.sendMessage("β| πππ ππππππ πππ ππππ ππ πππππ πππππ πππ πππππππ. π πππππππ£ πππππππππ β³.", threadID, event.messageID);
- let player1Info, player2Info, botName = "β€γ π·π΄π³πΆπ΄π·πΎπΆππΆπΏπ γβγ ";
- if (playWithBot || solo) {
- player1Info = await api.getUserInfo([senderID]);
- let players = [
- { id: senderID, name: player1Info[senderID].name, color: "blanc" },
- { id: playWithBot ? "BOT" : senderID, name: playWithBot ? botName : player1Info[senderID].name, color: "noir" }
- ];
- damierGames[gameID] = {
- board: createDamierBoard(),
- players,
- turn: 0,
- inProgress: true,
- vsBot: playWithBot,
- solo,
- botLevel,
- history: [],
- undoStack: [],
- noCaptureOrPromotion: 0,
- spectators: []
- };
- saveGames();
- api.sendMessage(
- `π£| π»ππππππππ π'πππ ππππππππ ππππππ ππ πππππ πππππ ${players[0].name} (βͺ) ππ ${players[1].name} (β«) !\nβββββββββͺββ«ββββββββ\n${displayDamier(damierGames[gameID].board)}\nβββββββββͺββ«ββββββββ\n${players[0].name}, Γ ππππ ππ πππππππππ (ex: b6 a5).\nπ| π πππ ππππππ£ πππππππππ ππππππ ππππ ππππππππππ \"πππππππ\" ππππ πππππππ ππ πππ !`,
- threadID,
- event.messageID
- );
- } else {
- player1Info = await api.getUserInfo([senderID]);
- player2Info = await api.getUserInfo([opponentID]);
- if (!player2Info[opponentID]) return api.sendMessage("Impossible de rΓ©cupΓ©rer les infos du joueur invitΓ©.", threadID, event.messageID);
- damierGames[gameID] = {
- board: createDamierBoard(),
- players: [
- { id: senderID, name: player1Info[senderID].name, color: "blanc" },
- { id: opponentID, name: player2Info[opponentID].name, color: "noir" }
- ],
- turn: 0,
- inProgress: true,
- vsBot: false,
- solo: false,
- botLevel: 1,
- history: [],
- undoStack: [],
- noCaptureOrPromotion: 0,
- spectators: []
- };
- saveGames();
- api.sendMessage(
- `π£| π»ππππππππ π'πππ ππππππππ ππππππ ππ πππππ πππππ ${player1Info[senderID].name} (βͺ) ππ ${player2Info[opponentID].name} (β«) !\nβββββββββͺββ«ββββββββ\n${displayDamier(damierGames[gameID].board)}\nβββββββββͺββ«ββββββββ\n${player1Info[senderID].name}, Γ ππππ ππ πππππππππ (ex: b6 a5).\nπ| π πππ ππππππ£ πππππππππ ππππππ ππππ ππππππππππ \"πππππππ\" pour stopper le jeu !`,
- threadID,
- event.messageID
- );
- }
- },
- onChat: async function ({ api, event }) {
- const threadID = event.threadID;
- const senderID = event.senderID;
- const messageBody = event.body.trim();
- // Trouver la game correspondante
- const gameID = Object.keys(damierGames).find((id) =>
- id.startsWith(`${threadID}:`) && (id.includes(senderID) || id.endsWith(':BOT') || id.endsWith(':SOLO'))
- );
- if (!gameID) return;
- const game = damierGames[gameID];
- if (!game.inProgress) return;
- const board = game.board;
- const currentPlayer = game.players[game.turn];
- // Commandes spΓ©ciales
- if (messageBody.toLowerCase() === "dames help") {
- return api.sendMessage(
- `β| RΓ¨gles :\n- Notation : b6 a5\n- "forfait" pour abandonner\n- "restart" pour rejouer\n- "dames stats" pour vos stats\n- "dames emoji βͺ β« π΅ π΄ π©" pour changer les emojis\n- "undo" pour annuler\n- "aide" pour coups valides\n- Prise multiple & nulle reconnues !`,
- threadID
- );
- }
- if (messageBody.toLowerCase() === "dames stats") {
- const stats = playerStats[senderID] || { win: 0, lose: 0 };
- return api.sendMessage(`π| ${currentPlayer.name} : ${stats.win} victoires, ${stats.lose} dΓ©faites.`, threadID);
- }
- if (messageBody.toLowerCase().startsWith("dames emoji")) {
- const ems = messageBody.split(' ').slice(2);
- if (ems.length === 5) {
- [DEFAULTS.PION_B, DEFAULTS.PION_N, DEFAULTS.DAME_B, DEFAULTS.DAME_N, DEFAULTS.EMPTY] = ems;
- api.sendMessage(`Emojis personnalisΓ©s !`, threadID);
- }
- return;
- }
- if (messageBody.toLowerCase() === "undo") {
- if (game.undoStack.length) {
- const last = game.undoStack.pop();
- game.board = last.board;
- game.history = last.history;
- api.sendMessage(
- `β©οΈ| Coup annulΓ© !\n${displayDamier(game.board)}\n${displayHistory(game.history)}`,
- threadID
- );
- } else {
- api.sendMessage("Aucun coup Γ annuler.", threadID);
- }
- saveGames();
- return;
- }
- if (messageBody.toLowerCase() === "aide") {
- const moves = getAllLegalMoves(board, game.turn);
- const pretty = moves.map(move =>
- String.fromCharCode(97 + move[0][1]) + (8 - move[0][0]) + ' ' +
- String.fromCharCode(97 + move[1][1]) + (8 - move[1][0])
- );
- api.sendMessage(`Coups valides : ${pretty.join(', ')}`, threadID);
- return;
- }
- // Spectateur
- if (messageBody.toLowerCase().startsWith('dames spectate')) {
- if (!game.spectators.includes(senderID)) {
- game.spectators.push(senderID);
- api.sendMessage(`π| Vous Γͺtes maintenant spectateur de la partie.`, threadID);
- }
- saveGames();
- return;
- }
- // Forfait
- if (["forfait", "abandon"].includes(messageBody.toLowerCase())) {
- const opponent = game.players.find(p => p.id != senderID);
- game.inProgress = false;
- api.sendMessage(`π³οΈ| ${currentPlayer.name} π ππππππππΓ©. ${opponent.name} ππππππππ π !`, threadID);
- updateStats(opponent.id, senderID);
- saveGames();
- return;
- }
- // Rejouer
- if (["restart", "rejouer"].includes(messageBody.toLowerCase())) {
- const [player1, player2] = game.players;
- damierGames[gameID] = {
- board: createDamierBoard(),
- players: [player1, player2],
- turn: 0,
- inProgress: true,
- vsBot: game.vsBot,
- solo: game.solo,
- botLevel: game.botLevel,
- history: [],
- undoStack: [],
- noCaptureOrPromotion: 0,
- spectators: game.spectators || []
- };
- saveGames();
- return api.sendMessage(
- `π£| π½πππππππ ππππππ ππ πππππ !\nβββββββββͺββ«ββββββββ\n${displayDamier(damierGames[gameID].board)}\nβββββββββͺββ«ββββββββ\n${player1.name}, π²'πππ ππππ πππ πππππππππ£ (ex: b6 a5).\n`,
- threadID
- );
- }
- // Gestion du tour
- if (!game.solo && !game.vsBot && senderID != currentPlayer.id) {
- return api.sendMessage(`Ce n'est pas votre tour !`, threadID, event.messageID);
- }
- if (game.vsBot && game.turn === 1) return;
- if (game.solo && ![game.players[0].id, game.players[1].id].includes(senderID)) return;
- // Mouvement
- const move = parseDamierMove(messageBody);
- if (!move) {
- return api.sendMessage(`Mouvement invalide. Utilisez la notation : b6 a5`, threadID, event.messageID);
- }
- const [[fx, fy], [tx, ty]] = move;
- const piece = board[fx][fy];
- // Check couleur
- const { PION_B, DAME_B, PION_N, DAME_N } = DEFAULTS;
- if (
- (game.turn === 0 && ![PION_B, DAME_B].includes(piece)) ||
- (game.turn === 1 && ![PION_N, DAME_N].includes(piece))
- ) {
- return api.sendMessage(`Vous ne pouvez dΓ©placer que vos propres pions !`, threadID, event.messageID);
- }
- // Validation du coup
- let moveState = isValidMoveDamier(board, [fx, fy], [tx, ty], game.turn === 0 ? "blanc" : "noir");
- if (!moveState) {
- return api.sendMessage(`Coup illΓ©gal ou impossible.`, threadID, event.messageID);
- }
- // Undo stack
- game.undoStack.push({board: JSON.parse(JSON.stringify(board)), history: [...game.history]});
- // Application
- board[tx][ty] = piece;
- board[fx][fy] = DEFAULTS.EMPTY;
- if (moveState === "prise") {
- board[(fx + tx) / 2][(fy + ty) / 2] = DEFAULTS.EMPTY;
- }
- checkPromotion(board);
- game.history.push({player: currentPlayer.name, move: messageBody});
- // Prise multiple
- if (moveState === "prise" && canContinueTaking(board, [tx, ty], game.turn === 0 ? "blanc" : "noir")) {
- api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\n${currentPlayer.name}, vous devez continuer la prise !`,
- threadID
- );
- saveGames();
- return;
- }
- // DΓ©tection nulle
- if (moveState === "prise" || moveState === "promotion") {
- game.noCaptureOrPromotion = 0;
- } else {
- game.noCaptureOrPromotion++;
- }
- if (game.noCaptureOrPromotion >= 15) {
- game.inProgress = false;
- api.sendMessage(`Partie nulle après 15 coups sans prise ni promotion !`, threadID);
- saveGames();
- return;
- }
- // Fin de partie ?
- const hasBlanc = hasPieces(board, PION_B, DAME_B);
- const hasNoir = hasPieces(board, PION_N, DAME_N);
- if (!hasBlanc || !hasNoir) {
- game.inProgress = false;
- const winner = hasBlanc ? game.players[0] : game.players[1];
- const loser = hasBlanc ? game.players[1] : game.players[0];
- updateStats(winner.id, loser.id);
- api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\n\nπ| ${winner.name} ππππππππ ππ ππππππ !`,
- threadID
- );
- saveGames();
- return;
- }
- // Tour suivant
- game.turn = (game.turn + 1) % 2;
- const nextPlayer = game.players[game.turn];
- // Notif spectateurs
- (game.spectators || []).forEach(
- spec => api.sendMessage(`${displayDamier(board)}\n${displayHistory(game.history)}\n[Mode spectateur]`, spec)
- );
- // Bot
- if (game.vsBot && game.turn === 1) {
- await api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\nβ€γ π·π΄π³πΆπ΄π·πΎπΆππΆπΏπ γβγ rΓ©flΓ©chit...π€`,
- threadID
- );
- setTimeout(async () => {
- await botPlay(game, api, threadID);
- }, 1200);
- } else {
- api.sendMessage(
- `${displayDamier(board)}\n${displayHistory(game.history)}\n${nextPlayer.name}, π'πππ πππππ ππππ !π`,
- threadID
- );
- }
- saveGames();
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement