CHAPTER 4
Loops
Sometimes - in fact, very often, you'll want to repeat the same operation: for example, to process each element of an array or to increment a variable several times in a row. Up to now, we've mostly written a linear flow of code, where instructions are executed one after another, with no repetition, like in this example:
linear_scores.zig |
|
const std = @import("std"); const print = std.debug.print; pub fn main() void { const a_scores = [_]u16{ 9000, 8000, 5000, 4200, 3800 }; print("\n", .{}); print(" ╔════════════════════════════╗\n", .{}); print(" ║ HIGH SCORES ║\n", .{}); print(" ║____________________________║\n", .{}); print(" ║ {}º | {} pts ║\n", .{ 1, a_scores[0] }); print(" ║ {}º | {} pts ║\n", .{ 2, a_scores[1] }); print(" ║ {}º | {} pts ║\n", .{ 3, a_scores[2] }); print(" ║ {}º | {} pts ║\n", .{ 4, a_scores[3] }); print(" ║ {}º | {} pts ║\n", .{ 5, a_scores[4] }); print(" ╚════════════════════════════╝\n", .{}); } |
|
$ zig run linear_scores.zig |
|
╔════════════════════════════╗ ║ HIGH SCORES ║ ║____________________________║ ║ 1º | 9000 pts ║ ║ 2º | 8000 pts ║ ║ 3º | 5000 pts ║ ║ 4º | 4200 pts ║ ║ 5º | 3800 pts ║ ╚════════════════════════════╝ |
In the example linear_scores.zig we print the values of the array a_scores line by line, which are the game's high scores. It works... though it’s so rigid! We’ve hardcoded the position and the score. Good thing there were only 5 - imagine having to do the same for 20, 30, 100, or 1000 entries in a table. Doesn’t seem like a good idea. A small improvement would be to use a variable to store the index (we’ll call it n_i) and increment it:
linear_scores_2.zig |
|
const std = @import("std"); const print = std.debug.print; pub fn main() void { const a_scores = [_]u16{ 9000, 8000, 5000, 4200, 3800 }; print("\n", .{}); print(" ╔════════════════════════════╗\n", .{}); print(" ║ HIGH SCORES ║\n", .{}); print(" ║____________________________║\n", .{}); var n_i: u8 = 0; print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); n_i = n_i + 1; print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); n_i += 1; print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); n_i += 1; print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); n_i += 1; print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); print(" ╚════════════════════════════╝\n", .{});
} |
|
$ zig run linear_scores_2.zig |
|
╔════════════════════════════╗ ║ HIGH SCORES ║ ║____________________________║ ║ 1º | 9000 pts ║ ║ 2º | 8000 pts ║ ║ 3º | 5000 pts ║ ║ 4º | 4200 pts ║ ║ 5º | 3800 pts ║ ╚════════════════════════════╝ |
By the way, to increment or decrement a variable like n_i, we can write it in two ways. The longer form looks like this:
|
// increment n_i by 1 n_i = n_i + 1; // we'll decrement variable n_a by 2 n_a = n_a - 2; |
Or, shorter:
|
// increment n_i by 1 n_i += 1; // we'll decrement variable n_a by 2 n_a -= 2; |
Going back to our score table program, the situation has improved a bit by having the index in a variable, but we’re still repeating the same code over and over. The lines:
|
print(" ║ {}º | {} pts ║\n", .{ n_i + 1, a_scores[n_i] }); n_i += 1; |
, are repeated one after another.
You're probably getting the sense that something's missing. And yes, you're right - it can be made much more dynamic and elegant, using recursion and iteration.
Recursion
Recursion here is a technical word meaning “executing a function that calls itself again.”
Iteration
Iteration means “repeating a block of code without writing it again”:
- Jumping to a label,
- Using for and while loops