fromcollectionsimportdequewithopen('input.txt','r')asf:data=deque()forlineinf:forvalinline.split(' '):data.append(int(val))classTree:def__init__(self,data):self.n_children=data.popleft()self.n_metadata=data.popleft()self.children=[Tree(data)for_inrange(self.n_children)]self.metadata=[data.popleft()for_inrange(self.n_metadata)]defget_total(self):returnsum(self.metadata)+sum(child.get_total()forchildinself.children)defget_child_value(self,child):ifchild<len(self.children):returnself.children[child].get_root_value()return0defget_root_value(self):ifnotself.children:returnsum(self.metadata)total=0foridxinself.metadata:total+=self.get_child_value(idx-1)# Index starts at 1 not 0 :( returntotaltree=Tree(data)print(tree.get_total())print(tree.get_root_value())
Woah, that recursive constructor for Tree is really clever!
I considered building an object and then processing it after the fact, but decided to process it as I parsed it...I regretted that when I saw part 2 though 😅
Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Looking for work!
I was missing parser combinators so came back and did day 8 again.
data classNode(valchildren:List<Node>,valmetadata:List<Int>)funparse(input:String):Node{valinteger=Terminals.IntegerLiteral.PARSER.map(String::toInt)valtreeRef=Parser.Reference<Node>()funnodeParser(numChildren:Int,numMetadata:Int):Parser<Node>=sequence(treeRef.lazy().times(numChildren),integer.times(numMetadata),::Node)valnodeInfo:Parser<Pair<Int,Int>>=sequence(integer,integer){nc,nm->Pair(nc,nm)}valtree:Parser<Node>=nodeInfo.next{(nc,nm)->nodeParser(nc,nm)}treeRef.set(tree)valparser=tree.from(Terminals.IntegerLiteral.TOKENIZER,Scanners.WHITESPACES)returnparser.parse(input.trim())}
It was initially much more dense but I tried to break it up to make it easier to follow. It's not the One True Way of parsing for nothing you know!
never met a part of the stack I didn't like. sr. engineer at clique studios in chicago, perpetual creative hobbyist, bird friend, local gay agenda promoter. she/her. tips: https://ko-fi.com/carlymho
Recursion, or: finally a chance to use my degree. Did I need to actually build the tree in Part 2? Probably not, but it made it easier to organize the data and actually do the recursion, so ¯_(ツ)_/¯
Here is my Golang solution for today's problem. It was more easy for me to solve today, but made me learn to use pointers in Golang to consume the input string. I don't think this is necessarily the best way to use pointers, but I liked the simplicity in this case.
packagemainimport("bufio""fmt""os""strconv""strings")// A simple structure of a node.typenodestruct{children[]nodemetaData[]int}// readLines reads a whole file into memory// and returns a slice of its lines.funcreadLines(pathstring)([]string,error){file,err:=os.Open(path)iferr!=nil{returnnil,err}deferfile.Close()varlines[]stringscanner:=bufio.NewScanner(file)forscanner.Scan(){lines=append(lines,scanner.Text())}returnlines,scanner.Err()}// function to consume elements from the input string.funcconsume(parseNodes*[]string)int{i,_:=strconv.Atoi((*parseNodes)[0])*parseNodes=(*parseNodes)[1:]returni}// function to parse a node from the input string.funcreadNode(parseNodes*[]string)node{// Read headernumChildren:=consume(parseNodes)numMetaData:=consume(parseNodes)// Read children:varchildren[]nodeforc:=0;c<numChildren;c++{children=append(children,readNode(parseNodes))}// Read meta data:varmetaData[]intform:=0;m<numMetaData;m++{metaData=append(metaData,consume(parseNodes))}// Create and return node:returnnode{children:children,metaData:metaData}}// function to get the sum of meta data from a given node.funcgetMeta(nodenode)int{// Read meta data of this node:meta:=node.metaData// Run through each child and get meta data:for_,c:=rangenode.children{meta=append(meta,getMeta(c))}varsumint// Sum the meta data:for_,m:=rangemeta{sum+=m}returnsum}// function to get the value of a given node.funcgetValue(nodenode)int{numChildren:=len(node.children)varvalueintifnumChildren==0{// If the node has no children return just the sum of// the meta data for thid node:value=getMeta(node)}else{// If this node has children return the sum of the// values for each child:for_,m:=rangenode.metaData{m--// for correct indexingifm>=0&&m<numChildren{// Only get value if index is not out of boundvalue+=getValue(node.children[m])}}}returnvalue}funcmain(){data,err:=readLines("input")iferr!=nil{panic(err)}nodeString:=strings.Split(data[0]," ")root:=readNode(&nodeString)fmt.Println("Part 1:")fmt.Println(getMeta(root))fmt.Println("Part 2:")fmt.Println(getValue(root))}
#!/usr/bin/perlusewarnings;usestrict;usefeatureqw{ say };useList::Utilqw{ sum };my@n=split' ',<>;sub process{my($pos,$sum)=@_;my$child_tally=$n[$pos++];my$data_size=$n[$pos++];for(1..$child_tally){my$ch=process($pos,$sum);$sum=$ch->[1];$pos=$ch->[0];}$sum+=sum(0,@n[$pos..$pos+$data_size-1]);$pos+=$data_size;return[$pos,$sum];}sayprocess(0,0)->[1];
Part 2
#!/usr/bin/perlusewarnings;usestrict;usefeatureqw{ say };useList::Utilqw{ sum };my@n=split' ',<>;sub process{my($pos,$sum)=@_;my$child_tally=$n[$pos++];my$data_size=$n[$pos++];my@ch;for(1..$child_tally){my$ch=process($pos,$sum);push@ch,$ch->[1];$pos=$ch->[0];}if($child_tally){$sum+=sum(map{$ch[$_-1]//0}@n[$pos..$pos+$data_size-1]);}else{my$v=sum(@n[$pos..$pos+$data_size-1]);$sum+=$v;}$pos+=$data_size;return[$pos,$sum];}sayprocess(0,0)->[1];
Ryan is an engineer in the Sacramento Area with a focus in Python, Ruby, and Rust. Bash/Python Exercism mentor. Coding, physics, calculus, music, woodworking. Looking for work!
@choroba , thanks again for putting this post up! Sorry for not getting it out on time yesterday.
I liked this challenge! Something about this one just worked out for me and I didn't have to wrestle with it very much. Also, this was my first time defining a recursive data structure in Rust, and I didn't have any issues -- hopefully I did it the right way!
Part 1
/// Day 8: Memory Maneuver/// /// Build a license tree!/// A node in a GPS Licensing tree structurepubstructNode{metadata:Vec<usize>,children:Vec<Box<Node>>,}implNode{pubfnnew()->Self{Self{metadata:vec![],children:vec![]}}/// Generates a node from a string of space-separated integerspubfnfrom_text(text:&str)->Self{letdata:Vec<usize>=text.split(' ').map(|num|{num.parse().unwrap()}).collect();let(node,_ptr)=Node::build_child(&data,0);node}/// Builds a child based on a strand of data and a pointer to start at./// /// These nodes are recursive in their layout. So, for example, /// the root node has a header at the start of the string, and its/// metadata comes after all of the rest of the nodes in the treefnbuild_child(data:&Vec<usize>,start:usize)->(Node,usize){letmutresult=Node::new();letmutptr=start;letchildren=data[ptr];ptr+=1;letmetadata=data[ptr];ptr+=1;// Generate and add childrenfor_iin0..children{let(node,new_ptr)=Node::build_child(&data,ptr);result.children.push(Box::new(node));ptr=new_ptr;}result.metadata.extend(&data[ptr..(ptr+metadata)]);ptr+=metadata;(result,ptr)}/// Calculate the recurive total of all the metadata here and belowpubfnmetadata_total(&self)->usize{letmy_metadata:usize=self.metadata.iter().sum();letchildren_total:usize=self.children.iter().map(|child|child.metadata_total()).sum();my_metadata+children_total}}
Part 2
For part 2, I didn't have to change the data structure at all, I just created the value function to describe how the new thing was calculated.
implNode{/// Calculates a node's value./// /// Value is defined like this:/// - if a node has no children, it's the sum of the metadata/// - if a node *does* have children, value is defined recursively,/// and each metadata is a pointer at a particular child./// This node's value is the sum of *those* nodes' values./// If a pointer is invalid, skip it.pubfnvalue(&self)->usize{ifself.children.is_empty(){returnself.metadata.iter().sum();}letmuttotal:usize=0;forpointerinself.metadata.iter(){if*pointer<1||*pointer>self.children.len(){continue;}total+=self.children.get(*pointer-1).expect("Couldn't get child value").value();}total}}
const{readFile}=require('./reader');const{buildTree}=require('./08-common');constsumMetadata=root=>{lettotal=0;letqueue=[root];while(queue.length>0){constnode=queue.shift();total+=node.metadataEntries.reduce((sum,entry)=>sum+entry,0);queue.push(...node.childNodes);}returntotal;};(async()=>{constlines=awaitreadFile('08-input.txt');consttree=buildTree(lines[0].split(' '));constsum=sumMetadata(tree);console.log(`The sum of all metadata entries is ${sum}`);})();
08b.js
const{readFile}=require('./reader');const{buildTree}=require('./08-common');constgetNodeValue=node=>{letvalue=0;if(node.childNodesSize===0){value+=node.metadataEntries.reduce((sum,entry)=>sum+entry,0);}else{for(letentryofnode.metadataEntries){constchild=node.childNodes[entry-1];if(child){value+=getNodeValue(child);}}}returnvalue;}constgetRootNodeValue=root=>{returngetNodeValue(root);};(async()=>{constlines=awaitreadFile('08-input.txt');consttree=buildTree(lines[0].split(' '));constrootNodeValue=getRootNodeValue(tree);console.log(`The value of the root node is is ${rootNodeValue}`);})();
import{readFileSync}from'fs'// data as arrayconstdata=readFileSync('./data',{encoding:'utf8'}).trim().split(" ").map(Number)// recursive fn// return the index that the current child ends and the children metadataconstaddNode=(index)=>{letchildren=data[index]letmetadata=data[index+1]lettotalMetadata=0while(children>0){constchildData=addNode(index+2)index=childData.newIndextotalMetadata+=childData.totalMetadatachildren--}for(leti=0;i<metadata;i++){totalMetadata+=data[index+i+2]}return{newIndex:index+metadata,totalMetadata}}console.log(addNode(0).totalMetadata)
Part 2
import{readFileSync}from'fs'constdata=readFileSync('./data',{encoding:'utf8'}).trim().split(" ").map(Number)// recursive fn// return the child index, metadata qty, and the metadata for the childsconstaddNode=(index)=>{constrealIndex=indexletchildren=data[index]letmetadata=data[index+1]lettotalMetadata=0letchildrenMetadata=[]if(children>0){for(leti=0;i<children;i++){constchildData=addNode(index+2)index=childData.newIndexchildrenMetadata[i]=childData.totalMetadata}for(leti=0;i<metadata;i++){constchildMetadataToGet=data[index+i+2]-1totalMetadata+=(childrenMetadata[childMetadataToGet]||0)}}else{for(leti=0;i<metadata;i++){totalMetadata+=data[index+i+2]}}return{newIndex:index+metadata,totalMetadata,childrenMetadata}}console.log(addNode(0).totalMetadata)
I liked this challenge a lot! It felt a lot more straightforward than the other problems.
The code came out extremely succinct, too, which is always nice. IMO it's quite readable:
Part 1:
function sum_metadata(input)nums=split(input," ")result=total_for_node(nums)returnresultendfunction total_for_node(nums)num_children=parse(Int,popfirst!(nums))num_metadata=parse(Int,popfirst!(nums))total=0foriin1:num_childrentotal+=total_for_node(nums)endforiin1:num_metadatameta=parse(Int,popfirst!(nums))total+=metaendreturntotalend
Part 2 looks almost identical to part 1, but with an extra branch in the middle.
function sum_child(input)nums=split(input," ")result=total_for_node(nums)[1]returnresultendfunction total_for_node(nums)num_children=parse(Int,popfirst!(nums))num_metadata=parse(Int,popfirst!(nums))all_childs=[]foriin1:num_childrenappend!(all_childs,total_for_node(nums))endtotal=0iflength(all_childs)==0foriin1:num_metadatameta=parse(Int,popfirst!(nums))total+=metaendelseforiin1:num_metadatameta=parse(Int,popfirst!(nums))ifmeta<=length(all_childs)total+=all_childs[meta]endendendreturn[total]end
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Kinda happy with this one!
Woah, that recursive constructor for
Tree
is really clever!I considered building an object and then processing it after the fact, but decided to process it as I parsed it...I regretted that when I saw part 2 though 😅
deque
FTW! Nice!I was missing parser combinators so came back and did day 8 again.
It was initially much more dense but I tried to break it up to make it easier to follow. It's not the One True Way of parsing for nothing you know!
PHP
Recursion, or: finally a chance to use my degree. Did I need to actually build the tree in Part 2? Probably not, but it made it easier to organize the data and actually do the recursion, so ¯_(ツ)_/¯
Part 1:
Part 2:
Here is my Golang solution for today's problem. It was more easy for me to solve today, but made me learn to use pointers in Golang to consume the input string. I don't think this is necessarily the best way to use pointers, but I liked the simplicity in this case.
Agreed, today's was much simpler. My Kotlin:
Here is my Python Solution:
Both parts
Part 1
Part 2
And here are my Perl solutions:
Part 1
Part 2
@choroba , thanks again for putting this post up! Sorry for not getting it out on time yesterday.
I liked this challenge! Something about this one just worked out for me and I didn't have to wrestle with it very much. Also, this was my first time defining a recursive data structure in Rust, and I didn't have any issues -- hopefully I did it the right way!
Part 1
Part 2
For part 2, I didn't have to change the data structure at all, I just created the
value
function to describe how the new thing was calculated.JavaScript solution
reader.js
08-common.js
08a.js
08b.js
This is my js solution using recursive functions
Part1
Part 2
github.com/ngleich/adventofcode2018/
I liked this challenge a lot! It felt a lot more straightforward than the other problems.
The code came out extremely succinct, too, which is always nice. IMO it's quite readable:
Part 1:
Part 2 looks almost identical to part 1, but with an extra branch in the middle.