mirror of
https://codeberg.org/ziglings/exercises.git
synced 2024-12-25 09:10:26 +00:00
Added Ex 101 "for loops part 5" (Closes #271)
Also gave a shot at explaining data-oriented design, a Zig "hot topic" ever since the red Hawaiian shirt talk(s).
This commit is contained in:
parent
f9aec283c8
commit
e2f3a5e519
3 changed files with 128 additions and 0 deletions
|
@ -1076,6 +1076,10 @@ const exercises = [_]Exercise{
|
|||
.main_file = "100_for4.zig",
|
||||
.output = "Arrays match!",
|
||||
},
|
||||
.{
|
||||
.main_file = "101_for5.zig",
|
||||
.output = "1. Wizard (Gold: 25, XP: 40)\n2. Bard (Gold: 11, XP: 17)\n3. Bard (Gold: 5, XP: 55)\n4. Warrior (Gold: 7392, XP: 21)",
|
||||
},
|
||||
.{
|
||||
.main_file = "999_the_end.zig",
|
||||
.output = "\nThis is the end for now!\nWe hope you had fun and were able to learn a lot, so visit us again when the next exercises are available.",
|
||||
|
|
120
exercises/101_for5.zig
Normal file
120
exercises/101_for5.zig
Normal file
|
@ -0,0 +1,120 @@
|
|||
//
|
||||
// The 'for' loop is not just limited to looping over one or two
|
||||
// items. Let's try an example with a whole bunch!
|
||||
//
|
||||
// But first, there's one last thing we've avoided mentioning
|
||||
// until now: The special range that leaves off the last value:
|
||||
//
|
||||
// for ( things, 0.. ) |t, i| { ... }
|
||||
//
|
||||
// That's how we tell Zig that we want to get a numeric value for
|
||||
// every item in "things", starting with 0.
|
||||
//
|
||||
// A nice feature of these index ranges is that you can have them
|
||||
// start with any number you choose. The first value of "i" in
|
||||
// this example will be 500, then 501, 502, etc.:
|
||||
//
|
||||
// for ( things, 500.. ) |t, i| { ... }
|
||||
//
|
||||
// Remember our RPG characters? They had the following
|
||||
// properties, which we stored in a struct type:
|
||||
//
|
||||
// class
|
||||
// gold
|
||||
// experience
|
||||
//
|
||||
// What we're going to do now is store the same RPG character
|
||||
// data, but in a separate array for each property.
|
||||
//
|
||||
// It might look a little awkward, but let's bear with it.
|
||||
//
|
||||
// We've started writing a program to print a numbered list of
|
||||
// characters with each of their properties, but it needs a
|
||||
// little help:
|
||||
//
|
||||
const std = @import("std");
|
||||
const print = std.debug.print;
|
||||
|
||||
// This is the same character class enum we've seen before.
|
||||
const Class = enum {
|
||||
wizard,
|
||||
thief,
|
||||
bard,
|
||||
warrior,
|
||||
};
|
||||
|
||||
pub fn main() void {
|
||||
// Here are the three "property" arrays:
|
||||
const classes = [4]Class{ .wizard, .bard, .bard, .warrior };
|
||||
const gold = [4]u16{ 25, 11, 5, 7392 };
|
||||
const experience = [4]u8{ 40, 17, 55, 21 };
|
||||
|
||||
// We would like to number our list starting with 1, not 0.
|
||||
// How do we do that?
|
||||
for (classes, gold, experience, ???) |c, g, e, i| {
|
||||
const class_name = switch (c) {
|
||||
.wizard => "Wizard",
|
||||
.thief => "Thief",
|
||||
.bard => "Bard",
|
||||
.warrior => "Warrior",
|
||||
};
|
||||
|
||||
std.debug.print("{d}. {s} (Gold: {d}, XP: {d})\n", .{
|
||||
i,
|
||||
class_name,
|
||||
g,
|
||||
e,
|
||||
});
|
||||
}
|
||||
}
|
||||
//
|
||||
// By the way, storing our character data in arrays like this
|
||||
// isn't *just* a silly way to demonstrate multi-object 'for'
|
||||
// loops.
|
||||
//
|
||||
// It's *also* a silly way to introduce a concept called
|
||||
// "data-oriented design".
|
||||
//
|
||||
// Let's use a metaphor to build up an intuition for what this is
|
||||
// all about:
|
||||
//
|
||||
// Let's say you've been tasked with grabbing three glass
|
||||
// marbles, three spoons, and three feathers from a bucket. But
|
||||
// you can't use your hands to grab them. Instead, you have a
|
||||
// special marble scoop, spoon magnet, and feather tongs to grab
|
||||
// each type of object.
|
||||
//
|
||||
// Now, would you rather have:
|
||||
//
|
||||
// A. The items layered so you have to pick up one marble, then
|
||||
// one spoon, then one feather?
|
||||
//
|
||||
// OR
|
||||
//
|
||||
// B. The items separated by type so you can pick up all of the
|
||||
// marbles at once, then all the spoons, then all of the
|
||||
// feathers?
|
||||
//
|
||||
// If this metaphor is working, hopefully it's clear that the 'B'
|
||||
// option would be much more efficient.
|
||||
//
|
||||
// Well, it probably comes as little surprise that storing and
|
||||
// using data in a sequential and uniform fashion is also more
|
||||
// efficient for modern CPUs.
|
||||
//
|
||||
// Decades of OOP practices have steered people towards grouping
|
||||
// different data types together into "objects" with the hope
|
||||
// that it would be friendlier to the human mind. But
|
||||
// data-oriented design groups data in a way that is more
|
||||
// efficient for the computer.
|
||||
//
|
||||
// In Zig terminology, the difference in groupings is sometimes
|
||||
// known as "Array of Structs" (AoS) versus "Struct of Arrays"
|
||||
// (SoA).
|
||||
//
|
||||
// To envision these two designs in action, imagine an array of
|
||||
// RPG character structs, each containing three different data
|
||||
// types (AoS) versus a single RPG character struct containing
|
||||
// three arrays of one data type each, like those in the exercise
|
||||
// above (SoA).
|
||||
//
|
4
patches/patches/101_for5.patch
Normal file
4
patches/patches/101_for5.patch
Normal file
|
@ -0,0 +1,4 @@
|
|||
54c54
|
||||
< for (classes, gold, experience, ???) |c, g, e, i| {
|
||||
---
|
||||
> for (classes, gold, experience, 1..) |c, g, e, i| {
|
Loading…
Reference in a new issue