diff --git a/src/aoc-2021-jour-2-dive.md b/src/aoc-2021-jour-2-dive.md new file mode 100644 index 0000000..f04018c --- /dev/null +++ b/src/aoc-2021-jour-2-dive.md @@ -0,0 +1,127 @@ +# AoC 2021 Jour 1: Sonar Sweep + +Comment piloter le sous-marin des elfes ? + +Le défi peut être trouvé [ici](https://adventofcode.com/2021/day/2), et le code +lié est sur [gitlab](https://gitlab.com/lovallat/advent-of-code-2021/-/tree/master/day2). + +## Consigne du défi + +Le sous-marin peut prendre 3 types de commandes : + +- `forward X` +- `down X` +- `up X` + +Le fichier d'entrée est une suite de ces ordres, que l'on doit interpréter pour +trouver la position du sous-marin dans l'espace (horizontalement et verticalement). + +## Lecture du fichier d'entrée + +La lecture du fichier d'entrée se fait à nouveau dans une seule fonction : + +```rust +fn parse_input(s: &str) -> Vec<(String, i32)> { + let mut r:Vec<(String, i32)> = vec![]; + let v = s.split("\n").into_iter(); + for e in v { + let p = e.split_whitespace().collect::>(); + if p.len() == 2 && p[1].parse::().is_ok() { + r.push((p[0].to_owned(), p[1].parse::().unwrap())); + } + } + return r; +} +``` + +Ici, on va tout simplement transformer une ligne en tuple `(String, i32)`, et +de transformer le fichier d'entrée en un tableau `Vec` de ces ordres. On découpe +donc une ligne `ordre X` en fonction d'un espace, et si on a bien 2 éléments et +que le deuxième peut être converti en entier signé stocké sur 32 bits, alors on +l'ajoute à notre tableau d'instructions. + +On pourrait ici utiliser une énumeration telle que `Direction::Forward`, +`Direction::Up` et `Direction::Down` pour éviter de stocker les chaînes de +caractère en entier dans le tableau. On pourrait aussi utiliser des entiers stockés +sur moins de bits, étant relativement petits. + +## Première partie + +Pour la première partie, l'interprétation des instructions est la suivante : + +- `forward X` qui permet de faire avancer le sous-marin de `X` unités horizontalement +- `down X` fait plonger le sous-marin et donc augmente sa profondeur de `X` unités +- `up X` fait remonter à l'inverse le sous-marin vers la surface + +La réponse à la première partie se trouve en multipliant la position horizontale +et verticale. Pour cela, on va faire un `fold` sur le tableau pour calculer toutes +les instructions à la suite et donnant le résultat en une seule ligne : + +```rust +fn get_horizontal_depth(v: Vec<(String, i32)>) -> (i32, i32) { + return v.into_iter().fold((0, 0), |acc, e| compute_horizontal_depth(e, acc)); +} +``` + +Chaque ligne est traîtée individuellement pour interprétation, en donnat en valeur +de retour les nouvelles positions du sous-marin après application de l'instruction +sur la position donnée en entrée : + +```rust +fn compute_horizontal_depth(t: (String, i32), a: (i32, i32)) -> (i32, i32) { + return match t.0.as_str() { + "up" => (a.0, a.1 - t.1), + "down" => (a.0, a.1 + t.1), + "forward" => (a.0 + t.1, a.1), + _ => a + }; +} +``` + +Ce traîtement est donc très simple. Pour chaque instruction et en partant d'une +position `(0, 0)`, on va appliquer les règles les unes après les autres en mettant +à jour la position à chaque fois. Cela se fait en temps linéaire sans calcul autre +que des additions. + +## Deuxième partie + +Pour la deuxième partie, le traîtement est assez similaire, mais on va calculer +une composante supplémentaire : la *visée*. + +Les instructions sont désormais à interpréter de cette manière : + +- `forward X` permet deux choses : + - augmente la position horizontale de `X` unités + - augmente la profondeur par la *visée* multipliée par `X` +- `down X` augmente la *visée* de `X` unités +- `up X` à l'inverse diminue la *visée* de `X` unités + +Le concept pour calculer est le même, on applique les instructions l'une après +l'autre en partant de `(0, 0, 0)`. + +```rust +fn compute_horizontal_depth_aim(t: (String, i32), a: (i32, i32, i32)) -> (i32, i32, i32) { + return match t.0.as_str() { + "up" => (a.0, a.1, a.2 - t.1), + "down" => (a.0, a.1, a.2 + t.1), + "forward" => (a.0 + t.1, a.1 + a.2 * t.1, a.2), + _ => a + }; +} +``` + +Enfin, la réponse à donner est la multiplication de la position horizontale et +verticale, comme pour la précédente partie. + +## Conclusion + +Ce défi n'était pas compliqué et ma réponse me semble adaptée. Bien sûr il y a +toujours des pistes d'améliorations, telle que le type de données stockées : +les chaînes de caractères étant moins performantes à traîter, mais aussi la taille +des entiers stockés, ou encore le fait que je ne passe pas de référence aux +fonctions, nécéssitant une copie systématique, consommant des cycles supplémentaires. + +Mais globalement je suis satisfait de ma réponse à ce défi. + +> À suivre +