Please continue AoC 2022 series till the end. It is amazing so far (from the perspective of someone learning Rust).
@chrisbiscardi2 жыл бұрын
I'm planning to do all of the problems this year 🤓
@tenthlegionstudios1343 Жыл бұрын
Discovered you through bevy videos. And then found your advent code rust videos, and these are great as well. Much appreciated!
@chrisbiscardi Жыл бұрын
Glad you're enjoying them!
@thirdvect0r2 жыл бұрын
Great vid, much clearer parsing than my answer, which was just a bunch of split()/skip()/step() calls. I also used drain() at first, then discovered split_off() which mutates the original Vec and returns a new Vec with the last N items (kinda like a reverse take) Really enjoying this series as someone fairly new to rust :)
@Cwiet Жыл бұрын
Thanks for the hint to use `split_off`. It was the last missing piece in order to solve the second puzzle. Thanks borrow checker.
@bloodynoobtubename2 жыл бұрын
Hey Chris, I just wanted to say thank you for this series so far. I've been wanting to learn Rust, and figured I'd give it a go during this years AoC. I no longer work in software engineering so I don't spend much time coding anymore. I've been following along with your videos and I just wanted to let you know I appreciate your method of explanation, it's really helping me grasp some of the key concepts of this language. I hope you keep this series up; I look forward to learning more as the days progress!
@chrisbiscardi2 жыл бұрын
Thank you for letting me know! I hope you enjoy the rest of the aoc videos ❤️
@ykhi2 жыл бұрын
My favourite way to learn rust! You're amazing
@finefindus2 жыл бұрын
I used vec split_off, it returns a new vec, which I then could push to another stack. So I did not have to drain and collect. Nice void tho
@SomethingSpecialLP2 жыл бұрын
I really like you series and how you approach the problems. It's a completely different approach and coding style than mine, so very interesting to follow. Keep up the good work! As some tidbits for today: - As some others already said you could have used either the r#crate name (which you tend to avoid, I read the comment) but you could also use the name "krate" which is the name other rustaceons agreed on for "crate" like the java guys "clazz" for class. - You dont need to get a value into a variable to dbg!() it. dbg! will open a new context and return the variable you pass in as a context so you basically can slap it anywhere (as I tend to do quite often) I hope my comment does not sound forcing, just wanted to let you know :)
@artemivasyuk16992 жыл бұрын
Hey Chris! This one was tough for me due to complex parsing so had to peek your video first in order to understand how nom works. Was able to solve both parts before blackout :)
@chrisbiscardi2 жыл бұрын
glad it helped and that you were able to get it completed!
@shortc1rcuit3262 жыл бұрын
thanks for this incredible showcase of the powers of nom. I'll definately be trying to use it in future AOC challenges
@sanderbos42432 жыл бұрын
Really loving Nom now I've seen how useful it is twice! Splitting by characters the old way now just feels dirty, haha
@flippert011 ай бұрын
Love the fact, that once part 1 was solved, part 2 was totally trivial (like in AoC 2022, Day 4)
@paweostrowski48692 жыл бұрын
Still watching the vid, but had a look at source code already. Really like how clean the nom parsing comes out, especially compared to my manual parsing code. I saw no reason to use nom for day-04, but now it's clear. Seems I'll be improving my solution now :)
@chrisbiscardi2 жыл бұрын
yeah I think as we get deeper into advent of code the solution space nom fills becomes more apparent, especially compared to manually splitting, etc.
@samroelants2 жыл бұрын
Eerily similar to how I solved it. You can forego the `.map_filter()` to weed out the `None`'s from the final stacks by just not pushing the `None`s onto the vertical stacks in the first place. ;-) Easy enough to match using an `if let Some(c) = ...` and only push when there's an actual crate present.
@awnion2 жыл бұрын
That one was fun in the context of Rust. Vec
@charlesbcraig2 жыл бұрын
I'm convinced that if I had just hand typed the Vec of Vecs instead of parsing the file, I'd have saved soooo much time haha. I actually used a HashMap of Vec so I could specify exact indexes instead of having to do a +1, but more so cause I wanted to try out HashMaps. Ran into mutable borrow issues though cause most of my work was done via functions... eventually scrapped all that code and made everything immutable and created some functional helper methods to add/remove using cloning side them to return a new immutable copy each time. Not the best route, but it's helping me learn!
@chrisbiscardi2 жыл бұрын
this day was definitely one of the harder parsing days, especially if you were using a .split style approach to it. glad you're finding good learning routes! I really think that's more important than getting to an "optimal" solution.
@tiloiam2 жыл бұрын
Great video again! What is the shortcut/setting in vscode to show/hide those return types/parameter types?
@chrisbiscardi2 жыл бұрын
I use a third party extension called toggle to turn inlay hints on and off
@Kay8B2 жыл бұрын
First time seeing rust and this looks pretty dope, Imagine the underscores are values you dont need to keep? I parsed the values for the crates starting from index 1, +4 until the end of line as all the values sat 4 chars apart. saved me abit of time.
@chrisbiscardi2 жыл бұрын
Yeah exactly, an underscore is something that is there but I'm not using in the rest of the program.
@Kay8B2 жыл бұрын
@@chrisbiscardi Ahh that makes alot of sense no wonder its performant. So you couldn't reference it after that line? Will watch more of your videos and maybe pick it up, subbed.
@chrisbiscardi2 жыл бұрын
@@Kay8B right, the underscore is something you can use when destructuring, so in this case I use it a lot when the parser returns a tuple. The first element is the rest of the input string, and the second element is whatever I parsed. Often I don't need the second value for anything, so I use _ instead of a variable name. I wouldn't say the feature is related to performance though. The Rust compiler already knows, and will warn you, about unused variables. So it's mostly a programmer convenience. Thanks for the sub! Feel free to drop any questions in the comments on videos.
@inzyster2 жыл бұрын
You can triple-click the text block with the test data on the AoC website to select all of it including the whitespaces. Found out today 😅
@bustamove3612 жыл бұрын
Nice. Nom for the win again. Any reason you stored the crates as &str instead of char? I parsed manually with for loops over the lines since the positions were so predictable but it seemed chars would be the most natural type to hold the base values in. Also, I wonder if you could have make the parser a little cleaner for the moves by just parsing for 3 u32s separated by arbitrary text that wasn't digits?
yeah, the &str in the parser was mostly because the tag parser returns a &str and matching the return values for both was easier than mapping to return an Option. It wasn't a strong choice, but also having chars wasn't a strong requirement either, they're more like opaque database ids in my mind than "chars". The parser for the numbers expands to 8 values in the real input, so we can't do a tuple(u32,u32,u32)(input), but there are likely other improvements that can be made.
@echobucket2 жыл бұрын
Today is the day that AoC in rust defeated me :( Had to just watch this to figure out how.
@chrisbiscardi2 жыл бұрын
What part did you end up having trouble with?
@DJSt3rling2 жыл бұрын
I'm enjoying the Go, Java, and Rust solutions! I'm doing mine in Python, which feels like cheating.
@MartinClausen Жыл бұрын
I think those long lists of let bindings can be avoided using do_parse!.
@chrisbiscardi Жыл бұрын
They can be avoided in a couple of ways, but it's generally easier for the people that copy paste and learn from my answers to debug as well if they're long lists of let bindings.
@cthutu2 жыл бұрын
You can just use the include_str! macro and put the data in a separate text file
@valeth64722 жыл бұрын
Guess it would've been possible to use the a bit awkward `r#crate` notation for this. Very unfortunate naming of things in today's problem for Rustaceans. 😆
@chrisbiscardi2 жыл бұрын
haha yeah, I could've gone with the r# notation. I *tend* to not use it myself which is why I didn't reach for it, but it's totally valid here and I could have used it.
@markday31452 жыл бұрын
I spent a lot of time trying to find non-existent bugs in my ad hoc input parser because the example input's first line starts with spaces (my problem input didn't). When putting that input into my unit test, I tried to do it like: let input = "\ [D] [N] [C] [Z] [M] [P] 1 2 3 ... "; Notice the backslash at the end of the first line. My intent is to make the input look identical to what I see on the web page. Without the backslash, my input would start with an extra newline. But since the second line starts with spaces, those spaces are *also* escaped. This is documented behavior, but I find it quite inconvenient. Once I figured out what was going on, I removed the backslash and just passed &input[1..] to my solution. The rest went pretty smoothly. I'm quite surprised how often my Rust code works on the first or second try. "If it compiles, it usually works." One problem I hit in part 1 was moving a single crate. I started by trying `stacks[dest-1].push(stacks[source-1].pop().unwrap())`. But it complains that I can't borrow `stacks` immutably more than once. Adding an `assert_ne!(source, dest)` didn't convince the compiler that I was trying to borrow two *different* elements of a vector. I solved it by popping from the source and storing that in a temporary variable, then pushing onto the destination. Anyone got a cleaner way of doing it? (I know I could use unsafe, but I prefer not to.)
@chrisbiscardi2 жыл бұрын
what does "cleaner" mean to you in this case?
@markday31452 жыл бұрын
@@chrisbiscardi Good question. In this case, I guess "cleaner" means a way to get mutable references to two elements of a Vec (or slice) at the same time. I think I'm balking at the need to create and name a temporary in order to get non-overlapping borrows. It would be more important if the element type wasn't Copy, and you had to do an expensive clone(). I know that the borrow checker added the ability to have multiple mutable references to different fields of a struct, in the not too distant past. I guess I'm looking for something similar for Vec or slice. But thinking about how I might go about creating such an API, the error handling gets cumbersome quickly (either of the indices could be out of bounds, or they could be the same index). You could have a version that panics on error. One that didn't panic would have to return something like Result. But how would that error type convey that one or both indices was out of bounds, or that they were the same? And it might not scale easily if you wanted 3 or more indices at once. When I first started using Rust for Advent of Code, I remember being annoyed that I had to name a temporary to get it to live long enough. I would do a std::fs::read_to_string() to read in the input. I would sometimes have a parse_input() function that take a &str (more convenient for unit tests), and return the parsed data. I would call it like parse_input(&read_to_string("input.txt")). If that parsed data included references to the input text, I'd get an error about a temporary (the return value from read_to_string) being dropped too soon. The solution is to assign the result of read_to_string() to a variable. I've gotten used to that particular case. That's really no different than the need to separate the pop and push in this problem. Not sure why this one was bothering me more. I also tend to get tripped up when doing an iter_mut() over a container, and then wanting to access some other element of the container inside the iteration. The solution ends up being to iterate over indices. That sometimes feels like a step backwards, to an older language like C or BASIC. A for ... in loop or iterator chain feels "cleaner" than doing a lot of array indexing.
@chrisbiscardi2 жыл бұрын
@@markday3145 > It would be more important if the element type wasn't Copy, and you had to do an expensive clone(). In the case of pop(), you're doing neither. pop() hands you the value. > I guess I'm looking for something similar for Vec or slice. It would be nice to have this, yeah. The closest we can get today is using something like split_at_mut() which will give you two slices which can then be mutably borrowed independently. Its safe Rust to use, but the implementation is unsafe -- doc.rust-lang.org/std/vec/struct.Vec.html#method.split_at_mut > I remember being annoyed that I had to name a temporary to get it to live long enough. Yeah definitely. I think understanding that if you don't tell Rust you want data to stick around it'll get rid of it for you (and if you have references into that data when it drops, then you're pointing at nothing, which is why the compiler stops you), is something everyone has to learn coming from other languages. This is also what leads to lifetimes (the data has to live at least as long as the references *to* that data). > when doing an iter_mut() over a container, I definitely default to immutable workflows first. If you're building up a new container, then you can have shared access all over the place. You can also use fancier iteration techniques like scan to hold state as you iterate.
@DJSt3rling2 жыл бұрын
I copy/pasted input instead of parsing initial input. This took me < 1min: stacks = { '1' : ['C', 'Z', 'N', 'B', 'M', 'W', 'Q', 'V'], '2' : ['H', 'Z', 'R', 'W', 'C', 'B'], '3' : ['F', 'Q', 'R', 'J'], '4' : ['Z', 'S', 'W', 'H', 'F', 'N', 'M', 'T'], '5' : ['G', 'F', 'W', 'L', 'N', 'Q', 'P'], '6' : ['L', 'P', 'W'], '7' : ['V', 'B', 'D', 'R', 'G', 'C', 'Q', 'J'], '8' : ['Z', 'Q', 'N', 'B', 'W'], '9' : ['H', 'L', 'F', 'C', 'G', 'T', 'J'], } I treated arrays like stacks, where operations are performed @ TOS. Here is the rest of my solution: github.com/lulzb0at/AdventOfCode-Solutions/blob/main/Day05/a.py Good job! It's cool seeing how other's solve. My goal is always to be as fast/lazy as possible.
@chrisbiscardi2 жыл бұрын
nice! if your goal is to be fast (at coding it), have you looked into programmatically downloading the input? I've seen a number of tools that do this for you
@YTCrazytieguy2 жыл бұрын
This is extremely similar to what I did 😅 vec has .last, you don't need to do vec.iter().last :)