Skip to content

Commit 0bf7064

Browse files
authored
Merge pull request #196 from atk/spiral-matrix
new exercise: spiral-matrix
2 parents 0ab8cf0 + a16cd48 commit 0bf7064

File tree

14 files changed

+353
-0
lines changed

14 files changed

+353
-0
lines changed

config.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,14 @@
447447
"prerequisites": [],
448448
"difficulty": 5
449449
},
450+
{
451+
"slug": "spiral-matrix",
452+
"name": "Spiral Matrix",
453+
"uuid": "cbf5bf2f-6b53-4d49-9ac7-0da10889c333",
454+
"practices": [],
455+
"prerequisites": [],
456+
"difficulty": 5
457+
},
450458
{
451459
"slug": "twelve-days",
452460
"name": "Twelve Days",
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
## Output format
2+
3+
The output is expected as a flat array of u16 numbers; it will be deserialized into the required square array of arrays:
4+
5+
```js
6+
// output
7+
[1,2,3,8,9,4,7,6,5]
8+
// =>
9+
// [[1, 2, 3],
10+
// [8, 9, 4],
11+
// [7, 6, 5]]
12+
```
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Instructions
2+
3+
Your task is to return a square matrix of a given size.
4+
5+
The matrix should be filled with natural numbers, starting from 1 in the top-left corner, increasing in an inward, clockwise spiral order, like these examples:
6+
7+
## Examples
8+
9+
### Spiral matrix of size 3
10+
11+
```text
12+
1 2 3
13+
8 9 4
14+
7 6 5
15+
```
16+
17+
### Spiral matrix of size 4
18+
19+
```text
20+
1 2 3 4
21+
12 13 14 5
22+
11 16 15 6
23+
10 9 8 7
24+
```
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Introduction
2+
3+
In a small village near an ancient forest, there was a legend of a hidden treasure buried deep within the woods.
4+
Despite numerous attempts, no one had ever succeeded in finding it.
5+
This was about to change, however, thanks to a young explorer named Elara.
6+
She had discovered an old document containing instructions on how to locate the treasure.
7+
Using these instructions, Elara was able to draw a map that revealed the path to the treasure.
8+
9+
To her surprise, the path followed a peculiar clockwise spiral.
10+
It was no wonder no one had been able to find the treasure before!
11+
With the map in hand, Elara embarks on her journey to uncover the hidden treasure.
Lines changed: 18 additions & 0 deletions
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+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"authors": [
3+
"atk"
4+
],
5+
"files": {
6+
"solution": [
7+
"spiral-matrix.wat"
8+
],
9+
"test": [
10+
"spiral-matrix.spec.js"
11+
],
12+
"example": [
13+
".meta/proof.ci.wat"
14+
],
15+
"invalidator": [
16+
"package.json"
17+
]
18+
},
19+
"blurb": "Given the size, return a square matrix of numbers in spiral order.",
20+
"source": "Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension.",
21+
"source_url": "https://web.archive.org/web/20230607064729/https://old.reddit.com/r/dailyprogrammer/comments/6i60lr/20170619_challenge_320_easy_spiral_ascension/",
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+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
(module
2+
(memory (export "mem") 1)
3+
4+
(global $outputOffset i32 (i32.const 64))
5+
6+
;;
7+
;; Recursively calculate one number from the spiral
8+
;;
9+
;; @param {i32} $width - remaining width of the spiral
10+
;; @param {i32} $height - remaining height of the spiral
11+
;; @param {i32} $x - current x position in the matrix
12+
;; @param {i32} $y - current y position in the matrix
13+
;;
14+
;; @returns {i32} - current number
15+
;;
16+
(func $spiral (param $width i32) (param $height i32) (param $x i32) (param $y i32) (result i32)
17+
(if (i32.le_s (local.get $y) (i32.const 0)) (then
18+
(return (i32.add (local.get $x) (i32.const 1)))))
19+
(i32.add (local.get $width)
20+
(call $spiral (i32.sub (local.get $height) (i32.const 1)) (local.get $width)
21+
(i32.sub (local.get $y) (i32.const 1))
22+
(i32.sub (i32.sub (local.get $width) (local.get $x)) (i32.const 1))))
23+
)
24+
25+
;;
26+
;; Generate an array of u16 numbers that when put into a square 2d-array will result in a spiral matrix
27+
;;
28+
;; @param {i32} $size - length of the sides of the matrix
29+
;;
30+
;; @returns {(i32,i32)} - offset and length of the u16 number array
31+
;;
32+
(func (export "spiralMatrix") (param $size i32) (result i32 i32)
33+
(local $x i32)
34+
(local $y i32)
35+
(loop $line
36+
(local.set $x (i32.const 0))
37+
(loop $column
38+
(i32.store16 (i32.add (global.get $outputOffset)
39+
(i32.shl (i32.add (i32.mul (local.get $y) (local.get $size))
40+
(local.get $x)) (i32.const 1)))
41+
(call $spiral (local.get $size) (local.get $size)
42+
(local.get $x) (local.get $y)))
43+
(local.set $x (i32.add (local.get $x) (i32.const 1)))
44+
(br_if $column (i32.le_u (local.get $x) (local.get $size))))
45+
(local.set $y (i32.add (local.get $y) (i32.const 1)))
46+
(br_if $line (i32.le_u (local.get $y) (local.get $size))))
47+
(global.get $outputOffset) (i32.mul (local.get $size) (local.get $size))
48+
)
49+
)
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
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+
[8f584201-b446-4bc9-b132-811c8edd9040]
13+
description = "empty spiral"
14+
15+
[e40ae5f3-e2c9-4639-8116-8a119d632ab2]
16+
description = "trivial spiral"
17+
18+
[cf05e42d-eb78-4098-a36e-cdaf0991bc48]
19+
description = "spiral of size 2"
20+
21+
[1c475667-c896-4c23-82e2-e033929de939]
22+
description = "spiral of size 3"
23+
24+
[05ccbc48-d891-44f5-9137-f4ce462a759d]
25+
description = "spiral of size 4"
26+
27+
[f4d2165b-1738-4e0c-bed0-c459045ae50d]
28+
description = "spiral of size 5"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
audit=false
Lines changed: 21 additions & 0 deletions
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.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default {
2+
presets: ["@exercism/babel-preset-javascript"],
3+
plugins: [],
4+
};
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
"name": "@exercism/wasm-spiral-matrix",
3+
"description": "Exercism exercises in WebAssembly.",
4+
"author": "Alex Lohr",
5+
"type": "module",
6+
"private": true,
7+
"license": "MIT",
8+
"repository": {
9+
"type": "git",
10+
"url": "https://github.com/exercism/wasm",
11+
"directory": "exercises/practice/spiral-matrix"
12+
},
13+
"jest": {
14+
"maxWorkers": 1
15+
},
16+
"devDependencies": {
17+
"@babel/core": "^7.23.3",
18+
"@exercism/babel-preset-javascript": "^0.4.0",
19+
"@exercism/eslint-config-javascript": "^0.6.0",
20+
"@types/jest": "^29.5.8",
21+
"@types/node": "^20.9.1",
22+
"babel-jest": "^29.7.0",
23+
"core-js": "^3.33.2",
24+
"eslint": "^8.54.0",
25+
"jest": "^29.7.0"
26+
},
27+
"dependencies": {
28+
"@exercism/wasm-lib": "^0.2.0"
29+
},
30+
"scripts": {
31+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js ./*",
32+
"watch": "node --experimental-vm-modules node_modules/jest/bin/jest.js --watch ./*",
33+
"lint": "eslint ."
34+
}
35+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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("./spiral-matrix.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 spiralMatrix = (size) => {
18+
const [outputOffset, outputLength] = currentInstance.exports.spiralMatrix(size);
19+
const output = currentInstance.get_mem_as_u16(outputOffset, outputLength);
20+
console.log(output);
21+
const outputIterator = output[Symbol.iterator]();
22+
return Array.from({ length: size }, () =>
23+
Array.from({ length: size}, () => outputIterator.next()?.value));
24+
}
25+
26+
describe('Spiral Matrix', () => {
27+
beforeEach(async () => {
28+
currentInstance = null;
29+
if (!wasmModule) {
30+
return Promise.reject();
31+
}
32+
try {
33+
currentInstance = await new WasmRunner(wasmModule);
34+
return Promise.resolve();
35+
} catch (err) {
36+
console.log(`Error instantiating WebAssembly module: ${err}`);
37+
return Promise.reject();
38+
}
39+
});
40+
41+
test('empty spiral', () => {
42+
const expected = [];
43+
const actual = spiralMatrix(0);
44+
45+
expect(actual).toEqual(expected);
46+
});
47+
48+
xtest('trivial spiral', () => {
49+
const expected = [[1]];
50+
const actual = spiralMatrix(1);
51+
52+
expect(actual).toEqual(expected);
53+
});
54+
55+
xtest('spiral of size 2', () => {
56+
const expected = [
57+
[1, 2],
58+
[4, 3],
59+
];
60+
const actual = spiralMatrix(2);
61+
62+
expect(actual).toEqual(expected);
63+
});
64+
65+
xtest('spiral of size 3', () => {
66+
const expected = [
67+
[1, 2, 3],
68+
[8, 9, 4],
69+
[7, 6, 5],
70+
];
71+
const actual = spiralMatrix(3);
72+
73+
expect(actual).toEqual(expected);
74+
});
75+
76+
xtest('spiral of size 4', () => {
77+
const expected = [
78+
[1, 2, 3, 4],
79+
[12, 13, 14, 5],
80+
[11, 16, 15, 6],
81+
[10, 9, 8, 7],
82+
];
83+
const actual = spiralMatrix(4);
84+
85+
expect(actual).toEqual(expected);
86+
});
87+
88+
xtest('spiral of size 5', () => {
89+
const expected = [
90+
[1, 2, 3, 4, 5],
91+
[16, 17, 18, 19, 6],
92+
[15, 24, 25, 20, 7],
93+
[14, 23, 22, 21, 8],
94+
[13, 12, 11, 10, 9],
95+
];
96+
const actual = spiralMatrix(5);
97+
98+
expect(expected).toEqual(actual);
99+
});
100+
});
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
(module
2+
(memory (export "mem") 1)
3+
4+
;;
5+
;; Generate an array of u16 numbers that when put into a square 2d-array will result in a spiral matrix
6+
;;
7+
;; @param {i32} $size - length of the sides of the matrix
8+
;;
9+
;; @returns {(i32,i32)} - offset and length of the u16 number array
10+
;;
11+
(func (export "spiralMatrix") (param $size i32) (result i32 i32)
12+
(i32.const 0) (i32.const 0)
13+
)
14+
)

0 commit comments

Comments
 (0)