import io import cv2 import datetime import calendar import numpy as np import pandas as pd import gradio as gr import matplotlib.pyplot as plt from PIL import ImageFont, ImageDraw, Image from datetime import date, timedelta from collections import Counter from typing import NamedTuple class Reward(): def __init__(self): self.stellar_jade = {} self.special_pass = {} self.oneiric_shard = 0 def weekday_count(start_date, end_date): week = {} for i in range((end_date - start_date).days): day = calendar.day_name[(start_date + datetime.timedelta(days=i+1)).weekday()] week[day] = week[day] + 1 if day in week else 1 return week def daterange(start_date, end_date): for n in range(int((end_date - start_date).days)): yield start_date + timedelta(n) def estimator(start_patch, end_patch, mode, equilibrium, data_patch, updating, play_memory_of_chaos, EXPRESS_SUPPLY, BP): limited_event, permanent_event, explore, moc_n_pf = updating duration = abs(start_patch - end_patch).days n_weekdays = weekday_count(start_patch, end_patch) n_weeks = Counter(n_weekdays.values()).most_common(1)[0][0] if mode == 1: start_half = start_patch end_half = start_half + datetime.timedelta(days = duration // 2 ) duration = abs(start_half - end_half).days if mode == 2: start_half = start_patch + datetime.timedelta(days = duration // 2 ) end_half = end_patch duration = abs(start_half - end_half).days reward = Reward() reward_SU = {0:75, 1:75, 2:105, 3:135, 4:165, 5:195, 6:225} reward.stellar_jade['daily_quest'] = 60 * duration # reward.stellar_jade['chat'] = 5 * duration if (mode == 0 or mode == 1) : reward.stellar_jade['update'] = 600 reward.stellar_jade['permanent_event'] = np.sum([permanent_event[i]['reward'] for i in permanent_event]) reward.stellar_jade['explore'] = explore special_event = 'gift_odyssey' if mode == 0: reward.stellar_jade['daily_login'] = 80 reward.stellar_jade['SU'] = reward_SU[equilibrium] * n_weekdays['Monday'] reward.stellar_jade['character_tryout'] = 20 * data_patch['n_character_banner'] reward.stellar_jade['character_quest'] = 100 * np.sum([data_patch['n_character_quest'][i] for i in data_patch['n_character_quest']]) reward.special_pass['Ember'] = 5 * Counter([single_date.day for single_date in daterange(start_patch, end_patch)])[1] #edit every patch reward.stellar_jade['event'] = np.sum([limited_event[i]['reward'] for i in limited_event if i != special_event]) reward.special_pass['event'] = limited_event[special_event]['reward'] if play_memory_of_chaos: reward.stellar_jade['moc_n_pf'] = 720 * moc_n_pf['MoC'] reward.stellar_jade['moc_n_pf'] += 720 * moc_n_pf['PF'] if EXPRESS_SUPPLY: reward.stellar_jade['EXPRESS_SUPPLY'] = 90 * duration reward.oneiric_shard = int(300 * np.ceil(duration/30)) if BP: reward.stellar_jade['BP'] = 680 reward.special_pass['BP'] = 4 reward.stellar_jade['redeem_code_next_patch'] = 300 else: reward.stellar_jade['daily_login'] = 40 reward.stellar_jade['SU'] = reward_SU[equilibrium] * (n_weekdays['Monday'] // 2) #companion quest if mode == 1: reward.stellar_jade['character_quest'] = 100 * data_patch['n_character_quest']['first_half'] elif mode == 2: reward.stellar_jade['character_quest'] = 100 * data_patch['n_character_quest']['second_half'] #temporary reward.stellar_jade['character_tryout'] = 20 * (data_patch['n_character_banner'] // 2) reward.special_pass['Ember'] = 5 * Counter([single_date.day for single_date in daterange(start_half, end_half)])[1] #edit every patch reward.stellar_jade['event'] = np.sum([limited_event[i]['reward'] for i in limited_event if (i != special_event) and (limited_event[i]['date'][0] >= start_half and limited_event[i]['date'][0] + datetime.timedelta(days = 7) < end_half)]) reward.special_pass['event'] = limited_event[special_event]['reward'] if (limited_event[special_event]['date'][0] >= start_half and start_half + datetime.timedelta(days = 7) < end_half) else 0 if play_memory_of_chaos: if mode == 1: reward.stellar_jade['moc_n_pf'] = 720 * (moc_n_pf['MoC'] + moc_n_pf['PF'] - 1) else: reward.stellar_jade['moc_n_pf'] = 720 if EXPRESS_SUPPLY: reward.stellar_jade['EXPRESS_SUPPLY'] = 90 * duration reward.oneiric_shard = int(300 * np.ceil(duration/30)) if BP: if mode == 2: reward.stellar_jade['BP'] = 680 reward.special_pass['BP'] = 4 if mode == 2 : reward.stellar_jade['redeem_code_next_patch'] = 300 return reward def export_to_image(data): template = cv2.imread('./template.png') font = ImageFont.truetype("./DMSans-Regular.ttf", 80) color = (0, 78, 53) image_rgb = cv2.cvtColor(template, cv2.COLOR_BGR2RGB) pil_image = Image.fromarray(image_rgb) draw = ImageDraw.Draw(pil_image) pos = [(500, 50), (500, 280), (500, 530)] text = [int(sum(data.stellar_jade.values())), int(sum(data.special_pass.values())), int(data.oneiric_shard)] for d, position in zip(text, pos): draw.text(position, str(d), font=font, fill=color) return pil_image def export_to_graph(data): df = pd.DataFrame(sorted(data.stellar_jade.items(), key = lambda x:x[1], reverse = True), columns = ['source', 'stellar jade']) source_map = {'daily_quest':'Daily Quest', 'explore':'Exploration', 'permanent_event':'Permanent Event', 'event':'Limited Event', 'moc_n_pf': 'MoC & Pure Fiction', 'SU':'Simulate Universe', 'update':'Update', 'redeem_code_next_patch':'Code live next patch', 'character_quest':'Companion Quest', 'daily_login':'Website daily login', 'character_tryout':'Character trial', 'EXPRESS_SUPPLY':'Express supply', 'BP':'Battle pass', 'chat':'Daily Chat'} filtered = df[df['stellar jade'] != 0] source = [source_map[i] for i in filtered['source']] filtered['source'] = source df = filtered df['stellar jade'] = df['stellar jade'].astype('int') total_jade = df['stellar jade'].sum() # Figure Size fig, ax = plt.subplots(figsize =(16, 9)) stellar_jade = df['stellar jade'] # Horizontal Bar Plot ax.barh(source, stellar_jade) # Remove axes splines for s in ['top', 'bottom', 'left', 'right']: ax.spines[s].set_visible(False) # Remove x, y Ticks ax.xaxis.set_ticks_position('none') ax.yaxis.set_ticks_position('none') # Add padding between axes and labels ax.xaxis.set_tick_params(pad = 5) ax.yaxis.set_tick_params(pad = 10) # Add x, y gridlines ax.grid(color ='grey',linestyle ='--', linewidth = 0.5,alpha = 0.4) # Show top values ax.invert_yaxis() # Add annotation to bars for index, i in enumerate(ax.patches): if index < 3 : number_color = 'red' elif index < 6: number_color = 'orange' else: number_color = 'grey' plt.text(i.get_width()+10, i.get_y()+0.5, str(round((i.get_width()), 2)) + ' ({0}%)'.format(round(100 * (i.get_width() / total_jade), 2)), fontsize = 10, color = number_color) title = 'The Stellar Jade Counter' ax.set_title(title, loc ='left', ) # Add Text watermark fig.text(0.9, 0.15, 'CHAYEN', fontsize = 12, color ='grey', ha ='right', va ='bottom', alpha = 0.7) buf = io.BytesIO() fig.savefig(buf) buf.seek(0) img = Image.open(buf) return img