diff options
| author | Louis Burda <quent.burda@gmail.com> | 2023-04-07 17:18:18 -0400 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2023-04-07 17:19:39 -0400 |
| commit | 87ab487d59fa85dbe2afa55cc841b02805ae42ca (patch) | |
| tree | cd90ab715e1b5b5803674045dbafd6d51d27ac90 /src/24/solve.py | |
| parent | 1bcc82c5bfbde87edd03c01ffdf9ee5934681592 (diff) | |
| download | aoc2018-python-87ab487d59fa85dbe2afa55cc841b02805ae42ca.tar.gz aoc2018-python-87ab487d59fa85dbe2afa55cc841b02805ae42ca.zip | |
Reorder days into src
Diffstat (limited to 'src/24/solve.py')
| -rw-r--r-- | src/24/solve.py | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/src/24/solve.py b/src/24/solve.py new file mode 100644 index 0000000..fc89c84 --- /dev/null +++ b/src/24/solve.py @@ -0,0 +1,127 @@ +import sys
+sys.path.append("../common")
+import aoc
+
+immunesys = 0
+infection = 1
+ctype = 0
+
+# parse input from file
+def parse_input():
+ groups = list()
+ for l in aoc.data.split("\n"):
+ pl = parse_entry(l)
+ if pl != None:
+ groups.append(pl)
+ return groups
+
+# parse line of input
+def parse_entry(line):
+ global ctype
+ group = None
+ if "Immune" in line:
+ ctype = immunesys
+ elif "Infection" in line:
+ ctype = infection
+ elif line != "":
+ ls = line.split()
+ group = dict()
+ group["type"] = ctype
+ group["units"] = int(ls[0])
+ group["unithp"] = int(ls[4])
+ group["initiative"] = int(ls[-1])
+ group["weak"] = list()
+ group["immune"] = list()
+ if "(" in line:
+ parenthstr = line.split("(")[1].split(")")[0]
+ traits = parenthstr.split(";")
+ for traitstr in traits:
+ info = traitstr.split()
+ group[info[0]] = [v.replace(",","") for v in info[2:]]
+ dmginfo = line.split("does")[1].split("damage")[0].split()
+ group["dmg"] = int(dmginfo[0])
+ group["dmgtype"] = dmginfo[1]
+ return group
+
+def effective_power(g):
+ return g["units"] * g["dmg"]
+
+def damage(attacker, defender):
+ dmg = effective_power(attacker)
+ dmg *= (0 if attacker["dmgtype"] in defender["immune"] else 1)
+ dmg *= (2 if attacker["dmgtype"] in defender["weak"] else 1)
+ return dmg
+
+groups = parse_input()
+
+def fight():
+ global groups
+
+ lunits = 0
+
+ immalive = len([g for g in groups if g["type"] == immunesys])
+ infalive = len([g for g in groups if g["type"] == infection])
+
+ while immalive > 0 and infalive > 0:
+ # target selection
+ attacked = list()
+ attackpairs = list()
+ groups = sorted(groups, key = lambda x : (effective_power(x), x["initiative"]), reverse = True)
+ for group in groups:
+ # choose group of other army, which is not already being attacked and sort appropriately
+ enemies = [g for g in groups if g["type"] != group["type"] and g not in attacked]
+ if len(enemies) == 0:
+ continue
+ target = max(enemies, key = lambda x : \
+ (damage(group, x), effective_power(x), x["initiative"]))
+ if damage(group, target) != 0: # enemies which arent immune
+ attacked.append(target)
+ attackpairs.append((groups.index(group), groups.index(target)))
+
+ # attacking phase
+ attackpairs = sorted(attackpairs, key = lambda x : groups[x[0]]["initiative"], reverse = True)
+
+ for ap in attackpairs:
+ attacker = groups[ap[0]]
+ attacked = groups[ap[1]]
+ # if attacker or defender is dead, no need to attack
+ if attacker["units"] > 0 and attacked["units"] > 0:
+ dmg = damage(attacker, attacked)
+ # remove whole numbers of units
+ attacked["units"] = max(0, attacked["units"] - dmg // attacked["unithp"])
+
+ groups = [g for g in groups if g["units"] > 0]
+ immalive = sum([g["units"] for g in groups if g["type"] == immunesys])
+ infalive = sum([g["units"] for g in groups if g["type"] == infection])
+ units = immalive + infalive
+ if units == lunits:
+ return units
+ lunits = units
+
+ return units
+
+def solve1(args):
+ return fight()
+
+def solve2(args):
+ global groups
+
+ immunewin = False
+ boost = 1
+ while not immunewin:
+ groups = parse_input()
+ for g in groups:
+ if g["type"] == immunesys:
+ g["dmg"] += boost
+
+ fight()
+
+ immunewin = (sum([0 if g["type"] == immunesys else 1 for g in groups]) == 0)
+
+ boost += 1
+
+ aoc.debug("boost:", boost)
+
+ return sum([v["units"] for v in groups])
+
+aoc.run(solve1, solve2, sols=[10538, 9174])
|
