 alright welcome to day 12 of the advent of code we did a double feature yesterday turned out to be three and a half hours or even more let's hope it's not that long today but you know it is a Sunday and sometimes I think the weekend challenges might be a bit harder but yeah so let's get to it all right with your submarine subterranean subsystems subsisting suboptimally the only way you're getting out of this cave anytime soon is by finding a path yourself let me check one thing just checking the audio a bit all right not just a path the only way to know if you found the best path is to find all of them fortunately the senses are still mostly working so you build a rough map of the remaining caves you're possibly but for example start is linked to a a start is linked to b a to c a to b a b to d and this is a list of all the case are connected all right we're gonna be doing graph algorithms you start in the cave named start and your destination is cave named and another like PD means that cave B is connected to cave D that is you can move between them so the above case system looks roughly like this your undergoes find a number of distinct while all right let's say let's get get this input let's get it in there all right so we are going to be doing some a rap algorithms today and let's get to it okay hey how do we we read input file path okay we're gonna return our list of map of a string string for that we need data dot map map report data dot qualified I don't know report qualified a data dot map is map let's actually check because I think there's like a Haskell graph data dot graph right adjacency list representation of a graph graph from edges oh wow we could have been using this earlier right okay a graph from edges accept the return value does not include functions which map keys the vertices graph from edges okay so we just give a note and a key and the list of keys we have to be able to order the key okay so let's use this import data dot graph graph import qualified data dot graph is graph does not do it I'm a map let's use the proper data structure what does it take a okay okay oh it doesn't actually care about the okay let's see okay input let me see a FP equals and so we we're gonna we're gonna do a map f now we had to do a map a map to node a over lines dot read input this is gonna be IO graph where to know and why doesn't it like this oh no it's a read Wow right and this doesn't work because right we need to do graph dot graph from edges actual type IO oh okay right this graph from edges returns more things okay so it returns a graph vertex and it is like a vertex to okay let's do type g node equals just have it a string string string vertex to a g node and we have a string which is our key to maybe vertex we might might change this afterwards now it's complaining that a graph let's see let's actually just have a list of g node first why is it ding ding ding ding ding what's happening okay okay so read file gives us a list of it's an IO string right no yeah oh my god okay we just tell this one okay now the type of two node has to be to know is a string to g no photograph unless of you know that by keys with the list of keys of these nodes should have edges to okay so we first have to kind of figure out the yeah yeah thanks very we're stuck on that for like two minutes anyway what can I do with this data.graph I can do forest I can do returns true reachable strongly connected components reverse top sort let me see what can we do with graph can we like we have to all right I think we might have to just do things ourselves and I'm not I'm not sure this is the best way to do it okay but how does our so the code find number of distinct paths that start at start ended and and don't visit all small caves more than this like the Euler's algorithm oh and there we have small caves and big caves so it's not just a graph okay this is this is gonna be a lot of work okay and let's change it let's just do input okay so first of all we have a file path to IO and let's not care about something so we want to end up with a IO map string of a list of string and then we want to have we can figure out the keys and stuff later read input equals have map a map dot from list dot map pars dot lines read file because I think like it's not a regular graph hello bello little Annie welcome to the stream and thank you for this cookie super good cookie okay that's it so powers here has to return a list of string okay where parts okay so parts is it gonna be equal to powers prime and okay let's break it all into pairs the lns okay so we're gonna say map where SPL is equal to super good cookie actually not equal to this character and then we have drop one that we want to like remove the first letter lns so the SPL here is a list of strings okay then we're gonna say pair to list we're gonna say you know a comma B is equal to a comma B okay so we map a pair to list because we might be getting we might be getting you know like in here like the start might not be the first one so now we have a oh no it's a list yeah okay but these are two strings okay and then we're gonna but we're actually gonna sort them so that why are we sorting them because so we can't actually sort them we would want we want like start always to be at the start would I buy followers and viewers they won't chat right if you buy viewers you want people chatting not not just like about the thing not just me me I don't know okay so now we have the now they're sorted there is like a add a connection let's have it a map not a list of strings but a set of strings and then let's avoid this a no okay so this one is going to be okay we import data set now we want these to be maps so pair to pair to map okay so this is gonna be map out from list see at so it's gonna be a okay let's just say a comma B not from set dot singleton and now we import data that set as set and it's a set of B okay so now these are a maps pair to now we don't need this one pair to map so this is gonna be a list of strings to set of chars and now we're gonna say a map dot union we have like we can do like unions with data map lazy aim from list unions unions with okay so right so we say unions with set dot union map dot so now this is going to be one big map so it's gonna be this whole thing okay but now we don't need to do so let's check it out for the example rate input example into print gco three day 12 dot HS and day 12 so a connects to BC and then start B connects okay and start connects to a and B so we have the kind of the map representing the cave system and we know how each is connected so if this were a regular graph search we could just start we could just we could just start from start and then kind of check which ones we visited before that would like so we were trying to have the shortest paths goes by the number of distinct paths that start at start and at end and don't visit small caves more than once so what is the starting and okay yeah the number of distinct paths let's just Google it but there are cycles so there are we can't treat this as a T tree okay we can do backtracking yeah okay I guess the backtracking way works so kind of start at start right and then we pick one and do another function is is big string to pull is big equals all his upper case and I think this one is in is a ASCII upper okay so is big okay let's see if we can do like a backtracking solution num paths so we do map string set a strings and we do num paths prime map start set dot empty where num paths prime big visited MP equals okay so let's think about this problem recursly okay so if I'm at I'm at an edge so so let's have here like we do start to occur node okay so so we don't we don't want to we start at start so set dot empty is gonna be set dot singleton what we can pretend that's a big visited now num paths prime if we have big visited okay so we have a big visited and we have if we're at end the path we have is and now a num paths big visited okay is equal to this is gonna return us the list of string let's see let's see so what are the next paths okay where next paths equals so this is like the MP is a MP map dot bang okay and they get the next next pause equals and then we do a set set dot we remove the small visited from this set okay and we say set dot to list on this now so the next wasn't it oh right there's gonna be a list of next paths so if we're at the end the only possible path is in and maybe this should be like a list of lists yeah it's a list of strings right there's a list of paths so the next possible ones are a small visit okay now you you won't link to yourself so we say so we have the next possible ones and then we have a SV so small visited so let's just call these next small visited prime equals equals small if it is big K then small visited else set that insert okay small visited okay so we insert and this is gonna be our next small visited so now we will say a next pass equals so we do concat map num pass prime a small visited prime over next there's gonna be a list of charts and then we have map K next pass map K so we're gonna add K on the front of all the next paths let's just check it might actually work this is the magic of recursive things they're gonna loop where it's gonna work oh no okay a print pass so start a b a c a and I think it actually worked I think it actually worked damn see and this is the beauty of recursive stuff you don't really have to you don't have to be sure like you just you just kind of this is how we solve Sudoku's like we pretend we know the next step and then we just like we find that yeah I think this one works let's run up for example to God damn to do 19 paths okay and then we have even larger I'd like to see you do this in rust 226 okay let's do for the input I am going to chalk this up as an absolute V for functional programming okay let's see time it 5178 23 milliseconds paste it save it we did part one and it only took us 35 minutes we will celebrate with slightly more cookie that's good cookie it's called vanilla cripple vanilla cripple crippling cripple no I'll get the name soon I think a little I might know the name okay big kids can be visited a number of times single small kids can be visited most twice and the remaining small kids can be visited and most ones vanilla keep furl vanilla Kefal okay now have the cookie porn okay however the caves named start and end can only be visited exactly once each once you leave the start cave you may not return to it and once you reach the end case a pet post and immediately okay I think so let's call this task one this is a length okay so what I'm gonna do now is I am just going to pick one of them one of the small ones and and then we're just gonna pretend it pretend we do it okay so let's see ding ding ding ding ding ding ding ding so task two okay so we're gonna keep the same approximate structure but we are going to say we are going to say map we're gonna map these over the small ones okay so we're gonna say a small keys equals a filter so it's not equal to start so okay we have x a key and then a key is not equal to start and key not equal to end and not is not his big K over a map keys NP so these are the fixes over small keys where a lip I think I can do it like this and then we have a two K2 twice key and this one is not happy because yeah it will return a list of list of strings but I want this to be unique set dot from list a dollar set dot to list dollar right so I have a concat map so but now I get some paths twice probably so we just do set dot to list dot set dot from list over this look at the unique paths okay so we could do this for the K2 twice key let's say twice key now this is not pass a concat map not pass twice key now okay so now we have the twice key but we need to check if if the twice key has been visited okay so the TK visited let's say twice key visited let's call it TKV TKV TKV is gonna be false big visited TKV the second argument if any numpads TK TKV okay so this one starts with a could my expected type map string what let's put the numpads prime it's a set of strings to pull to a string to a string to a list of a string well only TKV okay so twice key so a TKV prime is equal to a it's gonna be TKV or a K equals equals twice key we have here a TKV prime so small visited is gonna be if is big K then small visited else if not TKV then if twice key visited then um so this is gonna be if is big K or a TKV okay otherwise we don't insert it and then we check for the twice key and then we do the blah blah blah okay let's run this and now we seem to be getting to a loop oh it's doing it for the input that's not good let's run on the example example ding ding ding ding it's getting stuck somewhere that was G okay a let's just check first twice show it so the small keys are bcd now a so TKV of twice key so we don't actually care here okay no and we don't even care about the big visited here okay but here we care about the map K next pass let's do trace show ID on this expression I think we have to say not TKV here actually it seems to be doing too much work also like we're also supposed to count the path yeah okay anyway we we have the key we're allowed to visit twice mm-hmm I think it's just a small error somewhere okay at least look at our example this is our map maybe bc and dy is a C not in the map okay it's not equal star K is not and not is pk is it because wait right it's not in the it was not in the list which should be bcd okay it's okay let's ignore this one and let's ignore this one we're gonna make this into a a map string to int okay and then we're gonna put them back in there but we're gonna you're going to allow it to be we're gonna say we're gonna add start here so this is gonna be the we're not gonna have twice key here but rather a tk we're gonna say that this one is a map dot from list start comma one tk comma minus one okay then we are going to say and now we're just passing around the small visited and small visited prime is going to be a map dot update so this is going to take the map dot update update value at a specific key on the key is not okay so up adjust okay so update updates the value at x okay if it's if fx is nothing element to update with key so this is map update with key and we get the uh k and we get the v and we do a just v plus one we keep track of how many times we visit all of them well isn't it and so next is going to be a set to list a and now we're going to say a map dot filter map filter and so we check the ones that are mapped off filter larger than equal to one of the a amp and this is a new map keys let's see can i get like the uh how do i get like two list uh two ask list keys key set right keys set minus minus a map dot keys set okay now this one is a set it would wear now we're gonna say map from list ding ding ding ding okay now this one uh not passes by too too few arguments okay i would don't care about this one neither anymore and we don't have that twice key anymore and uh small visited prime a map update with key wait oh okay yeah map update with key and then a function and then the key updates the value if i want alter actually i want uh map dot alter and then it takes a up df okay and update is going to be up d of nothing is going to be equal to just one up d of just just n is equal to um just n plus one now this one is going to be mapped off filter larger than one and it doesn't like the one here uh why is it oh yeah this one should be let's see if this what is this this is not seem correct let's uh remove the uh all right it's because i am i forgot the if is big okay then this one looks better now let's compute the length we have 36 222 to school down to part two well there are 36 okay now example two 203 example three 3509 okay i think we're good 1394 we finished day 12 exactly in an hour we just did eight o'clock i think yeah this was good i mean it looked very bad at the beginning we're like oh no we're gonna have to use graph algorithms but turns out graph algorithms are just a graph algorithms are just yeah so like i mean we i mean we didn't know how to do it right so we had to like check right discrete i mean like we googled like number of paths on a graph and said backtrack okay that was the only thing we needed backtrack and i mean it does take a one two six seconds and we could probably get away with something faster but i kind of like here that we could technically um we can see we could you know if the problem had been count how many times each one has been visited in each of your we could have done that right and one point two seconds yeah is that that's okay right let's see because i usually have that like hey if it's more than one second we try to optimize it so let's see well how could we make this faster um so one of the things here is that we have to kind of iterate through all the keys in the key set how long do we was task one let's actually see how long does it take for us to find the unique path without the unique oh wow so just the part where we find the uniques is taking us um that's taking us a lot of time how can we avoid that so we've done it already but so we're taking a long time and it's because we kind of find all possible paths per key and then we have to and then we have to um then we have to find the unique one that's taking us a long time it's also like a list of list of strings i'm wondering if we could can we make it like smaller somehow okay because only the ones that the only the ones that visit that one twice will be if it only contains it yeah i'm not sure let's see how can can we like do it at all at once right like um in fact just kind of just figure out the paths that contain the one we visit twice yeah i mean there's probably like a some other solution that kind of does it in a better way because you can also like start from start and start from end and then kind of compute them at the same time so because we get 130,094 um but if we don't remove the duplicates we get 161,162 so there are like um let's see what what would we get for task one let's do here uh string 178 um and how many small keys are there let's say first show length small keys i just want to see does it has one we have five one seven eight and seven now seven times five one seven eight three six two six one six six three four zero okay we can't like yeah okay that's not enough okay let's see let's keep it at you know if it's still it's still it's still one second right you know it's not two seconds it's not it's not 20 seconds you know it's still i think it's still a reasonable amount of time to solve it and we can probably change the map right so that it's like uh can you kind of map yeah okay can we use like a school hash map because now it's like using like an ordered map but uh this is like uh this is unordered constrainers containers which is not uh yeah all right i think we're gonna cut it finish it today uh we did it in an hour it took us 1.2 seconds to finish uh where of a lot of that time is just making things unique which is uh yeah and i think there's probably a dynamic like we could probably keep track of the ones we found and then kind of um you know kind of yeah and then kind of like so if we had all the paths in the single visit case and then we could kind of from those you know figure out where to add the new cases and then compute it a bit faster but uh it's gonna it would take us like another hour or half or two to figure that out and i mean and we don't we don't like the gains wouldn't be crazy right it's not like oh we couldn't do it in a reasonable time um so i think we're gonna call it quits for today but uh yeah i like i like this solution because it also like keeps track of how often we visit how often we visit them what if we let me check is the filter here taking a long time the filter takes a very long time i mean it's also visiting a lot more things so let's see num scene tk let's pass that 2k here actually a tk string you don't care tk tk okay so uh num tk equals let's see um scene equals map dot dot keys set small visited okay map dot keys set small visited okay so and then we say all scene prime equals if a case a small visited map dot bang uh tk of just one is gonna be uh let me see uh i mean that's i think that's fine right because it's uh that should be fine that will let's check that later okay so let's see okay small visited map tk of okay if it's just the one then it's small visited then uh if it's just so if we've seen it only once then we do set dot delete then we do a tk set the delete all scene otherwise it's just all scene the square root function in haskell how is it not uh how is it not precise i don't quite i don't quite get the question actually um yeah okay i mean that's just the floating point error yeah we don't have infinite accuracy right so you have to you have to take care of floating point error specifically right so you just have to say you know fpeq ab is equal to uh a a b s a minus b less than equal to less than delta delta equals like 0.0001 right and then fpeq skirt a let's just do product another map sqrt a 5595 yeah so that's how you you do floating point equality right because you cannot trust you know i can do one plus and what what is it like uh floating it's like 0.2 plus 0.3 right something like that floating point error a what is the classic example a error mm-hmm i don't remember what it is uh floating point error in javascript and then you get like the yeah 0.1 plus 0.2 all right so you get this right so if you say is this equal to 0.3 you get false right so you have to write the fpeq so yeah so you always have to do a delta with floating point because it's not precise so i mean yeah because the square root kind of seems obvious right but like you know these numbers like how are you gonna how are you gonna make this equality work for that right another you have to like make this one be equal to 0.3 which some languages do or you do you like can figure like a delta oh and that's like and that's the thing right you need to know what your position is to make a to make a proper this decision um this is what this was first was it maps dot keys set a map dot filter larger than equal to one mp no a small reseted right look like this what is it what what did we change it was like this right it was doing the right thing yeah okay and then i just passed tk alone i'm just solving uh because it takes 1.2 seconds and we want to get it under a second how fast did you do it to me to me knows all the tricks right but like how was what's your i know it depends on cpu demi what what's your like approximate are you just saying that because it was slower num tk equals case a tk map dot bang yeah i mean it depends on the cpu right but we're doing 1200 milliseconds it is 300 milliseconds yeah so 60 milliseconds right that is you don't have a cpu that's 20 times faster right do do do do do let's see map stock map map dot key set okay and this is gonna be so if it's just two it's svks otherwise it's a svks set dot delete just in case and larger let's do svks set dot delete a tk right this is gonna be what's wrong here now we don't have to do this filter we can just say to remove right i think that should work because it's uh this one should be okay that optimization didn't help at all so yeah let's uh try this other one that instead of having these a set of strings we have them as this list of strings we actually don't do lookups uh well we do do lookups actually we do it here yeah i think that's the thing right we we want these three sets i mean we do set that list like always but okay okay demi how did you do it because we if we if we don't uh i think we yeah so because we we're not currently tracking the like unique path so we can do it in like 500 milliseconds but uh it's because we compute again again again without the unique paths and i'm thinking you can like uh yeah let's see you can kind of you can use the paths you find and then you can kind of compute from those right about yeah how about let's change it okay so instead of having the two key here let's try to copy task one but like add a fake node that has the same connections as um so task two mp prime this is gonna be um test two prime mp dollar and then we we need to still figure out the small keys we found the small keys and we're gonna so instead of referring to mp here i'm going to refer to i'm gonna say map to small keys task two prime mpk equals where so it's gonna be mp prime and mp prime is going to be um we're gonna say we're gonna say a so the the neighbors of a kn is equal to a map dot bang so it's gonna be mp map dot bang k uh so these are the the neighbors of k okay so um we are going to take those neighbors and we are going to say a map we're gonna say k plus i think this one the is big one fail so just say any here okay and this one will say case what is happening okay and it doesn't like this one it's actually like this okay so we get the and we're mapping over the the neighbors and so we get the k neighbors is a mp map bang k okay so n kn is going to be equal to uh so okay so mp prime is going to be equal to um map dot insert uh we just say you know two k we add two to the front of k or just a mod k and uh yeah two k okay and we're just hoping that this won't be let's have a dollar k map insert dollar k is going and then we add the kn so we added that um no it's complaining about the yeah yeah okay because we we return a so we still need the uh unique one no we don't need this actually so we just say oh we do need the the uniques because we're gonna still gonna get a bunch of uh but they won't be the same we're gonna give this optimization a go and then we are going to call it quits just to see if it actually does something but i don't think it does so we insert with the modified one the mp prime okay and we say a map fix path we need to fix all the paths as well where a fix path of uh equals map fix a so this is essentially saying that if it starts with dollar k it should just be k uh fix paths where fp dollar k dollar k is equal to k and fp otherwise is equal to a k is equal to k map fix path a map yeah okay okay so we fix the paths but this one is going to be we insert this one and then we do um mp prime prime is equal to folder um fold r and it's gonna be halter no it's gonna be update it's gonna be flip no i think it's update actually a yeah okay update and we're gonna say fold our update so we're gonna take in all the new other keys and we're going to add a we're gonna say a set dot insert a k so map dot update takes in an a and it turns to maybe a so we're gonna say just set dot insert k and mp prime um so mp prime is still the map right now fold r yeah it takes in the base value mp prime prime and it should get and the and the other one should be k and maybe it's fold out prime no it is fold r but it's saying that uh expected k map a k is actual type mp prime is applied to few argue oh right i didn't i forgot to k and mp prime mp so mp prime prime and then this one should be mp prime prime let's see if this actually does anything non exhaustive patterns in lambda all right okay that was actually way slower pretending to add a new value is just worse than just counting but let's see is it best because we produce a lot more paths now it's actually just it's actually just slower okay so we we're gonna prefer this one okay dammit can you tell us how you did it how did you make it so fast before we end this all right i mean so here's our approach right and we we just kind of generate a map so we have like a recursive descent algorithm uh with backtracking uh and it's kind of magic right it just kind of it finds all the next paths and then it maps like it adds k in front of those so you kind of yeah so you start somewhere right in you you find all the paths uh you figure it if you yeah i mean we do that here right we say we we kind of remove the ones we've already visited uh and we so instead of uh yeah and we keep track of it with a map so we just kind of mark every time we visit a k we count okay we visited that now um we actually this is it's simpler than this because you don't use the tk here we just mark it and uh and then so we kind of just say okay we mark the one with a minus one and but how did you represent your graph so our graph is represented by kind of just making a map of all the connections maybe if we made it like one way i'm not sure that's okay though let's see i don't think this works no exactly we can go both ways i mean so most of the time in our solution is actually kind of removing the ones that are so finding like which paths are unique or not that's actually taking half the time removing the non-unique path so do you like keep a track of uh do you keep track of it somehow let's uh yeah i think that's maybe uh maybe that works maybe we can because we have a map a map of set of strings because we take the key set here so but like maybe we can um maybe we can say here something like uh k set dot lm small visited equals nothing so if uh let's do like this maybe this like key set filter here is the one that's worse so if you've never visited it before then we want to do this if it's just one where viz equals small visited map k okay so if viz is a viz is nothing and it's like this this is just k one let's have tk here tk tk i've just one and uh so that's not added here okay equal to tk so we've seen it twice and okay let's see like this yeah that's what we also do here we do that in task one we always filter out if the if we've if we've seen it before right so we do task one the same but for task two we're like mapping over the small keys right and then for all the small keys we're gonna be generating a bunch of uh unique you know we generate a bunch of different ones right and then we have to check for those that are unique with respect to that let me say here now it just gives a k zero so if it's nothing it should be mapping over the next one probably just returning uh empty strings at this point let's see i'm just gonna be empty still why is it empty okay but take you here if and do do do do do oh okay otherwise it's gonna be okay so we do um let's see right let's print uh small visited okay it's uh not actually checking any of them all right because we were starting at start and then we just do map dot empty here are we just looping now or is it just super slow okay but now we're now it's doing the the thing except it's not doing the unique ones but it's doing it slightly faster right okay um so we don't actually yeah okay okay so uh if set cut that member let's see tkv that's tk visited okay let's see set that member a k small visited okay if so if we've seen it before and k is equal to tk and and tkv and k is equal to tk then it's empty okay um okay so if uh otherwise uh visited equals k set on member small visited okay if it's been visited and we've seen it before comma tkv is equal to so then this one should be tk and it starts with uh it actually starts with false okay if visited okay otherwise if it's not visited or then we do the uh otherwise we say visited the next path this is gonna be kkv or is what we're gonna do initially right okay but now it's not visiting it twice and it's taking like 300 milliseconds just to do that and see now and this is just uh i don't know what's happening here like that the new one value is like either it's already true or we're looking at the new looking at it right now okay so if it's visited and we've seen it before uh what am i doing wrong so we're not allowing it to be seen twice visited not tkv so k not tkv k equals tk then it's a continue otherwise if it's with visit of it and uh k is not equal to tk then we're done okay otherwise if it's visited and tkv and k is equal to tkv tk then we are done visited uh i'm doing something wrong here i don't think this one works let's just keep it as it was trust in the undo buffer yeah i'm gonna i think let's uh change it if it's if it takes longer than two hours then we no two minutes then we quit let's call it quits for today uh we've been doing trying to optimize this for an hour and nothing's happening right and i'm gonna do different stuff all right thanks for tuning in and see you tomorrow at seven o'clock again or the next one all right bye