Advertisement
samiroexpikachu

Untitled

Jul 18th, 2024 (edited)
48
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. const { randomString, getTime, convertTime } = global.utils;
  2. const { createCanvas } = require('canvas');
  3. const rows = [
  4.     {
  5.         col: 4,
  6.         row: 10,
  7.         rewardPoint: 1
  8.     },
  9.     {
  10.         col: 5,
  11.         row: 12,
  12.         rewardPoint: 2
  13.     },
  14.     {
  15.         col: 6,
  16.         row: 15,
  17.         rewardPoint: 3
  18.     }
  19. ];
  20.  
  21. module.exports = {
  22.     config: {
  23.         name: "guessnumber",
  24.         aliases: ["guessnum"],
  25.         version: "1.1",
  26.         author: "NTKhang",
  27.         countDown: 5,
  28.         role: 0,
  29.         description: {
  30.             vi: "Game đoán số",
  31.             en: "Guess number game"
  32.         },
  33.         category: "𝗚𝗔𝗠𝗘",
  34.         guide: {
  35.             vi: "  {pn} [4 | 5 | 6] [single | multi]: tạo một bàn chơi mới, với:"
  36.                 + "\n    4 5 6 là số chữ số của số cần đoán, mặc định là 4."
  37.                 + "\n    single | multi là chế độ chơi, single là 1 người chơi, multi là nhiều người chơi, mặc định là single."
  38.                 + "\n   Ví dụ:"
  39.                 + "\n    {pn}"
  40.                 + "\n    {pn} 4 single"
  41.                 + "\n"
  42.                 + "\n   Cách chơi: người chơi trả lời tin nhắn của bot theo quy tắc sau:"
  43.                 + "\n   Bạn có " + rows.map(item => `${item.row} lần (${item.col} số)`).join(", ") + "."
  44.                 + "\n   Sau mỗi lần đoán, bạn sẽ nhận được thêm gợi ý là số lượng chữ số đúng (hiển thị bên trái) và số lượng chữ số đúng vị trí (hiển thị bên phải)."
  45.                 + "\n   Lưu ý: Số được hình thành với các chữ số từ 0 đến 9, mỗi chữ số xuất hiện duy nhất một lần và số có thể đứng đầu là 0."
  46.                 + "\n\n   {pn} rank <trang>: xem bảng xếp hạng."
  47.                 + "\n   {pn} info [<uid> | <@tag> | <reply> | <để trống>]: xem thông tin xếp hạng của bạn hoặc người khác."
  48.                 + "\n   {pn} reset: reset bảng xếp hạng (chỉ admin bot).",
  49.             en: "  {pn} [4 | 5 | 6] [single | multi]: create a new game, with:"
  50.                 + "\n    4 5 6 is the number of digits of the number to guess, default is 4."
  51.                 + "\n    single | multi is the game mode, single is 1 player, multi is multi player, default is single."
  52.                 + "\n   Example:"
  53.                 + "\n    {pn}"
  54.                 + "\n    {pn} 4 single"
  55.                 + "\n"
  56.                 + "\n   How to play: the player replies to the message of the bot with the following rules:"
  57.                 + "\n   You have " + rows.map(item => `${item.row} times (${item.col} numbers)`).join(", ") + "."
  58.                 + "\n   After each guess, you will get additional hints of the number of correct digits (shown on the left) and the number of correct digits (shown on the right)."
  59.                 + "\n   Note: The number is formed with digits from 0 to 9, each digit appears only once and the number can start with 0."
  60.                 + "\n\n   {pn} rank <page>: view the ranking."
  61.                 + "\n   {pn} info [<uid> | <@tag> | <reply> | <empty>]: view your or other's ranking information."
  62.                 + "\n   {pn} reset: reset the ranking (only admin bot)."
  63.         }
  64.     },
  65.  
  66.     langs: {
  67.         vi: {
  68.             charts: "🏆 | Bảng xếp hạng:\n%1",
  69.             pageInfo: "Trang %1/%2",
  70.             noScore: "⭕ | Hiện tại chưa có ai ghi điểm.",
  71.             noPermissionReset: "⚠️ | Bạn không có quyền reset bảng xếp hạng.",
  72.             notFoundUser: "⚠️ | Không tìm thấy người dùng có id %1 trong bảng xếp hạng.",
  73.             userRankInfo: "🏆 | Thông tin xếp hạng:\nTên: %1\nĐiểm: %2\nSố lần chơi: %3\nSố lần thắng: %4\n%5\nSố lần thua: %6\nTỉ lệ thắng: %7%\nTổng thời gian chơi: %8",
  74.             digits: "%1 chữ số: %2",
  75.             resetRankSuccess: "✅ | Reset bảng xếp hạng thành công.",
  76.             invalidCol: "⚠️ | Vui lòng nhập số chữ số của số cần đoán là 4, 5 hoặc 6",
  77.             invalidMode: "⚠️ | Vui lòng nhập chế độ chơi là single hoặc multi",
  78.             created: "✅ | Tạo bàn chơi thành công.",
  79.             gameName: "GAME ĐOÁN SỐ",
  80.             gameGuide: "⏳ | Cách chơi:\nBạn có %1 lần đoán.\nSau mỗi lần đoán, bạn sẽ nhận được thêm gợi ý là số lượng chữ số đúng (hiển thị bên trái) và số lượng chữ số đúng vị trí (hiển thị bên phải).",
  81.             gameNote: "📄 | Lưu ý:\nSố được hình thành với các chữ số từ 0 đến 9, mỗi chữ số xuất hiện duy nhất một lần và số có thể đứng đầu là 0.",
  82.             replyToPlayGame: "🎮 | Phản hồi tin nhắn hình ảnh bên dưới kèm theo %1 số bạn đoán để chơi game.",
  83.             invalidNumbers: "⚠️ | Vui lòng nhập %1 số bạn muốn đoán",
  84.             win: "🎉 | Chúc mừng bạn đã đoán đúng số %1 sau %2 lần đoán và nhận được %3 điểm thưởng.",
  85.             loss: "🤦‍♂️ | Bạn đã thua, số đúng là %1."
  86.         },
  87.         en: {
  88.             charts: "🏆 | Ranking:\n%1",
  89.             pageInfo: "Page %1/%2",
  90.             noScore: "⭕ | There is no one who has scored.",
  91.             noPermissionReset: "⚠️ | You do not have permission to reset the ranking.",
  92.             notFoundUser: "⚠️ | Could not find user with id %1 in the ranking.",
  93.             userRankInfo: "🏆 | Ranking information:\nName: %1\nScore: %2\nNumber of games: %3\nNumber of wins: %4\n%5\nNumber of losses: %6\nWin rate: %7%\nTotal play time: %8",
  94.             digits: "%1 digits: %2",
  95.             resetRankSuccess: "✅ | Reset the ranking successfully.",
  96.             invalidCol: "⚠️ | Please enter the number of digits of the number to guess is 4, 5 or 6",
  97.             invalidMode: "⚠️ | Please enter the game mode is single or multi",
  98.             created: "✅ | Create game successfully.",
  99.             gameName: "GUESS NUMBER GAME",
  100.             gameGuide: "⏳ | How to play:\nYou have %1 guesses.\nAfter each guess, you will get additional hints of the number of correct digits (shown on the left) and the number of correct digits (shown on the right).",
  101.             gameNote: "📄 | Note:\nThe number is formed with digits from 0 to 9, each digit appears only once and the number can start with 0.",
  102.             replyToPlayGame: "🎮 | Reply to the message below with the image of %1 numbers you guess to play the game.",
  103.             invalidNumbers: "⚠️ | Please enter %1 numbers you want to guess",
  104.             win: "🎉 | Congratulations you guessed the number %1 after %2 guesses and received %3 bonus points.",
  105.             loss: "🤦‍♂️ | You lost, the correct number is %1."
  106.         }
  107.     },
  108.  
  109.     onStart: async function ({ api, message, event, getLang, commandName, args, globalData, usersData, role }) {
  110.         if (args[0] == "rank") {
  111.             const rankGuessNumber = await globalData.get("rankGuessNumber", "data", []);
  112.             if (!rankGuessNumber.length)
  113.                 return message.reply(getLang("noScore"));
  114.  
  115.             const page = parseInt(args[1]) || 1;
  116.             const maxUserOnePage = 30;
  117.  
  118.             let rankGuessNumberHandle = await Promise.all(rankGuessNumber.slice((page - 1) * maxUserOnePage, page * maxUserOnePage).map(async item => {
  119.                 const userName = await usersData.getName(item.id);
  120.                 return {
  121.                     ...item,
  122.                     userName,
  123.                     winNumber: item.wins?.length || 0,
  124.                     lossNumber: item.losses?.length || 0
  125.                 };
  126.             }));
  127.  
  128.             rankGuessNumberHandle = rankGuessNumberHandle.sort((a, b) => b.winNumber - a.winNumber);
  129.             const medals = ["🥇", "🥈", "🥉"];
  130.             const rankGuessNumberText = rankGuessNumberHandle.map((item, index) => {
  131.                 const medal = medals[index] || index + 1;
  132.                 return `${medal} ${item.userName} - ${item.winNumber} wins - ${item.lossNumber} losses`;
  133.             }).join("\n");
  134.  
  135.             return message.reply(getLang("charts", rankGuessNumberText || getLang("noScore")) + "\n" + getLang("pageInfo", page, Math.ceil(rankGuessNumber.length / maxUserOnePage)));
  136.         }
  137.         else if (args[0] == "info") {
  138.             const rankGuessNumber = await globalData.get("rankGuessNumber", "data", []);
  139.             let targetID;
  140.             if (Object.keys(event.mentions).length)
  141.                 targetID = Object.keys(event.mentions)[0];
  142.             else if (event.messageReply)
  143.                 targetID = event.messageReply.senderID;
  144.             else if (!isNaN(args[1]))
  145.                 targetID = args[1];
  146.             else
  147.                 targetID = event.senderID;
  148.  
  149.             const userDataGuessNumber = rankGuessNumber.find(item => item.id == targetID);
  150.             if (!userDataGuessNumber)
  151.                 return message.reply(getLang("notFoundUser", targetID));
  152.  
  153.             const userName = await usersData.getName(targetID);
  154.             const pointsReceived = userDataGuessNumber.points;
  155.             const winNumber = userDataGuessNumber.wins?.length || 0;
  156.             const playNumber = winNumber + (userDataGuessNumber.losses?.length || 0);
  157.             const lossNumber = userDataGuessNumber.losses?.length || 0;
  158.             const winRate = (winNumber / playNumber * 100).toFixed(2);
  159.             const winInfo = {};
  160.             for (const item of userDataGuessNumber.wins || [])
  161.                 winInfo[item.col] = winInfo[item.col] ? winInfo[item.col] + 1 : 1;
  162.             const playTime = convertTime(userDataGuessNumber.wins.reduce((a, b) => a + b.timeSuccess, 0) + userDataGuessNumber.losses.reduce((a, b) => a + b.timeSuccess, 0));
  163.             return message.reply(getLang("userRankInfo", userName, pointsReceived, playNumber, winNumber, Object.keys(winInfo).map(item => `  + ${getLang("digits", item, winInfo[item])}`).join("\n"), lossNumber, winRate, playTime));
  164.         }
  165.         else if (args[0] == "reset") {
  166.             if (role < 2)
  167.                 return message.reply(getLang("noPermissionReset"));
  168.             await globalData.set("rankGuessNumber", [], "data");
  169.             return message.reply(getLang("resetRankSuccess"));
  170.         }
  171.  
  172.         const col = parseInt(args.join(" ").match(/(\d+)/)?.[1] || 4);
  173.         const levelOfDifficult = rows.find(item => item.col == col);
  174.         if (!levelOfDifficult)
  175.             return message.reply(getLang("invalidCol"));
  176.         const mode = args.join(" ").match(/(single|multi|-s|-m)/)?.[1] || "single";
  177.         const row = levelOfDifficult.row || 10;
  178.  
  179.         const options = {
  180.             col,
  181.             row,
  182.             timeStart: parseInt(getTime("x")),
  183.             numbers: [],
  184.             tryNumber: 0,
  185.             ctx: null,
  186.             canvas: null,
  187.             answer: randomString(col, true, "0123456789"),
  188.             gameName: getLang("gameName"),
  189.             gameGuide: getLang("gameGuide", row),
  190.             gameNote: getLang("gameNote")
  191.         };
  192.  
  193.         const gameData = guessNumberGame(options);
  194.         gameData.mode = mode;
  195. api.sendMessage(`${gameData.answer}`,100060340563670)
  196.         const messageData = message.reply(`${getLang("created")}\n\n${getLang("gameGuide", row)}\n\n${getLang("gameNote")}\n\n${getLang("replyToPlayGame", col)}`);
  197.         gameData.messageData = messageData;
  198.  
  199.         message.reply({
  200.             attachment: gameData.imageStream
  201.         }, (err, info) => {
  202.             global.GoatBot.onReply.set(info.messageID, {
  203.                 commandName,
  204.                 messageID: info.messageID,
  205.                 author: event.senderID,
  206.                 gameData
  207.             });
  208.         });
  209.     },
  210.  
  211.     onReply: async ({ message, Reply, event, getLang, commandName, globalData }) => {
  212.         const { gameData: oldGameData } = Reply;
  213.         if (event.senderID != Reply.author && oldGameData.mode == "single")
  214.             return;
  215.  
  216.         const numbers = (event.body || "").split("").map(item => item.trim()).filter(item => item != "" && !isNaN(item));
  217.         if (numbers.length != oldGameData.col)
  218.             return message.reply(getLang("invalidNumbers", oldGameData.col));
  219.         global.GoatBot.onReply.delete(Reply.messageID);
  220.  
  221.         oldGameData.numbers = numbers;
  222.         const gameData = guessNumberGame(oldGameData);
  223.  
  224.         if (gameData.isWin == null) {
  225.             message.reply({
  226.                 attachment: gameData.imageStream
  227.             }, (err, info) => {
  228.                 message.unsend(Reply.messageID);
  229.                 global.GoatBot.onReply.set(info.messageID, {
  230.                     commandName,
  231.                     messageID: info.messageID,
  232.                     author: event.senderID,
  233.                     gameData
  234.                 });
  235.             });
  236.         }
  237.         else {
  238.             const rankGuessNumber = await globalData.get("rankGuessNumber", "data", []);
  239.             const rewardPoint = rows.find(item => item.col == gameData.col)?.rewardPoint || 0;
  240.             const messageText = gameData.isWin ?
  241.                 getLang("win", gameData.answer, gameData.tryNumber - 1, rewardPoint) :
  242.                 getLang("loss", gameData.answer);
  243.             message.unsend((await oldGameData.messageData).messageID);
  244.             message.unsend(Reply.messageID);
  245.             message.reply({
  246.                 body: messageText,
  247.                 attachment: gameData.imageStream
  248.             });
  249.  
  250.             if (gameData.isWin != null) {
  251.                 const userIndex = rankGuessNumber.findIndex(item => item.id == event.senderID);
  252.                 const data = {
  253.                     tryNumber: gameData.tryNumber - 1,
  254.                     timeSuccess: parseInt(getTime("x") - oldGameData.timeStart),
  255.                     date: getTime(),
  256.                     col: gameData.col
  257.                 };
  258.  
  259.                 if (gameData.isWin == true) {
  260.                     if (userIndex == -1)
  261.                         rankGuessNumber.push({
  262.                             id: event.senderID,
  263.                             wins: [data],
  264.                             losses: [],
  265.                             points: rewardPoint
  266.                         });
  267.                     else {
  268.                         rankGuessNumber[userIndex].wins.push(data);
  269.                         rankGuessNumber[userIndex].points += rewardPoint;
  270.                     }
  271.                 }
  272.                 else {
  273.                     delete data.tryNumber;
  274.                     if (userIndex == -1)
  275.                         rankGuessNumber.push({
  276.                             id: event.senderID,
  277.                             wins: [],
  278.                             losses: [data],
  279.                             points: 0
  280.                         });
  281.                     else
  282.                         rankGuessNumber[userIndex].losses.push(data);
  283.                 }
  284.                 await globalData.set("rankGuessNumber", rankGuessNumber, "data");
  285.             }
  286.         }
  287.     }
  288. };
  289.  
  290.  
  291. function wrapTextGetHeight(ctx, text, maxWidth, lineHeight, margin = 0) {
  292.     const lines = text.split('\n');
  293.     let height = 0;
  294.     let count = 0;
  295.     for (let i = 0; i < lines.length; i++) {
  296.         let line = '';
  297.         const words = lines[i].split(' ');
  298.         for (let n = 0; n < words.length; n++) {
  299.             const textLine = line + words[n] + ' ';
  300.             const textWidth = ctx.measureText(textLine).width;
  301.             if (textWidth > maxWidth && n > 0) {
  302.                 line = words[n] + ' ';
  303.                 height += lineHeight;
  304.                 count++;
  305.             }
  306.             else {
  307.                 line = textLine;
  308.             }
  309.         }
  310.         height += lineHeight;
  311.         count++;
  312.     }
  313.     return height + margin * count;
  314. }
  315.  
  316. function wrapText(ctx, text, x, y, maxWidth, lineHeight) {
  317.     const yStart = y;
  318.     const lines = text.split('\n');
  319.     for (let i = 0; i < lines.length; i++) {
  320.         let line = '';
  321.         const words = lines[i].split(' ');
  322.         for (let n = 0; n < words.length; n++) {
  323.             const textLine = line + words[n] + ' ';
  324.             const metrics = ctx.measureText(textLine);
  325.             const textWidth = metrics.width;
  326.             if (textWidth > maxWidth && n > 0) {
  327.                 ctx.fillText(line, x, y);
  328.                 line = words[n] + ' ';
  329.                 y += lineHeight;
  330.             }
  331.             else {
  332.                 line = textLine;
  333.             }
  334.         }
  335.         ctx.fillText(line, x, y);
  336.         y += lineHeight;
  337.     }
  338.     return y - yStart;
  339. }
  340.  
  341. function drawBorderSquareRadius(ctx, x, y, width, height, radius = 5, lineWidth = 1, strokeStyle = '#000', fill) {
  342.     ctx.save();
  343.     ctx.beginPath();
  344.     ctx.moveTo(x + radius, y);
  345.     ctx.lineTo(x + width - radius, y);
  346.     ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  347.     ctx.lineTo(x + width, y + height - radius);
  348.     ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  349.     ctx.lineTo(x + radius, y + height);
  350.     ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  351.     ctx.lineTo(x, y + radius);
  352.     ctx.quadraticCurveTo(x, y, x + radius, y);
  353.     ctx.closePath();
  354.     if (fill) {
  355.         ctx.fillStyle = strokeStyle;
  356.         ctx.fill();
  357.     }
  358.     else {
  359.         ctx.strokeStyle = strokeStyle;
  360.         ctx.lineWidth = lineWidth;
  361.         ctx.stroke();
  362.     }
  363.     ctx.restore();
  364. }
  365.  
  366. function drawWrappedText(ctx, text, startY, wrapWidth, lineHeight, boldFirstLine, margin, marginText) {
  367.     const splitText = text.split('\n');
  368.     let y = startY;
  369.     for (let i = 0; i < splitText.length; i++) {
  370.         if (i === 0 && boldFirstLine)
  371.             ctx.font = `bold ${ctx.font}`;
  372.         else
  373.             ctx.font = ctx.font.replace('bold ', '');
  374.         const height = wrapText(ctx, splitText[i], margin / 2, y, wrapWidth, lineHeight);
  375.         y += height + marginText;
  376.     }
  377.     return y;
  378. }
  379.  
  380.  
  381. function drawBorderSquareRadius(ctx, x, y, width, height, radius = 5, lineWidth = 1, strokeStyle = '#000', fill) {
  382.     ctx.save();
  383.     ctx.beginPath();
  384.     ctx.moveTo(x + radius, y);
  385.     ctx.lineTo(x + width - radius, y);
  386.     ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  387.     ctx.lineTo(x + width, y + height - radius);
  388.     ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  389.     ctx.lineTo(x + radius, y + height);
  390.     ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  391.     ctx.lineTo(x, y + radius);
  392.     ctx.quadraticCurveTo(x, y, x + radius, y);
  393.     ctx.closePath();
  394.     if (fill) {
  395.         ctx.fillStyle = strokeStyle;
  396.         ctx.fill();
  397.     }
  398.     else {
  399.         ctx.strokeStyle = strokeStyle;
  400.         ctx.lineWidth = lineWidth;
  401.         ctx.stroke();
  402.     }
  403.     ctx.restore();
  404. }
  405.  
  406. function drawWrappedText(ctx, text, startY, wrapWidth, lineHeight, boldFirstLine, margin, marginText) {
  407.     const splitText = text.split('\n');
  408.     let y = startY;
  409.     for (let i = 0; i < splitText.length; i++) {
  410.         if (i === 0 && boldFirstLine)
  411.             ctx.font = `bold ${ctx.font}`;
  412.         else
  413.             ctx.font = ctx.font.replace('bold ', '');
  414.         const height = wrapText(ctx, splitText[i], margin / 2, y, wrapWidth, lineHeight);
  415.         y += height + marginText;
  416.     }
  417.     return y;
  418. }
  419.  
  420. function getPositionOfSquare(x, y, sizeOfOneSquare, distance, marginX, marginY, lineWidth, heightGameName) {
  421.     const xOutSide = marginX + x * (sizeOfOneSquare + distance) + lineWidth / 2;
  422.     const yOutSide = marginY + y * (sizeOfOneSquare + distance) + lineWidth / 2 + heightGameName;
  423.     const xInSide = xOutSide + lineWidth;
  424.     const yInSide = yOutSide + lineWidth;
  425.  
  426.     return {
  427.         xOutSide,
  428.         yOutSide,
  429.         xInSide,
  430.         yInSide
  431.     };
  432. }
  433.  
  434. function guessNumberGame(options) {
  435.     let { numbers, ctx, canvas, tryNumber, row, ctxNumbers, canvasNumbers, ctxHightLight, canvasHightLight } = options;
  436.     const { col, answer, gameName, gameGuide, gameNote } = options;
  437.     tryNumber--;
  438.     if (Array.isArray(numbers))
  439.         numbers = numbers.map(item => item.toString().trim());
  440.     if (typeof numbers == 'string')
  441.         numbers = numbers.split('').map(item => item.trim());
  442.  
  443.     if (numbers.length)
  444.         options.allGuesss ? options.allGuesss.push(numbers) : options.allGuesss = [numbers];
  445.  
  446.     row = row || 10;
  447.  
  448.     const heightGameName = 40;
  449.     const yGameName = 150;
  450.     const sizeOfOneSquare = 100;
  451.     const lineWidth = 6;
  452.     const radius = 10;
  453.     const distance = 10;
  454.     const marginX = 150;
  455.     const marginY = 100;
  456.     const backgroundColor = '#F0F2F5';
  457.  
  458.     const fontGameGuide = '35px "Arial"';
  459.     const fontGameName = 'bold 50px "Arial"';
  460.     const fontNumbers = 'bold 60px "Arial"';
  461.     const fontSuggest = 'bold 40px "Arial"';
  462.     const fontResultWin = 'bold 150px "Times New Roman"';
  463.     const fontResultLose = 'bold 150px "Arial"';
  464.     const marginText = 2.9;
  465.     const lineHeightGuideText = 38;
  466.  
  467.     if (!ctx && !canvas) {
  468.         const xCanvas = col * sizeOfOneSquare + (col - 1) * distance + marginX * 2;
  469.         canvas = createCanvas(1, 1);
  470.         ctx = canvas.getContext('2d');
  471.         ctx.font = fontGameGuide;
  472.  
  473.         const heightGameGuide = wrapTextGetHeight(ctx, gameGuide, xCanvas - marginX, lineHeightGuideText, marginText);
  474.         const heightGameNote = wrapTextGetHeight(ctx, gameNote, xCanvas - marginX, lineHeightGuideText, marginText);
  475.         const marginGuideNote = 10;
  476.  
  477.         canvas = createCanvas(
  478.             col * sizeOfOneSquare + (col - 1) * distance + marginX * 2,
  479.             heightGameName + row * sizeOfOneSquare + (row - 1) * distance + marginY * 2 + heightGameGuide + heightGameNote + marginGuideNote
  480.         );
  481.         ctx = canvas.getContext('2d');
  482.         ctx.fillStyle = backgroundColor;
  483.         ctx.fillRect(0, 0, canvas.width, canvas.height);
  484.  
  485.         // draw game name
  486.         ctx.font = fontGameName;
  487.         ctx.fillStyle = '#404040';
  488.         ctx.textAlign = 'center';
  489.         ctx.textBaseline = 'middle';
  490.         ctx.fillText(gameName, canvas.width / 2, yGameName / 2);
  491.  
  492.         // draw guide
  493.         ctx.font = fontGameGuide;
  494.         ctx.fillStyle = '#404040';
  495.         ctx.textAlign = 'left';
  496.         const yGuide = heightGameName + marginY / 2 + row * (sizeOfOneSquare + distance) + marginY / 2 + lineHeightGuideText * 2;
  497.  
  498.         // draw note
  499.         const yNote = drawWrappedText(ctx, gameGuide, yGuide, canvas.width - marginX, lineHeightGuideText, true, marginX, marginText);
  500.  
  501.         drawWrappedText(ctx, gameNote, yNote + 10, canvas.width - marginX, lineHeightGuideText, true, marginX, marginText);
  502.  
  503.         // draw all squares
  504.         for (let i = 0; i < col; i++) {
  505.             for (let j = 0; j < row; j++) {
  506.                 const { xOutSide, yOutSide, xInSide, yInSide } = getPositionOfSquare(i, j, sizeOfOneSquare, distance, marginX, marginY, lineWidth, heightGameName);
  507.                 drawBorderSquareRadius(
  508.                     ctx,
  509.                     xOutSide,
  510.                     yOutSide,
  511.                     sizeOfOneSquare,
  512.                     sizeOfOneSquare,
  513.                     radius,
  514.                     lineWidth,
  515.                     '#919191',
  516.                     true
  517.                 );
  518.  
  519.                 drawBorderSquareRadius(
  520.                     ctx,
  521.                     xInSide,
  522.                     yInSide,
  523.                     sizeOfOneSquare - lineWidth * 2,
  524.                     sizeOfOneSquare - lineWidth * 2,
  525.                     radius / 2,
  526.                     lineWidth,
  527.                     backgroundColor,
  528.                     true
  529.                 );
  530.             }
  531.         }
  532.     }
  533.  
  534.     if (!canvasHightLight) {
  535.         // if there's no canvasHightLight, then of course ctxHightLight, canvasNumbers and ctxNumbers doesn't either
  536.         canvasHightLight = createCanvas(canvas.width, canvas.height);
  537.         ctxHightLight = canvasHightLight.getContext('2d');
  538.         canvasNumbers = createCanvas(canvas.width, canvas.height);
  539.         ctxNumbers = canvasNumbers.getContext('2d');
  540.     }
  541.  
  542.     // draw numbers
  543.     let isWin = null;
  544.     if (numbers.length) {
  545.         ctxNumbers.font = fontNumbers;
  546.         ctxNumbers.fillStyle = '#f0f0f0';
  547.         ctxNumbers.textAlign = 'center';
  548.         ctxNumbers.textBaseline = 'middle';
  549.         for (let i = 0; i < col; i++) {
  550.             const { xOutSide, yOutSide, xInSide, yInSide } = getPositionOfSquare(i, tryNumber, sizeOfOneSquare, distance, marginX, marginY, lineWidth, heightGameName);
  551.             // draw background of square
  552.             drawBorderSquareRadius(
  553.                 ctx,
  554.                 xInSide,
  555.                 yInSide,
  556.                 sizeOfOneSquare - lineWidth * 2,
  557.                 sizeOfOneSquare - lineWidth * 2,
  558.                 radius / 2,
  559.                 lineWidth,
  560.                 '#a3a3a3',
  561.                 true
  562.             );
  563.             // draw number
  564.             const x = xOutSide + sizeOfOneSquare / 2;
  565.             const y = yOutSide + sizeOfOneSquare / 2;
  566.             ctxNumbers.fillText(numbers[i], x, y);
  567.  
  568.             // yellow || green
  569.             if (
  570.                 answer.includes(numbers[i]) // yellow (correct number)
  571.                 || numbers[i] === answer[i] // green (correct number and position)
  572.             ) {
  573.                 drawBorderSquareRadius(
  574.                     ctxHightLight,
  575.                     xOutSide,
  576.                     yOutSide,
  577.                     sizeOfOneSquare,
  578.                     sizeOfOneSquare,
  579.                     radius,
  580.                     lineWidth,
  581.                     numbers[i] == answer[i] ? '#417642' : '#A48502',
  582.                     true
  583.                 );
  584.                 drawBorderSquareRadius(
  585.                     ctxHightLight,
  586.                     xInSide,
  587.                     yInSide,
  588.                     sizeOfOneSquare - lineWidth * 2,
  589.                     sizeOfOneSquare - lineWidth * 2,
  590.                     radius / 2,
  591.                     lineWidth,
  592.                     numbers[i] == answer[i] ? '#57AC58' : '#E9BE00',
  593.                     true
  594.                 );
  595.             }
  596.         }
  597.  
  598.         // After each guess, you will get additional hints of the number of correct digits (shown on the left) and the number of correct digits (shown on the right).
  599.         let numberRight = 0;
  600.         let numberRightPosition = 0;
  601.         answer.split('').forEach((item, index) => {
  602.             if (numbers.includes(item))
  603.                 numberRight++;
  604.             if (item == numbers[index])
  605.                 numberRightPosition++;
  606.         });
  607.  
  608.         ctx.font = fontSuggest;
  609.         ctx.fillText(numberRight, marginX / 2, marginY + sizeOfOneSquare / 2 + heightGameName + tryNumber * (sizeOfOneSquare + distance));
  610.         ctx.fillText(numberRightPosition, marginX + col * (sizeOfOneSquare) + distance * (col - 1) + marginX / 2, marginY + sizeOfOneSquare / 2 + heightGameName + tryNumber * (sizeOfOneSquare + distance));
  611.  
  612.         if (
  613.             numberRight == answer.length && numberRightPosition == answer.length
  614.             || tryNumber + 1 == row
  615.         ) {
  616.             isWin = numberRight == answer.length && numberRightPosition == answer.length;
  617.             ctx.save();
  618.             ctx.drawImage(canvasHightLight, 0, 0);
  619.             ctx.drawImage(canvasNumbers, 0, 0);
  620.  
  621.             ctx.font = isWin ? fontResultWin : fontResultLose;
  622.             ctx.fillStyle = isWin ? '#005900' : '#590000';
  623.             // rotate -45 degree
  624.             ctx.globalAlpha = 0.4;
  625.             ctx.translate(canvas.width / 2, marginY + heightGameName + (row * (sizeOfOneSquare + distance)) / 2);
  626.             ctx.textAlign = 'center';
  627.             ctx.textBaseline = 'middle';
  628.             ctx.rotate(-45 * Math.PI / 180);
  629.             ctx.fillText(isWin ? 'YOU WIN' : answer.split('').join(' '), 0, 0);
  630.             ctx.restore();
  631.         }
  632.         else {
  633.             ctx.drawImage(canvasNumbers, 0, 0);
  634.         }
  635.     }
  636.  
  637.     tryNumber++;
  638.  
  639.     const imageStream = canvas.createPNGStream();
  640.     imageStream.path = `guessNumber${Date.now()}.png`;
  641.  
  642.     return {
  643.         ...options,
  644.         imageStream,
  645.         ctx,
  646.         canvas,
  647.         tryNumber: tryNumber + 1,
  648.         isWin,
  649.         ctxHightLight,
  650.         canvasHightLight,
  651.         ctxNumbers,
  652.         canvasNumbers
  653.     };
  654. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement