diff options
Diffstat (limited to '2018/aoc2018-d15-p1.py')
-rw-r--r-- | 2018/aoc2018-d15-p1.py | 324 |
1 files changed, 324 insertions, 0 deletions
diff --git a/2018/aoc2018-d15-p1.py b/2018/aoc2018-d15-p1.py new file mode 100644 index 0000000..6a2665d --- /dev/null +++ b/2018/aoc2018-d15-p1.py @@ -0,0 +1,324 @@ +#advent of code 2018 +#day 13 +#part 1 +import heapq + +f = open("input.txt",'r'); +Testing = False; +Testing = True; +if Testing: + f.close(); + f = open("testinput.txt",'r'); +Testing2 = False; +Testing2 = True; +if Testing2: + f.close(); + f = open("testinput2.txt",'r'); +Testing3 = False; +#Testing3 = True; +if Testing3: + f.close(); + f = open("testinput3.txt",'r'); +Testing4 = False; +#Testing4 = True; +if Testing4: + f.close(); + f = open("testinput4.txt",'r'); +Testing5 = False; +Testing5 = True; +if Testing5: + f.close(); + f = open("testinput5.txt",'r'); +Testing6 = False; +Testing6 = True; +if Testing6: + f.close(); + f = open("testinput6.txt",'r'); +Testing7 = False; +Testing7 = True; +if Testing7: + f.close(); + f = open("testinput7.txt",'r'); +NotTesting = False; +NotTesting = True; +if NotTesting: + f.close(); + f = open("input.txt",'r'); + #f = open("shit.txt",'r'); + +class thing: + def __init__(self, Pos, sign, currentID): + self.sign = sign; + self.PosX = Pos[1]; + self.PosY = Pos[0]; + self.IsAlive = False; + if (sign == "."): + self.IsPassable = True; + else: + self.IsPassable = False; + def __str__(self): + return self.sign; + + def SquaresInRange(self,bg): + squares = []; + p = (self.PosY-1,self.PosX); + if(bg[p].IsPassable): squares.append(p); + p = (self.PosY,self.PosX-1); + if(bg[p].IsPassable): squares.append(p); + p = (self.PosY,self.PosX+1); + if(bg[p].IsPassable): squares.append(p); + p = (self.PosY+1,self.PosX); + if(bg[p].IsPassable): squares.append(p); + return squares; + +class creature(thing): + def __init__(self, Pos, sign, currentID): + thing.__init__(self, Pos, sign, currentID); + self.ID = currentID; + self.health = 200; + self.damage = 3; + self.side = sign; + self.IsAlive = True; + if (self.side == "G"): + self.enemy = "E"; + if (self.side == "E"): + self.enemy = "G"; + + def death(self,bg): + self.IsPassable = True; + self.IsAlive = False; + self.health = 0; + unitcords[(self.PosY,self.PosX)] = None; + bg[(self.PosY,self.PosX)].IsPassable = True; + + + def movement(self,bg,PosNow,PosNew): + self.PosX = PosNew[1]; + self.PosY = PosNew[0]; + bg[PosNow].IsPassable = True; + bg[PosNew].IsPassable = False; + unitcords[PosNew] = self.ID; + unitcords[PosNow] = None; + + + def ScanProximity(self): + targets = []; + p = (self.PosY-1,self.PosX); + if p in unitcords and unitcords[p] in units and units[unitcords[p]].side == self.enemy and units[unitcords[p]].health >0: + targets.append(p); + p = (self.PosY,self.PosX-1); + if p in unitcords and unitcords[p] in units and units[unitcords[p]].side == self.enemy and units[unitcords[p]].health >0: + targets.append(p); + p = (self.PosY,self.PosX+1); + if p in unitcords and unitcords[p] in units and units[unitcords[p]].side == self.enemy and units[unitcords[p]].health >0: + targets.append(p); + p = (self.PosY+1,self.PosX); + if p in unitcords and unitcords[p] in units and units[unitcords[p]].side == self.enemy and units[unitcords[p]].health >0: + targets.append(p); + if targets: + targets.sort(key = lambda x: (units[unitcords[x]].health,units[unitcords[x]].PosY,units[unitcords[x]].PosX)); + return targets; + + + def IdentifyTargets_ALL(self,creaturelist,bg): + points = []; + for c in creaturelist: + if units[c].side == self.side or not units[c].IsAlive: continue; + points.extend(units[c].SquaresInRange(bg)); + return points; + + + def ShortestPaths(self, pointlist, bg): + paths = []; + pathlen = len(bg); + queue = []; + heapq.heappush(queue, (0,[(self.PosY,self.PosX)])); + visited = []; + while queue: + d, path = heapq.heappop(queue); + if d > pathlen: + return paths; + if path[-1] in pointlist: + if pathlen > len(path): + paths.append(path); + pathlen = len(path); + continue; + if path[-1] in visited: + continue; + else: + visited.append(path[-1]); + for a in bg[path[-1]].SquaresInRange(bg): + if a in visited: continue; + heapq.heappush(queue, (d+1, path + [a])); + return paths; + + def ChosenPath(self, pointlist, bg): + paths = self.ShortestPaths(pointlist, bg); + if len(paths) != 0: + pathends = min([p[-1] for p in paths]); + paths2= self.ShortestPaths([pathends], bg); + if len(paths2) != 0: + moves = []; + for p in paths: + moves.append(p[1]); + moves = sorted(moves, key = lambda m: (m[0],m[1])); + m = moves[0]; + self.movement(bg,(self.PosY,self.PosX),m); + + +def PathSearch(bg, Coordinates, Destination): + pass; + +def strike(attacker, target,bg): + target.health -= attacker.damage; + if (target.health <= 0): + target.death(bg); + +def armystrength(army): + strength = 0; + for soldier in army: + strength += units[unitcords[soldier]].health; + return strength; + +def armyscores(): + ElfScore = 0; + GobScore = 0; + for u in units: + if units[u].side == "G": GobScore += units[u].health; + if units[u].side == "E": ElfScore += units[u].health; + + return max(ElfScore,GobScore); + + + +def FindEnemies(team): + Enemies = 0; + for u in units: + if units[u].IsAlive and units[u].side != team: Enemies += 1; + + return Enemies; +############################################################################### + + +bgsizex = 0; +bgsizey = 0; +battleground = {}; +units = {}; +unitcords = {}; + +identifier = 11; + +for y, line in enumerate(f): + bgsizey += 1; + bgsizex = 0; + for x, c in enumerate(line): + bgsizex += 1; + if c == "G" or c == "E": + battleground[(y,x)] = thing((y,x),".",identifier); + units[identifier] = creature((y,x),c, identifier); + units[identifier].movement(battleground, (y,x), (y,x)); + identifier += 1; + else: + battleground[(y,x)] = thing((y,x),c,identifier); +''' +for y in range(bgsizey): + for x in range(bgsizex): + if (y,x) in unitcords: + print("X",end=""); + else: + print(battleground[(y,x)],end=""); #''' + + +unitcords = {}; +for u in units: + unitcords[(units[u].PosY,units[u].PosX)] = units[u].ID; + + +elfs = sum([1 for x in units if units[x].IsAlive and units[x].side=="E"]); +goblins = sum([1 for x in units if units[x].IsAlive and units[x].side=="G"]); + +ElapsedRounds = 0; + + +while goblins and elfs: + fighters = []; + for u in units: + if units[u].IsAlive: + fighters.append(units[u].ID); + + fighters = sorted(fighters, key = lambda u: (units[u].PosY,units[u].PosX)); + + for fighter in fighters: + if not units[fighter].IsAlive: continue; + if FindEnemies(units[fighter].side) <= 0: + print("loop broken FIGHTERS"); + break; + tars = units[fighter].ScanProximity(); + if tars: + tar = tars[0]; + strike(units[fighter],units[unitcords[tar]],battleground); + else: + CurrentPos = (units[fighter].PosY,units[fighter].PosX); + IdenTars = units[fighter].IdentifyTargets_ALL(fighters,battleground); + units[fighter].ChosenPath(IdenTars,battleground); + if CurrentPos == (units[fighter].PosY,units[fighter].PosX): + continue; + else: + tars = units[fighter].ScanProximity(); + if tars: + tar = tars[0]; + strike(units[fighter],units[unitcords[tar]],battleground); + + unitcords = {}; + for u in units: + unitcords[(units[u].PosY,units[u].PosX)] = units[u].ID; + + print("ROUND ", ElapsedRounds); + unitcords = {}; + for u in units: + unitcords[(units[u].PosY,units[u].PosX)] = units[u].ID; + + ElapsedRounds += 1; + elfs = sum([1 for x in units if units[x].IsAlive and units[x].side=="E"]); + goblins = sum([1 for x in units if units[x].IsAlive and units[x].side=="G"]); + ''' + for y in range(bgsizey): + for x in range(bgsizex): + if (y,x) in unitcords and unitcords[(y,x)] in units and units[unitcords[(y,x)]].IsAlive: + print(units[unitcords[(y,x)]].side,end=""); + else: + print(battleground[(y,x)],end=""); + print(); + ''' + + ''' + for y in range(bgsizey): + for x in range(bgsizex): + print((y,x), " - ", battleground[(y,x)].IsPassable); + print(); + print(); + ''' + + + +unitcords = {}; +for u in units: + unitcords[(units[u].PosY,units[u].PosX)] = units[u].ID; + print(u, f'({units[u].side} / ({units[u].PosY},{units[u].PosX})) ', units[u].health); + + +for y in range(bgsizey): + for x in range(bgsizex): + if (y,x) in unitcords and unitcords[(y,x)] in units and units[unitcords[(y,x)]].IsAlive: + print(units[unitcords[(y,x)]].side,end=""); + else: + print(battleground[(y,x)],end=""); +print(); + + +print("part 1 = ", ElapsedRounds, "*",armyscores(), "=",ElapsedRounds*armyscores()); +print("lil cheat = ", (ElapsedRounds-1), "*",armyscores(), "=",(ElapsedRounds-1)*armyscores()); +#I cant get the correct answer without implementing any short circuit logics +#thats why I print 2 outputs, for number of rounds and (number of rounds -1) + +#190777 p1 correct |