Add diamond exercise (#184)

This commit is contained in:
Erik Schierboom
2024-05-14 19:06:28 +02:00
committed by GitHub
parent 042dc1e17b
commit 079dd18692
8 changed files with 406 additions and 0 deletions

View File

@@ -508,6 +508,14 @@
"practices": [],
"prerequisites": [],
"difficulty": 3
},
{
"slug": "diamond",
"name": "Diamond",
"uuid": "75ad9a69-8336-43b2-a4f3-467a43768772",
"practices": [],
"prerequisites": [],
"difficulty": 5
}
]
},

View File

@@ -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····
```

View File

@@ -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/"
}

View File

@@ -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
;

View File

@@ -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"

View File

@@ -0,0 +1,3 @@
: rows \ s -- a
;

View File

@@ -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
;

View File

@@ -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