diff options
author | b-idea <test@test.com> | 2023-10-20 23:22:25 +0200 |
---|---|---|
committer | b-idea <test@test.com> | 2023-10-20 23:22:25 +0200 |
commit | 61073dcec8e896b84fafbd6110e2da55a0dd2d5e (patch) | |
tree | 22f2f3c647f02102974df58f727601e0c66d429e /2018/aoc2018-d24.py | |
parent | 5b8623d06472ec9a4bcac8ea1e201b7ae528d7af (diff) |
added days: 15_p1, 17, 20, 21, 22, 23_p1, 24, 25
Diffstat (limited to '2018/aoc2018-d24.py')
-rw-r--r-- | 2018/aoc2018-d24.py | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/2018/aoc2018-d24.py b/2018/aoc2018-d24.py new file mode 100644 index 0000000..e5b45f5 --- /dev/null +++ b/2018/aoc2018-d24.py @@ -0,0 +1,211 @@ +#advent of code 2018 +#day 24 +#part 1 and part 2 + +#this was very fun to do +#easier version of 2018 day 15 due to no pathfinding +#part 1 no probs, but it took me way more time to finish part 2 than it should have +#at first I didn't account for a possible stalemate, but it was late at night +#(I read the input and didn't see any stalemate scenarios based on weaknesses +#but now that I think about it I was reading the testinput from the example lol) +#so I was trying to debug whats wrong with my current code +#instead of adding the few lines to resolve the stalemates +#the groups were simply refusing to fight +#but to be fair, there definitely were some bugs in a previous version, +#because I still wasn't getting the answer even when milk boost value was getting huge + +import copy; #library required for the deepcopy function + +f = open("input.txt",'r'); +Testing = False; +#Testing = True; +if Testing: + f.close(); + f = open("testinput.txt",'r'); + +def readinput(group): + if group.find("(") != -1: + immu_weak = group[group.find("("):group.find(")")+1]; + group = group.replace(immu_weak, ""); + immu_weak = immu_weak.replace("(",""); + immu_weak = immu_weak.replace(")",""); + immu_weak = immu_weak.replace(", ",","); + if immu_weak.find(";") != -1: + if (immu_weak[0] == "i"): + i_i = 0; + w_i = 1; + elif (immu_weak[0] == "w"): + i_i = 1; + w_i = 0; + immu_weak = immu_weak.replace("weak to ",""); + immu_weak = immu_weak.replace("immune to ",""); + immu_weak = immu_weak.replace(" ",""); + iw = immu_weak.split(";"); + immu = iw[i_i].split(","); + weak = iw[w_i].split(","); + elif immu_weak[0] == "w": + immu_weak = immu_weak.replace("weak to ",""); + immu = []; + weak = immu_weak.split(","); + else: + weak = []; + immu_weak = immu_weak.replace("immune to ",""); + immu = immu_weak.split(","); + else: + immu = []; + weak = []; + group = group.replace("units each with", " "); + group = group.replace("hit points", " "); + group = group.replace("with an attack that does", " "); + group = group.replace("damage at initiative", " "); + g = group.split(); + gr = [int(x) for x in g[:-2]]; + gr.append(g[-2]); + gr.append(int(g[-1])); + gr.append(immu); + gr.append(weak); + return gr; + + +class army: + def __init__(self, side, ID, inputlist): + self.side = side; + self.id = ID; + self.units = inputlist[0]; + self.hp = inputlist[1]; + self.dmgVal = inputlist[2]; + self.dmgType = inputlist[3]; + self.initiative = inputlist[4]; + self.immune = inputlist[5]; + self.weak = inputlist[6]; + self.IsDead = False; + self.IsTargeted = False; + self.Target = None; + def __str__(self): + return f'<{self.side}>: {self.units} units each with {self.hp} hit points (immune to {self.immune}; weak to {self.weak}) with an attack that does {self.dmgVal} {self.dmgType} damage at initiative {self.initiative}'; + + def EffectivePower(self,TargetWeak,TargetImmune): + DamageDealt = self.units*self.dmgVal; + if self.dmgType in TargetWeak: + DamageDealt = DamageDealt*2; + elif self.dmgType in TargetImmune: + DamageDealt = 0; + return DamageDealt; + + def TakeDamage(self, DamageReceived): + UnitsKilled = DamageReceived//self.hp; + self.units -= UnitsKilled; + if self.units <= 0: + self.IsDead = True; + self.units = 0; + +############ +#parse input +groups = {}; +side = "imm"; +currentid = 11; +f.readline(); +for l in f: + if(l=="\n"): break; + groups.update({currentid:army(side,currentid,readinput(l))}); + currentid += 1; +f.readline(); +side = "inf"; +for l in f: + if(l=="\n"): break; + groups.update({currentid:army(side,currentid,readinput(l))}); + currentid += 1; +f.close(); + +immsys = 0; +infect = 0; +for g in groups: + if groups[g].side == "imm": immsys +=1; + if groups[g].side == "inf": infect +=1; + +milk = 0; +groupcopy = copy.deepcopy(groups); #deepcopy of groups to reset them + +winner = "inf"; #just to initiate the algo + +#keep doing battles until immune system wins +while winner == "inf": + groups = copy.deepcopy(groupcopy); + #count the initial number of groups for immune system and infection + #apply milk booster to immune system + immsys = 0; + infect = 0; + for g in groups: + if groups[g].side == "imm": immsys +=1; + if groups[g].side == "inf": infect +=1; + if groups[g].side == "imm": groups[g].dmgVal += milk; + groups[g].IsDead = False; + + #battle algorythm + while immsys > 0 and infect > 0: + kills = 0; + UnitsBefore = 0; + for g in groups: + UnitsBefore += groups[g].units; + #phase 1 target selection + TSqueue = [g for g in groups if groups[g].IsDead == False]; + TSqueue = sorted(TSqueue, key=lambda g: (groups[g].EffectivePower([],[]),groups[g].initiative), reverse = True); + for a in TSqueue: + groups[a].Target = None; + PossibleTargets = [g for g in groups if groups[g].IsDead == False and groups[g].side != groups[a].side]; + PossibleTargets = sorted(PossibleTargets, key=lambda g: (groups[a].EffectivePower(groups[g].weak,groups[g].immune),groups[g].EffectivePower([],[]),groups[g].initiative), reverse=True); + for t in PossibleTargets: + if groups[t].IsTargeted == False and groups[a].EffectivePower(groups[t].weak,groups[t].immune) > 0: + groups[a].Target = int(t); + groups[t].IsTargeted = True; + break; + + #phase 2 attacking + ATqueue = TSqueue.copy(); + ATqueue = sorted(ATqueue, key=lambda g: groups[g].initiative, reverse = True); + for a in ATqueue: + if groups[a].IsDead or groups[a].Target == None: continue; + t = groups[a].Target; + groups[t].TakeDamage( groups[a].EffectivePower(groups[t].weak,groups[t].immune) ); + + #reset the IsTargeted parameter for the next iteration of the battle + #count the groups of each side and calculate kills + immsys = 0; + infect = 0; + UnitsAfter = 0; + for g in groups: + groups[g].IsTargeted = False; + if groups[g].side == "imm" and groups[g].IsDead == False: immsys +=1; + if groups[g].side == "inf" and groups[g].IsDead == False: infect +=1; + UnitsAfter += groups[g].units; + + #if there were no kills in the current iteration of battle - finish the battle + kills = UnitsBefore - UnitsAfter; + if kills == 0: + break; + + #declare the winner (infection wins in case of a stalemate) + if kills == 0: + winner = "inf"; + elif immsys == 0: + winner = "inf"; + else: + winner = "imm"; + + #calculate part 1 + if milk == 0: + part1 = 0; + for g in groups: + if groups[g].side == winner and groups[g].IsDead == False: + part1 += groups[g].units; + + milk += 1; #raise milk booster for upcoming new battle + +#calculate part 2 +part2 = 0; +for g in groups: + if groups[g].side == winner and groups[g].IsDead == False: + part2 += groups[g].units; + +print("part 1 = ", part1); +print("part 2 = ", part2); |