|
import gradio as gr
|
|
import pandas as pd
|
|
import pulp
|
|
import numpy as np
|
|
|
|
|
|
PLANTS_TIERS = {
|
|
"radiant": "RADIANT",
|
|
"flourishing": "FLOURISHING",
|
|
"hardy": "HARDY",
|
|
"feeble": "FEEBLE",
|
|
"radiant_rarecolor": "RADIANT+RARECOLOR",
|
|
"flourishing_rarecolor": "FLOURISHING+RARECOLOR",
|
|
"hardy_rarecolor": "HARDY+RARECOLOR",
|
|
}
|
|
|
|
PLANTS_LABLES = {
|
|
"fanged_geranium": "Fanged Geranium",
|
|
"gillyweed": "Gillyweed",
|
|
"rose": "Rose",
|
|
"puffapod": "Puffapod",
|
|
"wild_pansy": "Wild Pansy",
|
|
"nifflers_fancy": "Niffler's Fancy",
|
|
"fanwort": "Fanwort",
|
|
"ladys_mantle": "Lady's Mantle",
|
|
"kelp": "Kelp",
|
|
"mandrake": "Mandrake",
|
|
"chinese_chomping_cabbage": "Chinese Chomping Cabbage",
|
|
"dragons_breath_macroalgae": "Dragon's Breath Macroalgae",
|
|
"peony": "Peony",
|
|
"begonia": "Begonia",
|
|
"mayflower": "Mayflower",
|
|
"hydrangea": "Hydrangea",
|
|
"ludwigia_glandulosa": "Ludwigia Glandulosa",
|
|
"daffodil": "Daffodil",
|
|
"water_hyacinth": "Water Hyacinth",
|
|
"lily_of_the_valley": "Lily of the Valley",
|
|
"mosaic_flower": "Mosaic Flower",
|
|
"sunflower": "Sunflower",
|
|
"mimbulus_mimbletonia": "Mimbulus Mimbletonia",
|
|
"water_lily": "Water Lily",
|
|
}
|
|
|
|
INTERFACE_TEXTS = {
|
|
"cn": {
|
|
"gold_label": "葭碧の金币预算:",
|
|
"strategies_label": "请选择凑单策略:",
|
|
"clear_btn_label": "❌清除",
|
|
"calculate_btn_label": "🛠计算",
|
|
"output_label": "计算结果:",
|
|
"strategy_options": [
|
|
("最小化售出株数(优先出售高价植物)", "MaximizeStock"),
|
|
("最大化售出株数(优先出售低价植物)", "MinimizeStock"),
|
|
],
|
|
},
|
|
"en": {
|
|
"gold_label": "Gabby's Gold Budget:",
|
|
"strategies_label": "Select a strategy:",
|
|
"clear_btn_label": "❌Clear",
|
|
"calculate_btn_label": "🛠Calculate",
|
|
"output_label": "Output:",
|
|
"strategy_options": [
|
|
(
|
|
"Minimize the number of plants sold (prioritize high-priced plants)",
|
|
"MaximizeStock",
|
|
),
|
|
(
|
|
"Maximize the number of plants sold (prioritize low-priced plants)",
|
|
"MinimizeStock",
|
|
),
|
|
],
|
|
},
|
|
}
|
|
|
|
|
|
df = pd.read_csv("plants.csv")
|
|
|
|
|
|
df["species"] = pd.Categorical(df["species"])
|
|
df["tier"] = pd.Categorical(df["tier"])
|
|
df = df.dropna(subset=["gold"])
|
|
df = df.astype(
|
|
{
|
|
"gold": int,
|
|
"gems": int,
|
|
}
|
|
)
|
|
|
|
|
|
def calculator(*args):
|
|
"""
|
|
Calculate the optimal solution of plant sales based on the given budget
|
|
and inventory constraints.
|
|
|
|
Args:
|
|
*args (tuple): A tuple where the first element is Gabby's gold budget, the selected strategy for selling plants,
|
|
and the subsequent elements represent the stock levels of
|
|
each plant type.
|
|
|
|
Returns:
|
|
str: A description of the optimal solution, including which plants to sell,
|
|
the total gold earned, and the remaining inventory.
|
|
"""
|
|
budget = args[0]
|
|
strategy = args[1]
|
|
stocks = np.array([x if x else 0 for x in args[2:]])
|
|
|
|
|
|
plants_names = [
|
|
f"{PLANTS_TIERS[row['tier']]} {PLANTS_LABLES[row['species']]}"
|
|
for index, row in df.iterrows()
|
|
]
|
|
|
|
gold = np.array(df["gold"])
|
|
|
|
if sum([gold[i] * stocks[i] for i in range(len(stocks))]) < budget:
|
|
return "No solution found.\nThe total value of the plants is lower than the budget."
|
|
|
|
|
|
if strategy == "MaximizeStock":
|
|
prob = pulp.LpProblem("Maximize_Stock", pulp.LpMinimize)
|
|
else:
|
|
prob = pulp.LpProblem("Maximize_Stock", pulp.LpMaximize)
|
|
|
|
|
|
x = pulp.LpVariable.dicts("x", range(len(stocks)), lowBound=0, cat="Integer")
|
|
|
|
|
|
for i in range(len(stocks)):
|
|
x[i].upBound = stocks[i]
|
|
|
|
|
|
prob += pulp.lpSum([x[i] for i in range(len(stocks))])
|
|
|
|
|
|
prob += pulp.lpSum([gold[i] * x[i] for i in range(len(stocks))]) == budget
|
|
|
|
|
|
|
|
solver = pulp.getSolver("PULP_CBC_CMD")
|
|
prob.solve(solver=solver)
|
|
|
|
if pulp.LpStatus[prob.status] == "Optimal":
|
|
|
|
sold = 0
|
|
solution = []
|
|
for i, v in x.items():
|
|
if v.varValue:
|
|
if v.varValue > 0:
|
|
solution.append(f"{plants_names[i]}: {int(v.varValue)}\n")
|
|
sold += int(v.varValue) * gold[i]
|
|
|
|
return f"Optimal solution found:\n\n{''.join(solution)}\nTotal Price: {sold}\nCount: {int(pulp.value(prob.objective))}"
|
|
|
|
else:
|
|
return "No solution found.\n"
|
|
|
|
|
|
|
|
css = """
|
|
.firstbox {background-color: #fafad2}
|
|
"""
|
|
|
|
with gr.Blocks(css=css) as demo:
|
|
gr.Markdown(
|
|
"""<center><font size=8>HP-Magic-Awakened Herbologist Toolkit👾</center>"""
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Column():
|
|
|
|
budget = gr.Number(
|
|
label="Gold",
|
|
info="Gabby's Gold Budget:",
|
|
value=0,
|
|
minimum=0,
|
|
maximum=20000,
|
|
step=100,
|
|
)
|
|
|
|
|
|
selected_strategy = gr.Radio(
|
|
[
|
|
(
|
|
"Minimize the number of plants sold (prioritize high-priced plants)",
|
|
"MaximizeStock",
|
|
),
|
|
(
|
|
"Maximize the number of plants sold (prioritize low-priced plants)",
|
|
"MinimizeStock",
|
|
),
|
|
],
|
|
value="MaximizeStock",
|
|
label="Strategies",
|
|
info="Select a strategy:",
|
|
)
|
|
|
|
|
|
with gr.Row():
|
|
inventory = {}
|
|
species_set = set()
|
|
species_count = 0
|
|
for _, row in df.iterrows():
|
|
if is_gold := row["gold"] != 0:
|
|
species_set.add(row["species"])
|
|
inventory[f"{row['species']}_{row['tier']}"] = gr.Number(
|
|
|
|
label=PLANTS_LABLES[row["species"]],
|
|
info=PLANTS_TIERS[row["tier"]],
|
|
value=0,
|
|
precision=0,
|
|
minimum=0,
|
|
maximum=500,
|
|
step=10,
|
|
visible=is_gold,
|
|
elem_classes=("firstbox" if len(species_set) > species_count else None),
|
|
)
|
|
species_count = len(species_set)
|
|
|
|
|
|
with gr.Row():
|
|
clear_btn = gr.ClearButton(list(inventory.values()), size="sm", value="❌Clear")
|
|
|
|
|
|
submit_btn = gr.Button(value="🛠Calculate")
|
|
|
|
|
|
with gr.Row():
|
|
result = gr.Textbox(label="Output")
|
|
|
|
|
|
submit_btn.click(
|
|
calculator,
|
|
inputs=[budget] + [selected_strategy] + list(inventory.values()),
|
|
outputs=[result],
|
|
api_name=False,
|
|
)
|
|
|
|
|
|
|
|
demo.queue(api_open=False)
|
|
demo.launch(max_threads=5, share=False)
|
|
|