diff options
| author | Louis Burda <quent.burda@gmail.com> | 2020-12-08 21:53:34 +0100 |
|---|---|---|
| committer | Louis Burda <quent.burda@gmail.com> | 2020-12-08 21:53:34 +0100 |
| commit | 61c19fd58a9c32919b9b06d38dd9ba202cf43bfb (patch) | |
| tree | 716d58ee8979d3df123acfedcd5cb8472722d422 /src/24 | |
| download | aoc2018-python-61c19fd58a9c32919b9b06d38dd9ba202cf43bfb.tar.gz aoc2018-python-61c19fd58a9c32919b9b06d38dd9ba202cf43bfb.zip | |
Solve 25 days
Diffstat (limited to 'src/24')
| -rw-r--r-- | src/24/input.txt | 23 | ||||
| -rw-r--r-- | src/24/notes.txt | 26 | ||||
| -rw-r--r-- | src/24/solve.py | 129 |
3 files changed, 178 insertions, 0 deletions
diff --git a/src/24/input.txt b/src/24/input.txt new file mode 100644 index 0000000..969be90 --- /dev/null +++ b/src/24/input.txt @@ -0,0 +1,23 @@ +Immune System: +2728 units each with 5703 hit points (weak to fire) with an attack that does 18 cold damage at initiative 12 +916 units each with 5535 hit points (weak to bludgeoning) with an attack that does 55 slashing damage at initiative 20 +2255 units each with 7442 hit points (weak to radiation) with an attack that does 31 bludgeoning damage at initiative 8 +112 units each with 4951 hit points (immune to cold) with an attack that does 360 fire damage at initiative 9 +7376 units each with 6574 hit points (immune to cold, slashing, fire) with an attack that does 7 bludgeoning damage at initiative 4 +77 units each with 5884 hit points (weak to slashing) with an attack that does 738 radiation damage at initiative 6 +6601 units each with 8652 hit points (weak to fire, cold) with an attack that does 11 fire damage at initiative 19 +3259 units each with 10067 hit points (weak to bludgeoning) with an attack that does 29 cold damage at initiative 13 +2033 units each with 4054 hit points (immune to cold; weak to fire, slashing) with an attack that does 18 slashing damage at initiative 3 +3109 units each with 3593 hit points with an attack that does 9 bludgeoning damage at initiative 11 + +Infection: +1466 units each with 57281 hit points (weak to slashing, fire) with an attack that does 58 slashing damage at initiative 7 +247 units each with 13627 hit points with an attack that does 108 fire damage at initiative 15 +1298 units each with 41570 hit points (immune to fire, bludgeoning) with an attack that does 63 fire damage at initiative 14 +2161 units each with 40187 hit points (weak to fire) with an attack that does 33 slashing damage at initiative 5 +57 units each with 55432 hit points (weak to cold) with an attack that does 1687 radiation damage at initiative 17 +3537 units each with 24220 hit points (weak to cold) with an attack that does 11 fire damage at initiative 10 +339 units each with 44733 hit points (immune to cold, bludgeoning; weak to radiation, fire) with an attack that does 258 cold damage at initiative 18 +1140 units each with 17741 hit points (weak to bludgeoning; immune to fire, slashing) with an attack that does 25 fire damage at initiative 2 +112 units each with 44488 hit points (weak to bludgeoning, radiation; immune to cold) with an attack that does 749 radiation damage at initiative 16 +2918 units each with 36170 hit points (immune to bludgeoning; weak to slashing, cold) with an attack that does 24 radiation damage at initiative 1 diff --git a/src/24/notes.txt b/src/24/notes.txt new file mode 100644 index 0000000..c81d665 --- /dev/null +++ b/src/24/notes.txt @@ -0,0 +1,26 @@ +infection and immune sys are armies + - made of groups of identical units + - group: + - same hitpoint + - same attack damage + - same initiative (who attacks first has highest) + - same weaknesses / immunities + - effective power = n of members * attack damage + +target selection: + - highest effective power chooses first sorted + if tie => higher initiative chooses first + - choose group it would damage most + if tie => largest effective power + if tie => largest intiative + if no group => no attack + +attack: + - attack in descending order of initiative + - regardless of army + - immune: 0 dmg + - weak: 2 x dmg + - only full death, units dont have dynamic health + + +(army, # of units, # of hp, initiative, dict of weaknesses / immunity, damage, type) diff --git a/src/24/solve.py b/src/24/solve.py new file mode 100644 index 0000000..020af79 --- /dev/null +++ b/src/24/solve.py @@ -0,0 +1,129 @@ +from sys import argv as args
+
+sinput = open("input.txt").read()
+
+immunesys = 0
+infection = 1
+ctype = 0
+
+# parse input from file
+def parseInput():
+ groups = list()
+ for l in sinput.split("\n"):
+ pl = parseLine(l)
+ if pl != None:
+ groups.append(pl)
+ return groups
+
+# parse line of input
+def parseLine(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 getEffectivePower(g):
+ return g["units"] * g["dmg"]
+
+def getDamage(attacker, defender):
+ dmg = getEffectivePower(attacker)
+ dmg *= (0 if attacker["dmgtype"] in defender["immune"] else 1)
+ dmg *= (2 if attacker["dmgtype"] in defender["weak"] else 1)
+ return dmg
+
+groups = parseInput()
+
+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 : (getEffectivePower(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 : (getDamage(group, x), getEffectivePower(x), x["initiative"]))
+ if getDamage(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["units"] > 0 and attacked["units"] > 0: # if attacker or defender is dead, no need to attack
+ dmg = getDamage(attacker, attacked)
+ attacked["units"] = max(0, attacked["units"] - dmg // attacked["unithp"]) # remove whole numbers of units
+
+ 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():
+ print(fight())
+
+def solve2():
+ global groups
+
+ immunewin = False
+ boost = 1
+ while not immunewin:
+ groups = parseInput()
+ 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
+
+ #print("boost:", boost)
+ print("units:", sum([v["units"] for v in groups]))
+
+def main():
+ if len(args) > 1:
+ if args[1] == "1":
+ solve1()
+ elif args[1] == "2":
+ solve2()
+
+main()
|
