#AoC 2022 | Day 13 | Solutions & Spoilers

1225 messages ยท Page 2 of 2 (latest)

gilded ridge
#

holy moly, that code is terrifying

finite orchid
#

?

gilded ridge
#

it's like my code, except you took an industrial grade hydraulic press to it

#

that's so compact that I'm surprised it doesn't collapse into a black hole when run

finite orchid
strange jolt
random canyon
#

I like to revisit my code and clean it up.. but my brain isn't thinky enough to get it as compact as some ๐Ÿ˜ฆ

finite orchid
strange jolt
#

i think it's pretty compact

gilded ridge
#

you people terrify me

strange jolt
#

good

#

be afraid

random canyon
#

You should be scared

gilded ridge
#

impostor syndrome through the roof right now lmao

random canyon
#

They have struck deals with creatures of unimaginable horror to do what they do

finite orchid
#

lol. just a matter of being too lazy to type it out longer while wanting to be able to reuse/maintain it later. ๐Ÿ™‚

strange jolt
#

i am a creature of unimaginable horror

gilded ridge
#

what does filter(None, ...) do?

finite orchid
jagged helm
#

can't you just do if type(a)==type(b)==int: return a-b and return len(aslist(a)) - len(aslist(b))

strange jolt
#

too long

jagged helm
#

shorter than what's in the code right now

strange jolt
#

xelf's code in general is too long

jagged helm
#

x

strange jolt
#

get it less than 300 bytes and then i might reconsider

finite orchid
gilded ridge
gilded ridge
#

oh, yeah, sorry

#

thanks

#

another little nugget to add to my python shorthand toolkit

strange jolt
#

have you heard of our lord and savior ~-?

gilded ridge
#

bitwise operators terrify me

finite orchid
gilded ridge
#

they're fun to operator overload though

jagged helm
#

i'm also scrolling through all the solutions everyday to learn fascinating stuff

strange jolt
jagged helm
#

reverse golf?

gilded ridge
#

bitwise operators make me feel bitdumb

finite orchid
#

hmmm, instead of eval I could have used json.loads

strange jolt
#

43 ^ 110

finite orchid
#
data = list(map(eval,filter(None,open(filename).read().splitlines())))
data = list(map(loads,filter(None,open(filename).read().splitlines())))

both work.

strange jolt
#

but loads is too long

finite orchid
#

again, I'm not trying to golf,

strange jolt
#

you're adding 1 byte + however many the import is

random canyon
#

here's my full code for posterity:

Packet = list["int | Packet"]


def compare_packets(p1: Packet, p2: Packet) -> int:
    if p1 and not p2:
        return 1

    if p2 and not p1:
        return -1

    for e1, e2 in zip_longest(p1, p2):
        if e1 is None:
            return -1

        if e2 is None:
            return 1

        if isinstance(e1, int) and isinstance(e2, int):
            if e1 < e2:
                return -1

            elif e2 < e1:
                return 1

        else:

            e1 = e1 if isinstance(e1, list) else [e1]
            e2 = e2 if isinstance(e2, list) else [e2]

            r = compare_packets(e1, e2)
            if r != 0:
                return r

    return 0


def part_1(packets: list[Packet]) -> int:
    index = 1
    total = 0

    for p1, p2 in zip(packets[::2], packets[1::2]):
        if compare_packets(p1, p2) == -1:
            total += index

        index += 1

    return total


def part_2(packets: list[Packet]) -> int:
    packets.extend(
        [[[2]], [[6]]]
    )
    sorted_packets = sorted(packets, key=cmp_to_key(compare_packets))

    i1 = sorted_packets.index([[2]]) + 1
    i2 = sorted_packets.index([[6]]) + 1

    return i1 * i2
gilded ridge
#

finally

#

a normal, sane person

#

with normal sane code

strange jolt
#

my code is normal and sane ๐Ÿ˜ 

finite orchid
#

I get that you are, and there's a channel explicitly for that. but please stop trying to assert that my code could be shorter.
I'm not trying to compete in golf

random canyon
gilded ridge
#

my eyes no longer require a built-in decompression algorithm to read code

gilded ridge
strange jolt
#

1177 bytes

random canyon
#

A way to go for 300KB, oh well. Maybe tomorrow.

strange jolt
#

ยฏ_(ใƒ„)_/ยฏ

#

glgl

random canyon
#

Hard coding the input into my file might get me a fair way ๐Ÿ˜„

finite orchid
strange jolt
#

using laser beams from their eyes

random canyon
#

A utility function I wrote that accepts a function to transform each line

finite orchid
#

hi-tech

random canyon
#

I passed in literal_eval

strange jolt
#

gotta use those laser beams

gilded ridge
#

Could someone please help me figure out why my assertion is failing?

sort_key = cmp_to_key(lambda a, b: -1 if is_right_order(a, b) else 1)
packets.sort(key=sort_key)

for i in range(len(packets) - 1):
    assert is_right_order(packets[i], packets[i + 1])
strange jolt
#

is_right_order returns false

#

yw

jagged helm
#

fax

#

but unhelpful

gilded ridge
#

i am convinced you are a compiler

strange jolt
gilded ridge
#
  • produces unintelligible minified code
strange jolt
#

it is perfectly intelligible

random canyon
gilded ridge
#
  • explains errors like a compiler traceback
strange jolt
#

we don't know how you implemented is_right_order

gilded ridge
#

that shouldn't matter though, right?

strange jolt
#

no, it does matter

gilded ridge
#

since if that was the sort key, even if the function was wrong, using the same function to validate should produce a consistent result

#

what's more, the function worked perfectly fine for me in part 1

#

and i haven't changed it in the slightest

strange jolt
#

if it's always false for some pair of inputs, then you will not produce a consistent result

#

for part 1, you might not encounter such a case, since you're only comparing pairs

#

but for part 2, you will need to compare every packet

#

one such comparison could return false both ways

gilded ridge
#

doesn't python's sorting algorithm work by comparing elements in pairs though?

strange jolt
#

by pairs, i meant the ones given in the input

gilded ridge
#

ohhhh right

#

so you're suggesting there could be an edge case where my function returns true or false for both orientations

strange jolt
#

correct

gilded ridge
#

and it just happened to be correct for part 1

#

therefore i never caught it

strange jolt
#

that's what i'm getting at

gilded ridge
#

i see

#

welp, seems like today's input being shorter than usual has come back to bite me in the butt

strange jolt
#

i cannot confirm this unless i know how you implemented your function, but that is my hypothesis

gilded ridge
#

i may have gotten really unlucky

#
def is_right_order(left: list[PacketData], right: list[PacketData]) -> bool:
    for pair in zip(left, right):
        if type(pair[0]) != type(pair[1]):
            pair = [[item] if isinstance(item, int) else item for item in pair]

        if pair[0] == pair[1]:
            continue

        match pair:
            case (int(), int()):
                return pair[0] < pair[1]
            case (list(), list()):
                return is_right_order(*pair)

    return len(left) < len(right)

here's my implementation

random canyon
# finite orchid now that is handy

I do the same stuff all the time when reading in the input, so figured time to write a func for that ๐Ÿ˜„

So far I have:

load_input_as_string()
load_one_line_as_list()
load_input_as_lines()  # most often used
load_input_as_chunks()  # every n lines or by delimiter (like blank line)
load_input_as_grid()

Most accept a callable to convert the values from a str to whatever.

strange jolt
#

comparing these two returns false both ways

#

so my hypothesis was correct

gilded ridge
#

hmm

#

debugging time

#

and thank you so much

strange jolt
#

np

finite orchid
#

anyone have a preference over these:

part1 = sum(i+2 for i in range(0,len(data),2) if rcmp(*data[i:i+2])<0)//2
part1 = sum(i for i,(a,b) in enumerate(zip(data[::2],data[1::2]), 1) if rcmp(a,b)<0)

they get the same answer. The second feels more pythonic, but more cluttered.

dire kiln
#

making a chunk function would be nice and pythonic

finite orchid
#

I suppose I also could have read them in as pairs, they er were after all split-table that way.

dire kiln
#

either chunking to get pairs

#

or flattening

finite orchid
# dire kiln or flattening

yeah you end up doing both ways regardless I suppose. Done with today I think. See you all tomorrow. ๐Ÿ™‚

magic breach
#

Seen a few people use the match statement so far, wondering if I did some kind of weird thing with the patterns

# `packet` being a tuple (Left, Right)
def run_packet(packet):

    match packet:
            case [[*L], [*R]]:
                for i, item in enumerate(zip(L, R)):
                    res = run_packet(item)
                    if res is not None:
                        return res
                if len(L) > len(R):
                    return False
                elif len(L) == len(R):
                    return None
            case [[*L], R]:
                return run_packet((L, [R]))
            case [L, [*R]]:
                return run_packet(([L], R))
            case [L, R]:
                if L > R:
                    return False
                elif L == R:
                    return None
    return True
obtuse lintel
#

you can check if they are lists or ints like this:

match packet:
  case [list(), list()]:
    ...
   case [list(), int()]:
    ...
finite orchid
magic breach
#

I see

#

I guess mine worked because of the order it checks the patterns in

finite orchid
plucky root
#

did everyone use eval for this

obtuse lintel
#

yea

sand trellis
south yarrow
tame heron
#

hated it when there was a [1, 2, os.system("sudo <redacted>"), 3, [4, 5]] in the input

plucky root
patent cave
#

Hm... this challenge seems to be impossible. One of the inputs isn't valid.

patent cave
#

os.system("sudo <redacted>") is not valid int

#

also, it would have to be __import__("os").system("") unless you pass the os import via globals

tame heron
#

||(i cant tell if youre joking but i was)||

patent cave
#

I am ๐Ÿ™‚

#

I finished the challenge this morning

proud bramble
# tame heron

This graph is wrong, there've been about 2 aoc bugs

#

(outage technically wasn't a bug but still)

#

I love xkcd substitutions lmao
The best part is that the prose is still accurately justified

#

Oh wait it's not manually justified

#

For some reason I thought it was lol

obtuse lintel
proud bramble
#

Basically lol

#

He's right, that is sad

#

Anyway part two is, very fittingly, ||recursive bugs||

bright wraith
#

Is there a way in numpy to select (and set a value) to a range of cells in the array?

sand trellis
#
import numpy as np
arr = np.zeros((5,5))
arr[2, 1:4] = 1

sets the middle 3 of the middle row to ones

#

if you want to do a column just switch the order

bright wraith
#

ah damn thats too obvious

#

I don't know how ive been using python for nearly 5 years and never bothered to learn numpy properly

sand trellis
#

i never officially learnt it tbh

#

just started using it for aoc 2021

#

and everytime i use it i read the docs

#

and eventually i got kinda familiar with some stuff

#

still a lot of numpy i don't know tho

bright wraith
#

another question, given a list of 3 items like [1,2,3] Is it possible to generate a list [1,2], [2,3] ?

#

i feel like this is something itertools will have

sand trellis
#

itertools.pairwise

proud bramble
bright wraith
#

Is there a way in numpy to find the first col / row that contains a certain element? Just thinking of a way of cropping this visulisation automatically?

sand trellis
#

you can do np.where(x==8) and take the minimal element of whichever one you want

#

if you want to find 8

bright wraith
#

whats the difference between .where and .argwhere ?

sand trellis
#

actually you should probably use np.nonzero() instead of np.where()

#

np.argwhere() is just transpose of np.nonzero()

#

and np.where() is equivalent to np.nonzero() if u only pass in the condition

bright wraith
#

You know solving these problems is hard enough, I cant imagine what it must take to write a script to generate problem inputs

sand trellis
#

it'd depend on the day

bright wraith
#

oh yikes I think my Pt2 will take forever to solve too ๐Ÿ˜‚

#

I assume theres a trick where you dont have to simulate every falling piece of sand?

#

oh it solved

#

and it was right

sand trellis
#

this is day 13 btw not 14

bright wraith
#

ah damn

nocturne tigerBOT
long mural
#

I had the same problem with my recursive solution to part 1. The problem turned out to be that returning the result of a recursion call was propagating True or False through to the checking function, causing premature return from the checking function. Ensure that the recursive function does NOT return True or False until the answer is found. In my case, the final line of the recursion function had to be changed to return None and ensuring that the integer comparisons and running out of arguments were caught for the real return values.

sand trellis
#

cleaned up my key function method for comparing lists

#
def nested_enumerate(num: list | V, index: tuple[int, ...]=()) -> list[tuple[tuple[int, ...], V]]:
    if isinstance(num, list) and num:
        return [vv for i, v in enumerate(num) for vv in nested_enumerate(v, (*index, i))]
    else:
        return [(index, num)]

def convert(index: tuple[int, ...], num: list | int) -> int:
    return sum(v * 69 ** i for i, v in enumerate(index)) + (num or len(index)-9)


def flatten_for_compare(num: list[list | int]) -> list[int]:
    return [convert(i, v) for i, v in nested_enumerate(num)]



def part_a_solver(list_pairs: list[list[list, list]]):
    return sum(i for i, (j, k) in enumerate(list_pairs, 1) if flatten_for_compare(j) < flatten_for_compare(k))


def part_b_solver(list_pairs: list[list[list, list]]):
    packets = sum(list_pairs, [[[2]], [[6]]])
    packets.sort(key=flatten_for_compare)
    return (packets.index([[2]])+1) * (packets.index([[6]])+1)
#

have no clue how to type hint nested lists of arbitrary nesting level

proud bramble
sand trellis
proud bramble
sand trellis
#

oh

#

huh

#

i thought they made it so typing.Union was equivalent to |

#

TIL

proud bramble
#

It is, with the exception that you can use forward declarations more easily with union

#

You can do it with | syntax if you put the whole expression in quotes I think

#

("Foo | list[Foo]")

sand trellis
#

i didn't know we could use strings in type hints like that

#

shame pycharm doesn't seem to know about it

#

or at least my version of it

proud bramble
#

It's basically an instruction for your type checker to eval whatever is in your string at type checking time

#

Also afaik only pylance supports recursive type definitions

sand trellis
#

that's a shame

#

no way to easily type hint like a tree I guess

proud bramble
#

I mean basically that

#

If you're using a class, you can forward declare its children

sand trellis
#

I mean like if you're using a list or a dict or something

#

if only pylance supports recursive stuff

proud bramble
#

I don't think so

#

You just have to guess how deep you wanna go I guess

#

And cast

sand trellis
#

tfw you have a 100 height tree

#

just ```py
A = list[int|list[int|list[int|list[int|]...]]]

proud bramble
#

I'd say just go two layers deep and cast

#

Like the stairs in sm64

sand trellis
#

cast?

proud bramble
#

Typing.cast

#

Essentially telling the type checker that you know better than it

#

If you know C you can think of it like a reinterpret

sand trellis
#

huh

#

still so much stuff i don't know about typing

proud bramble
#

Cast is a bit like a # type: ignore but it gives you a (thing you told the function it is) instead of an Any

sand trellis
#

so kinda like a walrus

proud bramble
#

?

#

How so