Skip to content

Commit fe6d853

Browse files
Add diamond exercise (#506)
1 parent 768d28f commit fe6d853

File tree

7 files changed

+281
-0
lines changed

7 files changed

+281
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,14 @@
780780
"prerequisites": [],
781781
"difficulty": 4
782782
},
783+
{
784+
"slug": "diamond",
785+
"name": "Diamond",
786+
"uuid": "7f07006a-eafb-4dc3-87f3-4bbf945f6da7",
787+
"practices": [],
788+
"prerequisites": [],
789+
"difficulty": 4
790+
},
783791
{
784792
"slug": "house",
785793
"name": "House",
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Instructions
2+
3+
The diamond kata takes as its input a letter, and outputs it in a diamond shape.
4+
Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point.
5+
6+
## Requirements
7+
8+
- The first row contains one 'A'.
9+
- The last row contains one 'A'.
10+
- All rows, except the first and last, have exactly two identical letters.
11+
- All rows have as many trailing spaces as leading spaces. (This might be 0).
12+
- The diamond is horizontally symmetric.
13+
- The diamond is vertically symmetric.
14+
- The diamond has a square shape (width equals height).
15+
- The letters form a diamond shape.
16+
- The top half has the letters in ascending order.
17+
- The bottom half has the letters in descending order.
18+
- The four corners (containing the spaces) are triangles.
19+
20+
## Examples
21+
22+
In the following examples, spaces are indicated by `·` characters.
23+
24+
Diamond for letter 'A':
25+
26+
```text
27+
A
28+
```
29+
30+
Diamond for letter 'C':
31+
32+
```text
33+
··A··
34+
·B·B·
35+
C···C
36+
·B·B·
37+
··A··
38+
```
39+
40+
Diamond for letter 'E':
41+
42+
```text
43+
····A····
44+
···B·B···
45+
··C···C··
46+
·D·····D·
47+
E·······E
48+
·D·····D·
49+
··C···C··
50+
···B·B···
51+
····A····
52+
```
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"keiravillekode"
4+
],
5+
"files": {
6+
"solution": [
7+
"diamond.zig"
8+
],
9+
"test": [
10+
"test_diamond.zig"
11+
],
12+
"example": [
13+
".meta/example.zig"
14+
]
15+
},
16+
"blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.",
17+
"source": "Seb Rose",
18+
"source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/"
19+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
4+
fn free(allocator: mem.Allocator, array_list: *std.ArrayList([]u8)) void {
5+
for (array_list.items) |item| {
6+
allocator.free(item);
7+
}
8+
array_list.deinit(allocator);
9+
}
10+
11+
pub fn rows(allocator: mem.Allocator, letter: u8) mem.Allocator.Error![][]u8 {
12+
std.debug.assert(letter >= 'A');
13+
std.debug.assert(letter <= 'Z');
14+
const mid = letter - 'A';
15+
const len = 2 * mid + 1;
16+
var array_list = try std.ArrayList([]u8).initCapacity(allocator, len);
17+
errdefer free(allocator, &array_list);
18+
19+
for (0..len) |i| {
20+
var row = try allocator.alloc(u8, len);
21+
@memset(row, ' ');
22+
const j = if (i <= mid) i else (len - 1 - i);
23+
const ch: u8 = @as(u8, @intCast('A' + j));
24+
row[mid - j] = ch;
25+
row[mid + j] = ch;
26+
27+
array_list.appendAssumeCapacity(row);
28+
}
29+
30+
return array_list.toOwnedSlice(allocator);
31+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[202fb4cc-6a38-4883-9193-a29d5cb92076]
13+
description = "Degenerate case with a single 'A' row"
14+
15+
[bd6a6d78-9302-42e9-8f60-ac1461e9abae]
16+
description = "Degenerate case with no row containing 3 distinct groups of spaces"
17+
18+
[af8efb49-14ed-447f-8944-4cc59ce3fd76]
19+
description = "Smallest non-degenerate case with odd diamond side length"
20+
21+
[e0c19a95-9888-4d05-86a0-fa81b9e70d1d]
22+
description = "Smallest non-degenerate case with even diamond side length"
23+
24+
[82ea9aa9-4c0e-442a-b07e-40204e925944]
25+
description = "Largest possible diamond"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const std = @import("std");
2+
const mem = std.mem;
3+
4+
pub fn rows(allocator: mem.Allocator, letter: u8) mem.Allocator.Error![][]u8 {
5+
std.debug.assert(letter >= 'A');
6+
std.debug.assert(letter <= 'Z');
7+
_ = allocator;
8+
@compileError("please implement the rows function");
9+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
const std = @import("std");
2+
const testing = std.testing;
3+
4+
const rows = @import("diamond.zig").rows;
5+
6+
fn free(slices: [][]u8) void {
7+
for (slices) |slice| {
8+
testing.allocator.free(slice);
9+
}
10+
testing.allocator.free(slices);
11+
}
12+
13+
fn testRows(allocator: std.mem.Allocator, expected: []const []const u8, letter: u8) !void {
14+
const actual = try rows(allocator, letter);
15+
defer free(actual);
16+
try testing.expectEqual(expected.len, actual.len);
17+
for (0..expected.len) |i| {
18+
try testing.expectEqualStrings(expected[i], actual[i]);
19+
}
20+
}
21+
22+
test "Degenerate case with a single 'A' row" {
23+
const expected = [_][]const u8{
24+
"A", //
25+
};
26+
try std.testing.checkAllAllocationFailures(
27+
std.testing.allocator,
28+
testRows,
29+
.{ &expected, 'A' },
30+
);
31+
}
32+
33+
test "Degenerate case with no row containing 3 distinct groups of spaces" {
34+
const expected = [_][]const u8{
35+
" A ", //
36+
"B B", //
37+
" A ", //
38+
};
39+
try std.testing.checkAllAllocationFailures(
40+
std.testing.allocator,
41+
testRows,
42+
.{ &expected, 'B' },
43+
);
44+
}
45+
46+
test "Smallest non-degenerate case with odd diamond side length" {
47+
const expected = [_][]const u8{
48+
" A ", //
49+
" B B ", //
50+
"C C", //
51+
" B B ", //
52+
" A ", //
53+
};
54+
try std.testing.checkAllAllocationFailures(
55+
std.testing.allocator,
56+
testRows,
57+
.{ &expected, 'C' },
58+
);
59+
}
60+
61+
test "Smallest non-degenerate case with even diamond side length" {
62+
const expected = [_][]const u8{
63+
" A ", //
64+
" B B ", //
65+
" C C ", //
66+
"D D", //
67+
" C C ", //
68+
" B B ", //
69+
" A ", //
70+
};
71+
try std.testing.checkAllAllocationFailures(
72+
std.testing.allocator,
73+
testRows,
74+
.{ &expected, 'D' },
75+
);
76+
}
77+
78+
test "Largest possible diamond" {
79+
const expected = [_][]const u8{
80+
" A ", //
81+
" B B ", //
82+
" C C ", //
83+
" D D ", //
84+
" E E ", //
85+
" F F ", //
86+
" G G ", //
87+
" H H ", //
88+
" I I ", //
89+
" J J ", //
90+
" K K ", //
91+
" L L ", //
92+
" M M ", //
93+
" N N ", //
94+
" O O ", //
95+
" P P ", //
96+
" Q Q ", //
97+
" R R ", //
98+
" S S ", //
99+
" T T ", //
100+
" U U ", //
101+
" V V ", //
102+
" W W ", //
103+
" X X ", //
104+
" Y Y ", //
105+
"Z Z", //
106+
" Y Y ", //
107+
" X X ", //
108+
" W W ", //
109+
" V V ", //
110+
" U U ", //
111+
" T T ", //
112+
" S S ", //
113+
" R R ", //
114+
" Q Q ", //
115+
" P P ", //
116+
" O O ", //
117+
" N N ", //
118+
" M M ", //
119+
" L L ", //
120+
" K K ", //
121+
" J J ", //
122+
" I I ", //
123+
" H H ", //
124+
" G G ", //
125+
" F F ", //
126+
" E E ", //
127+
" D D ", //
128+
" C C ", //
129+
" B B ", //
130+
" A ", //
131+
};
132+
try std.testing.checkAllAllocationFailures(
133+
std.testing.allocator,
134+
testRows,
135+
.{ &expected, 'Z' },
136+
);
137+
}

0 commit comments

Comments
 (0)