#AoC 2023 | Day 4 | Solutions & Spoilers

1161 messages · Page 2 of 2 (latest)

arctic moss
#

I see in the documentation

#

thanks for the heads up

#

I was really using it to remember how to use decorators I think.

#

More accuracy is good.

tulip oar
#

Fair enough :)

arctic moss
#

honestly it's been so long since I did anything like this so it felt really good

tulip oar
#

re sub feels a little bit unnecessary but otherwise ok. I’d probably say just do a string split on : to remove the label first

arctic moss
#

What do you mean by "strong split"?

tulip oar
#

Autocorrect lol

#

I meant string

arctic moss
#

hahah

#

could you split it inside the list comprehension or would you break it apart for clarity?

tulip oar
#

This is how I did it

#

Interesting - you used recursion

#

I did not think to do that

arctic moss
#

I had a brain cramp and couldn't think of how to do it iteratively

#

recursion was easier

#

I was thinking in trees

tulip oar
#

The only thing I would say with recursion is that if you had a longer file, you could get into issues

#

Python and recursion are not the best of bedfellows

arctic moss
#

yeah I was worried about exceeding the recursion limit

tulip oar
#

Eh - with only 200 or so that’s not going to happen

#

But only one extra order of magnitude and it would

#

Typically I’d say - unless the problem screams recursion, don’t use it in Python

#

Go iteratively wherever you can

arctic moss
#

Oh wow it's only 1,000

tulip oar
#

Yup

#

And Python does not have tail call optimisation

#

In your code I’m not sure that would help you anyway

#

But the point is - it’s not really recursion-oriented

#

My code shows how it can be done iteratively

arctic moss
#

Yeah I will study that.

#

Thanks.

#

thanks for looking at my code too

tulip oar
#

One last thing

#

Why do you use double underscore prefix on one of your methods?

arctic moss
#

Did I biff that? Should it be single? I looked up how to do private-ish methods in Python and that's what I read.

tulip oar
#

It should be single

#

People think double is for private methods

#

It really really isn’t

arctic moss
#

ok thanks. I probably read single then just did double

tulip oar
#

Double underscore prefix does a thing called name mangling

#

Basically you can’t call the method in a normal way outside the class if you do it - you have to call it differently

#

People think that it’s Python’s way of doing private methods

#

What it actually is is a way to prevent subclasses from overriding parent class methods when the method is critical

arctic moss
#

I see.

tulip oar
#

You use double underscore if overriding the method would break class functionality

arctic moss
tulip oar
#

Ehhhhh

arctic moss
#

haha

tulip oar
#

I go back and forth on this one

#

There are serious problems with it

#

The articles aren’t written well

arctic moss
#

Like "grain of salt" problems or "don't trust it at all" problems?

tulip oar
#

The code examples are almost never in idiomatic Python

arctic moss
#

AH

#

gotcha

tulip oar
#

One code example was printing its results rather than adding to a list

#

Which just blew my mind

#

So yeah - many issues

arctic moss
#

Well that's good to know. Thank you.

tulip oar
#

But - sometimes if you have a problem and GFG is there, you might be very happy it is

#

A lot of other resources might be very technical to understand

#

Where GFG just goes straight to the point with the problem you have - mostly

arctic moss
#

I guess there's also probably some xy problem where you're looking up how to do something in a way you think you should do it

#

that might be tangential

#

anyways, thanks again for looking at my code. I'm going to look at your solution to see how I could have done it differently.

tulip oar
#

No worries!

#

Also I think you have an unused import

#

Itertools takewhile

arctic moss
#

oh shoot

tulip oar
#

Kinda a shame cos I wanted to see how you used it!

arctic moss
#

yeah I was going to go one way and did something else

tulip oar
#

I’ve never used that one. Never seem to have a reason to do so

arctic moss
#

that would've been for the iterative approach I was coming up with

tulip oar
#

Right

arctic moss
#

but like I said I broke my brain haha

#

it was late

tulip oar
#

!d itertools.takewhile

pallid canyonBOT
#

itertools.takewhile(predicate, iterable)```
Make an iterator that returns elements from the iterable as long as the predicate is true. Roughly equivalent to:

```py
def takewhile(predicate, iterable):
    # takewhile(lambda x: x<5, [1,4,6,4,1]) --> 1 4
    for x in iterable:
        if predicate(x):
            yield x
        else:
            break
arctic moss
#

I don't even know if it would've worked the way I envisioned it.

tulip oar
#

Interesting

#

Yah I’ve never used that

arctic moss
#

I might've been optimizing prematurely in my head.

tulip oar
#

I’m not sure if I ever will use that one

arctic moss
#

itertools has some interesting methods

tulip oar
#

So there’s a bunch I like

#

Windowing and chunking are the big ones

#

Product is good if you want to collapse multiple for loops

#

Combinations is sometimes useful

#

Cycle and accumulate are good to know for a AoC context - one Day 1 problem was literally just combining those two together lol

arctic moss
#

!d itertools.zip_longest

pallid canyonBOT
#

itertools.zip_longest(*iterables, fillvalue=None)```
Make an iterator that aggregates elements from each of the iterables. If the iterables are of uneven length, missing values are filled-in with *fillvalue*. Iteration continues until the longest iterable is exhausted. Roughly equivalent to:
tulip oar
#

There’s one that’s good to know about in theory

arctic moss
#

that one is interesting

tulip oar
#

In practice, it’s going to be a rare day that you need to zip two things of different lengths

#

It just never happens

arctic moss
#

some of the methods I was reading about in the itertools documentation fit that bill I think

tulip oar
#

Yup

arctic moss
#

or at least I'm not smart enough to think of a way to use them effectively

#

!d itertools.starmap

pallid canyonBOT
#

itertools.starmap(function, iterable)```
Make an iterator that computes the function using arguments obtained from the iterable. Used instead of [`map()`](https://docs.python.org/3/library/functions.html#map) when argument parameters are already grouped in tuples from a single iterable (when the data has been “pre-zipped”).

The difference between [`map()`](https://docs.python.org/3/library/functions.html#map) and [`starmap()`](https://docs.python.org/3/library/itertools.html#itertools.starmap) parallels the distinction between `function(a,b)` and `function(*c)`. Roughly equivalent to:

```py
def starmap(function, iterable):
    # starmap(pow, [(2,5), (3,2), (10,3)]) --> 32 9 1000
    for args in iterable:
        yield function(*args)
tulip oar
#

Stickie likes groupby but I’m not too interested in it

arctic moss
#

OH starmap -> *map

#

I get that now

tulip oar
#

Starmap is another odd one

#

I would just list comprehension and then use *

arctic moss
#

sure

tulip oar
#

Using map in general is odd for Python

arctic moss
#

Is it? I used to use map reduce and filter a lot in Perl

tulip oar
#

It’s similar to the recursion thing

#

Map and filter can just be replaced with comprehensions

#

And reduce

arctic moss
#

sure

#

I really like how nice and neat they made everything feel.

tulip oar
#

It’s very rare that you need to reduce. Many functions that would be nice for it already have a better way

#

Rather than reduce + add, use sum

arctic moss
#

sure

tulip oar
#

Rather than reduce + add, use math.prod

#

Rather than reduce + set operation, just use set operations because they take in multiple sets anyway

#

That’s the top three things I would want to use reduce for and there are already more idiomatic ways to approach them

#

Chain is also good to know as well but rarely will you need it

#

That’s about it really

arctic moss
#

math.chain?

tulip oar
#

Itertools chain

arctic moss
#

ok, I'll look it up

tulip oar
#

Use it if you need to concat a lot of stuff

#

It’ll prevent the formation of large temporary structures

arctic moss
#

That's good. That's what I like to do. I need to read more about how Python does that.

tulip oar
#

But yeah itertools is very important to know in general

#

The other one, IMO, is functools

#

functools.cache especially

#

If you love recursion you need to know that one :)

arctic moss
#

oh I'll check that out

#

I only looked at functools for wraps thusfar but I like fp

#

(if you haven't surmised yet)

#

I'll look into all the stuff we've discussed. Thank you very much for the insight.

#

I'm going to get lunch but I'm sure we'll talk again. Good luck at work tomorrow.

clever lintel
#

my part 1:

import re
total_points = 0


def get_numbers(str):
    numbers = re.findall(r'[0-9]+', str)
    return numbers


with open("aoc4.txt", 'r') as file:
    for line in file.readlines():
        numbers = get_numbers(line)
        matches = [n for n in numbers[1:11] if n in numbers[11:36]]
        if len(matches) > 2:
            total_points += 2**(len(matches) - 1)
        else:
            total_points += len(matches)

print(total_points)
clever lintel
#

part 1 and 2:

import re
total_points = 0
total_cards = 0
matches = []
bonus_cards = []


def get_numbers(st):
    numbers = re.findall(r'[0-9]+', st)
    return numbers


with open("aoc4.txt", 'r') as file:
    for line in file.readlines():
        numbers = get_numbers(line)
        matches = [n for n in numbers[1:11] if n in numbers[11:36]]
        bonus_cards.append([len(matches), 1])
        if len(matches) > 2:
            total_points += 2**(len(matches) - 1)
        else:
            total_points += len(matches)
    for x, card_a in enumerate(bonus_cards):
        total_cards += card_a[1]
        for card_b in bonus_cards[x+1: x + card_a[0] + 1]:
            card_b[1] += card_a[1]


print(total_points)
print(total_cards)
wooden widget
#
#!/usr/bin/python3


def read_input():
    with open("input.txt") as f:
        return read_cards(f.readlines())


def read_cards(lines):
    cards = {}
    for line in lines:
        card_num, winning_numbers, numbers = read_card(line)
        cards[card_num] = {"winning_numbers": winning_numbers, "numbers": numbers}
    return cards


def read_card(line):
    card_num, _, card_info = line.partition(":")
    winning_numbers, _, numbers = card_info.partition("|")

    card_num = int(card_num[5:])
    winning_numbers = [int(num) for num in winning_numbers.split()]
    numbers = [int(num) for num in numbers.split()]

    return (card_num, winning_numbers, numbers)


def count_wins(card):
    return sum([1 for num in card["numbers"] if num in card["winning_numbers"]])


def count_points(cards):
    return int(sum([2 ** (count_wins(card) - 1) for card in cards.values()]))


def play_cards(deck):
    owned_cards = [1 for _ in range(len(deck))]
    for card_num in range(len(deck)):
        cur_card = card_num + 1
        if wins := count_wins(deck[cur_card]):
            while wins:
                cur_card += 1
                owned_cards[cur_card - 1] += owned_cards[card_num]
                wins -= 1
    return sum(owned_cards)


if __name__ == "__main__":
    cards = read_input()
    print(count_points(cards))
    print(play_cards(cards))```
heavy temple
#

Has day 4 been released?

ember shell
plucky gate
#
def xmas_counter(data: list[str]) -> int:
    counter = 0

    for line in range(len(data)):
        for char in range(len(data[line])):
            if data[line][char] == "X":
                # check right
                right = "X"
                for i in range(1, 4):
                    if (char + i) >= len(data[line]):
                        break

                    right += data[line][char + i]

                # check left
                left = "X"
                for i in range(1, 4):
                    if (char - i) <= 0:
                        break

                    left += data[line][char - i]

                # check up
                up = "X"
                for i in range(1, 4):
                    if (line - i) <= 0:
                        break

                    up += data[line - i][char]
 
                # check down
                down = "X"
                for i in range(1, 4):
                    if (line + i) >= len(data):
                        break

                    down += data[line + i][char]

                # check diagonal (nord-ovest)
                no = "X"
                for i in range(1, 4):
                    if (line - i) <= 0 or (char - i) <= 0:
                        break

                    no += data[line - i][char - i]
                
                # check diagonal (nord-est)
                ne = "X"
                for i in range(1, 4):
                    if (line - i) <= 0 or (char + i) >= len(data[line - i]):
                        break

                    ne += data[line - i][char + i]
                
                # check diagonal (sud-ovest)
                so = "X"
                for i in range(1, 4):
                    if (line + i) >= len(data) or (char - i) <= 0:
                        break

                    so += data[line + i][char - i]
                
                # check diagonal (sud-est)
                se = "X"
                for i in range(1, 4):
                    if (line + i) >= len(data) or (char + i) >= len(data[line + i]):
                        break

                    se += data[line + i][char + i]
                
                if right == "XMAS":
                    counter += 1
                if left == "XMAS":
                    counter += 1
                if up == "XMAS":
                    counter += 1
                if down == "XMAS":
                    counter += 1
                if no == "XMAS":
                    counter += 1
                if ne == "XMAS":
                    counter += 1
                if so == "XMAS":
                    counter += 1
                if se == "XMAS":
                    counter += 1

    return counter
#

@keen locust

#

ik it's not so good, a lot of redundancy

keen locust
#

for all comparisons with 0, equality is ok

#

just can't be less than

plucky gate
keen locust
#

what?

plucky gate
#

wait

#

nvm

#

yeah that was the issue

#

ty

keen locust
#

np

fast stag
#

oh crap this is the wrong day. sorry about that

fast stag
plucky gate