451 lines
15 KiB
Python
451 lines
15 KiB
Python
import os
|
||
import datetime
|
||
import time
|
||
|
||
import db
|
||
|
||
import sqlite3
|
||
|
||
import discord
|
||
from discord.ext import commands
|
||
|
||
import gamelogic as gamlog
|
||
|
||
import re
|
||
|
||
from collections import Counter
|
||
|
||
from dotenv import load_dotenv
|
||
|
||
WORDLE_CHANNEL = 1317916234863480832
|
||
|
||
MISC_GEOGRAPHY = 1317916442342981722
|
||
|
||
GLOBLE_CHANNEL = 1320505660701413511
|
||
|
||
WHEN_WHERE_CHANNEL = 1320505906592612394
|
||
|
||
MISC_CHANNEL = 1317916469660618752
|
||
|
||
GENSHINDLE_CHANNEL = 1320505821112832010
|
||
|
||
CHANNELS = [
|
||
WORDLE_CHANNEL,
|
||
MISC_GEOGRAPHY,
|
||
GLOBLE_CHANNEL,
|
||
WHEN_WHERE_CHANNEL,
|
||
MISC_CHANNEL,
|
||
GENSHINDLE_CHANNEL
|
||
]
|
||
|
||
possible_games = [
|
||
"Wordle",
|
||
"Connections",
|
||
"Satle",
|
||
"Globle",
|
||
"Airport Guessr",
|
||
"WhereTaken",
|
||
"WhenTaken",
|
||
"Flagle",
|
||
"Genshindle",
|
||
"Planespottle",
|
||
"Travle",
|
||
"Costcodle"
|
||
]
|
||
|
||
chat_limit = 1000
|
||
|
||
load_dotenv()
|
||
TOKEN = os.getenv('DISCORD_TOKEN')
|
||
|
||
intents = discord.Intents.default()
|
||
intents.message_content = True
|
||
|
||
bot = commands.Bot(intents=intents)
|
||
|
||
db.create_table();
|
||
|
||
@bot.slash_command(
|
||
name="stats",
|
||
description="Prints out your stats in a daily game, examples include wordle",
|
||
guild_ids=[261345598987436033]
|
||
)
|
||
async def stats(
|
||
interaction: discord.Interaction,
|
||
game : discord.Option(
|
||
str,
|
||
choices=possible_games),
|
||
user: discord.User = None
|
||
):
|
||
await interaction.response.defer()
|
||
|
||
if user is None:
|
||
user = interaction.user
|
||
|
||
conn = sqlite3.connect("stats.db")
|
||
cursor = conn.cursor()
|
||
|
||
if not game in possible_games:
|
||
|
||
print("SQL Injection???")
|
||
await interaction.followup.send(
|
||
"Sorry, something fucky wucky happened",
|
||
ephemeral=True
|
||
)
|
||
return
|
||
|
||
sql = 'SELECT * FROM ' + game.upper().replace(" ", "_") + ' WHERE NAME = ?'
|
||
cursor.execute(sql, (user.id,))
|
||
data = cursor.fetchone()
|
||
conn.close()
|
||
|
||
if not data:
|
||
await interaction.followup.send(
|
||
"No %s results found." % (game),
|
||
ephemeral=True
|
||
)
|
||
return
|
||
|
||
match game.lower():
|
||
case "wordle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Wordle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "connections":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
perfects = data[3]
|
||
win_rate = data[4]
|
||
perfect_rate = data[5]
|
||
total_guesses = data[6]
|
||
average_guesses = data[7]
|
||
|
||
await interaction.followup.send(
|
||
f"Connections stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n"
|
||
f"Perfect Games: {perfects}\n",
|
||
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "satle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Satle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "globle":
|
||
total_games = data[1]
|
||
total_guesses = data[2]
|
||
average_guesses = data[3]
|
||
|
||
await interaction.followup.send(
|
||
f"Globle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Game: {average_guesses:.2f}\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "airport guessr":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Airport Guessr stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "whentaken":
|
||
total_games = data[1]
|
||
total_distance = data[2]
|
||
average_distance = data[3]
|
||
total_points = data[4]
|
||
average_points = data[5]
|
||
total_years = data[6]
|
||
average_years = data[7]
|
||
|
||
await interaction.followup.send(
|
||
f"When Taken stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Distance: {average_distance:.2f} km\n"
|
||
f"Average Time Distance: {average_years:.2f} years\n"
|
||
f"Average Score: {average_points:.2f}\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "wheretaken":
|
||
total_games = data[1]
|
||
total_distance = data[2]
|
||
average_distance = data[3]
|
||
total_points = data[4]
|
||
average_points = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Where Taken stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Distance: {average_distance:.2f} km\n"
|
||
f"Average Score: {average_points:.2f}\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "flagle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Flagle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "genshindle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Genshindle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "planespottle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Planespottle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "travle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
perfects = data[3]
|
||
win_rate = data[4]
|
||
perfect_rate = data[5]
|
||
total_guesses = data[6]
|
||
average_guesses = data[7]
|
||
|
||
await interaction.followup.send(
|
||
f"Travle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Extra Guesses per Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n"
|
||
f"Perfect Games: {perfects}\n",
|
||
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case "costcodle":
|
||
total_games = data[1]
|
||
wins = data[2]
|
||
win_rate = data[3]
|
||
total_guesses = data[4]
|
||
average_guesses = data[5]
|
||
|
||
await interaction.followup.send(
|
||
f"Costcodle stats for {user.mention}:\n"
|
||
f"Total Games Played: {total_games}\n"
|
||
f"Average Guesses per Winning Game: {average_guesses:.2f}\n"
|
||
f"Win Rate: {win_rate:.2f}%\n",
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
case _:
|
||
await interaction.followup.send(
|
||
"Not a game.",
|
||
ephemeral=True
|
||
)
|
||
|
||
table_dict = {
|
||
"games" : "GAMES",
|
||
"total wins" : "WINS",
|
||
"win rate" : "WIN_RATE",
|
||
"average guesses" : "GUESS_AVG",
|
||
"perfects" : "PERFECTS",
|
||
"perfect rate" : "PERFECT_RATE",
|
||
"distance" : "DISTANCE_AVG",
|
||
"score" : "POINTS_AVG",
|
||
"time distance" : "YEARS_AVG"
|
||
}
|
||
|
||
async def get_table_options(ctx : discord.AutocompleteContext):
|
||
game = ctx.options['game']
|
||
match game.lower():
|
||
case "wordle":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "connections":
|
||
return ["games","total wins","win rate","average guesses","perfects","perfect_rate"]
|
||
case "satle":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "globle":
|
||
return ["games","average guesses"]
|
||
case "airport guessr":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "whentaken":
|
||
return ["games", "distance", "score", "time distance"]
|
||
case "wheretaken":
|
||
return ["games", "distance", "score"]
|
||
case "flagle":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "genshindle":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "planespottle":
|
||
return ["games","total wins","win rate","average guesses"]
|
||
case "travle":
|
||
return ["games","total wins","win rate","average guesses","perfects","perfect_rate"]
|
||
case _:
|
||
return ["HOW DID YOU GET HERE? SCREW YOU FOR MESSING WITH MY PROGRAM"]
|
||
|
||
|
||
@bot.slash_command(
|
||
name="top",
|
||
description="Prints out the top players of the given game.",
|
||
guild_ids=[261345598987436033],
|
||
)
|
||
async def top(
|
||
interaction: discord.Interaction,
|
||
game : discord.Option(
|
||
str,
|
||
choices=possible_games),
|
||
sort_by : discord.Option(str, autocomplete=discord.utils.basic_autocomplete(get_table_options)),
|
||
count : discord.Option(int) = 3
|
||
):
|
||
await interaction.response.defer()
|
||
|
||
table_column = table_dict[sort_by]
|
||
|
||
conn = sqlite3.connect("stats.db")
|
||
cursor = conn.cursor()
|
||
|
||
if not game in possible_games:
|
||
|
||
print("SQL Injection???")
|
||
await interaction.followup.send(
|
||
"Sorry, something fucky wucky happened",
|
||
ephemeral=True
|
||
)
|
||
return
|
||
|
||
order = "DESC"
|
||
if table_column in ["GUESS_AVG", "DISTANCE_AVG", "YEARS_AVG"]:
|
||
order = "ASC"
|
||
|
||
sql = 'SELECT NAME,' + table_column + ' FROM ' + game.upper().replace(" ", "_") + ' ORDER BY ' + table_column + '=0, ' + table_column + " " + order
|
||
cursor.execute(sql)
|
||
data = cursor.fetchmany(count)
|
||
conn.close()
|
||
|
||
if not data:
|
||
await interaction.followup.send(
|
||
"No %s results found." % (game),
|
||
ephemeral=True
|
||
)
|
||
return
|
||
|
||
return_message = "Top " + str(len(data)) + " Players for " + game + " by " + sort_by + "\n"
|
||
|
||
for i, stat in enumerate(data):
|
||
modifier = ''
|
||
match table_column:
|
||
case "WIN_RATE" | "PERFECT_RATE":
|
||
modifier = "%"
|
||
case "DISTANCE_AVG":
|
||
modifier = " km"
|
||
case "YEARS_AVG":
|
||
modifier = " years"
|
||
case "GAMES":
|
||
modifier = " games"
|
||
case "GUESS_AVG":
|
||
modifier = " guesses"
|
||
|
||
line = f"#{i+1} <@{stat[0]}> Stats: {stat[1]:.2f}{modifier}\n"
|
||
|
||
return_message += line
|
||
|
||
|
||
await interaction.followup.send(
|
||
return_message,
|
||
ephemeral=False # Send message only to the user who called the command
|
||
)
|
||
|
||
def process_message(message : discord.message, reverse : bool):
|
||
channel = bot.get_channel(WORDLE_CHANNEL)
|
||
|
||
PATTERNS = {
|
||
gamlog.wordle : r"Wordle (\d{1,3}(?:,\d{3})*) (X|\d+)/(\d+)",
|
||
gamlog.connections : r"Connections\nPuzzle #",
|
||
gamlog.satle : r"🛰Satle #[0-9]+ (\d)/6",
|
||
gamlog.bad_globle: r"🌎 [a-zA-Z]{3} [0-9]+, [0-9]{4} 🌍",
|
||
gamlog.globle : r"I guessed today’s Globle in ([0-9]+) tries:",
|
||
gamlog.airport_guessr : r"I (got the|did not guess the) airport (in \d (guess|guesses) )?today:",
|
||
gamlog.wheretaken : r"#WhereTaken #[0-9]+ \([0-9]{2}\.[0-9]{2}\.[0-9]{4}\)",
|
||
gamlog.whentaken : r"#WhenTaken #[0-9]+ \([0-9]{2}\.[0-9]{2}\.[0-9]{4}\)",
|
||
gamlog.flagle : r"#Flagle #[0-9]+ \(.*\) ./6",
|
||
gamlog.genshindle : r"I (found|couldn't find) today's #Genshindle",
|
||
gamlog.planespottle : r"Planespottle #[0-9]+ (failed to guess|in \d/5 guesses)!",
|
||
gamlog.travle : r"#travle.* #[0-9]+ (\+([0-9]+)|\(([0-9]+) away\))",
|
||
gamlog.costcodle : r"Costcodle #[0-9]+ ./6",
|
||
}
|
||
|
||
|
||
for game, pattern in PATTERNS.items():
|
||
match = re.search(pattern, message.content.strip())
|
||
if match:
|
||
game(message, reverse)
|
||
continue
|
||
|
||
|
||
@bot.event
|
||
async def on_ready():
|
||
|
||
for channel in CHANNELS:
|
||
channel = bot.get_channel(channel)
|
||
async for message in channel.history(limit=chat_limit,oldest_first=True):
|
||
process_message(message, False)
|
||
|
||
print('Ready!')
|
||
|
||
@bot.event
|
||
async def on_message(message : discord.message):
|
||
process_message(message, False)
|
||
|
||
@bot.event
|
||
async def on_message_delete(message : discord.message):
|
||
process_message(message, True)
|
||
|
||
bot.run(TOKEN)
|
||
|