Parsing, données structurées et Map en Java

Manipulation de chaines de caractères, construction d’une classe et utilisation de Map

→ Challenge Correction: Bug-out Shelter #3 – Remote Connection

On poursuit les corrigés de l’édition 2025 de la Battle Dev Thales. Dans ce challenge, il était question de récupérer différentes informations sur des abris afin de leur calculer un « état vital ». Il fallait faire ce calcul pour tous les abris afin de trouver celui avec l’état vital le + élevé ainsi que la moyenne de l’état vital de tous les abris.

Spoiler alert : chaque jeu de données renvoyait l’abri « PRO » (= PROméthes) comme meilleur abri. Cela permettait de lancer la suite de l’histoire…

3 grandes étapes pour résoudre ce challenge

  1. Extraire les informations de chaque abri et les structurer
  2. Etre en capacité de calculer son état vital
  3. Pouvoir calculer la moyenne et rechercher le maximum

La complexité de ce challenge était assez abordable, mais sa résolution pouvait demander « beaucoup » de code. Pour ce corrigé, on va le résoudre en Java, avec une approche orientée objet très structurée.

Class Shelter, parsing et instanciation

On va structurer la classe Shelter avec toutes les informations qu’un abri peut contenir :

class Shelter {
    // Propriétés
    private String trigram;
    private int equipement;
    private int nourriture;
    private int sante;
    private int score;

    // Constructeur
    public Shelter(String trigram, int equipement, int nourriture, int sante) {
        this.trigram = trigram;
        this.equipement = equipement;
        this.nourriture = nourriture;
        this.sante = sante;
    }
}

On crée donc les propriétés, avec les types associés et le constructeur qui va avec, qui permet de définir chaque propriété, à l’exception du score qui sera calculé plus tard.

Mais comme le challenge nous fournit les informations d’un abri sous cette forme « QXG_E:15_N:19_S:16 », on ne peut pas utiliser le constructeur tel quel. Il faut parser ces données préalablement. C’est là qu’il est intéressant de créer une méthode statique dans la class Shelter, qui sera à la fois chargée de parser les données ET de retourner une nouvelle instance de Shelter :

public static Shelter fromString(String data) {
    String[] parts = data.split("_");
    String trigram = parts[0];
    int e = Integer.parseInt(parts[1].split(":")[1]);
    int n = Integer.parseInt(parts[2].split(":")[1]);
    int s = Integer.parseInt(parts[3].split(":")[1]);
    return new Shelter(trigram, e, n, s);
}

Un peu d’explications :

  • Grâce à la méthode split, on découpe la chaine de caractère de type « QXG_E:15_N:19_S:16 » selon le « _ », ce qui nous donne un tableau [« QXG », « E:15 », … , « S:16 »]
  • Le trigramme est récupéré directement à l’index 0
  • Pour les autres données, il faut à nouveau parser selon le « : ». Mais cette fois-ci on ne stocke rien dans une variable intermédiaire, on va aller chercher directement ce qui se trouve en position [1] que l’on va typer en entier grâce à Integer.parseInt
  • Enfin, on retourne une nouvelle instance de Shelter en passant en paramètre les différentes valeurs extraites de la chaine de caractères de départ.

Calcul de l’état vital

Les informations étant maintenant stockées dans des propriétés, on peut s’en servir pour calculer l’état vital (score) et le stocker dans l’objet. Voici la méthode que l’on peut mettre en place :

public void calculateScore() {
    double base = (equipement * 0.25 + nourriture * 0.40 + sante * 0.35) * 2.25;

    if (equipement >= 15 && nourriture >= 15 && sante >= 15) {
        base += 8; // bonus
    }

    if (nourriture <= 10 || sante <= 10) {
        base -= 10; // malus
    }

    base = Math.max(0, Math.min(100, base)); // bornes 0–100
    this.score = (int) Math.floor(base);
}

Un peu d’explications :

  • On reprend ici les indications de l’énoncé sur les pondérations et les conditions de bonus ou malus à appliquer.
  • L’enchainement max(0, min(100, base)) permet de borner les valeurs entre 0 et 100
  • Avant de stocker la valeur dans la propriété, on l’arrondit à l’entier

Getters

Comme les propriétés trigram et score sont privés, il nous faut 2 getters pour pouvoir y accéder depuis le programme principal. Il n’y en a pas besoin pour les autres propriétés :

public String getTrigram() { return trigram; }
public int getScore() { return score; }

Classe complète et programme principal

Voici la classe Shelter complète :

class Shelter {
    private String trigram;
    private int equipement;
    private int nourriture;
    private int sante;
    private int score;

    public Shelter(String trigram, int equipement, int nourriture, int sante) {
        this.trigram = trigram;
        this.equipement = equipement;
        this.nourriture = nourriture;
        this.sante = sante;
    }

    // Méthode de parsing à partir de la chaîne "ABC_E:10_N:20_S:30"
    public static Shelter fromString(String data) {
        String[] parts = data.split("_");
        String trigram = parts[0];
        int e = Integer.parseInt(parts[1].split(":")[1]);
        int n = Integer.parseInt(parts[2].split(":")[1]);
        int s = Integer.parseInt(parts[3].split(":")[1]);
        return new Shelter(trigram, e, n, s);
    }

    // Calcul du score selon les règles données
    public void calculateScore() {
        double base = (equipement * 0.25 + nourriture * 0.40 + sante * 0.35) * 2.25;

        if (equipement >= 15 && nourriture >= 15 && sante >= 15) {
            base += 8; // bonus
        }
        if (nourriture <= 10 || sante <= 10) {
            base -= 10; // malus
        }

        base = Math.max(0, Math.min(100, base)); // bornes 0–100
        this.score = (int) Math.floor(base);
    }

    // Getters
    public String getTrigram() { return trigram; }
    public int getScore() { return score; }
}

Et le programme principal :

public class Challenge {
    public static void main(String[] args) {
        //== NE PAS TOUCHER
        String[] shelters = {
            "QXG_E:15_N:19_S:16", "OKE_E:24_N:6_S:7", "GCJ_E:21_N:3_S:7",
            "GLH_E:13_N:11_S:12", "HAF_E:9_N:12_S:12", "VKL_E:1_N:5_S:3",
            "HRS_E:25_N:5_S:21", "PRO_E:32_N:33_S:38", "CEX_E:22_N:8_S:28",
            "MNN_E:8_N:20_S:14"
        };
        //== NE PAS TOUCHER

        // Map pour stocker les résultats
        Map<String, Integer> scores = new HashMap<>();
        int total = 0;

        // Parsing et calcul du score
        for (String data : shelters) {
            Shelter s = Shelter.fromString(data);
            s.calculateScore();
            scores.put(s.getTrigram(), s.getScore());
            total += s.getScore();
        }

        // Recherche du meilleur abri
        String best = Collections.max(scores.entrySet(), Map.Entry.comparingByValue()).getKey();
        int bestScore = scores.get(best);

        // Moyenne des scores arrondie à l'entier inférieur
        int avg = (int) Math.floor((double) total / shelters.length);

        // Résultat final
        System.out.println(best + "_" + bestScore + "_" + avg);
    }
}

Un peu d’explications :

  • On commencer par créer une Map qui permettra d’associer le trigramme et le score de chaque abri
  • On crée enfin une variable total qui servira pour le calcul de la moyenne
  • Dans la boucle for, on parcourt donc chaque abri pour instancier l’objet associé, calculer le score de l’abri et stocker les informations clés dans la Map. On incrémente également le total avec le score de l’abri.
  • Plutôt que de parcourir à nouveau tout le tableau, on laisse Java comparer les valeurs de la Map et on récupère la clé (le trigramme) gagnante.
    • scores.entrySet() expose les paires (trigramme, score).
    • Map.Entry.comparingByValue() dit “compare sur les scores”.
    • Collections.max(…) renvoie l’entrée au score maximal.
    • .getKey() récupère le trigramme.
  • On divise la somme par le nombre d’abris, en double pour éviter la division entière, puis floor.
  • Enfin, on affiche la réponse au format attendu

Ce corrigé montre comment transformer des données textuelles en informations exploitables grâce à un parsing simple, une structuration des données dans une classe, et l’utilisation d’une Map pour identifier, comparer et agréger les résultats de façon claire en Java.


Qui a codé ce superbe contenu ?

Keep learning

Other content to discover