Skip to content

Commit feb7702

Browse files
authored
new exercise: diamond (#161)
1 parent 9f6125a commit feb7702

13 files changed

+396
-0
lines changed

config.json

+8
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,14 @@
303303
"prerequisites": [],
304304
"difficulty": 5
305305
},
306+
{
307+
"slug": "diamond",
308+
"name": "Diamond",
309+
"uuid": "97eadf6f-beb9-4c34-8344-d866888d2164",
310+
"practices": [],
311+
"prerequisites": [],
312+
"difficulty": 5
313+
},
306314
{
307315
"slug": "grains",
308316
"name": "Grains",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Diamond format
2+
3+
The diamond is represented as a string, with a newline character at the end of each row.
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+
```

exercises/practice/diamond/.eslintrc

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"root": true,
3+
"extends": "@exercism/eslint-config-javascript",
4+
"env": {
5+
"jest": true
6+
},
7+
"overrides": [
8+
{
9+
"files": [
10+
"*.spec.js"
11+
],
12+
"excludedFiles": [
13+
"custom.spec.js"
14+
],
15+
"extends": "@exercism/eslint-config-javascript/maintainers"
16+
}
17+
]
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"authors": [
3+
"atk"
4+
],
5+
"files": {
6+
"solution": [
7+
"diamond.wat"
8+
],
9+
"test": [
10+
"diamond.spec.js"
11+
],
12+
"example": [
13+
".meta/proof.ci.wat"
14+
],
15+
"invalidator": [
16+
"package.json"
17+
]
18+
},
19+
"blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.",
20+
"source": "Seb Rose",
21+
"source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/",
22+
"custom": {
23+
"version.tests.compatibility": "jest-27",
24+
"flag.tests.task-per-describe": false,
25+
"flag.tests.may-run-long": false,
26+
"flag.tests.includes-optional": false
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
(module
2+
(memory (export "mem") 1)
3+
4+
(global $outputOffset i32 (i32.const 0))
5+
(global $linebreak i32 (i32.const 10))
6+
(global $space i32 (i32.const 32))
7+
(global $A i32 (i32.const 65))
8+
9+
;;
10+
;; Output a diamond made of letters with line breaks after each line.
11+
;;
12+
;; @param {i32} $letter - the character code of the letter in the middle of the diamond
13+
;;
14+
;; @returns {(i32,i32)} - the offset and length of the output string in linear memory
15+
;;
16+
(func (export "rows") (param $letter i32) (result i32 i32)
17+
(local $size i32)
18+
(local $outputLength i32)
19+
(local $pos i32)
20+
(local $top i32)
21+
(local $bottom i32)
22+
(local $left i32)
23+
(local $right i32)
24+
;; size of the diamond A = 1, B = 3, C = 5...
25+
(local.set $size (i32.add (i32.const -1) (i32.shl
26+
(i32.sub (local.get $letter) (i32.const 64)) (i32.const 1))))
27+
;; fill grid with spaces
28+
(local.set $outputLength (i32.mul (local.get $size) (i32.add (local.get $size) (i32.const 1))))
29+
(memory.fill (global.get $outputOffset) (global.get $space) (local.get $outputLength))
30+
;; add line breaks
31+
(local.set $pos (local.get $size))
32+
(loop $linebreaks
33+
(i32.store8 (i32.add (global.get $outputOffset) (local.get $pos)) (global.get $linebreak))
34+
(local.set $pos (i32.add (local.get $pos) (i32.add (local.get $size) (i32.const 1))))
35+
(br_if $linebreaks (i32.lt_u (local.get $pos) (local.get $outputLength))))
36+
;; rows: letter - a, size - (letter - A)
37+
;; cols: (size >> 1) +/- (letter - A)
38+
;; start of a row (beginning with 0): row * (size + 1)
39+
(loop $lines
40+
(local.set $pos (i32.sub (local.get $letter) (global.get $A)))
41+
(local.set $top (i32.mul (local.get $pos) (i32.add (local.get $size) (i32.const 1))))
42+
(local.set $bottom (i32.mul (i32.sub (i32.sub (local.get $size) (local.get $pos)) (i32.const 1))
43+
(i32.add (local.get $size) (i32.const 1))))
44+
(local.set $left (i32.sub (i32.shr_u (local.get $size) (i32.const 1)) (local.get $pos)))
45+
(local.set $right (i32.add (i32.shr_u (local.get $size) (i32.const 1)) (local.get $pos)))
46+
(i32.store8 (i32.add (i32.add (global.get $outputOffset)
47+
(local.get $top)) (local.get $left)) (local.get $letter))
48+
(i32.store8 (i32.add (i32.add (global.get $outputOffset)
49+
(local.get $top)) (local.get $right)) (local.get $letter))
50+
(i32.store8 (i32.add (i32.add (global.get $outputOffset)
51+
(local.get $bottom)) (local.get $left)) (local.get $letter))
52+
(i32.store8 (i32.add (i32.add (global.get $outputOffset)
53+
(local.get $bottom)) (local.get $right)) (local.get $letter))
54+
(local.set $letter (i32.sub (local.get $letter) (i32.const 1)))
55+
(br_if $lines (i32.ge_u (local.get $letter) (global.get $A))))
56+
(global.get $outputOffset) (local.get $outputLength)
57+
)
58+
)
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"

exercises/practice/diamond/.npmrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
audit=false

exercises/practice/diamond/LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Exercism
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
presets: ["@exercism/babel-preset-javascript"],
3+
plugins: [],
4+
};
+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { compileWat, WasmRunner } from "@exercism/wasm-lib";
2+
3+
let wasmModule;
4+
let currentInstance;
5+
6+
beforeAll(async () => {
7+
try {
8+
const watPath = new URL("./diamond.wat", import.meta.url);
9+
const { buffer } = await compileWat(watPath);
10+
wasmModule = await WebAssembly.compile(buffer);
11+
} catch (err) {
12+
console.log(`Error compiling *.wat: \n${err}`);
13+
process.exit(1);
14+
}
15+
});
16+
17+
const rows = (letter) => {
18+
const [outputOffset, outputLength] = currentInstance.exports.rows(letter.charCodeAt(0));
19+
const output = currentInstance.get_mem_as_utf8(outputOffset, outputLength);
20+
return output ? output.split('\n').slice(0, -1) : []
21+
}
22+
23+
describe('Diamond', () => {
24+
beforeEach(async () => {
25+
currentInstance = null;
26+
27+
if (!wasmModule) {
28+
return Promise.reject();
29+
}
30+
try {
31+
currentInstance = await new WasmRunner(wasmModule);
32+
return Promise.resolve();
33+
} catch (err) {
34+
console.log(`Error instantiating WebAssembly module: ${err}`);
35+
return Promise.reject();
36+
}
37+
});
38+
test("Degenerate case with a single 'A' row", () => {
39+
expect(rows('A')).toEqual(['A']);
40+
});
41+
42+
xtest('Degenerate case with no row containing 3 distinct groups of spaces', () => {
43+
// prettier-ignore
44+
expect(rows('B')).toEqual([
45+
' A ',
46+
'B B',
47+
' A '
48+
]);
49+
});
50+
51+
xtest('Smallest non-degenerate case with odd diamond side length', () => {
52+
// prettier-ignore
53+
expect(rows('C')).toEqual([
54+
' A ',
55+
' B B ',
56+
'C C',
57+
' B B ',
58+
' A '
59+
]);
60+
});
61+
62+
xtest('Smallest non-degenerate case with even diamond side length', () => {
63+
expect(rows('D')).toEqual([
64+
' A ',
65+
' B B ',
66+
' C C ',
67+
'D D',
68+
' C C ',
69+
' B B ',
70+
' A ',
71+
]);
72+
});
73+
74+
xtest('Largest possible diamond', () => {
75+
expect(rows('Z')).toEqual([
76+
' A ',
77+
' B B ',
78+
' C C ',
79+
' D D ',
80+
' E E ',
81+
' F F ',
82+
' G G ',
83+
' H H ',
84+
' I I ',
85+
' J J ',
86+
' K K ',
87+
' L L ',
88+
' M M ',
89+
' N N ',
90+
' O O ',
91+
' P P ',
92+
' Q Q ',
93+
' R R ',
94+
' S S ',
95+
' T T ',
96+
' U U ',
97+
' V V ',
98+
' W W ',
99+
' X X ',
100+
' Y Y ',
101+
'Z Z',
102+
' Y Y ',
103+
' X X ',
104+
' W W ',
105+
' V V ',
106+
' U U ',
107+
' T T ',
108+
' S S ',
109+
' R R ',
110+
' Q Q ',
111+
' P P ',
112+
' O O ',
113+
' N N ',
114+
' M M ',
115+
' L L ',
116+
' K K ',
117+
' J J ',
118+
' I I ',
119+
' H H ',
120+
' G G ',
121+
' F F ',
122+
' E E ',
123+
' D D ',
124+
' C C ',
125+
' B B ',
126+
' A ',
127+
]);
128+
});
129+
});
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(module
2+
(memory (export "mem") 1)
3+
4+
;;
5+
;; Output a diamond made of letters.
6+
;;
7+
;; @param {i32} $letter - the character code of the letter in the middle of the diamond
8+
;;
9+
;; @returns {(i32,i32)} - the offset and length of the output string in linear memory
10+
;;
11+
(func (export "rows") (param $letter i32) (result i32 i32)
12+
(i32.const 0) (i32.const 0)
13+
)
14+
)

0 commit comments

Comments
 (0)