Просмотр исходного кода

Consistent instructions and examples

I started off with "hints" that required the poor student to piece
together the information from incomplete bits. A complete example is
like a picture that is worth 1000 words and far clearer.
Dave Gauer 4 лет назад
Родитель
Сommit
adf5ddb27d
16 измененных файлов с 186 добавлено и 90 удалено
  1. 10 4
      01_hello.zig
  2. 9 6
      02_std.zig
  3. 28 10
      03_assignment.zig
  4. 26 8
      04_arrays.zig
  5. 13 6
      05_arrays2.zig
  6. 17 9
      06_strings.zig
  7. 11 10
      09_if.zig
  8. 7 2
      10_if2.zig
  9. 7 6
      11_while.zig
  10. 3 1
      12_while2.zig
  11. 4 3
      13_while3.zig
  12. 7 5
      14_while4.zig
  13. 6 2
      15_for.zig
  14. 8 2
      16_for2.zig
  15. 17 6
      18_functions.zig
  16. 13 10
      19_functions2.zig

+ 10 - 4
01_hello.zig

@@ -2,11 +2,17 @@
 // Oh no! This program is supposed to print "Hello world!" but it needs
 // your help!
 //
-// Hint: Zig functions are private by default.
-//       The main() function should be public.
-//       Declare a public function with "pub fn ..."
+// 
+// Zig functions are private by default but the main() function should
+// be public.
 //
-// Try to fix the program and run `ziglings` to see if it passes.
+// A function is declared public with the "pub" statement like so:
+//
+//     pub fn foo() void {
+//         ...
+//     }
+//
+// Try to fix the program and run `ziglings` to see if it works!
 //
 const std = @import("std");
 

+ 9 - 6
02_std.zig

@@ -2,13 +2,16 @@
 // Oops! This program is supposed to print a line like our Hello World
 // example. But we forgot how to import the Zig Standard Library.
 //
-// Hint 1: The @import() built-in function returns a value representing
-//         imported code. We need to give that value a name to use it.
-// Hint 2: We use the name "std" in the main function (see below).
-// Hint 3: Imports need to be named by declaring them as "const" values.
-// Hint 4: Take a look at how the previous exercise did this!
+// The @import() function is built into Zig. It returns a value which
+// represents the imported code. It's a good idea to store the import as
+// a constant value with the same name as the import:
 //
-@import("std");
+//     const foo = @import("foo");
+//
+// Please complete the import below:
+//
+
+??? = @import("std");
 
 pub fn main() void {
     std.debug.print("Standard Library.\n", .{});

+ 28 - 10
03_assignment.zig

@@ -1,14 +1,32 @@
 //
-// Oh dear! It seems we got a little carried away making const u8 values.
-//     * const means constant (cannot be changed)
-//     * u8 means unsigned (cannot be negative), 8-bit integer
-//
-// Hint 1: Use 'var' for values that can change.
-// Hint 2: Use enough bits to hold the value you want:
-//             u8             255
-//             u16         65,535
-//             u32  4,294,967,295
-// Hint 3: Use 'i' (e.g. 'i8', 'i16') for signed integers.
+// It seems we got a little carried away making everything "const u8"!
+//
+//     "const" values cannot change.
+//     "u"     types are "unsigned" and cannot store negative values.
+//     "8"     means the type is 8 bits in size.
+//
+// Example: foo cannot change (it is CONSTant)
+//          bar can change (it is VARiable):
+//
+//     const foo: u8 = 20;
+//     var bar: u8 = 20;
+//
+// Example: foo cannot be negative and can hold 0 to 255
+//          bar CAN be negative and can hold −128 to 127
+//
+//     const foo: u8 = 20;
+//     var bar: i8 = -20;
+//
+// Example: foo can hold 8 bits (0 to 255)
+//          bar can hold 16 bits (0 to 65,535)
+//
+// You can do just about any combination of these that you can think of:
+// 
+//     u32 can hold 0 to 4,294,967,295
+//     i64 can hold −9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
+//
+// Please fix this program so that the types can hold the desired values
+// and the errors go away!
 //
 const std = @import("std");
 

+ 26 - 8
04_arrays.zig

@@ -1,31 +1,49 @@
 //
 // Let's learn some array basics. Arrays are declared with:
 //
-//   const foo [size]<type> = [size]<type>{ values };
+//   var foo [3]u32 = [3]u32{ 42, 108, 5423 };
 //
 // When Zig can infer the size of the array, you can use '_' for the
 // size. You can also let Zig infer the type of the value so the
 // declaration is much less verbose.
 //
-//   const foo = [_]<type>{ values };
+//   var foo = [_]u32{ 42, 108, 5423 };
+//
+// Get values of an array using array[index] notation:
+//
+//     const bar = foo[3]; // 5423
+//
+// Set values of an array using array[index] notation:
+//
+//     foo[3] = 16;
+//
+// Get the length of an array using the len property:
+//
+//     const length = foo.len;
 //
 const std = @import("std");
 
 pub fn main() void {
-
+    // (Problem 1)
+    // This "const" is going to cause a problem later - can you see what it is?
+    // How do we fix it?
     const some_primes = [_]u8{ 1, 3, 5, 7, 11, 13, 17, 19 };
 
-    // Individual values can be set with '[]' notation. Let's fix
-    // the first prime (it should be 2!):
+    // Individual values can be set with '[]' notation.
+    // Example: This line changes the first prime to 2 (which is correct):
     some_primes[0] = 2;
 
     // Individual values can also be accessed with '[]' notation.
+    // Example: This line stores the first prime in "first":
     const first = some_primes[0];
 
-    // Looks like we need to complete this expression (like 'first'):
-    const fourth = ???;
+    // (Problem 2)
+    // Looks like we need to complete this expression. Use the example
+    // above to set "fourth" to the fourth element of the some_primes array:
+    const fourth = some_primes[???];
 
-    // Use '.len' to get the length of the array:
+    // (Problem 3)
+    // Use the len property to get the length of the array:
     const length = some_primes.???;
 
     std.debug.print("First: {}, Fourth: {}, Length: {}\n",

+ 13 - 6
05_arrays2.zig

@@ -2,12 +2,14 @@
 // Zig has some fun array operators.
 //
 // You can use '++' to concatenate two arrays:
+//
 //   const a = [_]u8{ 1,2 };
 //   const b = [_]u8{ 3,4 };
-//   const c = a ++ b ++ [_]u8{ 5 }; // 1,2,3,4,5
+//   const c = a ++ b ++ [_]u8{ 5 }; // equals 1 2 3 4 5
 //
 // You can use '**' to repeat an array:
-//   const d = [_]u8{ 1,2,3 } ** 2; // 1,2,3,1,2,3
+//
+//   const d = [_]u8{ 1,2,3 } ** 2; // equals 1 2 3 1 2 3
 //
 const std = @import("std");
 
@@ -15,15 +17,20 @@ pub fn main() void {
     const le = [_]u8{ 1, 3 };
     const et = [_]u8{ 3, 7 };
 
-    // I want this to contain digits: 1 3 3 7
+    // (Problem 1)
+    // Please set this array concatenating the two arrays above.
+    // It should result in: 1 3 3 7
     const leet = ???;
 
-    // I want this to contain digits: 1 0 0 1 1 0 0 1 1 0 0 1
+    // (Problem 2)
+    // Please set this array to using repetition.
+    // It should result in: 1 0 0 1 1 0 0 1 1 0 0 1
     const bit_pattern = [_]u8{ ??? } ** 3;
 
-
+    // Okay, that's all of the problems. Let's see the results.
+    //
     // We could print these arrays with leet[0], leet[1],...but let's
-    // have a little preview of Zig 'for' loops instead!
+    // have a little preview of Zig "for" loops instead:
     std.debug.print("LEET: ", .{});
 
     for (leet) |*n| {

+ 17 - 9
06_strings.zig

@@ -3,38 +3,46 @@
 // 
 // We've already seen Zig string literals: "Hello world.\n"
 //
-// Like the C language, Zig stores strings as arrays of bytes
-// encoded as UTF-8 characters terminated with a null value.
-// For now, just focus on the fact that strings are arrays of
-// characters!
+// Zig stores strings as arrays of bytes.
+//
+//     const foo = "Hello";
+//
+// Is the same as:
+//
+//     const foo = [_]u8{ 'H', 'e', 'l', 'l', 'o' };
 //
 const std = @import("std");
 
 pub fn main() void {
     const ziggy = "stardust";
 
+    // (Problem 1)
     // Use array square bracket syntax to get the letter 'd' from
     // the string "stardust" above.
     const d: u8 = ziggy[???];
 
+    // (Problem 2)
     // Use the array repeat '**' operator to make "ha ha ha".
     const laugh = "ha " ???;
 
+    // (Problem 3)
     // Use the array concatenation '++' operator to make "Major Tom".
     // (You'll need to add a space as well!)
     const major = "Major";
     const tom = "Tom";
     const major_tom = major ??? tom;
 
+    // That's all the problems. Let's see our results:
     std.debug.print("d={u} {}{}\n",.{d, laugh, major_tom});
-    // Going deeper:
+    //
     // Keen eyes will notice that we've put a 'u' inside the '{}'
     // placeholder in the format string above. This tells the
-    // print() function (which uses std.fmt.format() function) to
-    // print out a UTF-8 character. Otherwise we'd see '100', which
-    // is the decimal number corresponding with the 'd' character
-    // in UTF-8.
+    // print() function to format the values as a UTF-8 character.
+    // If we didn't do this, we'd see '100', which is the decimal
+    // number corresponding with the 'd' character in UTF-8.
+    //
     // While we're on this subject, 'c' (ASCII encoded character)
     // would work in place for 'u' because the first 128 characters
     // of UTF-8 are the same as ASCII!
+    //
 }

+ 11 - 10
09_if.zig

@@ -1,19 +1,19 @@
 //
 // Now we get into the fun stuff, starting with the 'if' statement!
 //
-//   if (true) {
-//      // stuff
-//   } else {
-//      // other stuff
-//   }
+//     if (true) {
+//         ...
+//     } else {
+//         ...
+//     }
 //
-// Zig has the usual comparison operators such as:
+// Zig has the "usual" comparison operators such as:
 //
-//   a == b   a equals b
-//   a < b    a is less than b
-//   a !=b    a does not equal b
+//     a == b   means "a equals b"
+//     a < b    means "a is less than b"
+//     a !=b    means "a does not equal b"
 //
-// The important thing about Zig's 'if' is that it *only* accepts
+// The important thing about Zig's "if" is that it *only* accepts
 // boolean values. It won't coerce numbers or other types of data
 // to true and false.
 //
@@ -22,6 +22,7 @@ const std = @import("std");
 pub fn main() void {
     const foo = 1;
 
+    // Please fix this condition:
     if (foo) {
         // We want out program to print this message!
         std.debug.print("Foo is 1!\n", .{});

+ 7 - 2
10_if2.zig

@@ -1,17 +1,22 @@
 //
 // If statements are also valid expressions:
 //
-//   foo = if (a) 2 else 3;
+//     var foo: u8 = if (a) 2 else 3;
 //
-// Note: you'll need to declare a variable type when assigning a value
+// Note: You'll need to declare a variable type when assigning a value
 // from a statement like this because the compiler isn't smart enough
 // to infer the type for you.
 //
+// This WON'T work:
+//
+//     var foo = if (a) 2 else 3; // error!
+//
 const std = @import("std");
 
 pub fn main() void {
     var discount = true;
 
+    // Please use an if...else expression to set "price".
     // If discount is true, the price should be $17, otherwise $20:
     var price = if ???;
 

+ 7 - 6
11_while.zig

@@ -1,6 +1,6 @@
 //
 // Zig 'while' statements create a loop that runs while the
-// condition is true:
+// condition is true. This runs once (at most):
 //
 //     while (condition) {
 //         condition = false;
@@ -10,16 +10,17 @@
 // that we can get a boolean value from conditional operators
 // such as:
 //
-//     a == b   a equals b
-//     a < b    a is less than b
-//     a > b    a is greater than b
-//     a !=b    a does not equal b
+//     a == b   means "a equals b"
+//     a < b    means "a is less than b"
+//     a > b    means "a is greater than b"
+//     a !=b    means "a does not equal b"
 //
 const std = @import("std");
 
 pub fn main() void {
     var n: u32 = 2;
 
+    // Please use a condition that is true UNTIL "n" reaches 1024:
     while ( ??? ){
         // Print the current number
         std.debug.print("{} ", .{n});
@@ -28,6 +29,6 @@ pub fn main() void {
         n *= 2;
     }
 
-    // Make this print n=1024
+    // Once the above is correct, this will print "n=1024"
     std.debug.print("n={}\n", .{n});
 }

+ 3 - 1
12_while2.zig

@@ -23,11 +23,13 @@ const std = @import("std");
 pub fn main() void {
     var n: u32 = 2;
 
+    // Please set the continue expression so that we get the desired
+    // results in the print statement below.
     while (n < 1000) : ??? {
         // Print the current number
         std.debug.print("{} ", .{n});
     }
 
-    // Make this print n=1024
+    // As in the last exercise, we want this to result in "n=1024"
     std.debug.print("n={}\n", .{n});
 }

+ 4 - 3
13_while3.zig

@@ -6,12 +6,13 @@
 // Example:
 //
 //     while (condition) : (continue expression){
+//
 //         if(other condition) continue;
-//         ...
+//
 //     }
 //
-// The continue expression executes even when 'other condition'
-// is true and the loop is restarted by the 'continue' statement.
+// The "continue expression" executes every time the loop restarts
+// whether the "continue" statement happens or not.
 //
 const std = @import("std");
 

+ 7 - 5
14_while4.zig

@@ -1,20 +1,22 @@
 //
-// Continue expressions do NOT execute when a while loop stops
-// because of a 'break' statement.
-//
-// Example:
+// You can force a loop to exit immediately with a "break" statement:
 //
 //     while (condition) : (continue expression){
+//
 //         if(other condition) break;
-//         ...
+//
 //     }
 //
+// Continue expressions do NOT execute when a while loop stops
+// because of a break!
+//
 const std = @import("std");
 
 pub fn main() void {
     var n: u32 = 1;
 
     // Oh dear! This while loop will go forever!?
+    // Please fix this so the print statement below gives the desired output.
     while (true) : (n+=1) {
         if(???) ???;
     }

+ 6 - 2
15_for.zig

@@ -1,10 +1,11 @@
 //
 // Behold the 'for' loop! It lets you execute code for each
-// member of an array (and things called 'slices' which we'll
-// get to in a bit).
+// member of an array:
 //
 //     for (items) |item| {
+//
 //         // Do something with item
+//
 //     }
 //
 const std = @import("std");
@@ -22,3 +23,6 @@ pub fn main() void {
 
     std.debug.print("The End.\n", .{});
 }
+//
+// Note that "for" loops also work on things called "slices"
+// which we'll see later.

+ 8 - 2
16_for2.zig

@@ -3,9 +3,15 @@
 // number starting with 0 that counts up with each iteration:
 //
 //     for (items) |item, index| {
+//
 //         // Do something with item and index
+//
 //     }
 //
+// You can name "item" and "index" anything you want. "i" is a popular
+// shortening of "index". The item name is often the singular form of
+// the items you're looping through.
+//
 const std = @import("std");
 
 pub fn main() void {
@@ -15,9 +21,9 @@ pub fn main() void {
     var value: u32 = 0;
 
     // Now we'll convert the binary bits to a number value by adding
-    // the value of the place as a power of two for each bit. See if
-    // you can figure out the missing piece:
+    // the value of the place as a power of two for each bit.
     //
+    // See if you can figure out the missing piece:
     for (bits) |bit, ???| {
         var place_value = std.math.pow(u32, 2, @intCast(u32, i));
         value += place_value * bit;

+ 17 - 6
18_functions.zig

@@ -1,5 +1,18 @@
 //
-// Functions! FUNctions! FUN!
+// Functions! We've already seen a lot of one called "main()". Now let's try
+// writing one of our own:
+//
+//     fn foo(n: u8) u8 {
+//         return n+1;
+//     }
+//
+// The foo() function above takes a number "n" and returns a number that is
+// larger by one.
+//
+// If your function doesn't take any parameters and doesn't return anything,
+// it would be defined like main():
+//
+//     fn foo() void { }
 //
 const std = @import("std");
 
@@ -11,12 +24,10 @@ pub fn main() void {
 }
 
 //
-// We're just missing a couple things here. One thing we're NOT missing is the
-// keyword "pub", which is not needed here. Can you guess why?
+// Please define the deepThought() function below.
 //
-// Functions need to specify the type of value they return. The main() function
-// above has a special return type "void", which means it returns nothing. This
-// function returns something. What might that be?
+// We're just missing a couple things. One thing we're NOT missing is the
+// keyword "pub", which is not needed here. Can you guess why?
 //
 ??? deepThought() ??? {
     return 42; // Number courtesy Douglas Adams

+ 13 - 10
19_functions2.zig

@@ -1,5 +1,11 @@
 //
-// Now let's use a function that takes a parameter.
+// Now let's create a function that takes a parameter. Here's an
+// example that takes two parameters. As you can see, parameters
+// are declared just like an other types ("name": "type"):
+//
+//     fn myFunction( number: u8, is_lucky: bool ) {
+//         ...
+//     }
 //
 const std = @import( "std" );
 
@@ -13,16 +19,13 @@ pub fn main() void {
 }
 
 //
-// Oops! We seem to have forgotten something here. Function
-// parameters look like this:
-//
-//   fn myFunction( number: u8, is_lucky: bool ) {
-//       ...
-//   }
-//
-// As you can see, we declare the type of the parameter, just
-// like we declare the types of variables, with a colon ":".
+// Please give this function the correct input parameter(s).
+// You'll need to figure out the parameter name and type that we're
+// expecting. The output type has already been specified for you.
 //
 fn twoToThe(???) u32 {
     return std.math.pow(u32, 2, my_number);
+    // std.math.pow(type, a, b) takes a numeric type and two numbers
+    // of that type and returns "a to the power of b" as that same
+    // numeric type.
 }