From 5d789e960875c9fe6f4f28b439145cc2e3c0737b Mon Sep 17 00:00:00 2001 From: Eric Willigers Date: Wed, 4 Nov 2026 11:49:56 +1100 Subject: [PATCH] queen-attack: remove input validation tests We now use u3, so coordinates outside 0..7 are not possible. from ee7 https://github.com/exercism/zig/pull/335/ --- config.json | 4 +- .../practice/queen-attack/.meta/example.zig | 36 ++++---- .../practice/queen-attack/.meta/tests.toml | 4 + .../practice/queen-attack/queen_attack.zig | 11 ++- .../queen-attack/test_queen_attack.zig | 82 ++++++++----------- generators/exercises/queen_attack.py | 41 ++++------ 6 files changed, 73 insertions(+), 105 deletions(-) diff --git a/config.json b/config.json index 6de8f787..daa2513a 100644 --- a/config.json +++ b/config.json @@ -675,15 +675,15 @@ "name": "Queen Attack", "uuid": "6eb542c3-c14f-430a-81ce-ba9f2c0551c2", "practices": [ + "asserting", "control-flow", - "error-sets", "importing", "methods", "structs" ], "prerequisites": [ + "asserting", "control-flow", - "error-sets", "importing", "methods", "structs" diff --git a/exercises/practice/queen-attack/.meta/example.zig b/exercises/practice/queen-attack/.meta/example.zig index e42d7660..16491439 100644 --- a/exercises/practice/queen-attack/.meta/example.zig +++ b/exercises/practice/queen-attack/.meta/example.zig @@ -1,30 +1,22 @@ const std = @import("std"); -pub const QueenError = error{ - InitializationFailure, - InvalidAttack, -}; - pub const Queen = struct { - row: i8, - col: i8, + row: u3, + col: u3, - pub fn init(row: i8, col: i8) QueenError!Queen { - if (row < 0 or row > 7 or col < 0 or col > 7) { - return QueenError.InitializationFailure; - } - return .{ - .row = row, - .col = col, - }; + pub fn init(row: u3, col: u3) Queen { + return .{ .row = row, .col = col }; } - pub fn canAttack(self: Queen, other: Queen) QueenError!bool { - if (self.row == other.row and self.col == other.col) { - return QueenError.InvalidAttack; - } - const row_diff = self.row - other.row; - const col_diff = self.col - other.col; - return (row_diff == 0) or (col_diff == 0) or (row_diff == col_diff) or (row_diff == -col_diff); + /// Asserts that `a` and `b` are on different squares. + pub fn canAttack(a: Queen, b: Queen) bool { + std.debug.assert(a.row != b.row or a.col != b.col); + return a.row == b.row or a.col == b.col or + absDiff(u3, a.row, b.row) == absDiff(u3, a.col, b.col); } }; + +// Returns the absolute difference of `a` and `b`. +fn absDiff(comptime T: type, a: T, b: T) T { + return if (a > b) a - b else b - a; +} diff --git a/exercises/practice/queen-attack/.meta/tests.toml b/exercises/practice/queen-attack/.meta/tests.toml index e0624123..bb2e506d 100644 --- a/exercises/practice/queen-attack/.meta/tests.toml +++ b/exercises/practice/queen-attack/.meta/tests.toml @@ -14,15 +14,19 @@ description = "Test creation of Queens with valid and invalid positions -> queen [4e812d5d-b974-4e38-9a6b-8e0492bfa7be] description = "Test creation of Queens with valid and invalid positions -> queen must have positive row" +include = false [f07b7536-b66b-4f08-beb9-4d70d891d5c8] description = "Test creation of Queens with valid and invalid positions -> queen must have row on board" +include = false [15a10794-36d9-4907-ae6b-e5a0d4c54ebe] description = "Test creation of Queens with valid and invalid positions -> queen must have positive column" +include = false [6907762d-0e8a-4c38-87fb-12f2f65f0ce4] description = "Test creation of Queens with valid and invalid positions -> queen must have column on board" +include = false [33ae4113-d237-42ee-bac1-e1e699c0c007] description = "Test the ability of one queen to attack another -> cannot attack" diff --git a/exercises/practice/queen-attack/queen_attack.zig b/exercises/practice/queen-attack/queen_attack.zig index 2e8990ff..ebd6a3ff 100644 --- a/exercises/practice/queen-attack/queen_attack.zig +++ b/exercises/practice/queen-attack/queen_attack.zig @@ -1,15 +1,14 @@ -pub const QueenError = error{ - InitializationFailure, -}; - pub const Queen = struct { - pub fn init(row: i8, col: i8) QueenError!Queen { + // Please implement the fields of this struct. + + pub fn init(row: u3, col: u3) Queen { _ = row; _ = col; @compileError("please implement the init method"); } - pub fn canAttack(self: Queen, other: Queen) QueenError!bool { + /// Asserts that `self` and `other` are on different squares. + pub fn canAttack(self: Queen, other: Queen) bool { _ = self; _ = other; @compileError("please implement the canAttack method"); diff --git a/exercises/practice/queen-attack/test_queen_attack.zig b/exercises/practice/queen-attack/test_queen_attack.zig index fa04c476..a0e74436 100644 --- a/exercises/practice/queen-attack/test_queen_attack.zig +++ b/exercises/practice/queen-attack/test_queen_attack.zig @@ -2,87 +2,69 @@ const std = @import("std"); const testing = std.testing; const queen_attack = @import("queen_attack.zig"); -const QueenError = queen_attack.QueenError; -test "queen has exactly two fields" { - try testing.expectEqual(2, @typeInfo(queen_attack.Queen).@"struct".field_names.len); -} - -test "queen with a valid position" { - const queen = try queen_attack.Queen.init(2, 2); - // Allow the fields to have any name. +fn testCreate(row: u3, col: u3) !void { + const queen = queen_attack.Queen.init(row, col); + // Allow the fields to have any name, in any order. const field_names = @typeInfo(@TypeOf(queen)).@"struct".field_names; inline for (field_names) |name| { const actual = @field(queen, name); - const expected = @as(@TypeOf(actual), 2); - try testing.expectEqual(expected, actual); + try testing.expect(actual == row or actual == col); } } -test "queen must have positive row" { - const queen = queen_attack.Queen.init(-2, 2); - try testing.expectError(QueenError.InitializationFailure, queen); -} - -test "queen must have row on board" { - const queen = queen_attack.Queen.init(8, 4); - try testing.expectError(QueenError.InitializationFailure, queen); -} - -test "queen must have positive column" { - const queen = queen_attack.Queen.init(2, -2); - try testing.expectError(QueenError.InitializationFailure, queen); +test "queen has exactly two fields" { + try testing.expectEqual(2, @typeInfo(queen_attack.Queen).@"struct".field_names.len); } -test "queen must have column on board" { - const queen = queen_attack.Queen.init(4, 8); - try testing.expectError(QueenError.InitializationFailure, queen); +test "queen with a valid position" { + try testCreate(2, 2); } test "cannot attack" { - const white = try queen_attack.Queen.init(2, 4); - const black = try queen_attack.Queen.init(6, 6); - try testing.expect(!try white.canAttack(black)); + const white = queen_attack.Queen.init(2, 4); + const black = queen_attack.Queen.init(6, 6); + try testing.expect(!white.canAttack(black)); } test "can attack on same row" { - const white = try queen_attack.Queen.init(2, 4); - const black = try queen_attack.Queen.init(2, 6); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(2, 4); + const black = queen_attack.Queen.init(2, 6); + try testing.expect(white.canAttack(black)); } test "can attack on same column" { - const white = try queen_attack.Queen.init(4, 5); - const black = try queen_attack.Queen.init(2, 5); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(4, 5); + const black = queen_attack.Queen.init(2, 5); + try testing.expect(white.canAttack(black)); } test "can attack on first diagonal" { - const white = try queen_attack.Queen.init(2, 2); - const black = try queen_attack.Queen.init(0, 4); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(2, 2); + const black = queen_attack.Queen.init(0, 4); + try testing.expect(white.canAttack(black)); } test "can attack on second diagonal" { - const white = try queen_attack.Queen.init(2, 2); - const black = try queen_attack.Queen.init(3, 1); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(2, 2); + const black = queen_attack.Queen.init(3, 1); + try testing.expect(white.canAttack(black)); } test "can attack on third diagonal" { - const white = try queen_attack.Queen.init(2, 2); - const black = try queen_attack.Queen.init(1, 1); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(2, 2); + const black = queen_attack.Queen.init(1, 1); + try testing.expect(white.canAttack(black)); } test "can attack on fourth diagonal" { - const white = try queen_attack.Queen.init(1, 7); - const black = try queen_attack.Queen.init(0, 6); - try testing.expect(try white.canAttack(black)); + const white = queen_attack.Queen.init(1, 7); + const black = queen_attack.Queen.init(0, 6); + try testing.expect(white.canAttack(black)); } test "cannot attack if falling diagonals are only the same when reflected across the longest falling diagonal" { - const white = try queen_attack.Queen.init(4, 1); - const black = try queen_attack.Queen.init(2, 5); - try testing.expect(!try white.canAttack(black)); + const white = queen_attack.Queen.init(4, 1); + const black = queen_attack.Queen.init(2, 5); + try testing.expect(!white.canAttack(black)); } diff --git a/generators/exercises/queen_attack.py b/generators/exercises/queen_attack.py index 1692a833..ae02be15 100644 --- a/generators/exercises/queen_attack.py +++ b/generators/exercises/queen_attack.py @@ -1,6 +1,14 @@ -from lib import is_error - -HEADER = "const QueenError = queen_attack.QueenError;" +HEADER = """ +fn testCreate(row: u3, col: u3) !void { + const queen = queen_attack.Queen.init(row, col); + // Allow the fields to have any name, in any order. + const field_names = @typeInfo(@TypeOf(queen)).@"struct".field_names; + inline for (field_names) |name| { + const actual = @field(queen, name); + try testing.expect(actual == row or actual == col); + } +} +""" def describe(case, parent): @@ -22,30 +30,13 @@ def gen_case(case): return f" try testing.expectEqual({n}, @typeInfo(queen_attack.Queen).@\"struct\".field_names.len);\n" if prop == "create": pos = inp["queen"]["position"] - row, col = pos["row"], pos["column"] - if is_error(case["expected"]): - return ( - f" const queen = queen_attack.Queen.init({row}, {col});\n" - f" try testing.expectError(QueenError.InitializationFailure, queen);\n" - ) - # Valid position: allow any field names, all equal to the input value. - return ( - f" const queen = try queen_attack.Queen.init({row}, {col});\n" - f" // Allow the fields to have any name.\n" - f" const field_names = @typeInfo(@TypeOf(queen)).@\"struct\".field_names;\n" - f" inline for (field_names) |name| {{\n" - f" const actual = @field(queen, name);\n" - f" const expected = @as(@TypeOf(actual), {row});\n" - f" try testing.expectEqual(expected, actual);\n" - f" }}\n" - ) + return f" try testCreate({pos['row']}, {pos['column']});\n" # canAttack w = inp["white_queen"]["position"] b = inp["black_queen"]["position"] - expected = case["expected"] - bang = "" if expected else "!" + bang = "" if case["expected"] else "!" return ( - f" const white = try queen_attack.Queen.init({w['row']}, {w['column']});\n" - f" const black = try queen_attack.Queen.init({b['row']}, {b['column']});\n" - f" try testing.expect({bang}try white.canAttack(black));\n" + f" const white = queen_attack.Queen.init({w['row']}, {w['column']});\n" + f" const black = queen_attack.Queen.init({b['row']}, {b['column']});\n" + f" try testing.expect({bang}white.canAttack(black));\n" )