DEV Community

Cover image for Wizard Simulator 20XX
Robert Mion
Robert Mion

Posted on

Wizard Simulator 20XX

Advent of Code 2015 Day 22

Try battling your boss using the simulator!

Simulation of battle

Part 1

  1. Solve it? Maybe. Build it? Heck ya!
  2. Building the simulator

Solve it? Maybe. Build it? Heck ya!

  • Part 1 feels like Day 21 Part 3
  • Unlike in Day 21, the primary resource in this puzzle is not always decreasing
  • It seems like there are far more possible combinations that must be considered to identify the shortest path that is the smallest amount of mana used to win
  • I doubt I'll solve this
  • But I am determined to build a working Wizard Simulator!
  • Because I'd like to play out a few battles!

Building the simulator

I need:

  • Two inputs for the puzzle input
  • Five buttons, one for each spell I could cast
  • Text statuses for both player's stats

Logic that dictates:

  • whether a button can be pressed based on whether it is in a cooldown or not and whether the player has enough mana to cast that spell
  • whether a player has reached 0 hit points
  • the running mana amount spent
  • whether the player has any mana remaining
  • the damage dealt by the boss based on the player's armor
  • and more that I'm probably forgetting about

Buttons, stats and layout

I'll start by using my typical page framework and add the buttons:
Initial state of simulator

Now, with some player text status added:
Added player stats

Next, with a different layout and more text statuses added:
Updated layout and stats

Starting a new battle

  • The player can enter their unique boss's stats from their puzzle input
  • Then press the [Do battle] button
  • Seeing all the stats, hiding and preventing edits to the puzzle inputs

Starting a new battle

Casting the first spell

Magic Missile costs 53 mana. It instantly does 4 damage.

  • When a user presses the [magic missile] button
  • Player's mana decreases by 53
  • Boss's HP decreases by 4
  • Boss attacks for damage equal to the boss's damage amount minus player's armor amount

Magic missile spell working

Casting the second spell

Drain costs 73 mana. It instantly does 2 damage and heals you for 2 hit points.

  • When a user presses the [drain] button
  • Player's mana decreases by 73
  • Boss's HP decreases by 2
  • Player's HP increases by 2
  • Boss attacks for damage equal to the boss's damage amount minus player's armor amount

Drain spell working

Checking for endgame cases

The first character at or below 0 hit points loses.

If you cannot afford to cast any spell, you lose.

Checking for sufficient mana:

  • Before casting a spell
  • Check whether the player has enough mana
  • If not, disable that button
  • If no spell can be cast, restart the game

Checking for sufficient HP:

  • Before casting a spell
  • Check whether the player has at least 1 HP
  • If not, restart the game

Displaying an endgame message:

  • No mana left
  • No HP left
  • Boss defeated

Disabled spells and new game

Endgame message

Tracking effects

Effects apply at the start of both the player's turns and the boss' turns. Effects are created with a timer (the number of turns they last); at the start of each turn, after they apply any effect they have, their timer is decreased by one. If this decreases the timer to zero, the effect ends. You cannot cast a spell that would start an effect which is already active. However, effects can be started on the same turn they end.

Wow, there's a lot of nuance there.

I think I'll use an object with three keys and values starting at 0 to track each effect:

let effects = {
  "shield": 0,
  "poison": 0,
  "recharge": 0
}
Enter fullscreen mode Exit fullscreen mode

When any of the three respective buttons is pressed, the value corresponding the key associated with the pressed button will increment to the appropriate timer amount, only if value is not currently greater than 0.

Each turn, I'll decrement the value by 1 and either maintain the stat altered by the effect or apply the appropriate action to the appropriate player.

Lastly, based on each value, I'll disable or re-enable the respective button as available for spell-casting.

I predict a lot of debugging ahead.

...

I predicted correctly:

  • My control flow has become a bit wonky
  • It took me a while to diagnose why my HP started at 41 instead of 50 when auto-starting a new game
  • To address that, I added more control flow in hopes of accounting for every possible scenario after the player's turn

I think I've successfully implemented all five spells and their effect timers.

But after reviewing the example walkthrough, I'm confused.

Some spells apply immediately, but not others?

Looking at this:

-- Player turn --
- Player has 10 hit points, 0 armor, 250 mana
- Boss has 14 hit points
Player casts Recharge.

-- Boss turn --
- Player has 10 hit points, 0 armor, 21 mana
- Boss has 14 hit points
Recharge provides 101 mana; its timer is now 4.
Boss attacks for 8 damage!
Enter fullscreen mode Exit fullscreen mode

It seems a spell like Recharge doesn't provide 101 mana on the turn it is cast.

-- Player turn --
- Player has 2 hit points, 7 armor, 340 mana
- Boss has 12 hit points
Shield's timer is now 2.
Player casts Poison.

-- Boss turn --
- Player has 2 hit points, 7 armor, 167 mana
- Boss has 12 hit points
Shield's timer is now 1.
Poison deals 3 damage; its timer is now 5.
Boss attacks for 8 - 7 = 1 damage!
Enter fullscreen mode Exit fullscreen mode

Poison also waits a turn before dealing damage?

-- Player turn --
- Player has 2 hit points, 0 armor, 122 mana
- Boss has 14 hit points
Recharge provides 101 mana; its timer is now 3.
Player casts Shield, increasing armor by 7.
Enter fullscreen mode Exit fullscreen mode

But Shield works immediately?

This disparity causes me to question this rule:

Effects apply at the start of both the player's turns and the boss' turns.

I tried a simple fix in my code - re-ordering the parts that handled decrementing the effect timer and applying the effect.

Failing to re-create the example battle

  • Using the stats as outlined
  • And casting the spells in the order described
  • My simulator recreated everything...
  • ...except Poison, it seems
  • and Player incorrectly dies

Broken simulation

Redundant code...that hopefully works

  • Right now my code consists of several control flows and function calls
  • I hypothesize that I'm calling functions at the wrong time
  • So, I'm going to attempt to just put the code currently in the functions at all the spots I think it should go

Wish me luck...

...I think I did it!

Working simulation of example battle

Trying to win one battle with my boss input

  • First battle: I got my boss down to 2 HP, but lost
  • Second battle: I won! Spent 1916 mana

I had to submit that as a possible answer.

As I figured, it's too high.

  • Next winning battle: I spent 1823 mana

Submitted. Too high.

  • Next winning battle: I spent 1876 mana

  • Next winning battle: I spent 1744 mana

Submitted. Too high.

  • Next winning battle: I spent 1461 mana

Submitted. Not the right answer. I assume too high still.

Celebrating my accomplishments

  • I built a working - I think? - Wizard Simulator 20XX!
  • I can now play it throughout the 2015 year of puzzles, trying to beat my 1461 mana spend score!

Top comments (0)