diff --git a/config.json b/config.json index f301ceb..c2f30d1 100644 --- a/config.json +++ b/config.json @@ -508,6 +508,14 @@ "practices": [], "prerequisites": [], "difficulty": 3 + }, + { + "slug": "diamond", + "name": "Diamond", + "uuid": "75ad9a69-8336-43b2-a4f3-467a43768772", + "practices": [], + "prerequisites": [], + "difficulty": 5 } ] }, diff --git a/exercises/practice/diamond/.docs/instructions.md b/exercises/practice/diamond/.docs/instructions.md new file mode 100644 index 0000000..3034802 --- /dev/null +++ b/exercises/practice/diamond/.docs/instructions.md @@ -0,0 +1,52 @@ +# Instructions + +The diamond kata takes as its input a letter, and outputs it in a diamond shape. +Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point. + +## Requirements + +- The first row contains one 'A'. +- The last row contains one 'A'. +- All rows, except the first and last, have exactly two identical letters. +- All rows have as many trailing spaces as leading spaces. (This might be 0). +- The diamond is horizontally symmetric. +- The diamond is vertically symmetric. +- The diamond has a square shape (width equals height). +- The letters form a diamond shape. +- The top half has the letters in ascending order. +- The bottom half has the letters in descending order. +- The four corners (containing the spaces) are triangles. + +## Examples + +In the following examples, spaces are indicated by `·` characters. + +Diamond for letter 'A': + +```text +A +``` + +Diamond for letter 'C': + +```text +··A·· +·B·B· +C···C +·B·B· +··A·· +``` + +Diamond for letter 'E': + +```text +····A···· +···B·B··· +··C···C·· +·D·····D· +E·······E +·D·····D· +··C···C·· +···B·B··· +····A···· +``` diff --git a/exercises/practice/diamond/.meta/config.json b/exercises/practice/diamond/.meta/config.json new file mode 100644 index 0000000..ba2c68d --- /dev/null +++ b/exercises/practice/diamond/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "diamond.8th" + ], + "test": [ + "test.8th" + ], + "example": [ + ".meta/example.8th" + ] + }, + "blurb": "Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.", + "source": "Seb Rose", + "source_url": "https://web.archive.org/web/20220807163751/http://claysnow.co.uk/recycling-tests-in-tdd/" +} diff --git a/exercises/practice/diamond/.meta/example.8th b/exercises/practice/diamond/.meta/example.8th new file mode 100644 index 0000000..f3621d3 --- /dev/null +++ b/exercises/practice/diamond/.meta/example.8th @@ -0,0 +1,20 @@ +: vp \ s -- a + 0 s:@ nip ' noop 'A rot a:generate clone a:pop drop a:rev a:+ +; + +: hp \ s -- a + 0 s:@ nip ' noop 'A rot a:generate clone a:rev swap a:shift drop a:+ +; + +: cell \ n n -- n + 2dup n:= if nip ;then + 2drop 32 +; + +: row \ a n -- s + ( over cell ) rot swap a:map nip s:n> +; + +: rows \ s -- a + dup hp >r vp ( r@ swap row ) a:map rdrop +; diff --git a/exercises/practice/diamond/.meta/tests.toml b/exercises/practice/diamond/.meta/tests.toml new file mode 100644 index 0000000..4e7802e --- /dev/null +++ b/exercises/practice/diamond/.meta/tests.toml @@ -0,0 +1,25 @@ +# 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. + +[202fb4cc-6a38-4883-9193-a29d5cb92076] +description = "Degenerate case with a single 'A' row" + +[bd6a6d78-9302-42e9-8f60-ac1461e9abae] +description = "Degenerate case with no row containing 3 distinct groups of spaces" + +[af8efb49-14ed-447f-8944-4cc59ce3fd76] +description = "Smallest non-degenerate case with odd diamond side length" + +[e0c19a95-9888-4d05-86a0-fa81b9e70d1d] +description = "Smallest non-degenerate case with even diamond side length" + +[82ea9aa9-4c0e-442a-b07e-40204e925944] +description = "Largest possible diamond" diff --git a/exercises/practice/diamond/diamond.8th b/exercises/practice/diamond/diamond.8th new file mode 100644 index 0000000..508e8f3 --- /dev/null +++ b/exercises/practice/diamond/diamond.8th @@ -0,0 +1,3 @@ +: rows \ s -- a + +; diff --git a/exercises/practice/diamond/libs/exercism/test b/exercises/practice/diamond/libs/exercism/test new file mode 100644 index 0000000..1d08eb2 --- /dev/null +++ b/exercises/practice/diamond/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/diamond/test.8th b/exercises/practice/diamond/test.8th new file mode 100644 index 0000000..77d8808 --- /dev/null +++ b/exercises/practice/diamond/test.8th @@ -0,0 +1,106 @@ +"diamond.8th" f:include +needs exercism/test +with: test +5 tests + +"Degenerate case with a single 'A' row" + ( "A" rows ) + [ + "A" + ] + equal? + +SKIP-REST-OF-TESTS + +"Degenerate case with no row containing 3 distinct groups of spaces" + ( "B" rows ) + [ + " A ", + "B B", + " A " + ] + equal? + +"Smallest non-degenerate case with odd diamond side length" + ( "C" rows ) + [ + " A ", + " B B ", + "C C", + " B B ", + " A " + ] + equal? + +"Smallest non-degenerate case with even diamond side length" + ( "D" rows ) + [ + " A ", + " B B ", + " C C ", + "D D", + " C C ", + " B B ", + " A " + ] + equal? + +"Largest possible diamond" + ( "Z" rows ) + [ + " A ", + " B B ", + " C C ", + " D D ", + " E E ", + " F F ", + " G G ", + " H H ", + " I I ", + " J J ", + " K K ", + " L L ", + " M M ", + " N N ", + " O O ", + " P P ", + " Q Q ", + " R R ", + " S S ", + " T T ", + " U U ", + " V V ", + " W W ", + " X X ", + " Y Y ", + "Z Z", + " Y Y ", + " X X ", + " W W ", + " V V ", + " U U ", + " T T ", + " S S ", + " R R ", + " Q Q ", + " P P ", + " O O ", + " N N ", + " M M ", + " L L ", + " K K ", + " J J ", + " I I ", + " H H ", + " G G ", + " F F ", + " E E ", + " D D ", + " C C ", + " B B ", + " A " + ] + equal? + +end-of-tests +;with