diff --git a/README.md b/README.md index 653a9d4..e6b28cb 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Consistency is hard without proper goals to set a good (let's dare say "atomic") I'm also adding notes that may be useful if you're learning Ruby. Notes for solving: -* [2015, up to day 20](year_2015.md) +* [2015, up to day 21](year_2015.md) * [2023, up to day 03](year_2023.md) # How to use diff --git a/spec/year_2015/day_21_spec.rb b/spec/year_2015/day_21_spec.rb new file mode 100644 index 0000000..f50b8d5 --- /dev/null +++ b/spec/year_2015/day_21_spec.rb @@ -0,0 +1,21 @@ +require 'year_2015/day_21' + +describe Year2015::Day21 do + context 'when Results' do + subject(:input_data) do + { + hp: 100, + damage: 8, + armor: 2 + } + end + + it 'correctly answers part 1' do + expect(described_class.new(input_data, true).to_i).to eq(91) + end + + it 'correctly answers part 2' do + expect(described_class.new(input_data).to_i).to eq(158) + end + end +end diff --git a/year_2015.md b/year_2015.md index e79bea1..b9d989f 100644 --- a/year_2015.md +++ b/year_2015.md @@ -343,3 +343,14 @@ Year2015::Day20 I've had to calculate list of primes and divisors in the past, and it always sucked. My previous algorithms were correct but always too long (but what is "long" when you're nearing infinity?). Again, [outside help](https://dmatrix.dev/posts/advent-of-code-year-2015-day-20/) is a great resource to find algorithms better than yours. + +## Day 21 + +``` +Year2015::Day21 + when Results + correctly answers part 1 + correctly answers part 2 +``` + +...really nothing to say here. diff --git a/year_2015/day_21.rb b/year_2015/day_21.rb new file mode 100644 index 0000000..e3e8a5d --- /dev/null +++ b/year_2015/day_21.rb @@ -0,0 +1,90 @@ +class Year2015 + class Day21 + WEAPONS = [ + ['Dagger', 8, 4, 0], + ['Shortsword', 10, 5, 0], + ['Warhammer', 25, 6, 0], + ['Longsword', 40, 7, 0], + ['Greataxe', 74, 8, 0] + ].freeze + ARMORS = [ + ['None', 0, 0, 0], + ['Leather', 13, 0, 1], + ['Chainmail', 31, 0, 2], + ['Splintmail', 53, 0, 3], + ['Bandedmail', 75, 0, 4], + ['Platemail', 102, 0, 5] + ].freeze + ACCESSORIES = [ + ['None', 0, 0, 0], + ['None', 0, 0, 0], + ['Damage +1', 25, 1, 0], + ['Damage +2', 50, 2, 0], + ['Damage +3', 100, 3, 0], + ['Defense +1', 20, 0, 1], + ['Defense +2', 40, 0, 2], + ['Defense +3', 80, 0, 3] + ].freeze + + def initialize(input_boss, input_part_one = false) + @version = input_part_one ? 1 : 2 + @boss = input_boss + @best_price = @version == 1 ? 256 : 8 + end + + def simulate_battle(player_damage, player_armor) + player_hp = 100 + player_damage = [1, player_damage - @boss[:armor]].max + boss_hp = @boss[:hp] + boss_damage = [1, @boss[:damage] - player_armor].max + + player_turns = (player_hp / boss_damage) + 1 + boss_turns = (boss_hp / player_damage) + 1 + player_turns >= boss_turns + + # until boss_hp.negative? || player_hp.negative? + # boss_hp -= player_attack + # # puts "-> Player deals #{player_attack} damage; the boss goes down to #{boss_hp}" + # return true if boss_hp.negative? + + # player_hp -= boss_attack + # # puts "-> Boss deals #{boss_attack} damage; the player goes down to #{player_hp}" + # return false if player_hp.negative? + # end + end + + def use_equipment(equipment) + price = equipment.sum{|object| object[1] } + + damage = equipment.sum{|object| object[2] } + armor = equipment.sum{|object| object[3] } + result = simulate_battle(damage, armor) + update_price(price, result) + end + + def loop_equiment + WEAPONS.each do |weapon| + ARMORS.each do |armor| + ACCESSORIES[0..-2].each_with_index do |acc1, i| + ACCESSORIES[i..].each do |acc2| + use_equipment([weapon, armor, acc1, acc2]) + end + end + end + end + end + + def update_price(price, result) + if @version == 1 && result + @best_price = [@best_price, price].min + elsif @version == 2 && !result + @best_price = [@best_price, price].max + end + end + + def to_i + loop_equiment + @best_price + end + end +end