AoC 2016 Day 24: Venti

Source: Air Duct Spelunking

Part 1: Given a map of the form:

########### #0.1…..2# #.#######.# #4…….3# ###########

e>

The first part loads the map and the second part will flood fill out from each point. This will find the minimum distance from each named point to the given one, somewhat simplifying the problem.

Next, assume we have a list of points to visit in a given order. From that, we can add the distances between each pair to get the total distance:

def total_length(ordering):
    return sum(
        distances[p1][p2]
        for p1, p2 in zip(ordering, ordering[1:])
    )

Using that function, we can try all possible iterations using itertools.permutations . This is slightly complicated by having to start at point 0.

minimum_length = float("inf")
minimum_ordering = None

# Looks a bit funny since we have to start at 0
for ordering in itertools.permutations(names[1:], len(names) - 1):
    ordering = [0] + list(ordering)
    length = total_length(ordering)
    if not minimum_ordering or length < minimum_length:
        logging.info('New best ({} steps): {}'.format(length, ordering))
        minimum_length = length
        minimum_ordering = ordering

print('Best ordering ({} steps): {}'.format(minimum_length, minimum_ordering))

Part 2: Find the best route that also returns to the origin (point 0).

To do this, all we have to do is tweak our total_length function to include looping back to zero.

def total_length(ordering):
    # If we have to return back to the origin, the distance will from the last point to 0
    offset_ordering = ordering[1:]
    if args.must_return:
        offset_ordering += ordering[:1]

    return sum(
        distances[p1][p2]
        for p1, p2 in zip(ordering, offset_ordering)
    )

Then the same loop as above will find the best path using the new tweaked formula.