diff --git a/config.json b/config.json index 555c090..13040f2 100644 --- a/config.json +++ b/config.json @@ -484,6 +484,14 @@ "practices": [], "prerequisites": [], "difficulty": 2 + }, + { + "slug": "spiral-matrix", + "name": "Spiral Matrix", + "uuid": "edb07531-2e7c-4bcd-8bb4-8cbeb09f0057", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/spiral-matrix/.docs/instructions.md b/exercises/practice/spiral-matrix/.docs/instructions.md new file mode 100644 index 0000000..ba99e12 --- /dev/null +++ b/exercises/practice/spiral-matrix/.docs/instructions.md @@ -0,0 +1,24 @@ +# Instructions + +Given the size, return a square matrix of numbers in spiral order. + +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: + +## Examples + +### Spiral matrix of size 3 + +```text +1 2 3 +8 9 4 +7 6 5 +``` + +### Spiral matrix of size 4 + +```text + 1 2 3 4 +12 13 14 5 +11 16 15 6 +10 9 8 7 +``` diff --git a/exercises/practice/spiral-matrix/.meta/config.json b/exercises/practice/spiral-matrix/.meta/config.json new file mode 100644 index 0000000..c101607 --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "spiral-matrix.8th" + ], + "test": [ + "test.8th" + ], + "example": [ + ".meta/example.8th" + ] + }, + "blurb": "Given the size, return a square matrix of numbers in spiral order.", + "source": "Reddit r/dailyprogrammer challenge #320 [Easy] Spiral Ascension.", + "source_url": "https://web.archive.org/web/20230607064729/https://old.reddit.com/r/dailyprogrammer/comments/6i60lr/20170619_challenge_320_easy_spiral_ascension/" +} diff --git a/exercises/practice/spiral-matrix/.meta/example.8th b/exercises/practice/spiral-matrix/.meta/example.8th new file mode 100644 index 0000000..1b1f371 --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/example.8th @@ -0,0 +1,17 @@ +: extend \ a n -- a + 2 n:* swap ( swap n:1- dup -rot a:slide ) a:map nip +; + +: rotate \ a n -- a + 2 n:* n:1- swap ( ( over n:+ ) a:map ) a:map nip +; + +: reverse \ a -- a + ' a:rev a:map a:rev +; + +: spiral-matrix \ n -- a + dup 0 n:= if drop [] ;then + dup 2dup n:1- recurse + swap rotate swap extend reverse swap ' noop 1 rot a:generate a:slide +; diff --git a/exercises/practice/spiral-matrix/.meta/tests.toml b/exercises/practice/spiral-matrix/.meta/tests.toml new file mode 100644 index 0000000..9ac5bac --- /dev/null +++ b/exercises/practice/spiral-matrix/.meta/tests.toml @@ -0,0 +1,28 @@ +# This is an auto-generated file. +# +# Regenerating this file via `configlet sync` will: +# - Recreate every `description` key/value pair +# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications +# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion) +# - Preserve any other key/value pair +# +# As user-added comments (using the # character) will be removed when this file +# is regenerated, comments can be added via a `comment` key. + +[8f584201-b446-4bc9-b132-811c8edd9040] +description = "empty spiral" + +[e40ae5f3-e2c9-4639-8116-8a119d632ab2] +description = "trivial spiral" + +[cf05e42d-eb78-4098-a36e-cdaf0991bc48] +description = "spiral of size 2" + +[1c475667-c896-4c23-82e2-e033929de939] +description = "spiral of size 3" + +[05ccbc48-d891-44f5-9137-f4ce462a759d] +description = "spiral of size 4" + +[f4d2165b-1738-4e0c-bed0-c459045ae50d] +description = "spiral of size 5" diff --git a/exercises/practice/spiral-matrix/libs/exercism/test b/exercises/practice/spiral-matrix/libs/exercism/test new file mode 100644 index 0000000..1d08eb2 --- /dev/null +++ b/exercises/practice/spiral-matrix/libs/exercism/test @@ -0,0 +1,173 @@ +needs console/loaded + +\ ----------------------------------------------------------------- + +ns: test + +-1 var, test-count +var tests-passed +var tests-failed +var tests-skipped +true var, run-test + +\ Some utility words + + +: test-passed \ s x x -- \\ test name, expected value, actual value + 2drop + 1 tests-passed n:+! + con:green con:onBlack . space " ... OK" . con:white con:onBlack cr +; + +: test-skipped \ s -- + 1 tests-skipped n:+! + con:cyan con:onBlack . space " ... SKIPPED" . con:white con:onBlack cr +; + +: test-failed \ s x x -- \\ test name, expected value, actual value + 1 tests-failed n:+! + rot + con:red con:onBlack . space " ... FAIL" . con:white con:onBlack cr + " Actual: «" . . "»" . cr + " Expected: «" . . "»" . cr cr +; + +: isword? \ x -- x f + dup >kind ns:w n:= +; + +: run-test? \ -- T + run-test @ if true else "RUN_ALL_TESTS" getenv n:>bool then +; + +\ Num passed + num skipped + num failed should == num tests +: all-tests-run? \ -- T + tests-passed @ tests-skipped @ tests-failed @ n:+ n:+ + test-count @ n:= +; + +\ returns true if x is a date, false otherwise +: date? \ x -- x T + dup >kind ns:d n:= +; + +\ adapted from 8th forum -- https://8th-dev.com/forum/index.php/topic,2745.0.html +: eq? \ x x -- T + \ are the items the same kind? + 2dup >kind swap >kind n:= + !if 2drop false ;then + + \ same kind: try different comparators + number? if n:= ;then + string? if s:= ;then + array? if ' eq? a:= 2nip ;then + map? if ' eq? m:= 2nip ;then + date? if d:= ;then + + \ otherwise fall back to 'lazy evaluation' + l: = +; + +: eps_eq? \ n x x -- T + \ are the items the same kind? + 2dup >kind swap >kind n:= + !if 2drop false ;then + number? !if 2drop false ;then + rot n:~= +; + +: check-depth \ ... n -- ... + dup>r + n:1+ depth n:= + !if + con:red con:onBlack + "PANIC: expected stack depth to be " . r> . cr + "Stack is:" . cr + .s cr + 255 die + then + rdrop +; + +\ ----------------------------------------------------------------- + +\ status report at end of run +( all-tests-run? + !if con:red con:onBlack "... FAIL - not all tests completed" . con:white con:onBlack cr then +) onexit + +\ Print a summary of the tests run +( con:white con:onBlack + test-count @ . space "tests planned - " . + tests-passed @ . space "passed - " . + tests-skipped @ . space "skipped - " . + tests-failed @ . space "failed" . cr +) onexit + +\ ----------------------------------------------------------------- +\ The public-facing words +\ ----------------------------------------------------------------- + +: equal? \ s x w -- | s w x -- + run-test? !if 2drop test-skipped ;; then + isword? !if swap then + w:exec + 3 check-depth + 2dup \ so test-failed can show actual and expected + eq? if test-passed else test-failed then +; + +: approx_equal? \ s x w n -- | s w x n -- + run-test? !if 3drop test-skipped ;; then + -rot isword? !if swap then + w:exec + 4 check-depth + 3dup \ so test-failed can show actual and expected + eps_eq? + if rot drop test-passed else rot drop test-failed then +; + +: true? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + true swap dup \ so test-failed can show actual and expected + if test-passed else test-failed then +; + +: false? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + false swap dup \ so test-failed can show actual and expected + !if test-passed else test-failed then +; + +: null? \ s w -- + run-test? !if drop test-skipped ;; then + w:exec + 2 check-depth + null swap dup \ so test-failed can show actual and expected + G:null? nip if test-passed else test-failed then +; + +: SKIP-REST-OF-TESTS false run-test ! ; + +: tests \ n -- + test-count ! +; + +\ Set the exit status: +\ 0 = all OK +\ 1 = not all tests were run (some error occurred) +\ 2 = some tests failed +: end-of-tests \ -- + all-tests-run? + if + tests-failed @ 0 n:= if 0 else 2 then + else + 1 + then + die +; + diff --git a/exercises/practice/spiral-matrix/spiral-matrix.8th b/exercises/practice/spiral-matrix/spiral-matrix.8th new file mode 100644 index 0000000..d104e7b --- /dev/null +++ b/exercises/practice/spiral-matrix/spiral-matrix.8th @@ -0,0 +1,3 @@ +: spiral-matrix \ n -- a + +; diff --git a/exercises/practice/spiral-matrix/test.8th b/exercises/practice/spiral-matrix/test.8th new file mode 100644 index 0000000..6403465 --- /dev/null +++ b/exercises/practice/spiral-matrix/test.8th @@ -0,0 +1,57 @@ +"spiral-matrix.8th" f:include +needs exercism/test +with: test +6 tests + +"empty spiral" + ( 0 spiral-matrix ) + [] + equal? + +SKIP-REST-OF-TESTS + +"trivial spiral" + ( 1 spiral-matrix ) + [[1]] + equal? + +"spiral of size 2" + ( 2 spiral-matrix ) + [ + [1, 2], + [4, 3] + ] + equal? + +"spiral of size 3" + ( 3 spiral-matrix ) + [ + [1, 2, 3], + [8, 9, 4], + [7, 6, 5] + ] + equal? + +"spiral of size 4" + ( 4 spiral-matrix ) + [ + [1, 2, 3, 4], + [12, 13, 14, 5], + [11, 16, 15, 6], + [10, 9, 8, 7] + ] + equal? + +"spiral of size 5" + ( 5 spiral-matrix ) + [ + [1, 2, 3, 4, 5], + [16, 17, 18, 19, 6], + [15, 24, 25, 20, 7], + [14, 23, 22, 21, 8], + [13, 12, 11, 10, 9] + ] + equal? + +end-of-tests +;with