Have I ever mentioned before how much I hate Recursion?

So, I feel like I mentioned on a previous Advent of Code post, half the problem of these puzzles is figuring out how to massage the input. Which I started to work with until I found the eval() function, which I don’t recall using before. But it basically will take something like a string that looks like a list, say, “[2,[4,5,6]]” and make it into a list of lists. Which solved the first problem I had.

Then there was the checks itself. The puzzle was a series of lists full of lists and integers, that needed to be sorted based on some criteria. It basically amounts to a series of if checks, if the data is a list or an int and what to do, if the lengths are the same or different, if one value is larger than the other. Except it can be lists in lists, hence the need for recursion. I felt like I was really close, but then scrapped that for a new approach. Then I got stuck again, then I realized I needed to loop through the internal list. Everything eventually lined up for part 1 nicely.

On to Part 2. Which basically amounts to, using the algorithm on the entire list, instead of just pairs.

I was actually a bit disappointed because I was sure I had come up with a clever way to solve this without the sorting algorithm. I left it in the code, but it’s not used. Here it is anyway.

## Not Used But This really feels like it should have worked.
def decoder(decode_list):
    new_list = []
    for each in decode_list:
        each = each.replace("[]", "0")
        each = each.replace("[", "")
        each = each.replace("]", "")
        each = each.replace(",", "")
        new_list.append(int(each[0]))
    new_list.sort()
    print(new_list)
    print((new_list.index(6)+1)*(new_list.index(2)+1))

The idea was, that I would flatten each list out to an integer, then sort the data that way. The target values needed were simply, 2 and 6. The initial sort put 2 and 6 at basically positions 2 and 6. because 2 is less than 200 when sorting. So it dawned on me, that 2 and 6, would always be the “first” at the “start of the 2s” and “start of the 6s”. So the I just added the first digit to the list, then sorted that, and took the first 2 and first 6. And it still didn’t work.

Figures it wouldn’t be that simple.

While contemplating using nested for loops, I decided to check some other solutions, and found something I had not used before, “cmp_to_key”. After reading up on it, it seems it can be used with the sort function to generate sorts based on a key value returned from a function.

So I modified my sort unction to use +1, -1, and 0 instead of True and False.

Aaaaand, it still didn’t sort, it wasn’t sorting. I had forgotten that I needed to use eval() on each entry, to turn it into Lists instead of Strings. My sort wasn’t working because it doesn’t work on Strings. So I corrected that and bam! Working.

from functools import cmp_to_key

with open("Day13Input.txt") as file:
    data = file.read()

split_data = data.split("\n\n")
decode_data = []
for line in data.replace("\n\n", "\n").split("\n"):
    decode_data.append(eval(line))

def compare_lists(left,right):
    # print(left)
    # print(right)

    if isinstance(left, int) and isinstance(right, int):
        # print(f"{left} {right}")
        if left < right:
            return 1
        elif left > right:
            return -1
        return 0

    if isinstance(left, list) and isinstance(right, list):
        for value in range(min(len(left), len(right))):
            check_value = (compare_lists(left[value], right[value]))
            # print(f"{left[value]} {right[value]}")
            # print(check_value)
            if check_value != 0:
                return check_value

        if len(left) < len(right):
            return 1
        elif len(left) > len(right):
            return -1
    if isinstance(left, int) and isinstance(right, list):
        return compare_lists([left], right)
    if isinstance(left, list) and isinstance(right, int):
        return compare_lists(left, [right])

    return 0

## Not Used But This really feels like it should have worked.
def decoder(decode_list):
    new_list = []
    for each in decode_list:
        each = each.replace("[]", "0")
        each = each.replace("[", "")
        each = each.replace("]", "")
        each = each.replace(",", "")
        new_list.append(int(each[0]))
    new_list.sort()
    print(new_list)
    print((new_list.index(6)+1)*(new_list.index(2)+1))

index_sum = 0
for i in range(len(split_data)-1):
    set1 = split_data[i].split("\n")[0]
    set2 = split_data[i].split("\n")[1]

    match = compare_lists(eval(set1), eval(set2))
    # print(match)

    if match == 1:
        index_sum += (i+1)


print(index_sum)
# 6373 Too high
# 5997 Too low
# 6187

decode_data.append([[2]])
decode_data.append([[6]])
#decoder(decode_data)
decode_data.sort(key=cmp_to_key(compare_lists), reverse=True)
# for each in decode_data:
#     print(each)
print((decode_data.index([[2]])+1)*(decode_data.index([[6]])+1))

# 23520