#AoC 2022 | Day 13 | Solutions & Spoilers
1225 messages ยท Page 2 of 2 (latest)
?
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
Yeah that describes my style for aoc "almost golf, but moderately readable"
here's mine
e=enumerate;d=sorted([*sum(x:=[[*map(f:=lambda n,i=():int!=type(n)and[l for k,v in e(n)for l in f(v,(*i,k))]or[sum((x<<i*9for i,x in e(i)),[n,len(i)-5][n==[]])],eval(p))]for p in open(0).read().replace(*'\n,').split(',,')],[]),[2],[6]]).index;print(sum(-~i*(v<p)for i,(v,p)in e(x)),~d([2])*~d([6]))```
I like to revisit my code and clean it up.. but my brain isn't thinky enough to get it as compact as some ๐ฆ
now that would be a golf example.
i think it's pretty compact
you people terrify me
You should be scared
impostor syndrome through the roof right now lmao
They have struck deals with creatures of unimaginable horror to do what they do
lol. just a matter of being too lazy to type it out longer while wanting to be able to reuse/maintain it later. ๐
i am a creature of unimaginable horror
what does filter(None, ...) do?
removes the blank lines
can't you just do if type(a)==type(b)==int: return a-b and return len(aslist(a)) - len(aslist(b))
too long
shorter than what's in the code right now
xelf's code in general is too long
x
get it less than 300 bytes and then i might reconsider
I did change the first one:
if type(a)==type(b)==int: return -1 if a<b else int(a!=b)
I hadn't thought about them being anything other than -1 or 1 because of how cmp works in other languages but you're probably right.
ah, right - so filter(None, x) is equivalent to (_ for _ in x if x)?
yeah
if _
oh, yeah, sorry
thanks
another little nugget to add to my python shorthand toolkit
have you heard of our lord and savior ~-?
bitwise operators terrify me
words never said. This is my full code, not me golfing. ๐
they're fun to operator overload though
i'm also scrolling through all the solutions everyday to learn fascinating stuff
oooo~ ~-~-~1 ^ 3 & 15 | 27 << 4 ๐ป
reverse golf?
bitwise operators make me feel bitdumb
hmmm, instead of eval I could have used json.loads
43 ^ 110
data = list(map(eval,filter(None,open(filename).read().splitlines())))
data = list(map(loads,filter(None,open(filename).read().splitlines())))
both work.
but loads is too long
again, I'm not trying to golf,
you're adding 1 byte + however many the import is
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
holy hell that's massive
my code is normal and sane ๐
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
Yes, I'm playing bowling and trying to get a 300
my eyes no longer require a built-in decompression algorithm to read code
๐
excuses /s
th- nvm
1177 bytes
A way to go for 300KB, oh well. Maybe tomorrow.
Hard coding the input into my file might get me a fair way ๐
how did you parse the input?
using laser beams from their eyes
A utility function I wrote that accepts a function to transform each line
hi-tech
I passed in literal_eval
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])
i am convinced you are a compiler
do you have a more helpful answer?
- produces unintelligible minified code
it is perfectly intelligible
data: list[Packet] = utils.load_input_as_lines(INPUT_PATH, skip_empty=True, func=literal_eval)
- explains errors like a compiler traceback
we don't know how you implemented is_right_order
that shouldn't matter though, right?
no, it does matter
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
now that is handy
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
doesn't python's sorting algorithm work by comparing elements in pairs though?
by pairs, i meant the ones given in the input
ohhhh right
so you're suggesting there could be an edge case where my function returns true or false for both orientations
correct
that's what i'm getting at
i see
welp, seems like today's input being shorter than usual has come back to bite me in the butt
i cannot confirm this unless i know how you implemented your function, but that is my hypothesis
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
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.
[[3], []]
[[[3]], [[2, [0, 6]], 3, [7, [9, 3, 2, 2, 1], []], [5, 9]], [6, [[4, 4]], 10, [[], [0, 0], 7, [9, 9, 4], 4]], [[[7, 2], [7, 9, 1, 10, 9], 9]], [[[3, 3, 9, 3, 10]], [], [[], 3, 6]]]
comparing these two returns false both ways
so my hypothesis was correct
np
that's great!
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.
enumerate(zip(*[iter(data)]*2)) is another option
making a chunk function would be nice and pythonic
I suppose I also could have read them in as pairs, they er were after all split-table that way.
you'll need to do something weird in one of the parts
either chunking to get pairs
or flattening
yeah you end up doing both ways regardless I suppose. Done with today I think. See you all tomorrow. ๐
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
yup, when you use a variable like L or R that's a wildcard and it will be filled by anything
you can check if they are lists or ints like this:
match packet:
case [list(), list()]:
...
case [list(), int()]:
...
match l, r:
case int(), int():
case int(), list():
case list(), int():
case list(), list():
Ah, yours works? Cool. I didn't test it.
did everyone use eval for this
yea
I did the same thing with my match statements
I think some used json.loads instead.
hated it when there was a [1, 2, os.system("sudo <redacted>"), 3, [4, 5]] in the input
well good thing i'm on windows then ๐ ๐ญ
Hm... this challenge seems to be impossible. One of the inputs isn't valid.
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
||(i cant tell if youre joking but i was)||
This graph is wrong, there've been about 2 aoc bugs
(outage technically wasn't a bug but still)
Also, there have been lots of bugs in AoC: https://adventofcode.com/2019/day/24
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
so day 24 of 2019 was basically about implementing game of life? XD
Basically lol
He's right, that is sad
Anyway part two is, very fittingly, ||recursive bugs||
Is there a way in numpy to select (and set a value) to a range of cells in the array?
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
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
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
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
itertools.pairwise
I've been using Python longer than that and never even installed it, so ยฏ_(ใ)_/ยฏ
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?
you can do np.where(x==8) and take the minimal element of whichever one you want
if you want to find 8
whats the difference between .where and .argwhere ?
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
You know solving these problems is hard enough, I cant imagine what it must take to write a script to generate problem inputs
it'd depend on the day
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
this is day 13 btw not 14
ah damn
Here's your reminder: do that
[Jump back to when you created the reminder](#1052090781218902086 message)
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.
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
Foo = typing.Union[int, list["Foo"]]
i get a TypeError: unsupported operand type(s) for |: 'str' and 'type'
That's why I specified to use union lol
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]")
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
Using strings like that is a forward declaration for a name that doesn't exist yet
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
I mean basically that
If you're using a class, you can forward declare its children
I mean like if you're using a list or a dict or something
if only pylance supports recursive stuff
tfw you have a 100 height tree
just ```py
A = list[int|list[int|list[int|list[int|]...]]]
cast?
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
Cast is a bit like a # type: ignore but it gives you a (thing you told the function it is) instead of an Any
so kinda like a walrus
