Spaces:
Sleeping
Sleeping
File size: 10,879 Bytes
5e3846a 927fb0b 5e3846a 927fb0b 5e3846a 927fb0b 25e0d20 5e3846a 927fb0b 5e3846a 927fb0b 5e3846a 927fb0b 5e3846a 927fb0b 5e3846a 25e0d20 927fb0b 5e3846a 25e0d20 5e3846a 25e0d20 5e3846a 25e0d20 5e3846a 927fb0b 5e3846a 927fb0b 5e3846a 927fb0b 5e3846a |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
import math
from shiny import App, reactive, render, ui
# Crafting requirements for golem parts
ANIMATED_SNOW_PER_HEAD_TORSO = 20
ANIMATED_SNOW_PER_LIMB = 10
# Animated snow given from smashing golem parts
ANIMATED_SNOW_SMASH_HEAD_TORSO = 10
ANIMATED_SNOW_SMASH_PER_LIMB = 5
# Maximum number of each resource that user can input
RESOURCE_CAP = 100000
# Define app UI
app_ui = ui.page_fluid(
ui.h1("☃️ Snow Golem Crafting Optimizer for MouseHunt (GWH 2023) ☃️"),
ui.layout_sidebar(
ui.sidebar(
ui.p("Adjust the user inputs to view the maximum number of snow golems you can make with your current resources."),
ui.input_numeric("golem_heads", ui.HTML("<b>Enter the number of snow golem heads you currently have:</b>"), value = 10, min = 0, max = 1000),
ui.input_numeric("golem_torsos", ui.HTML("<b>Enter the number of snow golem torsos you currently have:</b>"), value = 5, min = 0, max = 1000),
ui.input_numeric("golem_limbs", ui.HTML("<b>Enter the number of snow golem limbs you currently have:</b>"), value = 30, min = 0, max = 1000),
ui.input_numeric("ani_snow", ui.HTML("<b>Enter the amount of animated snow you currently have:</b>"), value = 15, min = 0, max = 1000),
width = 350
),
ui.h3("User-selected inputs"),
ui.row(
ui.column(3, ui.output_text_verbatim("user_golem_heads")),
ui.column(3, ui.output_text_verbatim("user_golem_torsos")),
ui.column(3, ui.output_text_verbatim("user_golem_limbs")),
ui.column(3, ui.output_text_verbatim("user_ani_snow"))
),
ui.panel_conditional(
"!output.user_golem_heads.includes('Invalid') && !output.user_golem_torsos.includes('Invalid') && !output.user_golem_limbs.includes('Invalid') && !output.user_ani_snow.includes('Invalid') && input.golem_heads >= 0 && input.golem_torsos >= 0 && input.golem_limbs >= 0 && input.ani_snow >= 0 && input.golem_heads != null && input.golem_torsos != null && input.golem_limbs != null && input.ani_snow != null",
ui.h3("Maximum snow golems craftable with current resources"),
ui.output_text_verbatim("final_result"),
ui.hr(style = "border: none; border-top: 2px; margin-top: 10px; margin-bottom: 10px;"),
ui.h3("Detailed breakdown"),
ui.row(
ui.column(4, ui.h5("☃️ Golem Requirements"), ui.HTML(ui.output_ui("golem_req"))),
ui.column(4, ui.h5("💥 Smashing Requirements"), ui.HTML(ui.output_ui("smashing_req"))),
ui.column(4, ui.h5("🛠️ Crafting Requirements"), ui.HTML(ui.output_ui("crafting_req")))
),
ui.hr(style = "border: none; border-top: 2px; margin-top: 10px; margin-bottom: 10px;"),
ui.h5("❄️ Animated Snow Usage"), ui.HTML(ui.output_ui("ani_snow_usage"))
)
),
)
# Define app server
def server(input, output, session):
@output
@render.text
def user_golem_heads():
if input.golem_heads() is None:
return
return f"🙂 Head(s): {int(input.golem_heads()) if (input.golem_heads() >= 0 and input.golem_heads() <= RESOURCE_CAP) else 'Invalid'}"
@output
@render.text
def user_golem_torsos():
if input.golem_torsos() is None:
return
return f"👕 Torso(s): {int(input.golem_torsos()) if (input.golem_torsos() >= 0 and input.golem_torsos() <= RESOURCE_CAP) else 'Invalid'}"
@output
@render.text
def user_golem_limbs():
if input.golem_limbs() is None:
return
return f"🦵 Limb(s): {int(input.golem_limbs()) if (input.golem_limbs() >= 0 and input.golem_limbs() <= RESOURCE_CAP) else 'Invalid'}"
@output
@render.text
def user_ani_snow():
if input.ani_snow() is None:
return
return f"❄️ Anim. Snow: {int(input.ani_snow()) if (input.ani_snow() >= 0 and input.ani_snow() <= RESOURCE_CAP) else 'Invalid'}"
# Perform the calculation for the maximum number of snow golems possible
@reactive.Calc
def calculate():
# Get user inputs
initial_animated_snow = input.ani_snow()
heads_in_inventory = input.golem_heads()
torsos_in_inventory = input.golem_torsos()
limbs_in_inventory = input.golem_limbs()
# Perform data validation
if any(elem is None or elem < 0 for elem in [initial_animated_snow, heads_in_inventory, torsos_in_inventory, limbs_in_inventory]):
return tuple([0] * 10)
# Change to suitable data type
initial_animated_snow = int(initial_animated_snow)
heads_in_inventory = int(heads_in_inventory)
torsos_in_inventory = int(torsos_in_inventory)
limbs_in_inventory = int(limbs_in_inventory)
# Amount of animated snow used per golem
animated_snow_per_golem = ANIMATED_SNOW_PER_HEAD_TORSO * 2 + ANIMATED_SNOW_PER_LIMB * 4
# Calculate total animated snow equivalent units
animated_snow_eq_units = initial_animated_snow + (torsos_in_inventory + heads_in_inventory) * ANIMATED_SNOW_PER_HEAD_TORSO + limbs_in_inventory * ANIMATED_SNOW_PER_LIMB
# Theoretical maximum number of golems possible to be made based on the equivalent units of animated snow
res = math.floor(animated_snow_eq_units / animated_snow_per_golem)
# Scenario where golem parts need to be smashed to maximise number of snow golems built
if res < heads_in_inventory or res < torsos_in_inventory or res * 4 < limbs_in_inventory:
# Brute force method to determine how much of the excess part to smash
for i in range(1, max(heads_in_inventory + 1, torsos_in_inventory + 1, limbs_in_inventory // 4 + 1)):
# Start with smashing all but 1 of the largest excess piece then decrease from there
res = i
# Determine which golem parts that are to be smashed
smashed_heads = (heads_in_inventory - res) if res < heads_in_inventory else 0
smashed_torsos = (torsos_in_inventory - res) if res < torsos_in_inventory else 0
smashed_limbs = (limbs_in_inventory - res * 4) if res * 4 < limbs_in_inventory else 0
# Get value of animated snow from smashing golem parts
animated_snow_from_smashing = (smashed_heads + smashed_torsos) * ANIMATED_SNOW_SMASH_HEAD_TORSO + smashed_limbs * ANIMATED_SNOW_SMASH_PER_LIMB
# Get the revised amount of animated snow that need to be used to craft the snow golems
crafted_heads = (res - heads_in_inventory) if heads_in_inventory < res else 0
crafted_torsos = (res - torsos_in_inventory) if torsos_in_inventory < res else 0
crafted_limbs = (res * 4 - limbs_in_inventory) if limbs_in_inventory < res * 4 else 0
animated_snow_for_crafting = initial_animated_snow + animated_snow_from_smashing
# Check if available animated snow is insufficient to craft necessary snow golem parts, then go back 1 iteration (That will be the maximum of snow golems that are buildable with current resource constraints)
if animated_snow_for_crafting < (crafted_heads + crafted_torsos) * ANIMATED_SNOW_PER_HEAD_TORSO + crafted_limbs * ANIMATED_SNOW_PER_LIMB:
# Go to previous iteration
res -= 1
# Determine which golem parts that are needed to be smashed
smashed_heads = (heads_in_inventory - res) if res < heads_in_inventory else 0
smashed_torsos = (torsos_in_inventory - res) if res < torsos_in_inventory else 0
smashed_limbs = (limbs_in_inventory - res * 4) if res * 4 < limbs_in_inventory else 0
# Get value of animated snow from smashing golem parts
animated_snow_from_smashing = (smashed_heads + smashed_torsos) * ANIMATED_SNOW_SMASH_HEAD_TORSO + smashed_limbs * ANIMATED_SNOW_SMASH_PER_LIMB
# Get the revised amount of animated snow that need to be used to craft the snow golems
crafted_heads = (res - heads_in_inventory) if heads_in_inventory < res else 0
crafted_torsos = (res - torsos_in_inventory) if torsos_in_inventory < res else 0
crafted_limbs = (res * 4 - limbs_in_inventory) if limbs_in_inventory < res * 4 else 0
animated_snow_for_crafting = initial_animated_snow + animated_snow_from_smashing
break
else: # If no golem parts need to be smashed
smashed_heads, smashed_torsos, smashed_limbs = 0, 0, 0
animated_snow_for_crafting = initial_animated_snow
animated_snow_from_smashing = 0
crafted_heads = max(res - heads_in_inventory, 0)
crafted_torsos = max(res - torsos_in_inventory, 0)
crafted_limbs = max(res * 4 - limbs_in_inventory, 0)
# Calculate total amount of animated snow used
used_animated_snow = crafted_heads * ANIMATED_SNOW_PER_HEAD_TORSO + crafted_torsos * ANIMATED_SNOW_PER_HEAD_TORSO + crafted_limbs * ANIMATED_SNOW_PER_LIMB
leftover_animated_snow = initial_animated_snow + animated_snow_from_smashing - used_animated_snow
return res, smashed_heads, smashed_torsos, smashed_limbs, crafted_heads, crafted_torsos, crafted_limbs, animated_snow_for_crafting, used_animated_snow, leftover_animated_snow
@output
@render.text
def final_result():
return f"You can build a maximum of {calculate()[0]} golem(s). {calculate()[0] * '☃️'}"
@output
@render.text
def golem_req():
return f"<li>🙂 Head(s) needed: {calculate()[0]}</li><li>👕 Torso(s) needed: {calculate()[0]}</li><li>🦵 Limbs needed: {calculate()[0] * 4}</li>"
@output
@render.text
def smashing_req():
return f"<li>💥🙂 Smash head(s): {calculate()[1]}</li><li>💥👕 Smash torso(s): {calculate()[2]}</li><li>💥🦵 Smash limb(s): {calculate()[3]}</li>"
@output
@render.text
def crafting_req():
return f"<li>🛠️🙂 Craft head(s): {calculate()[4]}</li><li>🛠️👕 Craft torso(s): {calculate()[5]}</li><li>🛠️🦵 Craft limb(s): {calculate()[6]}</li>"
@output
@render.text
def ani_snow_usage():
return f"<li>➕❄️ Total Animated Snow available for use after smashing: {calculate()[7]}</li><li>➖❄️ Animated Snow used to craft necessary golem parts: {calculate()[8]}</li><li>🟰❄️ Remaining Animated Snow left over after smashing + crafting: {calculate()[9]}</li>"
# Create app
app = App(app_ui, server, debug = True)
|