4.1 KiB
AoC 2021 Jour 1: Sonar Sweep
À la recherche de la clef du traîneau à l'aide d'un sonar.
Le défi peut être trouvé ici, et le code lié est sur gitlab.
Consigne du défi
Le premier puzzle est assez simple, et peut se résumer en "compter les variations dans un fichier d'entrée".
Lecture du fichier d'entrée
Pour lire le fichier, rien de plus simple. L'entrée étant une simple liste d'entiers séparés par des retours à la ligne, il est assez facile de le transformer en tableau d'entiers.
En code, cela se traduit par :
fn parse_input(s: &str) -> Vec<i32> {
return s.split("\n").into_iter().filter_map(|f| f.parse::<i32>().ok()).collect::<Vec<i32>>();
}
Maintenant que j'ai acquis un peu plus d'expérience en Rust, je le ferais d'une manière assez différente :
- tout d'abord,
s.split("\n").into_iter()
peut être remplacé pars.lines()
, plus robuste et System Agnostic, les systèmes Windows utilisant une fin de ligne différente. - ensuite, utiliser des
u16
, soit des entiers non signés et encodés sur 16 bits. Ici utiliser 32 bits signés pour stocker des valeurs relativement faibles (dans ce jeu de données) et strictement positives n'est pas optimal.
Première partie
La première partie nécessite de compter les augmentations de nombres un-à-un.
Nous avons donc un tableau (vecteur) d'entiers, alors il suffira simplement de le parcourir, et si l'entier actuel est plus grand que le précédent, alors on retient qu'on a vu une augmentation supplémentaire.
Le code de cette partie est le suivant :
fn get_increase_nb(e: &Vec<i32>) -> i32 {
let mut n = 0;
for i in 1..e.len() {
n += if e[i] > e[i - 1] { 1 } else { 0 };
}
return n;
}
On a donc un entier n
qui va retenir le nombre d'augmentations observées,
et pour tous les entiers du tableau, de la case 1 (les tableaux en informatique
débutent à la case 0), à la case taille
(non incluse, toujours parce que les
tableaux commencent à 0). Si le nombre actuel est plus grand que le précédent,
alors n
augmente de 1.
Deuxième partie
Pour cette deuxième partie, le concept est le même mais cette fois on prend les entiers d'entrée par groupe de 3 et on compte les augmentations entre chaque sommes d'entiers.
On transforme donc le tableau d'entiers en un second tableau correspondant aux sommes de 3 entiers selon une fenêtre flottante.
fn get_sums(v: &Vec<i32>) -> BTreeMap<usize, i32> {
let mut sums = BTreeMap::new();
for i in 0..(v.len() - 2) {
sums.insert(i, v[i] + v[i + 1] + v[i + 2]);
}
return sums;
}
Ici, une BTreeMap est totalement inutile. Je ne sais pas trop pourquoi j'ai choisi ce type de structure de données. Surtout qu'après, cette Map est convertie en simple tableau en ignorant totalement la clef :
let map = get_sums(&vec_in).iter().map(|e| e.1.to_owned()).collect::<Vec<i32>>();
Ici il serait beaucoup plus intéressant d'utiliser un simple tableau, et à chaque nouvelle somme on peut l'envoyer sur le dessus du tableau (de sommes) d'entiers.
Ce tableau enfin obtenu sera alors envoyé à la même méthode que pour la partie une pour en obtenir le nombre d'augmentations.
Évidemment il serait aussi possible de simplement compter les augmentations en même temps que l'on parcourt les tableaux, pour éviter de multiples passages.
Conclusion
Ce puzzle était loin d'être compliqué. J'ai passé un peu de temps sur la compréhension du système de sommes de la partie 2, ne sachant que faire dans le cas où il n'y avait plus assez d'entiers pour faire une somme.
Après un peu de temps et d'essais, j'ai pu m'en sortir sans difficulté.
Concernant la qualité du code, je me demande bien ce que j'ai pu penser sur le moment pour choisir de stocker les sommes dans une map à arbre binaire...
À suivre