summaryrefslogtreecommitdiff
path: root/2018/aoc2018-d24.py
diff options
context:
space:
mode:
Diffstat (limited to '2018/aoc2018-d24.py')
-rw-r--r--2018/aoc2018-d24.py211
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);