day 15
beverage bandits
approach
this is the most structured solution of the year: a Grid class holding the open cells and a dict of Warriors by position. on its turn a warrior attacks the adjacent enemy with the lowest hp (ties in reading order) if there is one. otherwise it runs a bfs from its own square, with neighbours generated in reading order, to the nearest square next to an enemy, rebuilds the path from the parent map and takes one step, then tries to attack. a round ends early when someone finds no enemies left.
part 1 is the number of full rounds times the remaining hp. part 2 binary searches the elves' attack power between 3 and 200 for the lowest value where no elf dies, and reports that outcome.
the trick
binary search the elves' attack power, treating "no elf dies" as a yes/no test that flips once.
def part2(lines):
l, h = 3, 200
res = None
while l <= h:
m = (l + h) >> 1
poss, out = try_with_elves_attack_power(lines, m)
if poss:
res = (m, out)
h = m - 1
else:
l = m + 1
return res