Add the latest bossfight dash webapp
This commit is contained in:
parent
0e684ed82e
commit
4f813eb502
8 changed files with 449 additions and 0 deletions
BIN
bossfight-webapp/assets/current_roll.jpg
Normal file
BIN
bossfight-webapp/assets/current_roll.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 41 KiB |
BIN
bossfight-webapp/assets/dice-fpga.png
Normal file
BIN
bossfight-webapp/assets/dice-fpga.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 238 KiB |
BIN
bossfight-webapp/assets/dice-pc.png
Normal file
BIN
bossfight-webapp/assets/dice-pc.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 209 KiB |
BIN
bossfight-webapp/assets/oogie.gif
Normal file
BIN
bossfight-webapp/assets/oogie.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 763 KiB |
BIN
bossfight-webapp/assets/previous_roll.jpg
Normal file
BIN
bossfight-webapp/assets/previous_roll.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
73
bossfight-webapp/dice_roll_data.csv
Normal file
73
bossfight-webapp/dice_roll_data.csv
Normal file
|
@ -0,0 +1,73 @@
|
|||
id,roll
|
||||
1,6
|
||||
2,3
|
||||
3,1
|
||||
4,5
|
||||
5,5
|
||||
6,2
|
||||
7,4
|
||||
8,4
|
||||
9,4
|
||||
10,6
|
||||
11,4
|
||||
12,2
|
||||
13,2
|
||||
14,2
|
||||
15,4
|
||||
16,6
|
||||
17,5
|
||||
18,6
|
||||
19,2
|
||||
20,3
|
||||
21,6
|
||||
22,5
|
||||
23,1
|
||||
24,4
|
||||
25,3
|
||||
26,3
|
||||
27,3
|
||||
28,3
|
||||
29,5
|
||||
30,1
|
||||
31,5
|
||||
32,6
|
||||
33,1
|
||||
34,4
|
||||
35,3
|
||||
36,1
|
||||
37,2
|
||||
38,2
|
||||
39,2
|
||||
40,1
|
||||
41,2
|
||||
42,6
|
||||
43,1
|
||||
44,3
|
||||
45,4
|
||||
46,1
|
||||
47,4
|
||||
48,2
|
||||
49,4
|
||||
50,2
|
||||
51,2
|
||||
52,3
|
||||
53,5
|
||||
54,2
|
||||
55,1
|
||||
56,2
|
||||
57,3
|
||||
58,2
|
||||
59,1
|
||||
60,5
|
||||
61,2
|
||||
62,4
|
||||
63,5
|
||||
64,4
|
||||
65,3
|
||||
66,3
|
||||
67,2
|
||||
68,5
|
||||
69,3
|
||||
1,2
|
||||
2,5
|
||||
3,3
|
|
1
bossfight-webapp/info.txt
Normal file
1
bossfight-webapp/info.txt
Normal file
|
@ -0,0 +1 @@
|
|||
13019,76.81,1.73
|
375
bossfight-webapp/main.py
Normal file
375
bossfight-webapp/main.py
Normal file
|
@ -0,0 +1,375 @@
|
|||
import dash
|
||||
from dash import dcc, html
|
||||
import dash_bootstrap_components as dbc
|
||||
from dash.dependencies import Input, Output
|
||||
import pandas as pd
|
||||
import plotly.express as px
|
||||
from datetime import datetime, timedelta
|
||||
import itertools
|
||||
from PIL import Image
|
||||
|
||||
# Use the Dash Bootstrap Components theme
|
||||
app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
||||
|
||||
# Load the initial data from the dice_roll_data.csv file into a Pandas DataFrame
|
||||
df = pd.read_csv('dice_roll_data.csv')
|
||||
|
||||
# Calculate initial statistics
|
||||
result_counts = df['roll'].value_counts().sort_index()
|
||||
total_rolls = result_counts.sum()
|
||||
# Assuming df is the DataFrame containing the rolls
|
||||
current_roll = df['roll'].iloc[-1] if not df.empty else 0 # Default to 0 if the DataFrame is empty
|
||||
# Count consecutive occurrences of the current roll value
|
||||
consecutive_count = sum(1 for _ in itertools.takewhile(lambda x: x == current_roll, reversed(df['roll'])))
|
||||
# Initial health value, adjust as needed
|
||||
progress_value = 2000
|
||||
max_progress_value = 2000
|
||||
max_damage = 0
|
||||
|
||||
# Create initial figure with px.bar
|
||||
fig = px.bar(y=result_counts.index, x=result_counts.values, labels={'x': 'Count', 'y': 'Result'}, orientation='h')
|
||||
|
||||
# Update layout for the bar chart to make the axis titles and tick labels larger
|
||||
fig.update_xaxes(tickfont=dict(size=24), title_font=dict(size=28))
|
||||
fig.update_yaxes(tickfont=dict(size=24), title_font=dict(size=28))
|
||||
|
||||
# Add title to the bar chart
|
||||
# fig.update_layout(title_text="Allo", title_font=dict(size=32), title_x=0.5)
|
||||
|
||||
# Calculate the end time for the countdown timer (December 2, 2023, at 3:30 pm)
|
||||
end_time = datetime(2023, 12, 2, 15, 30, 0)
|
||||
|
||||
# Function to find the maximal consecutive occurrence of a given roll value
|
||||
def find_max_consecutive_occurrence(series, roll_value):
|
||||
max_consecutive_occurrence = 0
|
||||
current_consecutive_occurrence = 0
|
||||
|
||||
for i in range(1, len(series)):
|
||||
if series.iloc[i] == roll_value and series.iloc[i - 1] == roll_value and (series.index[i] - series.index[i - 1]) == 1:
|
||||
current_consecutive_occurrence += 1
|
||||
elif series.iloc[i] == roll_value:
|
||||
current_consecutive_occurrence = 1
|
||||
else:
|
||||
current_consecutive_occurrence = 0
|
||||
|
||||
max_consecutive_occurrence = max(max_consecutive_occurrence, current_consecutive_occurrence)
|
||||
|
||||
return max_consecutive_occurrence
|
||||
|
||||
def calculate_cumulative_damage(rolls):
|
||||
cumulative_damage = []
|
||||
current_value = None
|
||||
consecutive_count = 0
|
||||
|
||||
for roll in rolls:
|
||||
if roll == current_value:
|
||||
consecutive_count += 1
|
||||
else:
|
||||
consecutive_count = 1
|
||||
current_value = roll
|
||||
|
||||
damage = roll * (2 ** (consecutive_count - 1))
|
||||
cumulative_damage.append(damage)
|
||||
|
||||
return cumulative_damage
|
||||
|
||||
|
||||
# Function to read values from the info.txt file
|
||||
def read_info_file():
|
||||
try:
|
||||
with open('info.txt', 'r') as file:
|
||||
lines = file.readlines()
|
||||
if lines:
|
||||
values = lines[0].strip().split(',')
|
||||
if len(values) == 3:
|
||||
inference_rate, latency, power_consumption = map(float, values)
|
||||
return inference_rate, latency, power_consumption
|
||||
except Exception as e:
|
||||
print(f"Error reading info.txt: {e}")
|
||||
return None, None, None
|
||||
|
||||
# Calculate the maximal consecutive occurrence for each roll
|
||||
max_consecutive_occurrences = {roll: find_max_consecutive_occurrence(df['roll'], roll) for roll in range(1, 7)}
|
||||
|
||||
|
||||
# Define layout using Dash components and Dash Bootstrap Components
|
||||
app.layout = dbc.Container(
|
||||
fluid=True,
|
||||
children=[
|
||||
# Row 1: Cells 1 and 2
|
||||
dbc.Row([
|
||||
dbc.Col(
|
||||
dbc.Card(
|
||||
dbc.CardBody(
|
||||
[
|
||||
html.Img(src=dash.get_asset_url('oogie.gif'), alt='Oogie Boogie', className='img-fluid mx-auto my-auto', style={'width': '75%', 'max-height': '100%', 'border-radius': '25px'}),
|
||||
dbc.Progress(
|
||||
id='progress-bar',
|
||||
value=progress_value,
|
||||
color="success",
|
||||
max=max_progress_value,
|
||||
style={'margin-top': '20px', 'height': '30px', 'background-color': 'red'},
|
||||
),
|
||||
html.P(f'Health: {progress_value:.0f}/{max_progress_value}', id='health-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-top': '10px'}),
|
||||
],
|
||||
className='text-center'
|
||||
),
|
||||
className='border p-3',
|
||||
style={'height': '100%'}
|
||||
),
|
||||
width=6
|
||||
),
|
||||
dbc.Col(
|
||||
# Cell 2: Countdown, System infos, and Table with max consecutive occurrences for each roll
|
||||
dbc.Card(
|
||||
[
|
||||
dcc.Interval(
|
||||
id='interval-component',
|
||||
interval=1*1000, # in milliseconds
|
||||
n_intervals=0
|
||||
),
|
||||
html.P(id='countdown-timer', className='lead text-center fw-bold', style={'font-size': '32px'}),
|
||||
dbc.CardBody(
|
||||
[
|
||||
# Add new text and values from info.txt
|
||||
html.Div(
|
||||
[
|
||||
html.P(id='inference-rate-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-right': '10px'}),
|
||||
html.P(id='latency-text', className='lead text-center fw-bold', style={'font-size': '24px', 'margin-right': '10px'}),
|
||||
html.P(id='power-consumption-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
|
||||
],
|
||||
style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'margin-top': '20px'},
|
||||
),
|
||||
|
||||
html.Div(
|
||||
[
|
||||
html.Img(src=dash.get_asset_url('dice-pc.png'), alt='Actuel', className='img-fluid mx-auto my-auto', style={'width': '50%', 'max-height': '100%', 'border-radius': '25px'}),
|
||||
],
|
||||
style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center'},
|
||||
),
|
||||
html.Div(
|
||||
[
|
||||
html.Img(src=dash.get_asset_url('dice-fpga.png'), alt='Cible', className='img-fluid mx-auto my-auto', style={'width': '60%', 'max-height': '100%', 'border-radius': '25px'}),
|
||||
],
|
||||
style={'display': 'flex', 'align-items': 'center', 'justify-content': 'center', 'margin-top': '20px'},
|
||||
),
|
||||
# html.Img(src=dash.get_asset_url('dice-pc.png'), alt='Actuel', className='img-fluid mx-auto my-auto', style={'width': '55%', 'max-height': '100%', 'border-radius': '25px'}),
|
||||
# html.Img(src=dash.get_asset_url('dice-fpga.png'), alt='Cible', className='img-fluid mx-auto my-auto', style={'width': '5%', 'max-height': '100%', 'border-radius': '25px'}),
|
||||
# dbc.Table(
|
||||
# id='max-consecutive-occurrence-table',
|
||||
# children=[
|
||||
# html.Thead(
|
||||
# html.Tr([html.Th('Roll', style={'font-size': '28px'}), html.Th('Max Consecutive Occurrence', style={'font-size': '28px'})])
|
||||
# ),
|
||||
# html.Tbody(
|
||||
# [html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{max_consecutive_occurrences[roll]}', style={'font-size': '24px'})]) for roll in range(1, 7)]
|
||||
# )
|
||||
# ],
|
||||
# className='text-center',
|
||||
# style={'margin-top': '20px'}
|
||||
# ),
|
||||
],
|
||||
className='text-center'
|
||||
),
|
||||
],
|
||||
className='border p-3',
|
||||
style={'height': '100%'}
|
||||
),
|
||||
width=6
|
||||
)
|
||||
], align='stretch', style={'margin-bottom': '20px'}),
|
||||
|
||||
# Row 2: Cells 3 and 4
|
||||
dbc.Row([
|
||||
dbc.Col(
|
||||
# Cell 3
|
||||
dbc.Card(
|
||||
dbc.CardBody(
|
||||
[
|
||||
html.Div(
|
||||
[
|
||||
html.Div(
|
||||
[
|
||||
html.H5("Previous Roll", className="card-title fw-bold", style={'margin-bottom': '10px', 'font-size': '32px'}),
|
||||
html.Img(id='previous-roll-image', alt='previous roll image', className='img-fluid mx-auto my-auto', style={'width': '70%', 'max-height': '100%', 'border-radius': '15px'}),
|
||||
],
|
||||
style={'padding-bottom': '20px', 'padding-right': '75px'}
|
||||
),
|
||||
|
||||
html.Div(
|
||||
[
|
||||
html.H5("Current Roll", className="card-title fw-bold", style={'margin-bottom': '10px', 'font-size': '32px'}),
|
||||
html.Img(id='current-roll-image', alt='current roll image', className='img-fluid mx-auto my-auto', style={'width': '70%', 'max-height': '100%', 'border-radius': '15px'}),
|
||||
],
|
||||
style={'padding-bottom': '20px'}
|
||||
),
|
||||
],
|
||||
style={'display': 'flex', 'justify-content': 'center', 'margin-top': '75px'}
|
||||
),
|
||||
|
||||
html.P(id='consecutive-count-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
|
||||
html.P(id='damage-dealt-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
|
||||
html.P(id='max-damage-text', className='lead text-center fw-bold', style={'font-size': '24px'}),
|
||||
|
||||
],
|
||||
className='text-center'
|
||||
),
|
||||
className='border p-3',
|
||||
style={'height': '100%'}
|
||||
),
|
||||
width=6
|
||||
),
|
||||
dbc.Col(
|
||||
# Cell 4: Bar Chart and Probability Table
|
||||
dbc.Card(
|
||||
[
|
||||
dbc.CardBody(
|
||||
[
|
||||
html.P(id='total-rolls-text', className='lead text-center fw-bold', style={'font-size': '32px'}),
|
||||
html.Div(
|
||||
[
|
||||
# Bar Chart
|
||||
dcc.Graph(
|
||||
id='bar-chart',
|
||||
figure=fig,
|
||||
style={'height': '80%', 'width': '70%', 'display': 'inline-block'}
|
||||
),
|
||||
# Probability Table
|
||||
dbc.Table(
|
||||
id='probability-table',
|
||||
style={'margin-top': '20px', 'width': '30%', 'display': 'inline-block'},
|
||||
),
|
||||
],
|
||||
style={'width': '100%', 'display': 'flex', 'justify-content': 'space-between'}
|
||||
),
|
||||
],
|
||||
className='text-center'
|
||||
),
|
||||
],
|
||||
# Cell 4
|
||||
className='border p-3',
|
||||
style={'height': '100%'}
|
||||
),
|
||||
width=6
|
||||
)
|
||||
], align='stretch')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
# Callback to update countdown timer text
|
||||
@app.callback(Output('countdown-timer', 'children'),
|
||||
[Input('interval-component', 'n_intervals')])
|
||||
def update_timer(n_intervals):
|
||||
time_left = end_time - datetime.now()
|
||||
days, seconds = divmod(time_left.total_seconds(), 86400)
|
||||
hours, remainder = divmod(seconds, 3600)
|
||||
minutes, seconds = divmod(remainder, 60)
|
||||
|
||||
# Format components with leading zeros
|
||||
formatted_hours = str(int(hours)).zfill(2)
|
||||
formatted_minutes = str(int(minutes)).zfill(2)
|
||||
formatted_seconds = str(int(seconds)).zfill(2)
|
||||
|
||||
return f'Temps restant: {formatted_hours}:{formatted_minutes}:{formatted_seconds}'
|
||||
|
||||
|
||||
# Callback to update data every second
|
||||
@app.callback([Output('bar-chart', 'figure'),
|
||||
Output('total-rolls-text', 'children'),
|
||||
# Output('max-consecutive-occurrence-table', 'children'),
|
||||
Output('probability-table', 'children'),
|
||||
Output('inference-rate-text', 'children'),
|
||||
Output('latency-text', 'children'),
|
||||
Output('power-consumption-text', 'children'),
|
||||
Output('consecutive-count-text', 'children'),
|
||||
Output('damage-dealt-text', 'children'),
|
||||
Output('previous-roll-image', 'src'),
|
||||
Output('current-roll-image', 'src'),
|
||||
Output('progress-bar', 'value'),
|
||||
Output('health-text', 'children'),
|
||||
Output('max-damage-text', 'children'),],
|
||||
[Input('interval-component', 'n_intervals')])
|
||||
def update_data(n_intervals):
|
||||
global df, max_consecutive_occurrences, total_rolls, consecutive_count, current_roll, progress_value, max_damage
|
||||
|
||||
# Load the data from the dice_roll_data.csv file into a Pandas DataFrame
|
||||
df = pd.read_csv('dice_roll_data.csv')
|
||||
|
||||
# Calculate statistics
|
||||
result_counts = df['roll'].value_counts().sort_index()
|
||||
total_rolls = result_counts.sum()
|
||||
|
||||
# Create figure with px.bar
|
||||
fig = px.bar(y=result_counts.index, x=result_counts.values, labels={'x': 'Compte', 'y': 'Résultat'},
|
||||
orientation='h')
|
||||
|
||||
# Update layout for the bar chart to make the axis titles and tick labels larger
|
||||
fig.update_xaxes(tickfont=dict(size=24), title_font=dict(size=28))
|
||||
fig.update_yaxes(tickfont=dict(size=24), title_font=dict(size=28))
|
||||
|
||||
# Add numbers on the bars
|
||||
fig.update_traces(text=result_counts.values, textposition='inside', textfont_size=20)
|
||||
|
||||
# Calculate the maximal consecutive occurrence for each roll
|
||||
max_consecutive_occurrences = {roll: find_max_consecutive_occurrence(df['roll'], roll) for roll in range(1, 7)}
|
||||
|
||||
# Calculate the total and maximal damage dealt and apply it to the progress bar
|
||||
total_damage_dealt = sum(calculate_cumulative_damage(df['roll']))
|
||||
progress_value = max_progress_value - total_damage_dealt
|
||||
health_text = f'Points de vie: {progress_value:.0f}/{max_progress_value}'
|
||||
|
||||
# Update the table in Cell 2 with the new max consecutive occurrences
|
||||
max_occurrence_table = [
|
||||
html.Thead(
|
||||
html.Tr([html.Th('Résultat', style={'font-size': '28px'}), html.Th('Occurence Consécutive Max', style={'font-size': '28px'})])
|
||||
),
|
||||
html.Tbody(
|
||||
[html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{max_consecutive_occurrences[roll]}', style={'font-size': '24px'})]) for roll in range(1, 7)]
|
||||
)
|
||||
]
|
||||
|
||||
# Read values from the info.txt file
|
||||
inference_rate, latency, power_consumption = read_info_file()
|
||||
|
||||
# Update text in Cell 2 with values from info.txt
|
||||
inference_rate_text = f"Débit d'Inference: {inference_rate} fps" if inference_rate is not None else "Débit d'Inference: N/A"
|
||||
latency_text = f'Latence: {latency} µs' if latency is not None else 'Latence: N/A'
|
||||
power_consumption_text = f'Consomation Énergétique: {power_consumption} W' if power_consumption is not None else 'Consomation Énergétique: N/A'
|
||||
|
||||
# Calculate probabilities
|
||||
probabilities = result_counts / total_rolls * 100
|
||||
probability_table = [
|
||||
html.Thead(
|
||||
html.Tr([html.Th('Résultat', style={'font-size': '28px'}), html.Th('Probabilités', style={'font-size': '28px'})])
|
||||
),
|
||||
html.Tbody(
|
||||
[html.Tr([html.Td(f'{roll}', style={'font-size': '24px'}), html.Td(f'{probabilities[roll]:.2f}%', style={'font-size': '24px'})]) for roll in range(1, 7)]
|
||||
)
|
||||
]
|
||||
|
||||
# Update consecutive count and text
|
||||
current_roll = df['roll'].iloc[-1] if not df.empty else 0
|
||||
consecutive_count = sum(1 for _ in itertools.takewhile(lambda x: x == current_roll, reversed(df['roll'])))
|
||||
consecutive_count_text = f'Vous avez lancé {current_roll} pour la {consecutive_count}{"ère" if consecutive_count == 1 else "ème"} fois de suite!'
|
||||
|
||||
# Calculate damage dealt
|
||||
damage_dealt = current_roll * (2 ** (consecutive_count-1))
|
||||
damage_dealt_text = f'Dégat infligé: {damage_dealt}'
|
||||
|
||||
# Calculate max damage dealt
|
||||
if max_damage > damage_dealt:
|
||||
max_damage_text = f'Dégat Maximal: {max_damage}'
|
||||
else:
|
||||
max_damage = damage_dealt
|
||||
max_damage_text = f'Nouveau Dégat Maximal: {max_damage}! Bravo!'
|
||||
|
||||
# Get image sources based on the current and previous rolls
|
||||
previous_roll_image_source = Image.open('assets/previous_roll.jpg')
|
||||
current_roll_image_source = Image.open('assets/current_roll.jpg')
|
||||
|
||||
return fig, f'Total de tirs: {total_rolls}', probability_table, inference_rate_text, latency_text, power_consumption_text, consecutive_count_text, damage_dealt_text, previous_roll_image_source, current_roll_image_source, progress_value, health_text, max_damage_text
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run_server(debug=True, host='0.0.0.0', dev_tools_hot_reload=False)
|
Loading…
Reference in a new issue