mirror of
https://github.com/toast-ts/Daggerbot-TS.git
synced 2024-11-16 20:00:59 -05:00
Use Levenshtein algorithm
This commit is contained in:
parent
7a0c245311
commit
3afc39c903
@ -8,11 +8,51 @@ import MessageTool from '../helpers/MessageTool.js';
|
|||||||
import {FSData} from 'src/interfaces';
|
import {FSData} from 'src/interfaces';
|
||||||
import {requestServerData, mpModuleDisabled, refreshTimerSecs, playtimeStat, MPChannels} from '../modules/MPModule.js';
|
import {requestServerData, mpModuleDisabled, refreshTimerSecs, playtimeStat, MPChannels} from '../modules/MPModule.js';
|
||||||
|
|
||||||
|
// I asked Copilot lol, yes I said "wtf is that" when it suggested it to me.
|
||||||
|
// Works wonders, I'm surprised.
|
||||||
|
function levenshtein(a: string, b: string): number {
|
||||||
|
const matrix = Array.from({length: a.length+1}, ()=>Array(b.length+1).fill(0));
|
||||||
|
|
||||||
|
for (let i = 0; i <= a.length; i++) matrix[i][0] = i;
|
||||||
|
for (let j = 0; j <= b.length; j++) matrix[0][j] = j;
|
||||||
|
|
||||||
|
for (let i = 1; i <= a.length; i++) {
|
||||||
|
for (let j = 1; j <= b.length; j++) {
|
||||||
|
const cost = a[i-1] === b[j-1] ? 0 : 1;
|
||||||
|
matrix[i][j] = Math.min(
|
||||||
|
matrix[i-1][j] + 1, // Deletion
|
||||||
|
matrix[i][j-1] + 1, // Insertion
|
||||||
|
matrix[i-1][j-1] + cost // Substitution
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matrix[a.length][b.length];
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeString(s: string): string {
|
||||||
|
return s.toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||||
|
}
|
||||||
|
|
||||||
async function fetchData(client:TClient, interaction:Discord.ChatInputCommandInteraction, serverName:string):Promise<FSData|Discord.InteractionResponse> {
|
async function fetchData(client:TClient, interaction:Discord.ChatInputCommandInteraction, serverName:string):Promise<FSData|Discord.InteractionResponse> {
|
||||||
try {
|
try {
|
||||||
await interaction.deferReply();
|
await interaction.deferReply();
|
||||||
const db = await client.MPServer.findInCache();
|
const db = await client.MPServer.findInCache();
|
||||||
const data = await requestServerData(client, db.find(x=>x.serverName === serverName));
|
const server = db.find(x=>x.serverName === serverName);
|
||||||
|
if (!server) {
|
||||||
|
const normalizedServerName = normalizeString(serverName);
|
||||||
|
const servers = db.filter(x=>x.isActive).map(x=>x.serverName);
|
||||||
|
const closestMatch = servers.reduce((closest, current)=>{
|
||||||
|
const currentSimilarity = levenshtein(normalizeString(current), normalizedServerName);
|
||||||
|
const closestSimilarity = levenshtein(normalizeString(closest), normalizedServerName);
|
||||||
|
return currentSimilarity < closestSimilarity ? current : closest;
|
||||||
|
}, servers[0]);
|
||||||
|
|
||||||
|
await interaction.editReply(`**${serverName}** does not exist in database, closest server is **${closestMatch}**.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await requestServerData(client, server);
|
||||||
return data.dss as FSData;
|
return data.dss as FSData;
|
||||||
} catch {
|
} catch {
|
||||||
Logger.console('error', 'MPDB', 'Function failed - fetchData');
|
Logger.console('error', 'MPDB', 'Function failed - fetchData');
|
||||||
@ -21,7 +61,7 @@ async function fetchData(client:TClient, interaction:Discord.ChatInputCommandInt
|
|||||||
}
|
}
|
||||||
|
|
||||||
const logPrefix = 'MPDB';
|
const logPrefix = 'MPDB';
|
||||||
const PALLET_FILTER = ['PALLETS', 'BIGBAGPALLETS'];
|
const CATEGORY_FILTER = ['PALLETS', 'BIGBAGS', 'BIGBAGPALLETS'];
|
||||||
|
|
||||||
export default class MP {
|
export default class MP {
|
||||||
static async autocomplete(client:TClient, interaction:Discord.AutocompleteInteraction<'cached'>) {
|
static async autocomplete(client:TClient, interaction:Discord.AutocompleteInteraction<'cached'>) {
|
||||||
@ -102,7 +142,7 @@ export default class MP {
|
|||||||
pallets: async()=>{
|
pallets: async()=>{
|
||||||
const DSS = await fetchData(client, interaction, choiceSelector) as FSData;
|
const DSS = await fetchData(client, interaction, choiceSelector) as FSData;
|
||||||
if (!DSS) return console.log('Endpoint failed - pallets');
|
if (!DSS) return console.log('Endpoint failed - pallets');
|
||||||
const filter = DSS?.vehicles.filter(x=>PALLET_FILTER.includes(x.category));
|
const filter = DSS?.vehicles.filter(x=>CATEGORY_FILTER.includes(x.category));
|
||||||
const rules = {
|
const rules = {
|
||||||
one: 'single pallet',
|
one: 'single pallet',
|
||||||
two: 'pallets',
|
two: 'pallets',
|
||||||
@ -114,7 +154,7 @@ export default class MP {
|
|||||||
const getLongestName = Object.entries(this.getPalletCounts(DSS)).map(([name, _])=>name.length).sort((a,b)=>b-a)[0];
|
const getLongestName = Object.entries(this.getPalletCounts(DSS)).map(([name, _])=>name.length).sort((a,b)=>b-a)[0];
|
||||||
await interaction.editReply(MessageTool.concatMessage(
|
await interaction.editReply(MessageTool.concatMessage(
|
||||||
`There are currently **${filter.length}** ${rules} on the server. Here\'s the breakdown:\`\`\`ansi`,
|
`There are currently **${filter.length}** ${rules} on the server. Here\'s the breakdown:\`\`\`ansi`,
|
||||||
Object.entries(this.getPalletCounts(DSS)).map(([name, count])=>`${ansi.blue(name.padEnd(getLongestName+3))}${ansi.yellow(count.toString())}`).join('\n'),
|
Object.entries(this.getPalletCounts(DSS)).map(([name, count])=>`${ansi.bold(ansi.blue(name.padEnd(getLongestName+3)))}${ansi.bold(ansi.yellow(count.toString()))}`).join('\n'),
|
||||||
'```'
|
'```'
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -244,7 +284,7 @@ export default class MP {
|
|||||||
await Promise.all(numbersArr.slice(0, length).map(emote=>message.react(emote)));
|
await Promise.all(numbersArr.slice(0, length).map(emote=>message.react(emote)));
|
||||||
}
|
}
|
||||||
private static getPalletCounts(data:FSData) {
|
private static getPalletCounts(data:FSData) {
|
||||||
const pallets = data.vehicles.filter(x=>PALLET_FILTER.includes(x.category));
|
const pallets = data.vehicles.filter(x=>CATEGORY_FILTER.includes(x.category));
|
||||||
const counts = pallets.reduce((acc, name)=>{
|
const counts = pallets.reduce((acc, name)=>{
|
||||||
acc[name.name] = (acc[name.name] ?? 0) + 1;
|
acc[name.name] = (acc[name.name] ?? 0) + 1;
|
||||||
return acc;
|
return acc;
|
||||||
@ -328,7 +368,7 @@ export default class MP {
|
|||||||
.setName('reason')
|
.setName('reason')
|
||||||
.setDescription('The message to send to the channel after toggling')
|
.setDescription('The message to send to the channel after toggling')
|
||||||
.setRequired(true)))
|
.setRequired(true)))
|
||||||
.addSubcommandGroup(x=>x
|
/* .addSubcommandGroup(x=>x
|
||||||
.setName('poll')
|
.setName('poll')
|
||||||
.setDescription('Create or end a map poll in #mp-announcements channel')
|
.setDescription('Create or end a map poll in #mp-announcements channel')
|
||||||
.addSubcommand(x=>x
|
.addSubcommand(x=>x
|
||||||
@ -347,5 +387,5 @@ export default class MP {
|
|||||||
.setRequired(true)))
|
.setRequired(true)))
|
||||||
.addSubcommand(x=>x
|
.addSubcommand(x=>x
|
||||||
.setName('maps')
|
.setName('maps')
|
||||||
.setDescription('Fetch the list of maps currently in the suggestion pool')))
|
.setDescription('Fetch the list of maps currently in the suggestion pool'))) */
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user