# 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 traité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 traitement 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 traitement 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 à traiter, 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