Skip to content
This repository has been archived by the owner on Oct 12, 2024. It is now read-only.

Commit

Permalink
Update the bot, now it have more statistics (#3)
Browse files Browse the repository at this point in the history
* Initial push of the bot v2.0.0
  • Loading branch information
ekomlenovic authored Mar 29, 2023
1 parent 01e2ce9 commit ca442c7
Show file tree
Hide file tree
Showing 5 changed files with 353 additions and 279 deletions.
21 changes: 13 additions & 8 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,20 @@
[pip](https://pip.pypa.io/en/stable/) to install [discord.py](https://discordpy.readthedocs.io/en/stable/).

```bash
pip install discord numpy matplotlib
pip install discord numpy matplotlib pandas
```
In main.py put your discord bot token in
```python
bot.run('Your_TOKEN')
```

Or go in [release tab](https://github.com/ekomlenovic/RPG-Random-Bot/releases) and download .exe
And add it to your server : https://discord.com/oauth2/authorize?client_id=900518092944326686&scope=bot&permissions=8
In **config.json** put your discord bot token in
```json
{
"token": "Your_Bot_Token_Or_Ask_Me_For_It",
"prefix": "!",
"min": 1
}
```
You can also modify the min and the prefix of le bot

**Or go in [release tab](https://github.com/ekomlenovic/RPG-Random-Bot/releases) and download .exe**
And add it to your server : **https://discord.com/oauth2/authorize?client_id=900518092944326686&scope=bot&permissions=8**

## Usage

Expand Down
133 changes: 133 additions & 0 deletions bot/commands_aux.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import discord
import os
from PIL import Image
from datetime import datetime
import csv
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt

def loadCSV(ctx, data):
try:
with open(f"{ctx.guild.name}/roll.csv", mode="r", newline="") as file:
reader = csv.reader(file)
for i, row in enumerate(reader):
if i == 0:
continue
data[row[0]] = [float(x) for x in row[1:]]
return data
except FileNotFoundError:
print("File not found, creating the file")
with open(f"{ctx.guild.name}/roll.csv", mode="w", newline=""):
pass

def update_csv(ctx, name, value, data):
size = 0
for _, values in data.items():
if size < len(values):
size = len(values)
if name in data:
data[name].append(value)
else:
data[name] = [value]
with open(f"{ctx.guild.name}/roll.csv", mode="w", newline="") as file:
writer = csv.writer(file)
writer.writerow(["Name"] + [f"Value_{i}" for i in range(0, size+1)])
for name, values in data.items():
writer.writerow([name] + values)
return data



def stat(name, data):
name_data = data.loc[data['Name'] == name].iloc[:, 1:].values
name_values = name_data[~np.isnan(name_data)]
name_sum = name_values.sum()
name_mean = name_values.mean()
name_min = name_values.min()
name_max = name_values.max()
name_median = np.median(name_values)
name_std_dev = name_values.std()
bins = np.arange(0, 110, 10)
name_frequency, _ = np.histogram(name_values, bins=bins)
name_frequency = name_frequency.tolist()
name_variance = name_values.var()

name_stats = {
'Name': name,
'Number of Rolls': len(name_values),
'Sum': name_sum,
'Mean': name_mean,
'Min': name_min,
'Max': name_max,
'Median': name_median,
'Standard Deviation': name_std_dev,
'Frequency': name_frequency,
'Variance': name_variance,
}

return name_stats

def plot_aux(ctx, name, data):
bins = np.arange(0, 110, 10)
plot_data = stat(name, data)
fig, ax = plt.subplots()
plt.bar(bins[:-1]+5, plot_data['Frequency'], width=10, color='aqua', edgecolor='black', alpha=0.3, label=name + ' Frequency')
plt.axvline(plot_data['Mean'], color='r', linestyle='--', label=name + ' Mean')
plt.axvline(plot_data['Median'], color='g', linestyle='-.', label=name + ' Median')
plt.axvline(plot_data['Min'], color='black', linestyle=':', label=name + ' Min')
plt.axvline(plot_data['Max'], color='blue' ,linestyle=':', label=name + ' Max')
plt.legend()
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
ax.set_xticks(bins)
ax.set_title(f'{name}_statistics({plot_data["Number of Rolls"]} rolls)')
#plt.show()
fig.savefig(f"{ctx.guild.name}/users/{name}_plot.png")





def send_to_discord(ctx):
images = []

file_list = os.listdir(f"{ctx.guild.name}/users/")

png_files = [f for f in file_list if f.endswith('.png')]

for file_name in png_files:
file_path = os.path.join(f"{ctx.guild.name}/users/", file_name)
image = Image.open(file_path)
images.append(image)

total_width = sum(image.width for image in images)
max_height = max(image.height for image in images)

result_image = Image.new('RGB', (total_width, max_height))
x_offset = 0
for image in images:
result_image.paste(image, (x_offset, 0))
x_offset += image.width

result_image.save(f"{ctx.guild.name}/statistic.png")

result_file = discord.File(f"{ctx.guild.name}/statistic.png")

return result_file


def stat_player_value(ctx, data):
X = data.iloc[:, 1:].values
labels = data.iloc[:, 0].values
fig , ax= plt.subplots()
for i in range(labels.size):
plt.plot(X[i], label=labels[i])
ax.set_xlabel('Number of Rolls')
ax.set_ylabel('Value')
plt.title('Rolls Comparison')
plt.legend()
#plt.show()
fig.savefig(f"{ctx.guild.name}/compare.png")

return f"{ctx.guild.name}/compare.png"
201 changes: 201 additions & 0 deletions bot/commands_discord.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
import discord

from discord.ext import commands
import random
import numpy as np
import locale
import matplotlib.pyplot as plt
import os
from PIL import Image
from datetime import datetime
import csv
import pandas as pd
from bot.commands_aux import *
import shutil

lang = locale.getdefaultlocale()
if lang[0] == 'fr_FR':
from lang.fr import *

elif lang[0] == 'en_US':
from lang.en import *
elif lang[0] == 'sr_RS':
from lang.sr import *
else:
from lang.template import *


import json
with open('config.json') as f:
config = json.load(f)

TOKEN = config['token']
PREFIX = config['prefix']
MIN = config['min']

class Mybot(commands.Bot):
async def on_ready(self):
activity = discord.Game(name='RP', type=discord.ActivityType.playing)
await bot.change_presence(status=discord.Status.dnd, activity=activity)
print(login + f'{self.user} (ID: {self.user.id})')
print('------')
for i in bot.guilds:
print(connected_on + i.name)
print('------')


intents = discord.Intents.default()
intents.message_content = True
bot = Mybot(command_prefix=PREFIX,intents=intents)

data = {}

@bot.command(
description='This command rolls a random number between 0 and the specified number (default: 100). For example, to roll a number between 0 and 50, you can use the command "!r 50".',
help='This command rolls a random number between 0 and the specified number (default: 100). For example, to roll a number between 0 and 50, you can use the command "!r 50".'
)
async def r(ctx, number: int = 100):
if not os.path.exists(ctx.guild.name):
os.makedirs(ctx.guild.name)
loadCSV(ctx, data)
value = random.randrange(MIN, number+1)
_value = value/number*100
user = ctx.author.display_name

update_csv(ctx, user, _value, data)
x = await ctx.send(f"```{ctx.author.display_name} "+ made + str(value) + space + on + "[" + str(number) + "]```")
await ctx.message.delete()

if value == MIN:
await x.add_reaction('\N{CROSS MARK}')
elif value == number:
await x.add_reaction('\N{WHITE HEAVY CHECK MARK}')


@bot.command(
description='Deletes all images generated by !stat command in the current server',
help='This command deletes all images generated by !stat command in the current server. To use this command, type "!clear_images".'
)
async def clear_image(ctx):
file_list = os.listdir(f"{ctx.guild.name}/users/")
png_files = [f for f in file_list if f.endswith('.png')]
for file_name in png_files:
file_path = os.path.join(f"{ctx.guild.name}/users/", file_name)
os.remove(file_path)
os.remove(f"{ctx.guild.name}/statistic.png")
await ctx.message.delete()
await ctx.send('Clear successful !')


@bot.command(
name='save',
description='Saves the current plot data to a folder',
help='This command saves the current data, you can use the command "!s".'
)
async def save(ctx):
now = datetime.now()
folder_name = now.strftime("%Y-%m-%d %H.%M")

file_path = ctx.guild.name+"/save/" + folder_name

# Create the save folder if it doesn't exist
if not os.path.exists(file_path):
os.makedirs(file_path)

try:
file_list = os.listdir(f"{ctx.guild.name}/users/")
# Calculate the total width and maximum height of the result image
png_files = [f for f in file_list if f.endswith('.png')]
for file_name in png_files:
# Save the png image to a file in the save folder
with open(ctx.guild.name+ "/users/" + file_name, 'rb') as f:
image = f.read()
with open(os.path.join(file_path, file_name), 'wb') as f:
f.write(image)

with open(ctx.guild.name + "/statistic.png", 'rb') as f:
image = f.read()
with open(os.path.join(file_path, "statistic.png"), 'wb') as f:
f.write(image)
with open(ctx.guild.name + "/compare.png", 'rb') as f:
image = f.read()
with open(os.path.join(file_path, "compare.png"), 'wb') as f:
f.write(image)


shutil.copy2(f"{ctx.guild.name}/roll.csv", file_path)
# Send a message to confirm that the save was successful
await ctx.send('Files saved to the save folder!')
except:
await ctx.send(f'There is no data, try running the {PREFIX}plot, {PREFIX}stat commands for saving all data.')


@bot.command(
name='plot',
description='Plots the data of the current server',
help='This command plots the data of the current server, you can use the command "!plot", you can also specify a user to plot his data, for example "!plot @user".'
)
async def plot(ctx, user : discord.User = None):
try:
if not os.path.exists(f"{ctx.guild.name}/users/"):
os.makedirs(f"{ctx.guild.name}/users/")
ctx_data = pd.read_csv(f"{ctx.guild.name}/roll.csv", sep=',')
for names in ctx_data['Name']:
plot_aux(ctx, names, ctx_data)

x = send_to_discord(ctx)
if user is not None:
await ctx.send(file=discord.File(f"{ctx.guild.name}/users/{user.display_name}_plot.png"))
else:
await ctx.send(file = x)
except FileNotFoundError:
await ctx.send(f'There is no data, try running the {PREFIX}r command.')



@bot.command(
name='stat',
description='Compare players rolls',
help='This command Compare players rolls.'
)
async def stat(ctx):
try:
ctx_data = pd.read_csv(f"{ctx.guild.name}/roll.csv", sep=',')
x = stat_player_value(ctx, ctx_data)
await ctx.send(file=discord.File(x))
except FileNotFoundError:
await ctx.send(f'There is no data, try running the {PREFIX}r command.')


@bot.event
async def on_command_error(ctx, error):
command_list = '\n'.join([f'\t{c.name}: {c.description}' for c in bot.commands])

# Check if the error is a CommandNotFound error
if isinstance(error, commands.CommandNotFound):
# If the command is not found, send the help message to the user
await ctx.send(f'```Sorry, I don\'t recognize that command. Here is a list of the commands that I know:\n{command_list}```')
else:
# For other types of errors, print the error to the console
print(error)


@bot.event
async def on_reaction_add(reaction, user):
emoji = reaction.emoji
if user.bot:
return

if emoji == '\N{CROSS MARK}':
await reaction.message.reply(str(user.display_name) + space + laught)
elif emoji == '\N{WHITE HEAVY CHECK MARK}':
await reaction.message.reply(str(user.display_name) + space + congratulate)








bot.run(TOKEN)
5 changes: 5 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"token": "Your_Bot_Token_Or_Ask_Me_For_It",
"prefix": "!",
"min": 1
}
Loading

0 comments on commit ca442c7

Please sign in to comment.