I've also added an example that uses aho-corasick: one of the underlying matching libraries that powers the Rust regex crate. It is a bit slower (20 milliseconds vs 20 microseconds github.com/ChristopherBiscardi/advent-of-code/blob/dca401065808666c7553b4ba157eb0cbb31a6abf/2023/rust/benchmarks.txt ) but applies very well to the problem. github.com/ChristopherBiscardi/advent-of-code/blob/dca401065808666c7553b4ba157eb0cbb31a6abf/2023/rust/day-01/src/part2_aho_corasick.rs
@QuentinMcCormick-o4q Жыл бұрын
I am very new to Rust coming from a little bit of C, Javascript & C# mostly, so i am using advent of code to sharpen up my basics and understanding of syntax etc.. however i probably spent close to 3.5 hours trying to get Part 1 and 2 done in a way that i thought looked right and understood. But after seeing this video, I realize I still used so many levels of useless abstraction i did not need. And it has shown me allot of concepts in rust I either didn't know about or didn't understand how they were implemented. Subbed, great video 👍
@mariothrowsfireballsuntitl1841 Жыл бұрын
same. I think this way of solving the problem then watching the video is really helpful
@nomadvagabond1263 Жыл бұрын
Same😂, i solved those problems as if i was writing C.
@TheUkearchy Жыл бұрын
The amount of detail and explanation in this is extremely educational, thanks so much!
@MaikDiepenbroek Жыл бұрын
Great stuff, this year i'm gonna dive into rust myself. So your setup video helped me out a lot! GL with this years AoC!
@kevincodes674 Жыл бұрын
I took a different approach on part 2. Created an array of tuples like ("one", "o1e"), ("two","t2o"),("three","t3e"), etc... then looped with a replace. Luckily the numbers will only overlap by one letter max, so I just kept first and last letters. Then, just pulled out digits in the same order 😊
@tapu_ Жыл бұрын
Despite trying not to participate, I did and instantly did a war crime with .replace("one","one1one").replace("two","two2two").replace("three","three3three").replace("four","four4four").replace("five","five5five").replace("six","six6six").replace("seven","seven7seven").replace("eight","eight8eight").replace("nine","nine9nine").split(" ")[:]
@lielfr Жыл бұрын
almost as I did 😊 I was just lazier and did "one" to "one1one" etc.
@orizach01 Жыл бұрын
I had a list of all the numbers as strings, then looped over each line and each number and checked if line from i to i + len(num) == num, then I add the number to a new line and also all the normal numbers, then I do the sum
@chrisbiscardi Жыл бұрын
It seems a lot of people did end up with this approach. Its quite nice for re-using part1's code
@srgibberd Жыл бұрын
To get the last digit, I reversed the line, then used pattern matching on "eno", "owt", "1", etc.
@endrevestb895 Жыл бұрын
This is going to be a great year for AOC :D Thx! Looking foreward to tomorrow!
@ExpertOfNil Жыл бұрын
I'm glad I wasn't the only one that got hung up by the overlapping number words!
@ThePixelSlime Жыл бұрын
These are simply amazing! I'm learning Rust and the deep dives are super helpful. :D
@oghenemarho5694 Жыл бұрын
Thanks you for this Tutorial Chris, it really helped me with the part 2 of the challenge.
@pwbandwidth Жыл бұрын
This is such a great concept for a series. I've been solving the problems mostly in JS or Python and then just translating them to Rust, but this series really helps in learning how to think in Rust.
@diegoparraca Жыл бұрын
That's definitely awesome content for us beginners :D, please keep doing it!
@ericaustinbarber4186 Жыл бұрын
Thank you Chris!
@siddharthbisht8522 Жыл бұрын
Wrote my first rust code from scratch today. Took me 1 hour to get both stars but was worth it. Thanks to your previous video, I learned about Advent of Code, which also led me to discover Advent of Cyber.
@siddharthbisht8522 Жыл бұрын
@@Gers217 ✌️
@florianbopp187 Жыл бұрын
very interesting, I took a very different approach, which might not be performant, but I am just doing this to learn rust. Basically I had a couple of helper functions: get_first_and_last_digit(line: &str) -> (usize, char) // returns tuple of index and found digit as char get_first_and_last_sting_digit(line: &str) -> (usize, char) both of them use the string.find or rfind methods to get the index of first or last occurence, for the string based digits I had another helper funciton which matched from "one" => '1' etc. so both function would have the same output. then in the main() I compared both functions output and chose the lower index version for the first digit and higher index verison for the second input. concatenated with the same forma().parse() and tada it worked
@chrisbiscardi Жыл бұрын
nice! You might be interested in aho-corasick, which does multiple searches at the same time and seems like an evolution from your current approach -- github.com/ChristopherBiscardi/advent-of-code/blob/dca401065808666c7553b4ba157eb0cbb31a6abf/2023/rust/day-01/src/part2_aho_corasick.rs
@yumbuboyumbubo8230 Жыл бұрын
Hello fellow rfind and find user! My approach is similar, but I used a single array and instead of mapping I used index % 9 + 1
@kentbowling7513 Жыл бұрын
The "eightwothree" actually not mattering in the test input was so evil (either way would return 83)🤣 Your solution is much more elegant than mine. In part 2 I abused a regex, and in the process learned the std Rust crate doesn't have "lookahead assertions" to do it cleanly. There's another crate called "fancy_regex" that does, but I instead just matched multiple times and advanced where I was looking 1 index past the start of the last hit. If I had to guess, my approach would only work for ASCII and I'd be in trouble if someone for instance put a poop emoji in the input 💩. I'm not sure if yours is affected, but I'll probably go check it out for fun. Your more "functional programming" approach is so much cleaner in the end, and I need to train myself to take those sorts of opportunities.
@chrisbiscardi Жыл бұрын
as far as elegance goes, the "aho corasick" implementation in the repo is far better than even what I show in this video, although the benchmarks show it slower in this case (ms vs microseconds).
@markday3145 Жыл бұрын
This was the first time I made an effort to make my string processing Unicode-friendly. I ended up using str::char_indices to loop over valid character offsets. That also returns the character at that offset. So I checked if that character is_ascii_digit(), and called to_digit(10); otherwise, I looped over the words "one", ..., "nine" and did line[i..].starts_with(word), and using the word's index plus 1 as the digit.
@flyingsquirrel3271 Жыл бұрын
This is fun, thanks for making these videos! A much more efficient solution for "concatenating" two decimal digits would be to just multiply the first one by 10 and then add the second one. Allocating a string, parsing it and then deallocating it is kinda excessive, I'd say ;) On the other hand, your solution is probably more helpful for rust newbs that are watching since they learn how to do the string stuff.
@chrisbiscardi Жыл бұрын
Yeah, I refactored to do the math in the repo afterwards
@markday3145 Жыл бұрын
I keep forgetting about filter_map(). At least this time, I did .filter(...).next().unwrap().to_digit(10) instead of .map(|c| c.to_digit(10)), so clippy did't warn me about it. I feel marginally better about forgetting filter_map when I never actually used map(). I liked the way you did match it.last() to handle the case where the line only had one digit. In part 1, I ended up iterating over each line twice (once to get the first digit, and once for the last digit). In part 2, I was using a for loop instead of an iterator chain, so I used Option variables to keep track of whether I had seen a first or last digit yet.
@servalp Жыл бұрын
very nice to see some else's approach. I totally forgot about starts_with. You can "clean up" that if-else tree with a match, like so: match &word { w if w.starts_with("one") => Some(1), w if w.starts_with("two") => Some(2), w if w.starts_with("three") => Some(3), ... _ => None, }
@necuz Жыл бұрын
Checking this out after having completed day 1 (in Go, sorry but I have Rust burnout). I totally also tried cheesing part 2 with replace all ones etc. and then left-to-right search and replace. Liked the trickiness of this, but they should have had a test case that ended in like eightwo or something.
@chrisbiscardi Жыл бұрын
you don't need to apologize for using a different language. I definitely wish the test output for day 01 was comprehensive, but that's definitely something that is a factor in advent of code every year.
@Agryphos Жыл бұрын
I missed that for lines with only one number you just take the found number twice, messed me up for a bit with part 2
@jamstoast Жыл бұрын
for part 1 I used rusts' char.is_ascii_digit() and then for part 2, used an index to iterate, still using char.is_ascii_digit() for the normal digits and looked ahead for the spelled versions
@LloydHZA Жыл бұрын
This is great - just looking into Rust now and this has been super helpful. How did you do the selection in VSCode and paste at 12:41?
@chrisbiscardi Жыл бұрын
If you option+click you'll get another cursor. If the number of items you copied matches the number you're pasting into it will put one in each spot.
@IvanoColtellacci Жыл бұрын
In the video at a moment you togle the inlay hints of the rust-analyser, can you tell me how do you achive thta ?
@chrisbiscardi Жыл бұрын
kzbin.infowBTAMLp-gnc
@chrsolr Жыл бұрын
@chrisbiscardi do you have a video to make vscode do clean and simple? Theme, fonts, etc?
@chrisbiscardi Жыл бұрын
I have my setup described here: kzbin.info/www/bejne/l6GoiaCAhZqrrtk alongwith a link to some settings I was using at that time in the description. Its basically the same today.
@Ankstek Жыл бұрын
I got stuck on part 2, had the example been "threeightwo" then I'd understand that I needed to account for overlap.
@chrisbiscardi Жыл бұрын
yeah, really unfortunate that the test input didn't fully exercise what happens in the actual input
@teuluPaul Жыл бұрын
Thanks for the video Chris! I am very new to rust, and had a go a solving the problems before watching your video. I did succeed with part 1, but not part 2. I had an interesting issue with testing. If I put the test input into a file, and reference it in the same way as the code, I get a file not found error which I could only resolve by putting the full path in rather than a relative path. Which working directory does cargo use when running tests?
@chrisbiscardi Жыл бұрын
include_str! Is relative to the file that you use it in. doc.rust-lang.org/std/macro.include_str.html
@teuluPaul Жыл бұрын
@@chrisbiscardi Thanks for the reply!
@kusadasi8641 Жыл бұрын
Im new at programming, does two pointer work here? Just iterate the front and back until you get a number then combine them and then sum them. I have no idea how rust works... (Only part 1)
@chrisbiscardi Жыл бұрын
yep, in Rust there's find and rfind for searching from the front/back. Here's an example of that: github.com/ChristopherBiscardi/advent-of-code/blob/c8ccc5cb0f90d31565070be2187f9b499cfedca4/2023/rust/day-01/src/part1.rs#L4-L34
@mykalimba Жыл бұрын
11:00 For Part 2 on this challenge, I found that their examples of how words should be converted to actual numbers was not sufficient in explaining how the conversion needed to be performed. For example, if the input line is "abconeightdef", you need to convert that to "abc18def" for your checksum to match what they're expecting.
@mykalimba Жыл бұрын
@@fnmatrix And I assert that is is not "perfectly clear", in that there is ambiguity in what "last valid number" means. There is no concrete example of how an input that ends with something like "oneight" would resolve. Should it become "1ight", "18", or "on8"? _That_ is ambiguity.
@cryoexn7307 Жыл бұрын
Also I was wondering if you are manually updating your bench results with the table ligatures? I am adding benchmarking to my AOC setup and was wondering if there was anything fancy going on there :)
@chrisbiscardi Жыл бұрын
Nothing fancy, just running it and copy/pasting the terminal output. I'm not even doing the table layout, that's the bench tool output. I thought about automating it but didn't really feel like it was worth it.
@SkylerLinux Жыл бұрын
Part 2: that massive "ugly" if-else tree is crying out to be a switch, maybe an enum too
@chrisbiscardi Жыл бұрын
yeah it really is isn't it. idk why I didn't go for match guards to start with -- github.com/ChristopherBiscardi/advent-of-code/blob/3b00d6e270a90456289763e4697ceb608f7447a1/2023/rust/day-01/src/part2.rs#L17-L30
yeah ,maybe this is the only reason my solution was a bit faster: fn process(input: String) -> u32 { let c_iter = input.chars(); let mut digits: Vec = Vec::with_capacity(2); let mut sum: u32 = 0; for c in c_iter { if c == 0xA as char { sum += digits[0] * 10 + digits[1]; digits.clear(); } if c.is_ascii_digit() && digits.is_empty() { digits.push(c.to_digit(10).unwrap()); digits.push(c.to_digit(10).unwrap()); } if c.is_ascii_digit() { digits[1] = c.to_digit(10).unwrap(); } } sum += digits[0] * 10 + digits[1]; sum }
@misterwoody_ Жыл бұрын
English is unfortunately an imprecise language. I think from the spec it mentioned the "first" and "last" digit in a line of input (I could be wrong) so I thought of it as first "digit" could be found with a left to right search (stop looking at this point) last digit could be found with a right to left search. I think that does give the correct results without worrying about the overlapping and also picks up the single "digit" situation. I'm not sure about efficiency but hopefully that's a way of thinking about the problem in a clearer way? Many thanks
@chrisbiscardi Жыл бұрын
after some refactoring, that's exactly what I ended up with -- github.com/ChristopherBiscardi/advent-of-code/blob/dafde982166a4edca9a24f978c6a202fc7175dd2/2023/rust/day-01/src/part1.rs#L18-L27
@Metruzanca Жыл бұрын
On the topic of turbo-fish syntax "e.g. sum::()". Why do we need the turbofish here and can't just do sum()?
@chrisbiscardi Жыл бұрын
Basically because if you remove the :: then it's ambiguous as to whether you mean "type argument" or "comparison operator" (greater than/less than)
@CrazyLuke11 Жыл бұрын
Hey! Love your content!❤ Could you maybe to a tutorial on justbuild? Thank you 😊
@chrisbiscardi Жыл бұрын
Yep, is there anything you want to know specifically?
@xyzg34 Жыл бұрын
Is that a window manager for macos?
@chrisbiscardi Жыл бұрын
Yeah, it's yabai
@zzzzzzzzzzzzzzzzzzzzzzzzzzzz__ Жыл бұрын
if I try and run just work day-01 part1 it tells me the project root does not exist :/ not too used to this tooling I guess. all of it does seem really helpful though. but I guess perhaps I will use a basic cargo new for my aoc this year. thanks for the good videos anyway
@chrisbiscardi Жыл бұрын
Did you create the day 01 directory using ` just create day-01`?
@zzzzzzzzzzzzzzzzzzzzzzzzzzzz__ Жыл бұрын
@@chrisbiscardi i did, I tried it again just now, just create says the project was created, but running just work inside the day-01 folder gives the project root does not exist. Recipe work failed on line 3 with exit code 1
@lpanebr Жыл бұрын
Regular expressions
@vyorkin Жыл бұрын
damn, I tried to use nom for part2 parsing at first
@chrisbiscardi Жыл бұрын
you can definitely use nom for part 2 -- github.com/ChristopherBiscardi/advent-of-code/blob/14c04a3a056e648737d614da0e85d000e65af9ec/2023/rust/day-01/src/part2_nom.rs
@luckystrike91 Жыл бұрын
looks strange for me in part1, much simpler and efficien approach: let first = it.next().expect("line must contain at least one digit"); let last = it.next_back().unwrap_or(first); 10 * first + last
@chrisbiscardi Жыл бұрын
the code in the repo does get refactored after the initial day is completed (github.com/ChristopherBiscardi/advent-of-code/blob/c33be5e886003701134165bb938c5e5dad87c3f3/2023/rust/day-01/src/part1.rs). Day 1 also includes some interesting alternatives at this point that show off crates like aho-corasick, which powers the regex crate -- github.com/ChristopherBiscardi/advent-of-code/blob/c33be5e886003701134165bb938c5e5dad87c3f3/2023/rust/day-01/src/part2_aho_corasick.rs#L22
@steamedeggeggegg Жыл бұрын
doesnt expect it to be so hard in rust got it done in javascript, but i think my code is all reproducable in rust
@Gers217 Жыл бұрын
First comment 😊
@Enan_Andrew Жыл бұрын
It will more readable and concise way for combining and conversion. let mut it = line.chars().filter_map(|character| character.to_digit(10)); let first = it.next().expect("must be a number"); let last = it.last().map(|num| num.to_string()).unwrap_or_else(|| first.clone().to_string()); format!("{}{}", first, last).parse::().expect("a number")
@flwi10 ай бұрын
Nice solution! I went with a regex like this. Let's see if youtube likes it ;-) .*?(one|two|\d).*(one|two|\d).*?