/aocg/ - Advent of Code 2018 General #23

Actually using the pasta 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.

Private leaderboard join code (currently full):
368748-e33dcae3

People who are inactive for 5 days will be kicked, but other leaderboards can be made if desired.

Alternative leaderboard for those waiting for inactives to be kicked from the first:
208834-4a1a9383

Attached: binary_fractal_tree_02_15_45_05sqrt2.png (944x944, 404K)

Other urls found in this thread:

my.mixtape.moe/cgwvnz.xz
twitter.com/NSFWRedditVideo

private leaderboard is not currently full btw.

I've really got to get more used to recursion. I don't have an issue with the concept, but every time I need to implement it I struggle with the thought process.

>about to post new thread
>get as far as the last picture in the captcha
>firefox locks up
>wait a couple minutes, does not unfreeze
>open chrome, re-do everything
>post thread and link it
>firefox immediately starts working again
God damn it.

>somebody wrote this shit out

yeah that's gonna be a yikes from me

last thread had under 100 unique posters and was up for 11 hours

i think everyone who wants to join is in now, our numbers are dwindling

Attached: Screenshot at 2018-12-08 18-29-47.png (388x404, 24K)

The pace of the threads is starting to get closer to the one thread a day of last year.
Don't really mind desu, it means that the remaining people are more committed to going through with it. By the end last year, it was really comfy.

>tfw you solve the problem tacitly
{:(".}:fread'in')(($:^:([{~_2+{.@])2 0&+@])([+1&{::@],[:+/1&{::@]{.0&{::@]}.~{.@[)([;[{~>:@{.@]))0 0

if you're still around, here's my recursive function. i think its relatively self explanatory. the only not obvious thing is that the pine variable is just the list of integers from the input (the tree, do ya geddit)

def getmetadata(index, pine, metadata):
childnum, metanum = pine[index], pine[index+1]
index += 2
while (childnum > 0):
index = getmetadata(index, pine, metadata)
childnum -= 1
#index += (2 + (header[1]))
for i in range(metanum):
metadata.append(pine[index])
index += 1
return index

yeah, i guess. i liked how active these threads were early on right at midnight when the puzzles dropped. lots of people losing their shit and trying to figure stuff out, it feels lonely here by comparison. i miss the filtered brainlets

>tfw completely filtered by part 2
What am I missing, any hints?
Recursive string/array functions are a good way to conceptualize recursion:
size_t count_chars(const char *s, char c)
{
return !*s ? 0 : (*s == c) + count_chars(s+1, c);
}
/// -> return (s[0] == c) + (s[1] == c) + (s[2] == c)... + (s[n] == 0)
So the first call always returns last

>solves both parts while reading in the values
wow. that's some next level shit

What is that?

that'd be Steve, our resident code golf champion

It's J, a descendant of APL

you'll keep most of your recursive function from part 1. make a list of child node values towards the beginning. if a node has no children, return the sum of its metadata. the next level up will add this to its child list. when you have a full list of child values, use that nodes own metadata to pick the relevant values to sum, and then pass that value on up to its parent node, who will add the value to its own child list, etc. etc.

The general idea is that each node needs to know how many indices in the data set belong to it's children. From there, it can calculate it's own metadata and return how many indices it's own data took, plus the indices of it's children.

Your function should be called on the first node, which will then call that function on all of it's children, and those nodes will call it on their children, etc, until it reaches a node with no children. That node will return how many indices long it is and the value of itself (e.g.: a node with 0 2 2 11 as it's data will return (4, 13) for part 1). This will chain back upwards. Now the parents of those childless nodes know how far forward to skip to read their own metadata, so they read their own metadata, then return their length in indices plus the total of their children (e.g. a node like 1 1 0 2 2 11 5 will return (7, 18). The 7 being it's 3 indices plus the 4 from the child node and the 18 being it's total metadata of 5 plus the metadata of it's child, 13).

It's complicated to write out but you can do it, user.

me too. feels less fun without everyone losing their shit and trying to figure stuff out

see you lads tomorrow, hopefully some of the brainlets come back so this shit will be more lively for the weekend

I actually managed to write fairly simple and readable haskell today

import Data.Tree
import Data.Attoparsec.Text
import qualified Data.Text.IO as T

main :: IO ()
main = do
contents Int
value (Node metadata []) = sum metadata
value (Node metadata children) =
sum [ maybe 0 value (children !? (i - 1)) | i

I combined my two solution functions into a single one to pass through the data exactly once!

use std::fs::File;
use std::io::Read;

fn solve(tree: &Vec) -> (usize, usize) {
let mut s1 : usize = 0;
let mut iter = tree.iter();
let mut cstack = Vec::::new();
let mut mstack = Vec::::new();
let mut values = Vec::::new();

let nchilds = iter.next().unwrap();
cstack.push((*nchilds, *nchilds));
mstack.push(*iter.next().unwrap());

loop {
// No more children to process
if cstack.is_empty() { break; }

// Get next child
let (rem, orig) = cstack.pop().unwrap();

let mut sum : usize = 0;
match (rem, orig) {
// Node had no children, sum their metadata.
(0, 0) => {
let n = mstack.pop().unwrap();
for _ in 0..n { sum += iter.next().unwrap(); }

s1 += sum;
values.push(sum);
},
// Node had children, collapse their values.
(0, _) => {
let l = values.len() - orig - 1;
let n = mstack.pop().unwrap();

for _ in 0..n {
let m = iter.next().unwrap();
s1 += m;

if *m > orig || *m == 0 { continue; }
else { sum += values[l+m]; }
}

for _ in 0..orig { let _ = values.pop(); }
values.push(sum);
},
// More children to process.
(_, _) => {
let nchilds = iter.next().unwrap();
cstack.push((rem - 1, orig));
cstack.push((*nchilds, *nchilds));
mstack.push(*iter.next().unwrap());
},
}
}

let s2 = values.pop().unwrap();
(s1, s2)
}

fn main() {
let mut file = File::open("inputs/8.txt").unwrap();
let mut buffer = String::new();
let _ = file.read_to_string(&mut buffer);

let mut tree = Vec::::new();
for s in buffer.as_str().trim_end().split(' ') {
let i = s.parse::().unwrap();
tree.push(i);
}

let (sum, val) = solve(&tree);

println!("Sum of metadata: {}", sum);
println!("Root value: {}", val);
}

OURGUY ON A RAMPAGE
you are doing gods work user

How do you deal with the feeling of failure?

Attached: 1536942036763.jpg (437x431, 28K)

I don't. If I'm not succeeding, I keep pushing myself until I do.

That stuff is easy enough, I'd say because it's a single series even if it's done recursively. My issues are more tree type structures. I just need to work with them more in practice. It'd be nice next year to see tree/graph problems and just know how to do them off the top of my head.

Somewhat offtopic question but: what kind of software development involves regularly solving these interesting kind of problems?

The first thing I can think of is gamedev, but I want to work on something that actually helps productive people, I don't want the entire benefit of my work to be giving degenerates their next dopamine rush.

Attached: 1529539581795.jpg (637x900, 115K)

I put some +1s and some -1s in my function and it worked for reasons I know not.
I'm not proud.

Attached: cirnodeath.jpg (600x600, 68K)

Working at Google, Facebook or social media corpos.

can you tell me what this program is suppose to do? maybe i am just retarded but i can't tell

Probably doing smaller software solutions/projects on your own/in a company instead of being stuck at the same project for 8 years and drowning yourself in alcohol when your wife divorces because of your growing depression and apathy induced by your work environment

>My issues are more tree type structures
You don't need a tree, just compute the value on the fly.

Recursion in programming feels natural for me, but I struggled at first too. Maybe because I began with C it was confusing for me.
I can't really remember how I started getting it, but I remember it was an instant; it was something that happened between reading first 2 or 3 chapters of sicp and finally getting how hanoi problem works; I also remember I did a set of dozen of simple recursion problems in C taken from math textbooks and compiled for the specific purpose of teaching recursion and soon after I was doing data structures course where I had to implement each one of them and had to do a lot of traversal algorithms so it solidified it. Maybe play with LOGO a bit (and do cool stuff like OPs picrel), it's more fun than it seems.
I hope anything from the above helps you. It may seem big for you now but once you snap and get it it'll be like breathing air. Don't filter out bro.
Get used to it. That's how it feels like until you make it.
>it feels lonely here by comparison
I prefer it that way because when it's too much of a crowd and it goes too fast I don't bother to read the thread

Off by one errors are always a bitch

Someone has a big boy?

Any kinds of software development. Even if you are not paid to solve these kinds of problems at work, you can define your own problems and so, create the solutions for them.

For example, knowing how to write powerful recursions allow you to create scripts that extract information or modify all files inside a folder, including those inside its subfolders.

These kinds of utility scripts can boost your productivity exponentially.

Attached: done.png (1920x1008, 354K)

Try 2015 day 12 if you want an easy problem to train using recursion

Today was easy as fuck.
Brainlet filter when?

Attached: file.png (607x496, 92K)

Wait for day 13 (the second brainlet filter).

In my opinion social media also falls under
>giving degenerates their next dopamine rush
but thanks for the suggestion user.

Yes, but what kind of projects?
The majority of non-gamedev work seems to be just boilerplate and basic logic

So you're essentially suggesting that these kind of problems exist all over the place if you look for them rather than just going with your simple gut solution? Interesting idea.

>The majority of non-gamedev work seems to be just boilerplate and basic logic
Try to find a job as a backend dev.

>So you're essentially suggesting that these kind of problems exist all over the place if you look for them rather than just going with your simple gut solution? Interesting idea.
Actually nevermind I think I misread, I thought by "define your own problems" you meant what I was saying but I think you meant define your own different problems in your spare time

Nice

This was ridiculously easy.
Would have gotten it done in about 20 minutes or so but was away until a few hours after today started.
!/usr/bin/pypy3
from math import *
import json

with open('input') as f:
data = [int(x) for x in f.readline().strip().split(' ')]
#print(data)

nodes = {}

def readnode(data,label):
node = {}
node['label'] = label
node['children'] = []
node['metadata'] = []
label += 1
numchildren = data.pop(0)
numdata = data.pop(0)
for _ in range(numchildren):
child,data,label = readnode(data,label)
node['children'].append(child)
for _ in range(numdata):
node['metadata'].append(data.pop(0))
return node,data,label

tree,_,_ = readnode(data,0)
#print(json.dumps(tree, indent=4))

def sumdata(node):
return sum(node['metadata']) + sum([sumdata(child) for child in node['children']])
print(sumdata(tree))

def value(node):
if len(node['children']) == 0:
return sum(node['metadata'])
v = 0
for cn in node['metadata']:
if cn-1 < len(node['children']):
v += value(node['children'][cn-1])
return v
print(value(tree))


tux@oniichan /m/D/t/s/0/2/08> time -p ./prog.py
REDACTED
REDACTED
real 0.30
user 0.27
sys 0.01

>300ms
No you can go faster than that.

Any recursion filters many brainlets.
>t. hasn't started yet, just read the thread

As I web backend?
From my limited experience backend web just seems to be all routing, creating rest endpoints and using ORMs to interact with databases, does it get more iteresting than that?

Not, in the web. Try to work with engineers that do real stuff. Avoid the web.

For example, I am paid to develop some pajeet-tier Java enterprise software and I find my work involves too much repetitive shit.

So I define that as a problem and I write some scripts that write the Java codes instead of me.

>write some scripts that write the Java codes instead of me.
Usually code generator, is a symptom of non factorized code.

Yeah I'm passing data around all the time. That's expensive.
Making label and data a global trims it down to 250ms.

I'm at 2ms, you have a big margin.

Make projects on your own that help people then.
Projects that could be things in the future:
- Vision for blind people
- Work for a company or found your own that has its best motives to help people in times of crisis
- Better brainwave detector software for medical usage
- Early stage cancer detection through image processing

You can think of more, I'm certain.

You might have to do some processing on the data. Not just fetching it from the database and sending it to the client.
But yeah, webdev is usually pajeet stuff.

Small big boy incoming
my.mixtape.moe/cgwvnz.xz
$ time ./aoc8.c.bin

Post times!
Also, will we get big boy input today?

Attached: aoc8.png (708x505, 88K)

I love Rust
$ time ./8.elf
Sum of metadata: 100025641
Root value: 27826

real 0m0.392s
user 0m0.300s
sys 0m0.088s

Here Right now, I'm uploading a bigger big boy. But I upload it at 100kB/s

>my.mixtape.moe/cgwvnz.xz
2.007s
entirely due to all the 4k read()s required just to get the data.

Impressive. Could you shared the code, I want to test it on my hardware.

I might also be moving too much data around
Part 1: 1.6s
100025641
Part 2: 2.2ms
27826

$ time python3 08.py < inp08.txt
42798
23798

real 0m0,164s
user 0m0,152s
sys 0m0,012s

Yes, it looks like reading is the bottleneck with that problem.

See
You'll need to change the hardcoded filename on the first line of the main function.

Post your times on the big boy input.

atleast for me, I'm not measuring the time it takes nodejs to load the file.
Part 1: 873.3ms
100025641
Part 2: 2.2ms
27826

half of my part one was apparently the time it took to parse the input to integers

$ time ./soln

This makes me sad. Mine is so much dumber.
module Main where

import Data.Function
import Text.Printf

data Tree = State Tree Counters Input
| Node Children Meta deriving Show

type Counters = (Int, Int)
type Children = [Tree]
type Input = [Int]
type Meta = [Int]

type Solution = Int
type Length = Int

yield :: Input -> Tree
yield (a:b:xs) = eval$ State (Node [] []) (a, b) xs

eval :: Tree -> Tree
eval (State (Node kids _) (0, metas) xs) = Node (reverse kids) (take metas xs)
eval (State (Node kids _) (c, metas) (k:m:xs)) = eval$ State (Node (next:kids) []) (c-1, metas) ys
where next = eval$ State (Node [] []) (k,m) xs; ys = drop (yielded next - 2) xs

yielded :: Tree -> Length
yielded (Node ns vs) = 2 + length vs + (sum $yielded ns)

silver :: Tree -> Solution
silver (Node ns vs) = on (+) sum vs $silver ns

gold :: Tree -> Solution
gold (Node [] vs) = sum vs
gold (Node ns vs) = sum [gold.last
$take v ns | v

Attached: pout.png (562x999, 816K)

>Post your times on the big boy input.
you mean bigger than those 16721 numbers? will post code and try it yourself, maybe my laptop is just faster

import sys

checksum = []

def parse_node(nums):
ch, nums = nums[0], nums[1:]
mt, nums = nums[0], nums[1:]
ch_vals = []
for i in range(ch):
nums, v = parse_node(nums)
ch_vals.append(v)
metadata, nums = nums[:mt], nums[mt:]
checksum.extend(metadata)
if ch == 0:
return (nums, sum(metadata))
val = 0
for m in metadata:
m -= 1
if m >= len(ch_vals):
continue
val += ch_vals[m]
return (nums, val)

#nums = [2, 3, 0, 3, 10, 11, 12, 1, 1, 0, 1, 99, 2, 1, 1, 2]
nums = list(map(int, sys.stdin.read().split(' ')))

_, root_val = parse_node(nums)
print(sum(checksum))
print(root_val)

it's the same input so you should get the same answers as others.

That's fucking disgusting. Delete.

>answer is correct for the sample input but it's wrong for the actual input, again
JUST

I compiled and try it with small bigboy
$ time ./test
thread 'main' panicked at 'attempt to subtract with overflow', test.rs:34:25
note: Run with `RUST_BACKTRACE=1` for a backtrace.

real 0m2.334s
user 0m2.253s
sys 0m0.077s

I though that rust was safe.

I just rewrite my parsing code
$ time ./aoc8.c.bin

Here's what I get testing your code on my original input set:
time python3 user.py < inputs/8.txt
40309
28779

real 0m0.160s
user 0m0.148s
sys 0m0.008s


By comparison, here is my original Rust solution on the same input set:
time ./8.elf
Sum of metadata: 40309
Root value: 28779

real 0m0.002s
user 0m0.004s
sys 0m0.000s


As I'm typing, your code is still chugging along on the big boy input. I'll post the time when the program terminates.

Huh, weird. Seems I can get that error as well when I don't compile with optimizations. I've got a compile script that looks like this:

#!/bin/sh
rustc $1.rs -o $1.elf -C opt-level=3 -C lto=yes -C link-args=-s

Basically generated the smallest, fastest binary possible. While compiling with optimizations, Rust tends to ignore certain behavior though, which includes integer overflow. Now that I think about it, that particular line could generate an underflow. Nonetheless, the result of computing l+m should always be a valid index into the values stack.

The length - 1 is the last valid index of the stack/vector. The value orig represents the number of values on the stack that are associated with the children of the tree node being processed. If all of the nodes on that stack are associated with the children of the tree node (as will happen when collapsing the values to compute for the tree root), the value of l will be computed as length - length - 1, or usize::MAX (an underflow). When this value is used to subscript the values stack, the value of m (which must be at least 1) is added to it. Thus, the value will overflow back in the other direction to necessarily create a safe index.

I see no reason to change my program.

big boy too big
gotta find out how i can allocate more mem to node

Attached: aoc8bigboy out of mem.png (1341x573, 138K)

>allocate more mem to node
That's the idea behind that big boy. I could generate bigger, but uploading will be a nightmare.

>windows 7
>tfw alpine on docker is faster than native

Attached: tfw.png (653x276, 12K)

>could generate an underflow
>I see no reason to change my program.
LOL
Protip btw: -C codegen-units=1 -C incremental=0 -C panic=abort

>windows 7
Cringe

had to give it 8 gigs but here it is

Attached: Screenshot from 2018-12-08 12-17-04.png (199x87, 5K)

Hey Python guy, your program has been running for half an hour on my computer without spitting out an answer on the big boy input. Not sure if it's somehow stuck in an infinite loop on this particular input, or just really goddamn slow, but I'm gonna kill the process.

It underflows, but in a way that I can prove will never generate an index out of bounds. So yeah, no need to change.

try mine
array = list(map(int, open("input").readline().split(" ")))

def tree(array, p=0):
t = 0
n = array[p+1]
for i in range(array[p]):
p, val = tree(array, p + 2)
t += val
return p + n, t + sum(array[p+2:p+n+2])

print(tree(array)[1])

I should have used a for loop which sums instead of sum(sublist), to avoid making a sublist

try mine
fn main() {
fn walk(iter: &mut I) -> (usize, usize) where I: Iterator {
let children = iter.next().unwrap();
let metadata = iter.next().unwrap();

if children == 0 {
let m = iter.take(metadata).sum();
(m, m)
} else {
let children: Vec = (0..children).map(|_| walk(iter)).collect();

iter.take(metadata).fold((children.iter().map(|(a, _)| a).sum(), 0), |(a, b), m| (
a + m,
b + children.get(m - 1).map_or(0, |&(_, b)| b)
))
}
}

let input = std::fs::read_to_string("input").expect("failed to read input");
let (a, b) = walk(&mut input.trim_end().split(' ').map(|s| s.parse().unwrap()));
println!("Part 1: {}", a);
println!("Part 2: {}", b);
}

If I solved this with recursion does it mean I'm not a brainlet?

Attached: 1442638870925.jpg (272x350, 30K)

Would love to benchmark all of your programs, but need sleep.

Solving without recursion sounds harder...

What? My RAM usage is less than 100KB (without counting the binary itself).

Attached: 1425481293016.jpg (1280x720, 72K)

You will re implement a stack, so don't do it.

>was about to do yesterday and today
>crippling depression set in
what do

Attached: 67382957_p0.png (1199x1055, 831K)

stop being a faggot. """depression""" is a scam by big pharma to sell more pills.

Just do it

>is a scam by big pharma to sell more pills
No, it's a real thing. But yes, people should not buy pills to "heal" depression.

>it's a real thing
It isn't.

I've never taken pills for the shit. Never have, never will.
Do the puzzles of kill myself?

How do you call someone who is sad everyday?

*or, could've used a comma too