input<-read_lines("Day16Sample1.txt")
### make the maze into a dict, find the start and end
reindeermaze<-dict()
for(i in 1:length(input)){
x<-unlist(str_split(input[i],""))
for(j in 1:length(x)){
switch(x[j],
"#"=reindeermaze$set(str_flatten(c(i,j),"~"),0),
"S"=reinstart<-c(i,j),
"E"=reinend<-c(i,j),
{})}}
Part 1
Just a very, very straightforward search -
N=0 E=1 S=2 W=3
mazepath<-function(mz,st,en){
beenthere<-dict()
pq<-priority_queue()
### pushing starting position, direction, & score
### pq is the distance to the end + the current score
pq$push(c(st,1,0),-sum(abs(st-en)))
while(pq$size()>0){
curr<-pq$pop()
### if at the end, leave
if(all(curr[1:2]==en)){return(curr[4])}
### if have been there facing that direction, stop
if(beenthere$has(str_flatten(curr[1:3],"~"))){next}
beenthere$set(str_flatten(curr[1:3],"~"),0)
### turn clockwise & counterclockwise
pq$push(c(curr[1:2],(curr[3]+1)%%4,curr[4]+1000),-sum(abs(en-curr[1:2]),curr[4]))
pq$push(c(curr[1:2],(curr[3]-1)%%4,curr[4]+1000),-sum(abs(en-curr[1:2]),curr[4]))
### move, depending on which direction currently facing
nxt<-FALSE
d<-as.character(curr[3])
switch(d,
"0"=if(!mz$has(str_flatten(curr[1:2]+c(-1,0),"~"))){nxt<-curr[1:2]+c(-1,0)},
"1"=if(!mz$has(str_flatten(curr[1:2]+c(0,1),"~"))){nxt<-curr[1:2]+c(0,1)},
"2"=if(!mz$has(str_flatten(curr[1:2]+c(1,0),"~"))){nxt<-curr[1:2]+c(1,0)},
"3"=if(!mz$has(str_flatten(curr[1:2]+c(0,-1),"~"))){nxt<-curr[1:2]+c(0,-1)},
cat("bad direction\n"))
if(!any(nxt==FALSE)){
pq$push(c(nxt,curr[3],curr[4]+1),-sum(abs(en-nxt),curr[4]))}}
beenthere}
part1<-mazepath(reindeermaze,reinstart,reinend)
part1
[1] 7036
Part 2
Because I need to save the path during the search (and return all
paths), I need to make some small changes:
bestseat<-function(mz,st,en){
beenthere<-dict()
pq<-priority_queue()
### pushing starting position, direction, score, and path
### pq is the distance to the end + the current score
pq$push(list(st[1],st[2],1,0,c(str_flatten(st,"~"))),-sum(abs(st-en)))
bestlength<-Inf
paths<-c()
closer<-0
winctr<-0
while(pq$size()>0){
currlist<-pq$pop()
curr<-unlist(currlist[1:4])
pth<-unlist(currlist[5])
### if the current score > bestlength - stop
if(curr[4]>bestlength){break}
### if at the end
if(all(curr[1:2]==en)){
### if this is shorter than the best length
if(curr[4]<bestlength){
### make this the new bestlength
bestlength<-curr[4]
### this is the new best path list (should only happen once, but just in case)
paths<-pth
### if this matches the best length
}else if(curr[4]==bestlength){
### add this path to the list of path seats
paths<-c(paths,pth)}
next}
### check if we've been there faster - if faster, drop - if slower or equal, keep going
if(beenthere$has(str_flatten(curr[1:3],"~"))){
when<-beenthere$get(str_flatten(curr[1:3],"~"))
if(when<curr[4]){next}}
beenthere$set(str_flatten(curr[1:3],"~"),curr[4])
### turn clockwise & counterclockwise
pq$push(list(curr[1],curr[2],(curr[3]+1)%%4,curr[4]+1000,pth),-sum(abs(en-curr[1:2]),curr[4]))
pq$push(list(curr[1],curr[2],(curr[3]-1)%%4,curr[4]+1000,pth),-sum(abs(en-curr[1:2]),curr[4]))
### move, depending on which direction currently facing
nxt<-FALSE
d<-as.character(curr[3])
switch(d,
"0"=if(!mz$has(str_flatten(curr[1:2]+c(-1,0),"~"))){nxt<-curr[1:2]+c(-1,0)},
"1"=if(!mz$has(str_flatten(curr[1:2]+c(0,1),"~"))){nxt<-curr[1:2]+c(0,1)},
"2"=if(!mz$has(str_flatten(curr[1:2]+c(1,0),"~"))){nxt<-curr[1:2]+c(1,0)},
"3"=if(!mz$has(str_flatten(curr[1:2]+c(0,-1),"~"))){nxt<-curr[1:2]+c(0,-1)},
cat("bad direction\n"))
if(!any(nxt==FALSE)){
pq$push(list(nxt[1],nxt[2],curr[3],curr[4]+1,c(pth,str_flatten(nxt,"~"))),-sum(abs(en-nxt),curr[4]))}}
unique(paths)}
p2<-bestseat(reindeermaze,reinstart,reinend)
part2<-length(p2)
part2
[1] 45
LS0tDQp0aXRsZTogIkRheSAxNiBOb3RlYm9vayINCm91dHB1dDogaHRtbF9ub3RlYm9vaw0KLS0tDQoNCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQ0KbGlicmFyeShnZ2FuaW1hdGUpDQpsaWJyYXJ5KGdncGxvdDIpDQpsaWJyYXJ5KHJlc2hhcGUyKQ0KbGlicmFyeShrbml0cikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHN0cmluZ3IpDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkocmVhZHIpDQpsaWJyYXJ5KGNvbGxlY3Rpb25zKQ0Kb3B0aW9ucyhzY2lwZW4gPSA5OTkpDQpgYGANCg0KYGBge3J9DQppbnB1dDwtcmVhZF9saW5lcygiRGF5MTZTYW1wbGUxLnR4dCIpDQojIyMgbWFrZSB0aGUgbWF6ZSBpbnRvIGEgZGljdCwgZmluZCB0aGUgc3RhcnQgYW5kIGVuZA0KcmVpbmRlZXJtYXplPC1kaWN0KCkNCmZvcihpIGluIDE6bGVuZ3RoKGlucHV0KSl7DQogIHg8LXVubGlzdChzdHJfc3BsaXQoaW5wdXRbaV0sIiIpKQ0KICBmb3IoaiBpbiAxOmxlbmd0aCh4KSl7DQogICAgc3dpdGNoKHhbal0sDQogICAgICAgICAgICIjIj1yZWluZGVlcm1hemUkc2V0KHN0cl9mbGF0dGVuKGMoaSxqKSwifiIpLDApLA0KICAgICAgICAgICAiUyI9cmVpbnN0YXJ0PC1jKGksaiksDQogICAgICAgICAgICJFIj1yZWluZW5kPC1jKGksaiksDQogICAgICAgICAgIHt9KX19DQpgYGANCg0KDQojIyBQYXJ0IDENCkp1c3QgYSB2ZXJ5LCB2ZXJ5IHN0cmFpZ2h0Zm9yd2FyZCBzZWFyY2ggLSANCg0KTj0wDQpFPTENClM9Mg0KVz0zDQoNCmBgYHtyfQ0KbWF6ZXBhdGg8LWZ1bmN0aW9uKG16LHN0LGVuKXsNCiAgYmVlbnRoZXJlPC1kaWN0KCkNCiAgcHE8LXByaW9yaXR5X3F1ZXVlKCkNCiAgIyMjIHB1c2hpbmcgc3RhcnRpbmcgcG9zaXRpb24sIGRpcmVjdGlvbiwgJiBzY29yZQ0KICAjIyMgcHEgaXMgdGhlIGRpc3RhbmNlIHRvIHRoZSBlbmQgKyB0aGUgY3VycmVudCBzY29yZSANCiAgcHEkcHVzaChjKHN0LDEsMCksLXN1bShhYnMoc3QtZW4pKSkNCiAgd2hpbGUocHEkc2l6ZSgpPjApew0KICAgIGN1cnI8LXBxJHBvcCgpDQogICAgIyMjIGlmIGF0IHRoZSBlbmQsIGxlYXZlDQogICAgaWYoYWxsKGN1cnJbMToyXT09ZW4pKXtyZXR1cm4oY3Vycls0XSl9DQogICAgIyMjIGlmIGhhdmUgYmVlbiB0aGVyZSBmYWNpbmcgdGhhdCBkaXJlY3Rpb24sIHN0b3ANCiAgICBpZihiZWVudGhlcmUkaGFzKHN0cl9mbGF0dGVuKGN1cnJbMTozXSwifiIpKSl7bmV4dH0NCiAgICBiZWVudGhlcmUkc2V0KHN0cl9mbGF0dGVuKGN1cnJbMTozXSwifiIpLDApDQogICAgIyMjIHR1cm4gY2xvY2t3aXNlICYgY291bnRlcmNsb2Nrd2lzZQ0KICAgIHBxJHB1c2goYyhjdXJyWzE6Ml0sKGN1cnJbM10rMSklJTQsY3Vycls0XSsxMDAwKSwtc3VtKGFicyhlbi1jdXJyWzE6Ml0pLGN1cnJbNF0pKQ0KICAgIHBxJHB1c2goYyhjdXJyWzE6Ml0sKGN1cnJbM10tMSklJTQsY3Vycls0XSsxMDAwKSwtc3VtKGFicyhlbi1jdXJyWzE6Ml0pLGN1cnJbNF0pKQ0KICAgICMjIyBtb3ZlLCBkZXBlbmRpbmcgb24gd2hpY2ggZGlyZWN0aW9uIGN1cnJlbnRseSBmYWNpbmcNCiAgICBueHQ8LUZBTFNFDQogICAgZDwtYXMuY2hhcmFjdGVyKGN1cnJbM10pDQogICAgc3dpdGNoKGQsDQogICAgICAgICAgICIwIj1pZighbXokaGFzKHN0cl9mbGF0dGVuKGN1cnJbMToyXStjKC0xLDApLCJ+IikpKXtueHQ8LWN1cnJbMToyXStjKC0xLDApfSwNCiAgICAgICAgICAgIjEiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMCwxKSwifiIpKSl7bnh0PC1jdXJyWzE6Ml0rYygwLDEpfSwNCiAgICAgICAgICAgIjIiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMSwwKSwifiIpKSl7bnh0PC1jdXJyWzE6Ml0rYygxLDApfSwNCiAgICAgICAgICAgIjMiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMCwtMSksIn4iKSkpe254dDwtY3VyclsxOjJdK2MoMCwtMSl9LA0KICAgICAgICAgICBjYXQoImJhZCBkaXJlY3Rpb25cbiIpKQ0KICAgIGlmKCFhbnkobnh0PT1GQUxTRSkpew0KICAgICAgcHEkcHVzaChjKG54dCxjdXJyWzNdLGN1cnJbNF0rMSksLXN1bShhYnMoZW4tbnh0KSxjdXJyWzRdKSl9fQ0KICBiZWVudGhlcmV9DQpgYGANCg0KDQpgYGB7cn0NCnBhcnQxPC1tYXplcGF0aChyZWluZGVlcm1hemUscmVpbnN0YXJ0LHJlaW5lbmQpDQpwYXJ0MQ0KYGBgDQojIyBQYXJ0IDINCkJlY2F1c2UgSSBuZWVkIHRvIHNhdmUgdGhlIHBhdGggZHVyaW5nIHRoZSBzZWFyY2ggKGFuZCByZXR1cm4gYWxsIHBhdGhzKSwgSSBuZWVkIHRvIG1ha2Ugc29tZSBzbWFsbCBjaGFuZ2VzOg0KDQpgYGB7cn0NCmJlc3RzZWF0PC1mdW5jdGlvbihteixzdCxlbil7DQogIGJlZW50aGVyZTwtZGljdCgpDQogIHBxPC1wcmlvcml0eV9xdWV1ZSgpDQogICMjIyBwdXNoaW5nIHN0YXJ0aW5nIHBvc2l0aW9uLCBkaXJlY3Rpb24sIHNjb3JlLCBhbmQgcGF0aA0KICAjIyMgcHEgaXMgdGhlIGRpc3RhbmNlIHRvIHRoZSBlbmQgKyB0aGUgY3VycmVudCBzY29yZQ0KICBwcSRwdXNoKGxpc3Qoc3RbMV0sc3RbMl0sMSwwLGMoc3RyX2ZsYXR0ZW4oc3QsIn4iKSkpLC1zdW0oYWJzKHN0LWVuKSkpDQogIGJlc3RsZW5ndGg8LUluZg0KICBwYXRoczwtYygpDQogIGNsb3NlcjwtMA0KICB3aW5jdHI8LTANCiAgd2hpbGUocHEkc2l6ZSgpPjApew0KICAgIGN1cnJsaXN0PC1wcSRwb3AoKQ0KICAgIGN1cnI8LXVubGlzdChjdXJybGlzdFsxOjRdKQ0KICAgIHB0aDwtdW5saXN0KGN1cnJsaXN0WzVdKQ0KICAgICMjIyBpZiB0aGUgY3VycmVudCBzY29yZSA+IGJlc3RsZW5ndGggLSBzdG9wDQogICAgaWYoY3Vycls0XT5iZXN0bGVuZ3RoKXticmVha30NCiAgICAjIyMgaWYgYXQgdGhlIGVuZA0KICAgIGlmKGFsbChjdXJyWzE6Ml09PWVuKSl7DQogICAgICAjIyMgaWYgdGhpcyBpcyBzaG9ydGVyIHRoYW4gdGhlIGJlc3QgbGVuZ3RoDQogICAgICBpZihjdXJyWzRdPGJlc3RsZW5ndGgpew0KICAgICAgICAjIyMgbWFrZSB0aGlzIHRoZSBuZXcgYmVzdGxlbmd0aA0KICAgICAgICBiZXN0bGVuZ3RoPC1jdXJyWzRdDQogICAgICAgICMjIyB0aGlzIGlzIHRoZSBuZXcgYmVzdCBwYXRoIGxpc3QgKHNob3VsZCBvbmx5IGhhcHBlbiBvbmNlLCBidXQganVzdCBpbiBjYXNlKQ0KICAgICAgICBwYXRoczwtcHRoDQogICAgICAgICMjIyBpZiB0aGlzIG1hdGNoZXMgdGhlIGJlc3QgbGVuZ3RoDQogICAgICB9ZWxzZSBpZihjdXJyWzRdPT1iZXN0bGVuZ3RoKXsNCiAgICAgICAgIyMjIGFkZCB0aGlzIHBhdGggdG8gdGhlIGxpc3Qgb2YgcGF0aCBzZWF0cw0KICAgICAgICBwYXRoczwtYyhwYXRocyxwdGgpfQ0KICAgIG5leHR9DQogICAgIyMjIGNoZWNrIGlmIHdlJ3ZlIGJlZW4gdGhlcmUgZmFzdGVyIC0gaWYgZmFzdGVyLCBkcm9wIC0gaWYgc2xvd2VyIG9yIGVxdWFsLCBrZWVwIGdvaW5nDQogICAgaWYoYmVlbnRoZXJlJGhhcyhzdHJfZmxhdHRlbihjdXJyWzE6M10sIn4iKSkpew0KICAgICAgd2hlbjwtYmVlbnRoZXJlJGdldChzdHJfZmxhdHRlbihjdXJyWzE6M10sIn4iKSkNCiAgICAgIGlmKHdoZW48Y3Vycls0XSl7bmV4dH19DQogICAgYmVlbnRoZXJlJHNldChzdHJfZmxhdHRlbihjdXJyWzE6M10sIn4iKSxjdXJyWzRdKQ0KICAgICMjIyB0dXJuIGNsb2Nrd2lzZSAmIGNvdW50ZXJjbG9ja3dpc2UNCiAgICBwcSRwdXNoKGxpc3QoY3VyclsxXSxjdXJyWzJdLChjdXJyWzNdKzEpJSU0LGN1cnJbNF0rMTAwMCxwdGgpLC1zdW0oYWJzKGVuLWN1cnJbMToyXSksY3Vycls0XSkpDQogICAgcHEkcHVzaChsaXN0KGN1cnJbMV0sY3VyclsyXSwoY3VyclszXS0xKSUlNCxjdXJyWzRdKzEwMDAscHRoKSwtc3VtKGFicyhlbi1jdXJyWzE6Ml0pLGN1cnJbNF0pKQ0KICAgICMjIyBtb3ZlLCBkZXBlbmRpbmcgb24gd2hpY2ggZGlyZWN0aW9uIGN1cnJlbnRseSBmYWNpbmcNCiAgICBueHQ8LUZBTFNFDQogICAgZDwtYXMuY2hhcmFjdGVyKGN1cnJbM10pDQogICAgc3dpdGNoKGQsDQogICAgICAgICAgICIwIj1pZighbXokaGFzKHN0cl9mbGF0dGVuKGN1cnJbMToyXStjKC0xLDApLCJ+IikpKXtueHQ8LWN1cnJbMToyXStjKC0xLDApfSwNCiAgICAgICAgICAgIjEiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMCwxKSwifiIpKSl7bnh0PC1jdXJyWzE6Ml0rYygwLDEpfSwNCiAgICAgICAgICAgIjIiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMSwwKSwifiIpKSl7bnh0PC1jdXJyWzE6Ml0rYygxLDApfSwNCiAgICAgICAgICAgIjMiPWlmKCFteiRoYXMoc3RyX2ZsYXR0ZW4oY3VyclsxOjJdK2MoMCwtMSksIn4iKSkpe254dDwtY3VyclsxOjJdK2MoMCwtMSl9LA0KICAgICAgICAgICBjYXQoImJhZCBkaXJlY3Rpb25cbiIpKQ0KICAgIGlmKCFhbnkobnh0PT1GQUxTRSkpew0KICAgICAgcHEkcHVzaChsaXN0KG54dFsxXSxueHRbMl0sY3VyclszXSxjdXJyWzRdKzEsYyhwdGgsc3RyX2ZsYXR0ZW4obnh0LCJ+IikpKSwtc3VtKGFicyhlbi1ueHQpLGN1cnJbNF0pKX19DQogIHVuaXF1ZShwYXRocyl9DQpgYGANCg0KDQoNCmBgYHtyfQ0KcDI8LWJlc3RzZWF0KHJlaW5kZWVybWF6ZSxyZWluc3RhcnQscmVpbmVuZCkNCnBhcnQyPC1sZW5ndGgocDIpDQpwYXJ0Mg0KYGBgDQpgYGB7ciBlY2hvPUZBTFNFLCBmaWcuY2FwPSJCZXN0IFBhdGhzIiwgb3V0LndpZHRoID0gJzUwJSd9DQprbml0cjo6aW5jbHVkZV9ncmFwaGljcygibWF6ZXJ1bi5naWYiKQ0KYGBgDQoNCmBgYHtyLGluY2x1ZGU9RkFMU0UsZXZhbD1GQUxTRX0NCiMjIyBHcmFwaCBTdHVmZg0KDQoNCmdyZGY8LWFzLmRhdGEuZnJhbWUobWF0cml4KG5yb3c9MCxuY29sPTMpKQ0KaTwtMQ0KY3Q8LTENCndoaWxlKGk8bGVuZ3RoKHAyKSl7DQogIGlmKHAyW2krMV0hPSIxNDB+MiIpew0KICAgIGdyZGY8LXJiaW5kKGdyZGYsYyhwMltpXSxwMltpKzFdLGN0KSkNCiAgICB9ZWxzZXtjdDwtMH0NCiAgaTwtaSsxDQogIGN0PC1jdCsxfQ0KY29sbmFtZXMoZ3JkZik8LWMoInMiLCJlIiwidCIpDQoNCg0KDQoNCmdyZGY8LWdyZGYlPiVyb3d3aXNlJT4lbXV0YXRlKHhzPWFzLm51bWVyaWModW5saXN0KHN0cl9zcGxpdF9pKHMsIn4iLDIpKSksDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4ZT1hcy5udW1lcmljKHVubGlzdChzdHJfc3BsaXRfaShlLCJ+IiwyKSkpLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeXM9YXMubnVtZXJpYyh1bmxpc3Qoc3RyX3NwbGl0X2kocywifiIsMSkpKSwNCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllPWFzLm51bWVyaWModW5saXN0KHN0cl9zcGxpdF9pKGUsIn4iLDEpKSkpJT4lDQogIHNlbGVjdCgtYyhzLGUpKQ0KDQoNCnF1aWNrZ3JkZjwtdW5pcXVlKGdyZGYpJT4lbXV0YXRlKHQ9YXMubnVtZXJpYyh0KSkNCg0KZ3JiY2s8LWFzLmRhdGEuZnJhbWUobWF0cml4KG5jb2w9Mixucm93PTApKQ0KcmVpbm16a2V5czwtdW5saXN0KGFzLmxpc3QocmVpbmRlZXJtYXplJGtleXMoKSkpDQpmb3IoaSBpbiAxOmxlbmd0aChyZWlubXprZXlzKSl7Z3JiY2s8LXJiaW5kKGdyYmNrLGFzLm51bWVyaWModW5saXN0KHN0cl9zcGxpdChyZWlubXprZXlzW2ldLCJ+IikpKSl9DQpjb2xuYW1lcyhncmJjayk8LWMoIndhbGx5Iiwid2FsbHgiKQ0KDQpyZWlubWF6ZWdyYXBoPC1nZ3Bsb3QocXVpY2tncmRmKSsNCiAgZ2VvbV90aWxlKGRhdGE9Z3JiY2ssYWVzKHg9d2FsbHgseT13YWxseSksY29sb3I9IiM0NDQ0NDQiKSsNCiAgZ2VvbV9zZWdtZW50KGFlcyh4PXhzLHk9eXMseGVuZD14ZSx5ZW5kPXllKSxjb2xvcj0iI0ZGMDAwMCIpKw0KICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy54ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgYXhpcy50aWNrcy55ID0gZWxlbWVudF9ibGFuaygpLA0KICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgcGFuZWwuZ3JpZC5taW5vciA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uPSJub25lIikrDQogIHNjYWxlX3lfcmV2ZXJzZSgpKw0KICBjb29yZF9maXhlZCgpKw0KICB0cmFuc2l0aW9uX3N0YXRlcyh0LHdyYXA9RkFMU0UpKw0KICBzaGFkb3dfbWFyaygpDQpyZWlubWF6ZWdyYXBoDQpgYGANCg0K