Retour au cours

games / lua

Conditions et boucles

Leçon 21 exercice

Explication

Contrôler l'ordre d'exécution du programme

Une fois qu'on sait manipuler des valeurs (leçon précédente), l'étape suivante est de décider QUAND et COMBIEN DE FOIS une portion de code doit s'exécuter. C'est le rôle des structures conditionnelles (if/else) et des boucles (while, for, repeat).

Ce que vous allez apprendre

  • Écrire des conditions if/elseif/else à plusieurs branches
  • Choisir entre while et repeat...until selon que la condition doit être testée avant ou après
  • Parcourir une plage de nombres avec for i = début, fin, pas
  • Distinguer ipairs (ordre garanti) de pairs (toutes les clés, ordre non garanti)
  • Simuler un continue avec goto ::label::, absent nativement de Lua

Dans quel contexte ?

Un script de serveur RP doit parcourir la liste des joueurs connectés pour leur envoyer un message de bienvenue, tout en ignorant ceux qui sont encore en cours de chargement. Ce genre de traitement — répéter une action pour chaque élément d'une liste, en sautant certains cas particuliers — revient dans presque tous les scripts Lua un peu sérieux, et repose entièrement sur les structures présentées dans cette leçon.

StructureCondition testéeNombre minimum d'exécutions
whileAvant chaque itération0
repeat...untilAprès chaque itération1
for i = a, b, pasImplicite (bornes numériques)0

Astuce

Si tu dois absolument exécuter un bloc au moins une fois (par exemple demander une saisie tant qu'elle n'est pas valide), repeat...until évite d'initialiser artificiellement une variable juste pour entrer dans un while.

while vs repeat...until : une nuance qui a un vrai impact

La différence n'est pas juste stylistique. while teste sa condition AVANT d'exécuter le bloc — si la condition est fausse dès le départ, le bloc ne s'exécute jamais. repeat...until teste sa condition APRÈS avoir exécuté le bloc au moins une fois — et particularité propre à Lua, la condition du until peut voir les variables locales déclarées à l'intérieur du bloc repeat, ce qui n'est généralement pas possible avec un while. Choisir la bonne structure évite des bugs "off-by-one" (une itération en trop ou en moins).

Deux façons de parcourir une collection

for i = début, fin, pas sert pour les boucles numériques classiques (compter de 1 à 10, par exemple). Mais dès qu'on veut parcourir une table (l'équivalent Lua des tableaux/dictionnaires, vue en détail dans la prochaine leçon), on utilise ipairs (pour l'ordre séquentiel) ou pairs (pour toutes les clés, sans ordre garanti) — une distinction essentielle à bien comprendre avant même d'aborder les tables en profondeur.

L'absence volontaire de "continue"

Contrairement à beaucoup de langages, Lua n'a pas de mot-clé continue pour passer directement à l'itération suivante. Le langage propose à la place goto avec une étiquette, un choix de conception qui peut surprendre mais reste parfaitement lisible une fois l'habitude prise — et qui permet même de sortir proprement de boucles imbriquées, ce qu'un simple break ne peut pas faire seul (il ne sort que d'UNE seule boucle).

Commandes & code

Conditions et boucles

lua
-- if / elseif / else
local score = 87

if score >= 90 then
  print("A")
elseif score >= 80 then
  print("B")
elseif score >= 70 then
  print("C")
else
  print("F")
end
lua
-- Boucle "while" : condition testée avant chaque itération
local hp = 100
while hp > 0 do
  hp = hp - 25
  print("HP restant: " .. hp)
end
lua
-- Boucle "repeat...until" : condition testée APRÈS chaque itération (exécute au moins une fois)
-- Particularité Lua : la condition "until" a accès aux variables locales déclarées dans le bloc "repeat"
local attempts = 0
repeat
  attempts = attempts + 1
  local success = attempts >= 3   -- visible dans la condition "until" ci-dessous
until success
print("Réussi après " .. attempts .. " tentatives")
lua
-- Boucle "for" numérique : for var = début, fin, pas do ... end
for i = 1, 5 do
  print(i)              -- 1 2 3 4 5
end

for i = 10, 0, -2 do     -- pas négatif : compte à rebours par pas de 2
  print(i)                -- 10 8 6 4 2 0
end
lua
-- Boucle "for" générique avec ipairs (tableaux séquentiels, indices entiers 1..n sans trou)
local weapons = {"epee", "arc", "baton"}
for index, value in ipairs(weapons) do
  print(index, value)     -- 1 epee   2 arc   3 baton
end

-- pairs (parcourt TOUTES les clés, y compris non-entières, ordre non garanti)
local player = {name = "Alice", level = 12, class = "Mage"}
for key, value in pairs(player) do
  print(key, value)        -- ordre non déterministe entre les exécutions
end
lua
-- break interrompt la boucle ; Lua N'A PAS de "continue" natif -> pattern de contournement classique
for i = 1, 10 do
  if i > 5 then
    break                    -- sort complètement de la boucle
  end
  print(i)
end

for i = 1, 10 do
  if i % 2 == 0 then
    goto continue             -- goto vers un label : pattern idiomatique pour simuler "continue"
  end
  print(i)                     -- n'affiche que les nombres impairs
  ::continue::
end
lua
-- Boucles imbriquées avec labels distincts pour un "break" ciblé (goto au niveau externe)
for i = 1, 3 do
  for j = 1, 3 do
    if i == 2 and j == 2 then
      goto continue_outer       -- sort des DEUX boucles d'un coup
    end
    print(i, j)
  end
end
::continue_outer::

Résumé

  • while teste avant, repeat...until teste après (et voit les locales du bloc dans sa condition).
  • for i = début, fin, pas pour les boucles numériques ; ipairs/pairs pour parcourir des tables.
  • Lua n'a pas de continue : le pattern goto ::continue:: en tient lieu.
  • break ne sort que d'une seule boucle ; un goto externe permet de sortir de boucles imbriquées.

Exercices pratiques

1 disponible
1

Mission : réparer la boucle de bienvenue du serveur RP

Objectif : Corriger un script qui doit saluer les joueurs connectés en ignorant ceux encore en chargement, et justifier chaque choix de structure.

Contexte

Un script de bienvenue RP contient ce code, censé saluer chaque joueur connecté sauf ceux encore marqués loading = true :

lua
local players = {
  { name = "Alice", loading = false },
  { name = "Bob", loading = true },
  { name = "Chloe", loading = false },
}

for i, p in pairs(players) do
  if p.loading then
    print("Bienvenue " .. p.name)
  end
end

Résultat en production : seul Bob reçoit un message de bienvenue (celui encore en chargement !), et l'ordre d'affichage change parfois d'une exécution à l'autre sur un serveur avec beaucoup plus de joueurs et des clés supplémentaires dans la table.

Résoudre l’exercice →