From 97fa7eeededb8cd8e6cc4a5fb41b88ee04305ea7 Mon Sep 17 00:00:00 2001 From: keiravillekode Date: Fri, 31 Jan 2025 05:58:35 +1100 Subject: [PATCH] Add food-chain exercise (#438) --- config.json | 8 + .../practice/food-chain/.docs/instructions.md | 64 ++++++ .../practice/food-chain/.meta/config.json | 19 ++ .../practice/food-chain/.meta/example.zig | 76 +++++++ .../practice/food-chain/.meta/tests.toml | 40 ++++ exercises/practice/food-chain/food_chain.zig | 6 + .../practice/food-chain/test_food_chain.zig | 200 ++++++++++++++++++ 7 files changed, 413 insertions(+) create mode 100644 exercises/practice/food-chain/.docs/instructions.md create mode 100644 exercises/practice/food-chain/.meta/config.json create mode 100644 exercises/practice/food-chain/.meta/example.zig create mode 100644 exercises/practice/food-chain/.meta/tests.toml create mode 100644 exercises/practice/food-chain/food_chain.zig create mode 100644 exercises/practice/food-chain/test_food_chain.zig diff --git a/config.json b/config.json index e90ba28a..14bcb4b5 100644 --- a/config.json +++ b/config.json @@ -90,6 +90,14 @@ "prerequisites": [], "difficulty": 2 }, + { + "slug": "food-chain", + "name": "Food Chain", + "uuid": "fe7bad93-d829-4308-9eed-68ad6e5d522f", + "practices": [], + "prerequisites": [], + "difficulty": 5 + }, { "slug": "collatz-conjecture", "name": "Collatz Conjecture", diff --git a/exercises/practice/food-chain/.docs/instructions.md b/exercises/practice/food-chain/.docs/instructions.md new file mode 100644 index 00000000..125820e3 --- /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 00000000..4c9ea1cb --- /dev/null +++ b/exercises/practice/food-chain/.meta/config.json @@ -0,0 +1,19 @@ +{ + "authors": [ + "keiravillekode" + ], + "files": { + "solution": [ + "food_chain.zig" + ], + "test": [ + "test_food_chain.zig" + ], + "example": [ + ".meta/example.zig" + ] + }, + "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.zig b/exercises/practice/food-chain/.meta/example.zig new file mode 100644 index 00000000..818ece33 --- /dev/null +++ b/exercises/practice/food-chain/.meta/example.zig @@ -0,0 +1,76 @@ +const std = @import("std"); + +const i_know = "I know an old lady who swallowed a "; + +const stop = ".\n"; + +const she_swallowed = "She swallowed the "; + +const to_catch = " to catch the "; + +const that_wriggled = " that wriggled and jiggled and tickled inside her"; + +const animals = [_][]const u8{ "", "fly", "spider", "bird", "cat", "dog", "goat", "cow", "horse" }; + +const exclamations = [_][]const u8{ + "", + "I don't know why she swallowed the fly. Perhaps she'll die.", + "It wriggled and jiggled and tickled inside her.\n", + "How absurd to swallow a bird!\n", + "Imagine that, to swallow a cat!\n", + "What a hog, to swallow a dog!\n", + "Just opened her throat and swallowed a goat!\n", + "I don't know how she swallowed a cow!\n", + "She's dead, of course!" +}; + +fn appendString(buffer: []u8, offset: *usize, str: []const u8) void { + @memcpy(buffer[offset.*..(offset.* + str.len)], str); + offset.* += str.len; +} + +pub fn recite(buffer: []u8, start_verse: u32, end_verse: u32) []const u8 { + var offset: usize = 0; + + for (start_verse..end_verse+1) |verse| { + if (verse != start_verse) { + buffer[offset] = '\n'; + buffer[offset + 1] = '\n'; + offset += 2; + } + + appendString(buffer, &offset, i_know); + + appendString(buffer, &offset, animals[verse]); + + appendString(buffer, &offset, stop); + + appendString(buffer, &offset, exclamations[verse]); + + if (verse == 1 or verse == 8) { + continue; + } + + var animal = verse; + while (animal > 1) { + appendString(buffer, &offset, she_swallowed); + + appendString(buffer, &offset, animals[animal]); + + appendString(buffer, &offset, to_catch); + + animal -= 1; + appendString(buffer, &offset, animals[animal]); + + if (animal == 2) { + appendString(buffer, &offset, that_wriggled); + } + + appendString(buffer, &offset, stop); + } + + appendString(buffer, &offset, exclamations[1]); + } + + return buffer[0..offset]; +} diff --git a/exercises/practice/food-chain/.meta/tests.toml b/exercises/practice/food-chain/.meta/tests.toml new file mode 100644 index 00000000..30c5b980 --- /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.zig b/exercises/practice/food-chain/food_chain.zig new file mode 100644 index 00000000..f5000953 --- /dev/null +++ b/exercises/practice/food-chain/food_chain.zig @@ -0,0 +1,6 @@ +pub fn recite(buffer: []u8, start_verse: u32, end_verse: u32) []const u8 { + _ = buffer; + _ = start_verse; + _ = end_verse; + @compileError("please implement the recite function"); +} diff --git a/exercises/practice/food-chain/test_food_chain.zig b/exercises/practice/food-chain/test_food_chain.zig new file mode 100644 index 00000000..46507bdd --- /dev/null +++ b/exercises/practice/food-chain/test_food_chain.zig @@ -0,0 +1,200 @@ +const std = @import("std"); +const testing = std.testing; + +const food_chain = @import("food_chain.zig"); + +test "fly" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\I know an old lady who swallowed a fly. + \\I don't know why she swallowed the fly. Perhaps she'll die. + ; + const actual = food_chain.recite(&buffer, 1, 1); + try testing.expectEqualStrings(expected, actual); +} + +test "spider" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 2, 2); + try testing.expectEqualStrings(expected, actual); +} + +test "bird" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 3, 3); + try testing.expectEqualStrings(expected, actual); +} + +test "cat" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 4, 4); + try testing.expectEqualStrings(expected, actual); +} + +test "dog" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 5, 5); + try testing.expectEqualStrings(expected, actual); +} + +test "goat" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 6, 6); + try testing.expectEqualStrings(expected, actual); +} + +test "cow" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 7, 7); + try testing.expectEqualStrings(expected, actual); +} + +test "horse" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\I know an old lady who swallowed a horse. + \\She's dead, of course! + ; + const actual = food_chain.recite(&buffer, 8, 8); + try testing.expectEqualStrings(expected, actual); +} + +test "multiple verses" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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. + ; + const actual = food_chain.recite(&buffer, 1, 3); + try testing.expectEqualStrings(expected, actual); +} + +test "full song" { + const buffer_size = 4000; + var buffer: [buffer_size]u8 = undefined; + const expected: []const u8 = + \\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! + ; + const actual = food_chain.recite(&buffer, 1, 8); + try testing.expectEqualStrings(expected, actual); +}