diff --git a/commands/games-sp/akinator.js b/commands/games-sp/akinator.js index beb97691..6f4329fb 100644 --- a/commands/games-sp/akinator.js +++ b/commands/games-sp/akinator.js @@ -1,6 +1,6 @@ const Command = require('../../framework/Command'); const { EmbedBuilder, ActionRowBuilder, ButtonBuilder, PermissionFlagsBits, ButtonStyle } = require('discord.js'); -const { Aki, regions } = require('aki-api'); +const { Akinator, regions } = require('../../structures/Akinator'); module.exports = class AkinatorCommand extends Command { constructor(client) { @@ -32,13 +32,12 @@ module.exports = class AkinatorCommand extends Command { } async run(msg, { region }) { - const aki = new Aki({ region, childMode: !msg.channel.nsfw }); + const aki = new Akinator(region, !msg.channel.nsfw); let ans = null; let win = false; - let timesGuessed = 0; - let guessResetNum = 0; let wentBack = false; - let forceGuess = false; + let gameOver = false; + let timesGuessed = 0; const initialRow = new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId('true').setLabel('Ready!').setStyle(ButtonStyle.Primary), new ButtonBuilder().setCustomId('false').setLabel('Nevermind').setStyle(ButtonStyle.Secondary) @@ -59,9 +58,7 @@ module.exports = class AkinatorCommand extends Command { return gameMsg.edit({ content: 'Guess you didn\'t want to play after all...', components: [] }); } await this.sendLoadingMessage(buttonPress, [initialRow]); - const guessBlacklist = []; - while (timesGuessed < 3) { - if (guessResetNum > 0) guessResetNum--; + while (aki.akiWin === null && !gameOver) { if (ans === null) { await aki.start(); } else if (wentBack) { @@ -73,59 +70,15 @@ module.exports = class AkinatorCommand extends Command { await aki.step(ans); } } - if (!aki.answers || aki.currentStep >= 79) forceGuess = true; - const row = new ActionRowBuilder(); - for (const answer of aki.answers) { - row.addComponents(new ButtonBuilder().setCustomId(answer).setStyle(ButtonStyle.Primary).setLabel(answer)); - } - const sRow = new ActionRowBuilder(); - if (aki.currentStep > 0) { - sRow.addComponents(new ButtonBuilder().setCustomId('back').setStyle(ButtonStyle.Secondary).setLabel('Back')); - } - sRow.addComponents(new ButtonBuilder().setCustomId('end').setStyle(ButtonStyle.Danger).setLabel('End')); - await buttonPress.editReply({ - content: `**${aki.currentStep + 1}.** ${aki.question} (${Math.round(Number.parseInt(aki.progress, 10))}%)`, - components: [row, sRow], - embeds: [] - }); - try { - buttonPress = await gameMsg.awaitMessageComponent({ - filter: res => res.user.id === msg.author.id, - max: 1, - time: 30000 - }); - } catch { - win = 'time'; - break; - } - await this.sendLoadingMessage(buttonPress, [row, sRow]); - const choice = buttonPress.customId; - if (choice === 'end') { - forceGuess = true; - } else if (choice === 'back') { - if (guessResetNum > 0) guessResetNum++; - wentBack = true; - await aki.back(); - continue; - } else { - ans = aki.answers.indexOf(choice); - } - if ((aki.progress >= 90 && !guessResetNum) || forceGuess) { + if (aki.guessed) { + const guess = aki.guessed; timesGuessed++; - guessResetNum += 10; - await aki.win(); - const guess = aki.answers.filter(g => !guessBlacklist.includes(g.id))[0]; - if (!guess) { - win = true; - break; - } - guessBlacklist.push(guess.id); const embed = new EmbedBuilder() .setColor(0xF78B26) - .setTitle(`I'm ${Math.round(guess.proba * 100)}% sure it's...`) + .setTitle(`I'm ${Math.round(aki.progress)}% sure it's...`) .setDescription(`${guess.name}${guess.description ? `\n_${guess.description}_` : ''}`) - .setThumbnail(guess.absolute_picture_path || null) - .setFooter({ text: forceGuess ? 'Final Guess' : `Guess ${timesGuessed}` }); + .setThumbnail(guess.photo || null) + .setFooter({ text: `Guess ${timesGuessed}` }); const guessRow = new ActionRowBuilder().addComponents( new ButtonBuilder().setCustomId('true').setLabel('Yes').setStyle(ButtonStyle.Success), new ButtonBuilder().setCustomId('false').setLabel('No').setStyle(ButtonStyle.Danger) @@ -149,26 +102,61 @@ module.exports = class AkinatorCommand extends Command { if (buttonPress.customId === 'true') { win = false; break; - } else if (timesGuessed >= 3 || forceGuess) { - win = true; + } else if (buttonPress.customId === 'false') { + await aki.guess(false, true); + } + } else { + const row = new ActionRowBuilder(); + for (const answer of aki.answers) { + row.addComponents(new ButtonBuilder().setCustomId(answer).setStyle(ButtonStyle.Primary).setLabel(answer)); + } + const sRow = new ActionRowBuilder(); + if (aki.currentStep > 0) { + sRow.addComponents(new ButtonBuilder().setCustomId('back').setStyle(ButtonStyle.Secondary).setLabel('Back')); + } + sRow.addComponents(new ButtonBuilder().setCustomId('end').setStyle(ButtonStyle.Danger).setLabel('End')); + await buttonPress.editReply({ + content: `**${aki.currentStep}.** ${aki.question} (${Math.round(Number.parseInt(aki.progress, 10))}%)`, + components: [row, sRow], + embeds: [] + }); + try { + buttonPress = await gameMsg.awaitMessageComponent({ + filter: res => res.user.id === msg.author.id, + max: 1, + time: 30000 + }); + } catch { + win = 'time'; break; } + await this.sendLoadingMessage(buttonPress, [row, sRow]); + const choice = buttonPress.customId; + if (choice === 'end') { + break; + } else if (choice === 'back') { + wentBack = true; + await aki.back(); + continue; + } else { + ans = aki.answers.indexOf(choice); + } } } const row = new ActionRowBuilder(); row.addComponents( new ButtonBuilder().setLabel('Akinator Website').setStyle(ButtonStyle.Link).setURL('https://akinator.com/') ); - if (win === 'time') { + if (win === 'time' || aki.akiWin === null) { return buttonPress.editReply({ content: 'I guess your silence means I have won.', components: [row] }); } - if (win) { - return buttonPress.editReply({ content: 'Bravo, you have defeated me.', components: [row] }); + if (aki.akiWin) { + return buttonPress.editReply({ + content: 'Guessed right one more time! I love playing with you!', + components: [row] + }); } - return buttonPress.editReply({ - content: 'Guessed right one more time! I love playing with you!', - components: [row] - }); + return buttonPress.editReply({ content: 'Bravo, you have defeated me.', components: [row] }); } sendLoadingMessage(buttonPress, rows) { diff --git a/package.json b/package.json index c6e2262e..dac9715a 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,6 @@ "@tensorflow-models/face-detection": "^1.0.2", "@tensorflow/tfjs-node": "^4.17.0", "@twemoji/parser": "^15.1.1", - "aki-api": "^6.0.9", "bombsweeper.js": "^1.0.1", "canvas": "^2.11.2", "cheerio": "1.0.0-rc.12", diff --git a/structures/Akinator.js b/structures/Akinator.js new file mode 100644 index 00000000..b1476e5c --- /dev/null +++ b/structures/Akinator.js @@ -0,0 +1,105 @@ +const request = require('node-superfetch'); +const regions = ['en']; +const answers = ['Yes', 'No', 'Don\'t know', 'Probably', 'Probably not']; + +class Akinator { + constructor(region, childMode = false) { + if (!regions.includes(region.toLowerCase())) throw new TypeError('Invalid region.'); + this.region = region.toLowerCase(); + this.childMode = Boolean(childMode); + + this.currentStep = 0; + this.progress = '0.00000'; + this.answers = answers; + this.question = null; + this.session = null; + this.signature = null; + this.guessed = null; + this.akiWin = null; + } + + async start() { + const { text } = await request + .post(`https://${this.region}.akinator.com/game`) + .send({ + sid: '1', + cm: this.childMode + }); + this.question = text.match(/
(.+)<\/p>/)[1]; + this.session = text.match(/session: '(.+)'/)[1]; + this.signature = text.match(/signature: '(.+)'/)[1]; + return this; + } + + async step(answer) { + const { body } = await request + .post(`https://${this.region}.akinator.com/answer`) + .send({ + step: this.currentStep.toString(), + progression: this.progress, + sid: '1', + cm: this.childMode, + answer, + step_last_proposition: '', + session: this.session, + signature: this.signature + }); + if (body.id_proposition) { + this.guessed = { + id: body.id_proposition, + name: body.name_proposition, + description: body.description_proposition, + photo: body.photo + }; + return this; + } + this.step++; + this.progress = body.progression; + this.question = body.question; + return this; + } + + async back() { + const { body } = await request + .post(`https://${this.region}.akinator.com/cancel_answer`) + .send({ + step: this.currentStep.toString(), + progression: this.progress, + sid: '1', + cm: this.childMode, + session: this.session, + signature: this.signature + }); + this.step--; + this.progress = body.progression; + this.question = body.question; + return this; + } + + async guess(correct, keepGoing) { + if (correct) { + this.akiWin = true; + return this; + } + if (!correct && keepGoing) { + const { body } = await request + .post(`https://${this.region}.akinator.com/exclude`) + .send({ + step: this.currentStep.toString(), + sid: '1', + cm: this.childMode, + progression: this.progress, + session: this.session, + signature: this.signature + }); + this.guessed = null; + this.progress = body.progression; + this.question = body.question; + return this; + } + this.akiWin = false; + return this; + } +} + +module.exports = { Akinator, regions };