課題5: 制御構造の実践
マンダトリー要件 (80点)
Part 1: 条件分岐とループ (20点)
基本的な制御構造を使ったプログラムを実装してください。
ファイル: part1/control_basics.zig
const std = @import("std");
// TODO: 配列から最大値を見つける
fn findMax(numbers: []const i32) ?i32 {
// 実装
}
// TODO: 配列から最小値を見つける
fn findMin(numbers: []const i32) ?i32 {
// 実装
}
// TODO: 配列の合計を計算
fn sum(numbers: []const i32) i64 {
// 実装
}
// TODO: 配列の平均を計算
fn average(numbers: []const i32) ?f64 {
// 実装(空配列の場合はnull)
}
// TODO: 配列内の特定の値の出現回数を数える
fn count(numbers: []const i32, target: i32) usize {
// 実装
}
pub fn main() void {
const numbers = [_]i32{ 5, 2, 8, 1, 9, 3, 7 };
if (findMax(&numbers)) |max| {
std.debug.print("Max: {}\n", .{max});
}
if (findMin(&numbers)) |min| {
std.debug.print("Min: {}\n", .{min});
}
std.debug.print("Sum: {}\n", .{sum(&numbers)});
if (average(&numbers)) |avg| {
std.debug.print("Average: {d:.2}\n", .{avg});
}
std.debug.print("Count of 5: {}\n", .{count(&numbers, 5)});
}
Part 2: switchによるパターンマッチング (20点)
switchを使った分類プログラムを実装してください。
ファイル: part2/pattern_matching.zig
const std = @import("std");
const Grade = enum {
A,
B,
C,
D,
F,
};
// TODO: スコアから成績を判定
fn getGrade(score: u8) Grade {
// 実装
// 90-100: A
// 80-89: B
// 70-79: C
// 60-69: D
// 0-59: F
}
const DayOfWeek = enum {
monday,
tuesday,
wednesday,
thursday,
friday,
saturday,
sunday,
};
// TODO: 曜日が平日か週末かを判定
fn isWeekend(day: DayOfWeek) bool {
// 実装
}
const Season = enum {
spring,
summer,
autumn,
winter,
};
// TODO: 月から季節を判定(北半球)
fn getSeason(month: u8) ?Season {
// 実装
// 3-5: spring, 6-8: summer, 9-11: autumn, 12-2: winter
// 範囲外はnull
}
pub fn main() void {
std.debug.print("=== Grades ===\n", .{});
const scores = [_]u8{ 95, 82, 75, 68, 55 };
for (scores) |score| {
const grade = getGrade(score);
std.debug.print("Score {}: Grade {}\n", .{score, grade});
}
std.debug.print("\n=== Days ===\n", .{});
const days = [_]DayOfWeek{
.monday, .tuesday, .wednesday, .thursday,
.friday, .saturday, .sunday
};
for (days) |day| {
const weekend = isWeekend(day);
std.debug.print("{}: {s}\n", .{day, if (weekend) "Weekend" else "Weekday"});
}
std.debug.print("\n=== Seasons ===\n", .{});
for (1..13) |month| {
if (getSeason(@intCast(month))) |season| {
std.debug.print("Month {}: {}\n", .{month, season});
}
}
}
Part 3: ネストしたループ (20点)
ネストしたループを使ったプログラムを実装してください。
ファイル: part3/nested_loops.zig
const std = @import("std");
// TODO: 九九の表を出力
fn printMultiplicationTable() void {
// 実装
// 1x1=1 1x2=2 ... 1x9=9
// 2x1=2 2x2=4 ... 2x9=18
// ...
// 9x1=9 9x2=18 ... 9x9=81
}
// TODO: 2次元配列の合計を計算
fn sumMatrix(matrix: []const []const i32) i64 {
// 実装
}
// TODO: 2次元配列から最大値を見つける
fn findMaxInMatrix(matrix: []const []const i32) ?i32 {
// 実装
}
// TODO: 素数を見つける(エラトステネスの篩)
fn findPrimes(allocator: std.mem.Allocator, max: usize) ![]bool {
// 実装
// 戻り値: bool配列(true=素数、false=合成数)
}
pub fn main() !void {
std.debug.print("=== Multiplication Table ===\n", .{});
printMultiplicationTable();
std.debug.print("\n=== Matrix Operations ===\n", .{});
const row1 = [_]i32{ 1, 2, 3 };
const row2 = [_]i32{ 4, 5, 6 };
const row3 = [_]i32{ 7, 8, 9 };
const matrix = [_][]const i32{ &row1, &row2, &row3 };
std.debug.print("Sum: {}\n", .{sumMatrix(&matrix)});
if (findMaxInMatrix(&matrix)) |max| {
std.debug.print("Max: {}\n", .{max});
}
std.debug.print("\n=== Primes up to 30 ===\n", .{});
const allocator = std.heap.page_allocator;
const primes = try findPrimes(allocator, 30);
defer allocator.free(primes);
for (primes, 0..) |is_prime, i| {
if (is_prime) {
std.debug.print("{} ", .{i});
}
}
std.debug.print("\n", .{});
}
Part 4: エラーハンドリングと制御フロー (20点)
エラーハンドリングを組み合わせた制御フローを実装してください。
ファイル: part4/error_control.zig
const std = @import("std");
const ParseError = error{
InvalidCharacter,
Overflow,
EmptyString,
};
// TODO: 文字列を整数にパース(エラーハンドリング付き)
fn parseInt(str: []const u8) ParseError!i32 {
// 実装
// 空文字列: EmptyString
// 無効な文字: InvalidCharacter
// オーバーフロー: Overflow
}
const MathError = error{
DivisionByZero,
NegativeSquareRoot,
};
// TODO: 安全な除算
fn safeDivide(a: f64, b: f64) MathError!f64 {
// 実装
}
// TODO: 平方根(負の数はエラー)
fn safeSqrt(x: f64) MathError!f64 {
// 実装
}
// TODO: 配列から値を検索(見つからない場合はエラー)
fn findValue(numbers: []const i32, target: i32) !usize {
// 実装
}
pub fn main() !void {
std.debug.print("=== Parse Int ===\n", .{});
const test_strings = [_][]const u8{ "123", "-456", "abc", "999999999999" };
for (test_strings) |str| {
if (parseInt(str)) |value| {
std.debug.print("'{s}' -> {}\n", .{str, value});
} else |err| {
std.debug.print("'{s}' -> Error: {}\n", .{str, err});
}
}
std.debug.print("\n=== Safe Math ===\n", .{});
if (safeDivide(10.0, 2.0)) |result| {
std.debug.print("10 / 2 = {d:.2}\n", .{result});
} else |err| {
std.debug.print("Error: {}\n", .{err});
}
if (safeDivide(10.0, 0.0)) |result| {
std.debug.print("10 / 0 = {d:.2}\n", .{result});
} else |err| {
std.debug.print("10 / 0 -> Error: {}\n", .{err});
}
if (safeSqrt(-4.0)) |result| {
std.debug.print("sqrt(-4) = {d:.2}\n", .{result});
} else |err| {
std.debug.print("sqrt(-4) -> Error: {}\n", .{err});
}
std.debug.print("\n=== Find Value ===\n", .{});
const numbers = [_]i32{ 1, 2, 3, 4, 5 };
if (findValue(&numbers, 3)) |index| {
std.debug.print("Found 3 at index {}\n", .{index});
} else |err| {
std.debug.print("Error: {}\n", .{err});
}
}
ボーナス課題 (20点)
Bonus 1: 状態機械の実装 (10点)
状態機械を使った信号機シミュレーションを実装してください。
ファイル: bonus1/state_machine.zig
const std = @import("std");
const TrafficLight = enum {
red,
yellow,
green,
};
const LightState = struct {
current: TrafficLight,
duration: u32, // 秒数
// TODO: 次の状態に遷移
pub fn next(self: *LightState) void {
// 実装
// red (30秒) -> green (45秒) -> yellow (5秒) -> red
}
// TODO: 現在の状態を表示
pub fn display(self: LightState) void {
// 実装
}
// TODO: 時間を進める(1秒)
pub fn tick(self: *LightState) void {
// 実装
}
};
pub fn main() void {
var light = LightState{
.current = .red,
.duration = 30,
};
// 100秒間シミュレート
for (0..100) |second| {
std.debug.print("Time {}: ", .{second});
light.display();
light.tick();
}
}
Bonus 2: 簡易電卓 (10点)
再帰下降パーサーを使った簡易電卓を実装してください。
ファイル: bonus2/calculator.zig
const std = @import("std");
const CalcError = error{
InvalidExpression,
DivisionByZero,
UnknownOperator,
};
const Token = union(enum) {
number: i32,
operator: u8,
end,
};
const Parser = struct {
input: []const u8,
pos: usize,
// TODO: 次のトークンを取得
fn nextToken(self: *Parser) Token {
// 実装
}
// TODO: 式をパース(加算・減算)
fn parseExpression(self: *Parser) CalcError!i32 {
// 実装
}
// TODO: 項をパース(乗算・除算)
fn parseTerm(self: *Parser) CalcError!i32 {
// 実装
}
// TODO: 因子をパース(数値)
fn parseFactor(self: *Parser) CalcError!i32 {
// 実装
}
};
// TODO: 式を評価
fn evaluate(expression: []const u8) CalcError!i32 {
var parser = Parser{
.input = expression,
.pos = 0,
};
return parser.parseExpression();
}
pub fn main() !void {
const expressions = [_][]const u8{
"2+3",
"10-5",
"4*5",
"20/4",
"2+3*4",
"10-2*3",
};
for (expressions) |expr| {
if (evaluate(expr)) |result| {
std.debug.print("{s} = {}\n", .{expr, result});
} else |err| {
std.debug.print("{s} -> Error: {}\n", .{expr, err});
}
}
}
評価基準
| 項目 | 配点 |
|---|---|
| Part 1: 条件分岐とループ | 20点 |
| Part 2: switchによるパターンマッチング | 20点 |
| Part 3: ネストしたループ | 20点 |
| Part 4: エラーハンドリングと制御フロー | 20点 |
| **マンダトリー合計** | **80点** |
| Bonus 1: 状態機械の実装 | 10点 |
| Bonus 2: 簡易電卓 | 10点 |
| **ボーナス合計** | **20点** |
合格基準
- マンダトリー: 64点以上で合格(80点満点の80%)
- ボーナス: 追加評価(最終成績の加算)
提出方法
exercise05/
├── part1/
│ └── control_basics.zig
├── part2/
│ └── pattern_matching.zig
├── part3/
│ └── nested_loops.zig
├── part4/
│ └── error_control.zig
├── bonus1/
│ └── state_machine.zig
└── bonus2/
└── calculator.zig
テスト実行
# マンダトリー
zig run part1/control_basics.zig
zig run part2/pattern_matching.zig
zig run part3/nested_loops.zig
zig run part4/error_control.zig
# ボーナス
zig run bonus1/state_machine.zig
zig run bonus2/calculator.zig
ヒント
for (array) |item| {
// itemを使用
}
for (array, 0..) |item, index| {
// itemとindexを使用
}
- switchでの範囲マッチング:
switch (value) {
0...10 => {},
11...20 => {},
else => {},
}
- エラーハンドリング:
if (riskyFunc()) |value| {
// 成功時の処理
} else |err| {
// エラー時の処理
}
- オプショナルのアンラップ:
if (optional_value) |value| {
// 値が存在する場合
} else {
// nullの場合
}
- エラトステネスの篩:
// すべてをtrueで初期化
// 2から始めて、その倍数をfalseにマーク
// 次の素数に移動して繰り返し
参考資料
- Zig Language Reference - Control Flow: https://ziglang.org/documentation/master/#Control-Flow
- Ziglearn - Flow Control: https://ziglearn.org/chapter-1/#flow-control
- Ziglearn - Switch: https://ziglearn.org/chapter-1/#switch