aboutsummaryrefslogtreecommitdiff
path: root/2015
diff options
context:
space:
mode:
authorThomas Voss <thomasvoss@live.com> 2021-11-11 21:49:08 +0100
committerThomas Voss <thomasvoss@live.com> 2021-11-11 21:49:08 +0100
commit0bacf291012507634fed08df5ea2d7372c518a99 (patch)
tree4e42dd095f7f25c6264464e5ce683cc04db45ed6 /2015
parentc3fcf7a689fabb6677b8260f307faaae8a23beb0 (diff)
Add 2015 Day 21 solutions
Diffstat (limited to '2015')
-rw-r--r--2015/21/.gitignore1
-rw-r--r--2015/21/Makefile8
-rw-r--r--2015/21/input3
-rw-r--r--2015/21/puzzles.py89
4 files changed, 101 insertions, 0 deletions
diff --git a/2015/21/.gitignore b/2015/21/.gitignore
new file mode 100644
index 0000000..ffc46fe
--- /dev/null
+++ b/2015/21/.gitignore
@@ -0,0 +1 @@
+puzzle-[12].py
diff --git a/2015/21/Makefile b/2015/21/Makefile
new file mode 100644
index 0000000..9f0c9fb
--- /dev/null
+++ b/2015/21/Makefile
@@ -0,0 +1,8 @@
+all:
+ sed '/# START PART 2/,/# END PART 2/d' puzzles.py >puzzle-1.py
+ sed '/# START PART 1/,/# END PART 1/d' puzzles.py >puzzle-2.py
+ chmod +x puzzle-[12].py
+
+.PHONY: clean
+clean:
+ rm -f puzzle-[12].py
diff --git a/2015/21/input b/2015/21/input
new file mode 100644
index 0000000..e749051
--- /dev/null
+++ b/2015/21/input
@@ -0,0 +1,3 @@
+Hit Points: 103
+Damage: 9
+Armor: 2
diff --git a/2015/21/puzzles.py b/2015/21/puzzles.py
new file mode 100644
index 0000000..48e8c4e
--- /dev/null
+++ b/2015/21/puzzles.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python3
+
+
+import itertools
+import math
+
+SHOP = [
+ ("Weapon", 8, 4, 0),
+ ("Weapon", 10, 5, 0),
+ ("Weapon", 25, 6, 0),
+ ("Weapon", 40, 7, 0),
+ ("Weapon", 74, 8, 0),
+ ("Armor", 0, 0, 0),
+ ("Armor", 13, 0, 1),
+ ("Armor", 31, 0, 2),
+ ("Armor", 53, 0, 3),
+ ("Armor", 75, 0, 4),
+ ("Armor", 102, 0, 5),
+ ("Ring", 0, 0, 0),
+ ("Ring", 0, 0, 0),
+ ("Ring", 25, 1, 0),
+ ("Ring", 50, 2, 0),
+ ("Ring", 100, 3, 0),
+ ("Ring", 20, 0, 1),
+ ("Ring", 40, 0, 2),
+ ("Ring", 80, 0, 3),
+]
+
+
+def wins(d: int, hp: int) -> bool:
+ turns = hp / d
+ if turns > int(turns):
+ turns = math.ceil(turns)
+
+ return (turns - 1) * d < 100
+
+
+def valid(e: tuple[tuple[str, int, int, int], ...]) -> bool:
+ w = a = r = 0
+ for i in e:
+ if i[0] == "Weapon":
+ w += 1
+ elif i[0] == "Armor":
+ a += 1
+ elif i[0] == "Ring":
+ r += 1
+ return (w == 1) and (a <= 1) and (r <= 2)
+
+
+def main() -> None:
+ with open("input", "r", encoding="utf-8") as f:
+ b_health, b_damage, b_armor = f.readlines()
+ b_health = int(b_health.strip().split(": ")[1])
+ b_damage = int(b_damage.strip().split(": ")[1])
+ b_armor = int(b_armor.strip().split(": ")[1])
+
+ # START PART 1
+ min_cost = 999999999999999999999999999999999999999999999999999999999
+ # END PART 1
+ # START PART 2
+ max_cost = 0
+ # END PART 2
+
+ for combs in [itertools.combinations(SHOP, i) for i in range(1, 5)]:
+ for comb in list(filter(valid, combs)):
+ cost = sum(x[1] for x in comb)
+ damage = sum(x[2] for x in comb)
+ armor = sum(x[3] for x in comb)
+ delta = (damage - b_armor) - (b_damage - armor)
+
+ # START PART 1
+ if (delta > 0) or ((delta == 0) and wins(damage - b_armor, b_health)):
+ min_cost = min(cost, min_cost)
+ # END PART 1
+ # START PART 2
+ if (delta < 0) or ((delta == 0) and not wins(damage - b_armor, b_health)):
+ max_cost = max(cost, max_cost)
+ # END PART 2
+
+ # START PART 1
+ print(min_cost)
+ # END PART 1
+ # START PART 2
+ print(max_cost)
+ # END PART 2
+
+
+if __name__ == "__main__":
+ main()