Parcours
/
Rust
Rust
/
Exercices
/
Jeu embarqué à faible consommation
Jeu embarqué à faible consommation

Jeu embarqué à faible consommation

Exercice d'apprentissage

Introduction

Les tuples sont un moyen simple de regrouper un ensemble fixe de données de types arbitraires. Un tuple n'a pas de nom particulier ; nommer une structure de données en fait un struct. Les champs d'un tuple n'ont pas de nom ; on y accède par déstructuration ou par position.

Syntaxe

Création

Un tuple est toujours créé à l'aide d'une expression de tuple :

// pointless but legal
let unit = ();
// single element
let single_element = ("note the comma",);
// two element
let two_element = (123, "elements can be of differing types");

Un tuple peut contenir un nombre arbitraire d'éléments.

Accès par déstructuration

Il est possible d'accéder aux éléments d'un tuple par déstructuration. Cela consiste simplement à affecter des noms de variables aux différents éléments du tuple, ce qui le consomme.

let (elem1, _elem2) = two_element;
assert_eq!(elem1, 123);

Accès par position

Il est également possible d'accéder aux éléments d'un tuple par un indice de position numérique. L'indexation, comme toujours, commence à 0.

let notation = single_element.0;
assert_eq!(notation, "note the comma");

Structures tuples

On te demandera aussi de travailler avec des structures tuples. Comme les structures classiques, ce sont des types nommés ; contrairement aux structures classiques, leurs champs sont anonymes. Leur syntaxe est très proche de celle des tuples classiques. Il est possible d'utiliser à la fois la déstructuration et l'accès par position.

struct TupleStruct(u8, i32);
let my_tuple_struct = TupleStruct(123, -321);
let neg = my_tuple_struct.1;
let TupleStruct(byte, _) = my_tuple_struct;
assert_eq!(neg, -321);
assert_eq!(byte, 123);

Visibilité des champs

Tous les champs d'un tuple anonyme sont toujours publics. En revanche, les champs d'une structure tuple possèdent leur propre visibilité, qui est privée par défaut, tout comme les champs des structures classiques. Tu peux rendre les champs publics à l'aide du modificateur pub, exactement comme dans une structure classique.

// fails due to private fields
mod tuple { pub struct TupleStruct(u8, i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }
// succeeds: fields are public
mod tuple { pub struct TupleStruct(pub u8, pub i32); }
fn main() { let _my_tuple_struct = tuple::TupleStruct(123, -321); }

Instructions

Tu travailles sur un jeu destiné à un système embarqué à faible consommation et tu dois écrire plusieurs fonctions utilitaires qui seront utilisées par d'autres parties du jeu.

1. Calcule le quotient et le reste d'une division

Un quotient est le résultat d'une division.

fn divmod(dividend: i16, divisor: i16) -> (i16, i16)

Exemple :

assert_eq!(divmod(10, 3), (3, 1));

2. Choisis les éléments aux positions paires d'un itérateur

Cela sera utile pour activer une optimisation du tampon d'écran, promet ton patron.

Les itérateurs sont des éléments qui exposent les méthodes définies par le trait Iterator. Cette documentation est assez complète, car ils offrent de nombreuses méthodes ; voici les propriétés les plus pertinentes :

  • Un itérateur est un flux d'éléments de longueur arbitraire
  • Ils disposent d'une méthode enumerate qui renvoie un tuple (i, val) pour chaque valeur
  • Ils disposent d'une méthode filter qui utilise une fermeture pour déterminer s'il faut produire un élément de l'itérateur
  • Ils disposent d'une méthode map qui utilise une fermeture pour modifier les éléments de l'itérateur

Comme ta fonction peut fonctionner avec n'importe quel type d'itérateur, elle utilise impl pour signifier qu'il s'agit d'une instance de trait plutôt que d'un simple élément. De même, la syntaxe <Item=T> signifie simplement que le type d'élément produit par l'itérateur n'a pas d'importance ; ta fonction peut produire les éléments pairs de n'importe quel itérateur.

fn evens<T>(iter: impl Iterator<Item=T>) -> impl Iterator<Item=T>

Exemples :

let mut even_ints = evens(0_u8..);
assert_eq!(even_ints.next(), Some(0));
assert_eq!(even_ints.next(), Some(2));
assert_eq!(even_ints.next(), Some(4));
assert_eq!(even_ints.next(), Some(6));
let mut evens_from_odds = evens(1_i16..);
assert_eq!(evens_from_odds.next(), Some(1));
assert_eq!(evens_from_odds.next(), Some(3));
assert_eq!(evens_from_odds.next(), Some(5));
assert_eq!(evens_from_odds.next(), Some(7));

3. Calcule la distance de Manhattan d'une position par rapport à l'origine

Pour faciliter la cartographie, tu disposes d'une structure tuple Position :

struct Position(i16, i16);

Tu dois implémenter une méthode manhattan sur Position qui renvoie la distance de Manhattan de cette position par rapport à l'origine (Position(0, 0)).

impl Position {
    fn manhattan(&self) -> i16
}

Exemple :

assert_eq!(Position(3, 4).manhattan(), 7);
Modifie via GitHub Le lien s'ouvre dans une nouvelle fenêtre ou un nouvel onglet
Rust Exercism

Prêt à commencer Jeu embarqué à faible consommation ?

Inscris-toi sur Exercism pour apprendre et maîtriser Rust avec 99 exercices, et un vrai mentorat humain, le tout gratuitement.