diff --git a/config.json b/config.json index 557be4b..b5cbc7f 100644 --- a/config.json +++ b/config.json @@ -453,6 +453,14 @@ "prerequisites": [], "difficulty": 6 }, + { + "slug": "food-chain", + "name": "Food Chain", + "uuid": "830897ff-ef28-4553-97b4-5c43396c3cdc", + "practices": [], + "prerequisites": [], + "difficulty": 4 + }, { "slug": "binary-search", "name": "Binary Search", diff --git a/exercises/practice/food-chain/.docs/instructions.md b/exercises/practice/food-chain/.docs/instructions.md new file mode 100644 index 0000000..125820e --- /dev/null +++ b/exercises/practice/food-chain/.docs/instructions.md @@ -0,0 +1,64 @@ +# Instructions + +Generate the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'. + +While you could copy/paste the lyrics, or read them from a file, this problem is much more interesting if you approach it algorithmically. + +This is a [cumulative song][cumulative-song] of unknown origin. + +This is one of many common variants. + +```text +I know an old lady who swallowed a fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a spider. +It wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a bird. +How absurd to swallow a bird! +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cat. +Imagine that, to swallow a cat! +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a dog. +What a hog, to swallow a dog! +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a goat. +Just opened her throat and swallowed a goat! +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a cow. +I don't know how she swallowed a cow! +She swallowed the cow to catch the goat. +She swallowed the goat to catch the dog. +She swallowed the dog to catch the cat. +She swallowed the cat to catch the bird. +She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her. +She swallowed the spider to catch the fly. +I don't know why she swallowed the fly. Perhaps she'll die. + +I know an old lady who swallowed a horse. +She's dead, of course! +``` + +[cumulative-song]: https://en.wikipedia.org/wiki/Cumulative_song diff --git a/exercises/practice/food-chain/.meta/config.json b/exercises/practice/food-chain/.meta/config.json new file mode 100644 index 0000000..7861d21 --- /dev/null +++ b/exercises/practice/food-chain/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "erikschierboom" + ], + "files": { + "solution": [ + "food-chain.8th" + ], + "test": [ + "test.8th" + ], + "example": [ + ".meta/example.8th" + ] + }, + "blurb": "Generate the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'.", + "source": "Wikipedia", + "source_url": "https://en.wikipedia.org/wiki/There_Was_an_Old_Lady_Who_Swallowed_a_Fly" +} diff --git a/exercises/practice/food-chain/.meta/example.8th b/exercises/practice/food-chain/.meta/example.8th new file mode 100644 index 0000000..195a45b --- /dev/null +++ b/exercises/practice/food-chain/.meta/example.8th @@ -0,0 +1,55 @@ +["fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse"] constant animals + +{ + "fly": "I don't know why she swallowed the fly. Perhaps she'll die.", + "spider": "It wriggled and jiggled and tickled inside her.", + "bird": "How absurd to swallow a bird!", + "cat": "Imagine that, to swallow a cat!", + "dog": "What a hog, to swallow a dog!", + "goat": "Just opened her throat and swallowed a goat!", + "cow": "I don't know how she swallowed a cow!", + "horse": "She's dead, of course!" +} constant animal-remarks + +: animal \ n -- s + n:1- animals swap a:_@ +; + +: remark \ s -- s + animal-remarks swap m:_@ +; + +: verse-start \ n -- a + dup a:new swap + animal "I know an old lady who swallowed a %s." s:strfmt a:push + swap dup 1 n:= if drop ;then + animal remark a:push +; + +: verse-catch \ s s -- s + over "spider" s:= if swap " that wriggled and jiggled and tickled inside her" s:+ swap then + "She swallowed the %s to catch the %s." s:strfmt +; + +: verse-middle \ n -- a + n:1- >r animals ( a:open verse-catch ) 2 1 a:map+ 0 r> a:slice a:rev +; + +: verse-end \ -- s + "fly" remark +; + +: verse \ n -- a + dup a:new + swap verse-start a:+ + swap verse-middle a:+ + verse-end a:push +; + +: join-verses \ a -- a + ( swap a:len 0 n:= !if "" a:push then swap a:+ ) [] a:reduce +; + +: recite \ n n -- a + ' verse -rot a:generate join-verses +; diff --git a/exercises/practice/food-chain/.meta/tests.toml b/exercises/practice/food-chain/.meta/tests.toml new file mode 100644 index 0000000..30c5b98 --- /dev/null +++ b/exercises/practice/food-chain/.meta/tests.toml @@ -0,0 +1,40 @@ +# 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. + +[751dce68-9412-496e-b6e8-855998c56166] +description = "fly" + +[6c56f861-0c5e-4907-9a9d-b2efae389379] +description = "spider" + +[3edf5f33-bef1-4e39-ae67-ca5eb79203fa] +description = "bird" + +[e866a758-e1ff-400e-9f35-f27f28cc288f] +description = "cat" + +[3f02c30e-496b-4b2a-8491-bc7e2953cafb] +description = "dog" + +[4b3fd221-01ea-46e0-825b-5734634fbc59] +description = "goat" + +[1b707da9-7001-4fac-941f-22ad9c7a65d4] +description = "cow" + +[3cb10d46-ae4e-4d2c-9296-83c9ffc04cdc] +description = "horse" + +[22b863d5-17e4-4d1e-93e4-617329a5c050] +description = "multiple verses" + +[e626b32b-745c-4101-bcbd-3b13456893db] +description = "full song" diff --git a/exercises/practice/food-chain/food-chain.8th b/exercises/practice/food-chain/food-chain.8th new file mode 100644 index 0000000..344f1ea --- /dev/null +++ b/exercises/practice/food-chain/food-chain.8th @@ -0,0 +1,3 @@ +: recite \ n n -- a + +; diff --git a/exercises/practice/food-chain/libs/exercism/test b/exercises/practice/food-chain/libs/exercism/test new file mode 100644 index 0000000..1d08eb2 --- /dev/null +++ b/exercises/practice/food-chain/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/food-chain/test.8th b/exercises/practice/food-chain/test.8th new file mode 100644 index 0000000..52958d3 --- /dev/null +++ b/exercises/practice/food-chain/test.8th @@ -0,0 +1,175 @@ +"food-chain.8th" f:include +needs exercism/test +with: test +10 tests + +"fly" + ( 1 1 recite ) + [ + "I know an old lady who swallowed a fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +SKIP-REST-OF-TESTS + +"spider" + ( 2 2 recite ) + [ + "I know an old lady who swallowed a spider.", + "It wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"bird" + ( 3 3 recite ) + [ + "I know an old lady who swallowed a bird.", + "How absurd to swallow a bird!", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"cat" + ( 4 4 recite ) + [ + "I know an old lady who swallowed a cat.", + "Imagine that, to swallow a cat!", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"dog" + ( 5 5 recite ) + [ + "I know an old lady who swallowed a dog.", + "What a hog, to swallow a dog!", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"goat" + ( 6 6 recite ) + [ + "I know an old lady who swallowed a goat.", + "Just opened her throat and swallowed a goat!", + "She swallowed the goat to catch the dog.", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"cow" + ( 7 7 recite ) + [ + "I know an old lady who swallowed a cow.", + "I don't know how she swallowed a cow!", + "She swallowed the cow to catch the goat.", + "She swallowed the goat to catch the dog.", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"horse" + ( 8 8 recite ) + [ + "I know an old lady who swallowed a horse.", + "She's dead, of course!" + ] + equal? + +"multiple verses" + ( 1 3 recite ) + [ + "I know an old lady who swallowed a fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a spider.", + "It wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a bird.", + "How absurd to swallow a bird!", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die." + ] + equal? + +"full song" + ( 1 8 recite ) + [ + "I know an old lady who swallowed a fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a spider.", + "It wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a bird.", + "How absurd to swallow a bird!", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a cat.", + "Imagine that, to swallow a cat!", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a dog.", + "What a hog, to swallow a dog!", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a goat.", + "Just opened her throat and swallowed a goat!", + "She swallowed the goat to catch the dog.", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a cow.", + "I don't know how she swallowed a cow!", + "She swallowed the cow to catch the goat.", + "She swallowed the goat to catch the dog.", + "She swallowed the dog to catch the cat.", + "She swallowed the cat to catch the bird.", + "She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.", + "She swallowed the spider to catch the fly.", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "", + "I know an old lady who swallowed a horse.", + "She's dead, of course!" + ] + equal? + +end-of-tests +;with