// starMap defined as above...constgetAncestors=body=>bodyinstarMap?[...getAncestors(starMap[body]),starMap[body]]:[];constyouAncestors=getAncestors('YOU');constsantaAncestors=getAncestors('SAN');consttransfers=youAncestors.filter(body=>santaAncestors.includes(body)).map(body=>[// .reverse is actually not necessary......youAncestors.slice(youAncestors.indexOf(body)).reverse(),// + 1 because we'd include the common planet twice...santaAncestors.slice(santaAncestors.indexOf(body)+1)]);// - 1 because we're counting the movements, not the positionsconsole.log(Math.min(...transfers.map(xfer=>xfer.length-1)));
; Returns the number of orbits the given object is contained in (i.e. direct orbit + indirect orbits)(defnorbit-centers[orbit-mapobject](count(take-whilesome?(drop1(iterateorbit-mapobject))))); Returns the sum of the orbit centers for each object in the orbit map.(defndirect-and-indirect-orbits[orbit-map](apply+(map(partialorbit-centersorbit-map)(keysorbit-map)))); Parses the input format into a map of object -> orbit center(defnparse-orbit-map[raw](applyhash-map(flatten(map(compreverse#(.split#"\)"%))(.split#"\n"raw)))))(definput(parse-orbit-map(slurp(first*command-line-args*))))(println"Total number of (in)direct orbits:"(direct-and-indirect-orbitsinput))
I kinda got stuck on part 2, so the solution for this isn't really optimal (takes around half a second):
; Returns a sequence of objects that orbit the given center(defnorbiting[orbit-mapcenter](mapfirst(filter#(=(%1)center)orbit-map))); Calculates the minimum amount of traversals required in an orbit map to move from object to destination; (This is currently very inefficient and bad, I might still improve it)(defntraversals[orbit-mapobjectdestination](condp=objectnilInteger/MIN_VALUEdestination-2(inc(applymax(traversals(dissocorbit-mapobject)(orbit-mapobject)destination)(for[orbit-obj(orbiting(dissocorbit-mapobject)object)](traversals(dissocorbit-maporbit-obj)orbit-objdestination))))))(println"Traversals required to get from you to santa:"(traversalsinput"YOU""SAN"))
; Counts the amount of elements in coll before element appears. Returns (count coll) if it doesn't appear at all.(defncount-until[elementcoll](count(take-while(partialnot=element)coll))); Calculates the minimum amount of traversals required in an orbit map to move from object to destination(defntraversals[orbit-mapobjectdestination](let[object-centers(orbit-centersorbit-mapobject)destination-centers(orbit-centersorbit-mapdestination)first-common-center(some(setdestination-centers)object-centers)](+(count-untilfirst-common-centerobject-centers)(count-untilfirst-common-centerdestination-centers))))
I just fetch the first common center of both objects and add the steps it takes to get there for both.
There's got to be some better way to go about it, as even with memoisation it takes about half a minute to sort through part one, but hey, memoisation is cool.
Back to Prolog today but rather than battle with reading the input file in Prolog and turning it into relations, which I have no idea where to begin with, I used a Perl one-liner to turn it into Prolog source code. That's not cheating is it?
Part 2 was more involved but is ultimately a similar algorithm in Prolog, filtering the possible solutions down to a single path between the start and end which does not visit any location twice.
Since I solved one based on the Josephus Problem by hand once because I had just seen a numberphile video based upon it, it's only cheating (in my book) if someone else figured it out for you.
I don't think it's even cheating looking at someone else's solution, as long as you write your own version instead of copying it. (renaming doesn't count!)
I'm a Staff Software Engineer at Cisco. I specialize in Python and Go, building functional, practical, and maintainable web systems leveraging Kubernetes and the cloud. Blog opinions are my own.
After a weekend of flu, I'm back in action--albeit about four days behind the pace now. I'll catch up. Here's today's solution in Rust. No BFS for me. Just a hashtable of children, and a (likely inefficient, but good enough) reverse lookup to do some ancestor math.
/// Day 6: Universal Orbit Map/// /// Find out how many orbits there are in a galaxy mapusestd::fs::File;usestd::io::prelude::*;usestd::io::BufReader;usestd::collections::HashMap;/// An orbit map is a mapping of nodes to the names of their children.typeOMap=HashMap<String,Vec<String>>;/// Expects a list of mappings of the form AAA)BBB, one per line./// AAA here is the parent of BBB (and potentially many others)./// Nodes only have one parent.fnparse_input()->OMap{letbuf=BufReader::new(File::open("data/day6.txt").unwrap());letmutresult:OMap=HashMap::new();forlineinbuf.lines(){lettext=line.unwrap();letmutentities=text.split(")");letparent=entities.next().unwrap();letchild=entities.next().unwrap();letchildren=result.entry(parent.to_string()).or_default();children.push(child.to_string());result.entry(child.to_string()).or_default();}result}/// Count the sum of the number of steps it is from each node in a tree/// to the root./// /// The result is the sum of a node's distance from COM and all of its/// children's orbit counts.fncount_orbits(depth:usize,parent:&str,orbit_map:&OMap)->usize{letchildren=&orbit_map[parent];ifchildren.len()==0{depth}else{letchildren_total:usize=children.iter().map(|c|count_orbits(depth+1,c,orbit_map)).sum();depth+children_total}}/// Builds a list of the ancestors of an entity starting with its/// parent and ending with COM. Or, the String version of COM./// Or... the &String version of COM. Shut up, rust is stupid.fnancestors<'a>(orbit_map:&'aOMap,a:&String,mutso_far:Vec<&'aString>)->Vec<&'aString>{for(parent,children)inorbit_map.iter(){ifchildren.contains(a)&&parent=="COM"{so_far.push(parent);returnso_far;}elseifchildren.contains(a){so_far.push(parent);returnancestors(orbit_map,parent,so_far);}}panic!("Couldn't find parent!");}/// Find out how many steps minimum are between the parents of a and b./// /// Assumes that the orbit is acyclic with only one root,/// and thus, there is only one way to get from one to the other, /// up through the tree to a common ancestor and back downfnsteps_between(orbit_map:&OMap,a:&String,b:&String)->usize{leta_ancestors=ancestors(orbit_map,a,Vec::new());letb_ancestors=ancestors(orbit_map,b,Vec::new());letsame=a_ancestors.iter().rev().zip(b_ancestors.iter().rev()).filter(|(x,y)|x==y).count();(a_ancestors.len()-same)+(b_ancestors.len()-same)}pubfnrun(){letorbit_map=parse_input();letparent="COM".to_string();println!("Total orbits: {}",count_orbits(0,&parent,&orbit_map));letme="YOU".to_string();letsanta="SAN".to_string();println!("Distance between me and Santa: {}",steps_between(&orbit_map,&me,&santa))}
Part 2 was my old friend "Djikstra's Algorithm". It wasn't enough data to warrant breaking out A*Search, but if previous years are any indication we will probably need it at some point.
Honestly, Advent of Code is so much fun. This stuff makes me fall back in love with programming.
defget_data(_file):orbits={}objects=set()forlinein_file:to_orbit,orbiter=line.rstrip().split(")")orbits[orbiter]=to_orbitobjects.add(to_orbit)objects.add(orbiter)returnorbits,objectsdefget_orbit(current_obj,orbits):ifcurrent_objnotinorbits:return[]return[orbits[current_obj]]+get_orbit(orbits[current_obj],orbits)defget_total_orbits(orbits):returnsum(len(get_orbit(obj,orbits))forobjinobjects)defget_path_between(start,end,orbits):start_path,end_path=get_orbit(start,orbits),get_orbit(end,orbits)# Get the first point that is in both paths
overlapping_point=[iforiinstart_pathifiinend_path][0]returnstart_path.index(overlapping_point)+end_path.index(overlapping_point)withopen("input.txt")as_file:orbits,objects=get_data(_file)print(f"Part 1: {get_total_orbits(orbits)}")print(f'Part 2: {get_path_between("YOU", "SAN", orbits)}')
Interesting and challenging problem today. I went for a parent-to-children map for the first part and a tree for the second. Runs within a couple of milliseconds.
Bit late to the party on this one. With good reason, but also I kept making mistakes with how to add up the jumps.
Got there eventually.
Part 2 first:
functionorbitsToSanta(){letpretext=document.getElementsByTagName('pre')[0].innerHTML;letorbits=pretext.split('\n').filter(o=>o!=='');letorbithash={};letmeorbit='';letsanorbit='';for(letorbitoforbits){orbithash[orbit]=newleaf(orbit);}for(letorbitoforbits){let[main,sub]=orbit.split(')');if(sub==='YOU'){meorbit=orbit;}if(sub==='SAN'){sanorbit=orbit;}letparent=orbits.filter(oo=>{let[othermain,othersub]=oo.split(')');returnmain===othersub;})[0];if(typeof(parent)!=='undefined')//root node has no parent. {orbithash[orbit].parent=orbithash[parent];}}letmelist=orbithash[meorbit].listOrbits();letsanlist=orbithash[sanorbit].listOrbits();// hco is Highest Common Orbitlethco=melist.filter(o=>sanlist.indexOf(o)>-1).slice(-1)[0];lethcolist=orbithash[hco].listOrbits();letmelength=melist.filter(l=>hcolist.indexOf(l)===-1).length-1;// minus 1 because you exclude the current orbit.letsanlength=sanlist.filter(l=>hcolist.indexOf(l)===-1).length-1;// minus 1 because the hco is already counted.returnmelength+sanlength;}functionleaf(orbit){this.orbit=orbit;this.parent=null;}leaf.prototype.orbitCounts=function(){letcount=1;if(this.parent!==null){count=1+this.parent.orbitCounts();}returncount;};leaf.prototype.listOrbits=function(){if(this.parent===null){return[];}letpos=this.parent.listOrbits();pos.push(this.orbit);returnpos;};
Part 1 had the following code in place of the number of jumps calculation:
Late here, but as I am doing 2019 AOC now (yes, nearly 3 years later), and I noticed there was no C solution for this one here, I have one here.
Nothing special there, as the two parts are trivial after the tree has been built, and you get a way to find existing nodes by name (mainly to build tree). For that, instead of an usual hash-table, I decided to go for a trie structure. Don't ask me why ;-)
Finally a nice and short one.
My solutions aren't particularly efficient as they involve recursive functions, but still run pretty fast so whatever. ¯\_(ツ)_/¯
Part 1
Part 2
You can find my solutions on GitHub.
Maybe a future node version will add tail call optimization, and Javascript could have efficient recursion again.
Tail recursive functions are so much clearer to me than a while loop... something about walking down to a trivial solution just makes sense. 🤷♀️
I long the day they will tackle the problem once and for all. It's the last thing missing from ES2015! (Only Safari supports it.)
Part 1 was a no-brainer in clojure:
I kinda got stuck on part 2, so the solution for this isn't really optimal (takes around half a second):
Fun one nonetheless!
(Full code: github.com/jkoenig134/AdventOfCode...)
I am fake upset you didn't break out the clojure zipper library for this! (it's like using a cannon for flies in this case)
Oh, I will definitely look into that, thanks for the suggestion.
I only knew about (tree-seq),
I'm still a newbie in clj.
Zipper is extremely powerful for navigating trees efficiently.
It’s also as easy to read as overly point free Haskell.
I vastly improved it without using zippers now.
I just fetch the first common center of both objects and add the steps it takes to get there for both.
There's got to be some better way to go about it, as even with memoisation it takes about half a minute to sort through part one, but hey, memoisation is cool.
JavaScript
Unsolicited hints from a fellow 2+ minute initial runtime maker:
You're absolutely right. I've changed the approach and with this I managed to reduce the processing time from 43.3 seconds to 2.6:
Back to Prolog today but rather than battle with reading the input file in Prolog and turning it into relations, which I have no idea where to begin with, I used a Perl one-liner to turn it into Prolog source code. That's not cheating is it?
Part 1 boiled down to finding all possible paths in the graph and counting them.
Part 2 was more involved but is ultimately a similar algorithm in Prolog, filtering the possible solutions down to a single path between the start and end which does not visit any location twice.
Shortest code for the day?
Since I solved one based on the Josephus Problem by hand once because I had just seen a numberphile video based upon it, it's only cheating (in my book) if someone else figured it out for you.
I don't think it's even cheating looking at someone else's solution, as long as you write your own version instead of copying it. (renaming doesn't count!)
Solution for part two, in Elixir.
Here's part one
Javascript solution w/ Graph implementation
I liked that the explanation was much easier to understand today. I'm pretty happy with this one.
After a weekend of flu, I'm back in action--albeit about four days behind the pace now. I'll catch up. Here's today's solution in Rust. No BFS for me. Just a hashtable of children, and a (likely inefficient, but good enough) reverse lookup to do some ancestor math.
Without embarrassment, I show this code to you. Part 1 takes a few minutes to complete. I will respond with an optimized version later.
Part 2 was my old friend "Djikstra's Algorithm". It wasn't enough data to warrant breaking out A*Search, but if previous years are any indication we will probably need it at some point.
Ahhh... much better. This runs in msecs.
Honestly, Advent of Code is so much fun. This stuff makes me fall back in love with programming.
Day dusted with swift
Interesting and challenging problem today. I went for a parent-to-children map for the first part and a tree for the second. Runs within a couple of milliseconds.
Part 1:
Part 2:
Bit late to the party on this one. With good reason, but also I kept making mistakes with how to add up the jumps.
Got there eventually.
Part 2 first:
Part 1 had the following code in place of the number of jumps calculation:
A Python solution (also see github.com/devChad/advent_of_code)
Lots of recursive functions...
Late here, but as I am doing 2019 AOC now (yes, nearly 3 years later), and I noticed there was no
Csolution for this one here, I have one here.Nothing special there, as the two parts are trivial after the tree has been built, and you get a way to find existing nodes by name (mainly to build tree). For that, instead of an usual hash-table, I decided to go for a
triestructure. Don't ask me why ;-)A javascript walkthrough. I was happy to have coded the part 1 in a clean way because it helped me a ton for the part 2!