From 1c582811a2d34140088982918a265fff4fa26b31 Mon Sep 17 00:00:00 2001 From: red Date: Tue, 27 Feb 2024 02:42:05 +0100 Subject: [PATCH] Chore: Rewrote solving notes --- 2015.md | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ CHANGELOG.md | 4 +++ Cargo.toml | 2 +- 3 files changed, 95 insertions(+), 1 deletion(-) diff --git a/2015.md b/2015.md index 355e81a..d6be32e 100644 --- a/2015.md +++ b/2015.md @@ -1,6 +1,9 @@ # Notes for solving 2015 ## Day 01: Not Quite Lisp +
+Tests and benchmarks + ``` test year_2015::day_01::tests::works_with_samples_v1 ... ok test year_2015::day_01::tests::works_with_samples_v2 ... ok @@ -16,6 +19,14 @@ year_2015::day_01_v1/Slow/7000 year_2015::day_01_v1/Fast/7000 time: [5.6145 µs 5.9122 µs 6.2267 µs] ``` +
+ +
+Ruby version comments +Ruby's `String` class is very well-furnished, even without all of Rail's `ActiveSupport` goodness. In that case, just using [`#count()`](https://apidock.com/ruby/String/count) is enough to get us out of trouble quickly. + +I am pretty sure there must be an algorithm that doesn't include iterating through the whole string, but so far, the only idea I got would be to use bisecting until I get to the proper index, which just felt like a hassle. +
First day wasn't very complicated. I chose to use `i16` out of pragmatic reasons, I don't believe Santa would go this high or this low. @@ -23,6 +34,9 @@ I've added [a benchmark](benches/year_2015_day_01.rs) for this day. The first ve ## Day 02: I Was Told There Would Be No Math +
+Tests and benchmarks + ``` test year_2015::day_02::tests::works_with_samples_v1 ... ok test year_2015::day_02::tests::works_with_samples_v2 ... ok @@ -33,6 +47,12 @@ year_2015::day_02/year_2015::day_02_v1 year_2015::day_02/year_2015::day_02_v2 time: [74.636 µs 74.685 µs 74.727 µs] ``` +
+ +
+Ruby version comments +I..am not even sure this one was complicated in any way. +
I used an object-like approach on this one. Using `(&self)` as he first argument wasn't too much of a stretch since [that's exactly how Ruby handles its Object-Oriented pattern in its C code](https://silverhammermba.github.io/emberb/c/#Methods). @@ -42,6 +62,9 @@ The most annoying part here is dealing with many integers size. Clearly everythi ## Day 03: Perfectly Spherical Houses in a Vacuum +
+Tests and benchmarks + ``` test year_2015::day_03::tests::moves_characters_properly ... ok test year_2015::day_03::tests::works_with_samples_v1 ... ok @@ -62,6 +85,14 @@ year_2015::day_03_v2/BTreeSet/8192 year_2015::day_03_v2/HashSet/8192 time: [179.96 µs 180.06 µs 180.15 µs] ``` +
+ +
+Ruby version comments +The only thing to be wary of is on line 16: without the call to `#dup`, all of Santa's and Robo-Santa's positions will be overwritten, since Ruby's object model has a tendancy to pass references when you expect to pass values. + +Passing by value or reference is a really wonky subject, but this [blog post](https://robertheaton.com/2014/07/22/is-ruby-pass-by-reference-or-pass-by-value/) got nice examples that will get you started. +
Again, remember to clone your references before modifying, and everything will work out nicely. @@ -69,6 +100,9 @@ This time, [the benchmark](benches/year_2015_day_03.rs) checks which of [`BTreeS ## Day 04:The Ideal Stocking Stuffer +
+Tests and benchmarks + ``` test year_2015::day_04::tests::works_with_samples_v1 ... ignored test year_2015::day_04::tests::works_with_samples_v2 ... ignored @@ -80,11 +114,20 @@ Warning: Unable to complete 10 samples in 5.0s. You may wish to increase target year_2015::day_04/year_2015::day_04_v2 time: [1.8911 s 1.8941 s 1.8969 s] ``` +
+ +
+Ruby version comments +Not gonna lie, brute-forcing [MD5 hashes](https://en.wikipedia.org/wiki/MD5) is not something interesting. +
Of course, the bastard child had to be annoying, no matter what language we are in. We can actually win A BIT of time here, but we have to fiddle with bytes. ## Day 05: Doesn't He Have Intern-Elves For This? +
+Tests and benchmarks + ``` test year_2015::day_05::tests::finds_nice_strings_v1 ... ok test year_2015::day_05::tests::finds_nice_strings_v2 ... ok @@ -97,11 +140,20 @@ year_2015::day_05/year_2015::day_05_v1 year_2015::day_05/year_2015::day_05_v2 time: [299.92 µs 300.33 µs 300.68 µs] ``` +
+ +
+Ruby version comments +Again, [Regexp](https://ruby-doc.org/core-2.5.1/Regexp.html) really are one of the best tools in your developer arsenal. In this specific exercise, we can look for repetition by using `\1`, which will reference a previously-captured group. Nothing specifically hard beyond that. +
Another [benchmark](benches/year_2015_day_05.rs), and again it's about the performance of [`.contains()`](https://doc.rust-lang.org/std/primitive.str.html#method.contains). Using [`.try_fold()`](https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.try_fold) to return ASAP when any element doesn't satisfy our needs is also a nice touch. ## Day 06: Probably a Fire Hazard +
+Tests and benchmarks + ``` test year_2015::day_06::tests::works_with_samples_v1 ... ok test year_2015::day_06::tests::works_with_samples_v2 ... ok @@ -112,11 +164,28 @@ year_2015::day_06/year_2015::day_06_v1 year_2015::day_06/year_2015::day_06_v2 time: [13.481 ms 13.585 ms 13.720 ms] ``` +
+ +
+Ruby version comments +This one actually gave me SOME trouble. My first solution was iterating on each element one by one and was clearly too long. Thanksfully, Ruby is really smart when it comes to replacing slices of an array. + +There is an even more beautiful solution for part 2 that consist of only tracking the total numbers of flicks on/off/toggle, but in the off chance that a light already off is turned off again, the results would become false. + +Also of note: remember what was discussed earlier about references? Well, the [documentation covers that too](https://ruby-doc.org/core-3.0.1/Array.html#class-Array-label-Creating+Arrays). Quote: + +> Note that the second argument populates the array with references to the same object. Therefore, it is only recommended in cases when you need to instantiate arrays with natively immutable objects such as Symbols, numbers, true or false. +> +> To create an array with separate objects a block can be passed instead. This method is safe to use with mutable objects such as hashes, strings or other arrays: +
I started doing a copy of my original "naive" algorithm, and as it was too slow, I decided to learn [how to pass closures in Rust](https://doc.rust-lang.org/book/ch13-01-closures.html). ## Day 07: Some Assembly Required +
+Tests and benchmarks + ``` test year_2015::day_07::tests::works_with_samples_v1 ... ok test year_2015::day_07::tests::works_with_samples_v2 ... ok @@ -127,11 +196,24 @@ year_2015::day_07/year_2015::day_07_v1 year_2015::day_07/year_2015::day_07_v2 time: [129.92 µs 130.54 µs 131.09 µs] ``` +
+ +
+Ruby version comments +We already discovered bitwise operators in the previous exercises, so that shouldn't be too hard. The complication comes from building the wires. + +The naive implementation, that works very well with the sample input, consists of interpreting each line one by one, storing the value of each wire every time. Unfortunately, not all inputs are indicated in a linear way. + +The answer lies in to store all wires, setting up operations with [lazy evaluation](https://betterprogramming.pub/how-lazy-evaluation-works-in-ruby-a90237e99ac3), and letting intepretation work itself all the way back. +
This one was already complicated in Ruby, but it gets even worse when you have to deal with [Rust's lifetimes](https://doc.rust-lang.org/rust-by-example/scope/lifetime.html). The concept in itself is kinda okay to understand, but the way it has to be used sometimes makes no sense. I guess I'll get used to it with time. A [nice crate](https://docs.rs/advent-of-code/2022.0.66/src/advent_of_code/year2015/day07.rs.html) helped me see through it a bit more clearly. ## Day 08: Matchsticks +
+Tests and benchmarks + ``` test year_2015::day_08::tests::calculates_length_of_code_strings ... ok test year_2015::day_08::tests::calculates_length_of_memory_strings ... ok @@ -144,5 +226,13 @@ year_2015::day_08/year_2015::day_08_v1 year_2015::day_08/year_2015::day_08_v2 time: [8.3510 µs 8.6640 µs 9.1839 µs] ``` +
+ +
+Ruby version comments +Understanding how characters escaping works is a massive PAIN, and misunderstand the concept is a reason why [PHP MySQL injections](https://www.php.net/manual/en/security.database.sql-injection.php) were so infamous. Things get even more hairy when you have to work with MULTIPLE type of injections (paths, web, sql,...), or even multiple types of string that don't escape the same way, + +In that case, we are lucky, since Ruby already implements [dump](https://ruby-doc.org/3.2.2/String.html#method-i-dump) and [undump](https://ruby-doc.org/3.2.2/String.html#method-i-undump), which happens to work exactly as the exercise require. But since we're here to learn, the methods will alternate at runtime between the Ruby methods and the manual implementation. +
This one was actually very funny. For a while, I thought it would be a pain to not be able to index strings, but extracting slices actually works better. diff --git a/CHANGELOG.md b/CHANGELOG.md index c73f4e4..ddc36bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Of note: - The changelog 2015.5.2 has been rewritten from each commit content. - This file may be amended entirely in the future to adhere to the [GNU Changelog style](https://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html#Style-of-Change-Logs) +## [2015.8.2] +### Changed +- Rewrote [solving notes for 2015](2015.md). + ## [2015.8.1] ### Added - Solved [exercice for 2015, day 8](src/year_2015/day_08.rs). diff --git a/Cargo.toml b/Cargo.toml index baf77e9..85afab6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "advent-rs" -version = "2015.8.1" +version = "2015.8.2" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html