/aocg/ - Advent of Code 2017 General #11

Exactly where your waifu belongs edition
Previous thread adventofcode.com/
>Advent of Code is a series of small programming puzzles for a variety of skill levels. They are self-contained and are just as appropriate for an expert who wants to stay sharp as they are for a beginner who is just learning to code. Each puzzle calls upon different skills and has two parts that build on a theme.
You need to register with an account but you can appear as anonymous.

The new leaderboard with empty space is
join-code: 43046-941b8011

The old (full) leaderboard is
join-code: 194764-c554ff91

Other urls found in this thread:

ghostbin.com/paste/e22c9
hastebin.com/aqafiruzef.py
pastebin.com/wy1kfT8E
github.com/iamevn/advent-of-code-solutions/blob/master/2015/07-python/07.py
paste.pound-python.org/show/LC5GdQlc4vHTtt0ZBUtv/
paste.pound-python.org/show/gaKFaVVDYiULl6FE4kek/
paste.i-am-webscale.xyz/paste/1687097244
pastebin.com/h9DjUpbM
en.wikipedia.org/wiki/Cycle_detection#Algorithms
twitter.com/SFWRedditVideos

...

>that pic
Really nice

I'm working through the previous years' problems, and I just spent upwards of 8 hours on 2015 day 7, which yielded this godawful mess:

ghostbin.com/paste/e22c9
hastebin.com/aqafiruzef.py
pastebin.com/wy1kfT8E

What is the "right" way to do it? Cause I sure as shit don't know it right now.

>tfw your part 1 was a lexing routine to throw out all the garbage but then the garbage was what you had to look at in part 2

Today's problem had a lot of missed potential, in my opinion.

Same. I spent quite a bit of time coming up with a regex to throw out all the garbage. I managed to count the garbage, but now I'm rewriting it using an automaton.

I've came up with 3 possible solutions
the craziest was to actually emulate the circuits with coroutines and channels
another to just parse lines and then iterate over them, check if it has all dependencies and remove it from list until list length is zero, O(n^2) complexity probably but easiest to implement
the third was to take it recursively backwards , make some queue and go from desired output wire, adding to queue new dependencies until everything reaches input wires and it all resolves, would say more right than n.2

with open('input9.txt') as f:
for l in f.readlines():
stream = l.strip()

depth, nGroups, nCanceled = 0, 0, 0
ignore , garbage = False, False

for c in stream:

if ignore:
ignore = False

else:
if not garbage:
if c == '{':
depth += 1
nGroups += depth
if c == '}':
depth -= 1
if c == '' and c != '!':
nCanceled += 1
if c == '>':
garbage = False

if c == '!':
ignore = True

print(nGroups, nCanceled)


nothing fancy, but do you see any ways to optimise the control flow here?

virgin parser vs chad eval

let garbageChars = 0;

const removeComments = (str = '') => str.replace(/!./g, '');
const removeLetters = (str = '') => str.replace(/[^{},]/g, '');
const throwGarbageOut = (str = '') =>
str.replace(/\/g, s => ((garbageChars += s.length - 2), ''));
const makeArrs = (str = '') => str.replace(/\{/g, '[').replace(/\}/g, ']');

const countGroupPoints = (group, depth = 1) =>
depth +
group.map(gr => countGroupPoints(gr, depth + 1)).reduce((a, b) => a + b, 0);

const code = [removeComments, throwGarbageOut, removeLetters, makeArrs].reduce(
(s, f) => f(s),
group
);

const groups = eval(code);

console.log(countGroupPoints(groups));
console.log(garbageChars);

>what little signal is ultimately sent to wire a
The pairs of which the input list consists are in the wrong order, the first element in the pair is what you would use as a value, while the second element is what you would use as a key, so first you're gonna have to reverse the pairs, and then convert the list of pairs into a map. From there, it's only a matter of looking up the value of a and recursively evaluating stuff until your reach the bottom, like this:
a => lx
look up lx in the map
lx => lw OR lv
look up lw and lv, OR their values
...

This solution doesn't require you to actually build the circuit, and it's fairly efficient.

Is there actually going to be one on Christmas?

>programming on the anniversary of the birth of our Lord

That's what I'm saying, I'm hoping there's not one because I'm not going to be doing it. Might not even do day 24 if it's too complicated.

Well there has been one for the past two years, but yeah, I doubt i'll be doing it on the day either.

To people who have done the past years, when does this get hard?

in two or three days the constraint satisfaction and search problems will begin. Until then, parsers.

oops

previous years had a couple of intermediate difficulty problems by this point.

>tfw hacky regex solution is faster than FSM
JUST

If you're using python then the standard library functions will tend to be faster than whatever python you write because they're written in C

wtf today challenge was literally a bunch of if/else and switch.
Are these getting easier and easier?

I hope the next ones are harder than that because it's just a matter of "how quickly can you shit some code" right now

they're not getting easier nor harder, just require different skillsets in programming, if you're somewhat alright with most typical CS stuff then you'll find each of them relatively easy, as is the case every year

Advent of Code creator thinks enough people found day 8 hard; the day where pajeets could do what they always do and stick half of it in eval()

has JavaScript made people forget how to code?

Day7part2, despite me solving it (with few tries) took me AGES to write a proper solution afterwards (I came back to it).

Day9 was kinda hard because I failed to understand that the puzzle was exactly about that: when something looks complex but has simple and elegant solution.

Cant say day8 was hard. even without eval being part fo C# I did it in a hour or less

>day 7 seriously expected a recursive solution

>Crawling a tree without recursion
from re import match
from collections import defaultdict

class treeNode():
parent = None
weight = 0
children = []
name = ""

def __init__(self):
self.weight = 0
self.children = []
self.name = ""
self.parent = None

def getWeight(currentNode):
totalWeight = currentNode.weight
for nodes in currentNode.children:
totalWeight += getWeight(nodes)

return totalWeight

def getBranchesWeight(currentNode):
branchesWeight = []
for nodes in currentNode.children:
branchesWeight.append(getWeight(nodes))

return branchesWeight

def findWrongProgram(currentNode, dif = 0):
branchesWeight = getBranchesWeight(currentNode)
if (len(branchesWeight) == 0):
return currentNode, dif

if (dif == 0):
maxWeightOccurances = branchesWeight.count(max(branchesWeight))
if (maxWeightOccurances == 1):
dif = max(branchesWeight) - min(branchesWeight)
else:
dif = min(branchesWeight) - max(branchesWeight)
if (dif > 0):
branchNum = branchesWeight.index(max(branchesWeight))
else:
branchNum = branchesWeight.index(min(branchesWeight))

if (len(set(branchesWeight)) == 1):
return currentNode, dif

sortedWeights = sorted(branchesWeight)

branchToCheck = currentNode.children[branchNum]

return findWrongProgram(branchToCheck, dif)


treeNodes = defaultdict(treeNode)

with open("day7input.txt") as inputData:
for row in inputData:
m = match("^(\w+) \((\d+)\)(?: -> )?(.*)$", row)
prog = m.group(1)

treeNodes[prog].weight = int(m.group(2))
treeNodes[prog].name = prog

if m.group(3):
for el in m.group(3).split(", "):
treeNodes[prog].children.append(treeNodes[el])
treeNodes[el].parent = treeNodes[prog]

root = treeNodes[prog]

while (root.parent is not None):
root = root.parent
part2branch, dif = findWrongProgram(root)

print("Part 1 answer: {}".format(root.name))
print("Part 2 answer: {} ".format(part2branch.weight - dif, part2branch.name))

everybody here eval()'d their way out of it

>has JavaScript made people forget how to code?
My solution was javascript and didn't use eval

>Yeah I'll just wait for my tree to exceed the recursion depth limit and then I'll do it the right way

This problem (2015 day 7, not today's) wasn't as easy as I expected. First, I had to fuck around with formatting the input in vim for like 20 minutes, because the rows didn't all have the same layout. Then I implemented the program using Erlang's integers, but turns out the problem asked for 16-bit unsigned ints, while Erlang only has arbitrary precision signed ints, so I had to use binaries, and I had to implement my own binary or, and, lshift, rshift, and not functions, because the standard library doesn't have those. At this point, my program worked, except it had such awful performance that it couldn't give an answer to the real input in about 5 minutes, at which point I stopped it. The reason for this is that I was re-calculating the same values over and over. Imagine you have a Fibonacci function that works like this: Fib(N) = Fib(N-1) + Fib(N-2). Clearly, you have to calculate Fib(N-2) to calculate Fib(N-1), and then you have to calculate it again when you add it to Fib(N-1). This obviously means that you will calculate the same value an exponentially increasing number of times the deeper you go. The program I wrote had a similar problem, because one wire could be the input of multiple logic gates, meaning my program ended up calculating the value of the same wire multiple times. The solution to this was updating the value of the wire in the map after I calculated it, which meant I had to pass around the map, because >muh functional meme. It was worth it tho, because my program gives the result in about 1-2 milliseconds (timer:tc returns the time in microseconds, that's why it says 1020).

>recursion depth limit
so this is the power of python....

recursion is not pythonic, retard

>recursion is not pythonic
so this is the power of python....

Redid today's in Elixir, but it takes three times as long as my Ruby solution to complete. How performant is yours compared to Ruby/Python? I was expecting mine to at least match performance with those. Is the benefit to Erlang/Elixir only in cases where concurrency matters?

defmodule Day09 do
def parse(input) do
store = %{count: 0, depth: 1, skip: false, garbage: false, garbage_count: 0}
parse_helper(input, store)
end

def parse_helper([], store), do: {store[:count], store[:garbage_count]}

def parse_helper([h | t], store) do
case {store[:garbage], store[:skip]} do
{true, true} -> parse_helper(t, %{store | skip: false})
{true, false} -> case h do
">" -> parse_helper(t, %{store | garbage: false})
"!" -> parse_helper(t, %{store | skip: true})
_ -> parse_helper(t, %{store | garbage_count: store[:garbage_count] + 1})
end
{false, _} -> case h do
"{" -> parse_helper(t, %{store | count: store[:count] + store[:depth], depth: store[:depth] + 1})
"}" -> parse_helper(t, %{store | depth: store[:depth] - 1})
"

Fucking same. I had such a nice script to create a list of all groups without garbage, and then I realized it was a terrible way of going about it.

0.0035 seconds to parse
0.0045 seconds to read the input and parse it

My Erlang program does it in a few hundred microseconds, so less than a millisecond (nine_a: problem 1, nine_b : problem 2, nine_combined: problem 1 and 2 at the same time). The problem is that I'm not reading from files, I'm passing the input in the shell, so our times aren't really comparable.

Posted the wrong pic.

Mine is:
0.0064 to parse
0.0130 to read the input and parse.

Is it inefficient to store persistent data in one map instead of individual variables? I'm wondering why else mine would be so much slower, given it all compiles down to BEAM code in the end for both languages.

I don't know much about elixir, but it seems to me that you're comparing against strings, while I'm comparing against character values by using the $ operator. And yeah, using a map probably adds some overhead too.

Oh wow I was completely oblivious to all the conversion that must have been happening under the hood, thanks user. Getting times of around 0.003 now when I benchmark it from inside the code.

For Day 3: Spiral Memory, do you actually have to create an array of that size or is there a simple mathematical trick to it

Part one can do without building the spyral, part two may be possible but i'm too stupid for that so i build an array.

Nobody found a trick for part 2, so tell us if you do

who here /deeply nested logic/

for part 1 theres a closed formula, for part 2 you can dynamically increase your array using a 2d dictionary or similar.

Part 1: calculate the xy coordinates of N in the spiral with the origin set to 0 using basic arithmetic, then add abs(x)+abs(y) to get the Manhattan distance.
Part 2: use a map where the (x, y) coordinate tuples of the already visited squares are the keys, and do lookups based on those. When you want to know the value of n, get its xy coordinates, and get the values associated with (x-1, y), (x, y-1), (x+1, y), (x, y+1), (x-1, y-1), (x-1, y+1), (x+1, y-1), and (x+1, y+1) from the map. Use get with a default value of 0 in case some of the neighbours are not present, because they haven't been visited yet. You're still constructing the spiral in a way, but this way you can avoid all the ugliness associated with creating a resizeable 2D array.

I didn't want the answer senpai. Just a hint at the direction to take.

I wonder if it's more idiomatic to break the cases out into pattern-matched function definitions instead.

It's not the answer, building the coordinate function is hard, and part two of my answer is basically just "use a fucking map".

I think mine came out pretty well
github.com/iamevn/advent-of-code-solutions/blob/master/2015/07-python/07.py
>parse lines into dictionary mapping wire names to objects representing that wire's instructions
>evaluate each wire, recursively evaluating its dependencies if they haven't been evalutated yet

# 16 bit ops (unsigned)
def NOT(a):
return 65535 - a
def AND(a, b):
return a & b
def OR(a, b):
return a | b
def LSHIFT(a, b):
return (a * (2 ** b)) & 65535
def RSHIFT(a, b):
return a // (2 ** b)
was what I felt was the hardest part. pretty sure LSHIFT and RSHIFT don't break under edge cases. Also they never tried to shift a 1 past the left edge of a number so that mask on LSHIFT is unnecessary.

This
Getting the next (x,y) from the previous is not immediate, you have to write it down on paper
Do tell us if you find another solution than building the spiral

this challenge seems a bit unclear to me.

for example:
lf AND lq -> ls


are lf and lq register names, initialised to 0?
or are they register names initialised to the 2-byte values they represent?

If only APL had suffix this would've been simpler.
This makes me want to start the JT\APL project I had in mind.

in this challenge, registers don't have a default value. initial values only come in via 123 -> foo instructions (except for part b where one single register has an initial value before running anything).

>getting the next (x, y) from the previous is not immediate
It's fairly straightforward, considering you get it them from the next i, and not from the previous (x, y), somewhat like this:
solve(max)
map.add((0,0), 1) //set the value of the middle square to 1

for(i = 1; ; ++i)
sum = getSumOfNeighbours(i, map)
if(sum > max)
return sum
else
coords = getCoordinates(i)
map.add(coords, sum)

getSumOfNeighbours(i, map)
(x, y) = getCoordinates(i)
left = map.getOrDefault(map, (x-1, y), 0)
right = map.getOrDefault(map, (x+1, y), 0)
...
return left + right + ...

Getting the coordinates is somewhat ugly, but it can be done in O(1) time, pic related.

so in my input i've got like 20 lines before anything is set, do I just ignore those?

nope, those should still get run, they just need to run after any lines they depend on.
the idea is that the input describes a circuit where everything is just happening at once

So basically you did part 1 without summing x and y, that's pretty smart
What I mean by "getting the next (x, y) from the previous" is this :
def nextij(i,j):
if i < j or (i == j and i > 0):
if i

ah i see, thanks.

def nextspace():
# yield spiral coords forever
# (1 right, 1 up, 2 left, 2 down, 3 right, 3 up, 4 left, etc)
def dir():
while True:
yield lambda space: (space[0] + 1, space[1]) # right
yield lambda space: (space[0], space[1] + 1) # up
yield lambda space: (space[0] - 1, space[1]) # left
yield lambda space: (space[0], space[1] - 1) # down
def distance():
d = 1
while True:
yield d
yield d
d += 1
D = dir()
M = distance()
space = (0, 0)
steps = 0
nextspace = lambda x: x
while True:
if steps == 0:
steps = next(M)
nextspace = next(D)
space = nextspace(space)
steps -= 1
yield space

shell = ceil(sqrt(n-1)/2.0)
dists2sqs = (shell*2-1)^2-(shell*2-2)^2
sidepos = (n-1)%(dist2sqs/4) - (dist2sqs/8)
manhattenDistance = 2*(shell-1) - abs(sidepos)

there you go, day 3 in O(1)
take n=22 for example
shell = ceil(sqrt(21)/2.0) = ceil(2.291...) = 3
dist2sqs = 5^2-4^2 = 16
sidepos = 21%(16/4) - 16/8 = 1 - 2 = -1
manhattenDistance = 4 - abs(-1) = 3

tell me if I fudged an offbyone
now what was part2 to this problem?

today. Still haven't finished day 7

part 1: paste.pound-python.org/show/LC5GdQlc4vHTtt0ZBUtv/
part 2: paste.pound-python.org/show/gaKFaVVDYiULl6FE4kek/

>yield lambda space:
How does this work? I'm a python brainlet, I only use for and while

it yields a function taking the current position and returning the new position. you can think of it as an infinte stream of functions.

all three of those functions yield values instead of returning. you can iterate over them and they'll yield a sequence of values that can be used in the iteration. you can also pull successive values out with next().
yield is basically like return except the function sticks around to continue from the yield again next time it's called.

I finished my solution to day 3 in racket
paste.i-am-webscale.xyz/paste/1687097244

Oh I get it now
Thank you anons, I learned something new

nice work user

Nice

edit:
dist2sqs = (shell*2-1)^2 - (shell*2-3)^2

and in the example,
5^2-4^2 doesn't equal 16, 5^2-3^2 = 16

I'm doing last years challenges while waiting for the new one.

> Tfw working from 3PM to 1AM today

RIP leaderboard positions

Take a break

I wont have my laptop, and I sure as hell aint gonna do it on my phone

Why not? I did day 2 on my phone while at a party. It's not that bad.

>contest is literally to see who can make a working solution the fastest
>pssh these fokken pajeets aren't taking 6 hours to make an elegant solution like me!

keep crying

Who are you quoting?

Ended up doing it in the end. it's gross, but whatever.

pastebin.com/h9DjUpbM

I thought it was about stimulating camaraderie among the Sup Forums community

Holy fuck using the C++ standard regex lib makes a massive exe file. Holy shit.

meh, i'd say it's about 75-25 between helpful comments/support and "GIT GUD PAJEET"

>implying those aren't one and the same

I'd say over half the people here aren't even pajeet level

I wish I had a phone with a keypad

puzzle 3

1 idx = 1
2
3 while idx ** 2 < 312051:
4 idx += 2
5
6 print idx - (idx / 2) + (idx ** 2 - (idx / 2) - 312051) - 1
7
8 x, y, steps = 0, 0, 0
9 x_dir, y_dir, length = 1, 1, 1
10 vert = False
11 next_tile = "null"
12 spiral_dict = {"0 0" : 1, next_tile : 0}
13
14 def key_check(key):
15 return key if key in spiral_dict else "null"
16
17 while spiral_dict[next_tile] < 312051:
18 value = 0
19 x = x + (int(not vert) * x_dir)
20 y = y + (int(vert) * y_dir)
21
22 value += spiral_dict[key_check(str(x + 1) + " " + str(y))]
23 value += spiral_dict[key_check(str(x - 1) + " " + str(y))]
24 value += spiral_dict[key_check(str(x) + " " + str(y + 1))]
25 value += spiral_dict[key_check(str(x) + " " + str(y - 1))]
26 value += spiral_dict[key_check(str(x + 1) + " " + str(y + 1))]
27 value += spiral_dict[key_check(str(x + 1) + " " + str(y - 1))]
28 value += spiral_dict[key_check(str(x - 1) + " " + str(y + 1))]
29 value += spiral_dict[key_check(str(x - 1) + " " + str(y - 1))]
30
31 next_tile = str(x) + " " + str(y)
32 spiral_dict[next_tile] = value
33 steps += 1
34
35 if steps == length:
36 if vert:
37 length += 1
38 x_dir *= -1
39 y_dir *= -1
40 vert = not vert
41 steps = 0
42
43 print spiral_dict[next_tile]


I'm not proud of my solution but it works. I couldn't think of a better way to generate/store keys so it's constantly doing all that string building shit

I'm gonna study this, looking good

I started these yesterday and just finished problem 6 (How many redistribution cycles until it repeats). The second question (length of the infinite loop) was info I basically already had after solving the firs one. Does that mean there's a trick for solving the first one?

I just made a loop that follows the instructions almost verbatim, kept the array it spits out at every iteration, and compared the current array to all previous arrays looking for a match.

hahahahhahahahahahahahahahahahah

just use the formula omg

See Floyd's cycle detection algorithm: en.wikipedia.org/wiki/Cycle_detection#Algorithms

But you can also avoid comparing to all previous arrays using a hashtable of ones that had been seen.

T-minus 20 minutes

Hopefully I don't over-think tomorrows like I did today's.

I started writing a recursive parser before I realized I could just count the brackets lol

God my circuit looks pathetic

Recursion is of the devil user

I've still never gotten a single chip in my circuit

i keep getting these things

>over nine thousand eks deeeeee

HERE WE GO BOYS WEEKEND CHALLENGE II