From c6c05c3c86ee2ccc1b6a56d9a03bf80c60a5b984 Mon Sep 17 00:00:00 2001 From: Tomas Fischer Date: Tue, 20 Feb 2024 10:11:57 +0100 Subject: [PATCH] Added Satellite exercise (#1210) * Added Satellite exercise * Incorporate review comment. * Change rote tree to binary tree. * Remove superfluous dependency. --- config.json | 11 ++++ .../practice/satellite/.docs/instructions.md | 27 +++++++++ .../practice/satellite/.meta/config.json | 24 ++++++++ .../examples/success-standard/package.yaml | 20 +++++++ .../success-standard/src/BinaryTree.hs | 4 ++ .../success-standard/src/Satellite.hs | 26 +++++++++ exercises/practice/satellite/.meta/tests.toml | 28 +++++++++ exercises/practice/satellite/package.yaml | 23 ++++++++ .../practice/satellite/src/BinaryTree.hs | 4 ++ exercises/practice/satellite/src/Satellite.hs | 6 ++ exercises/practice/satellite/stack.yaml | 1 + exercises/practice/satellite/test/Tests.hs | 57 +++++++++++++++++++ 12 files changed, 231 insertions(+) create mode 100644 exercises/practice/satellite/.docs/instructions.md create mode 100644 exercises/practice/satellite/.meta/config.json create mode 100644 exercises/practice/satellite/.meta/examples/success-standard/package.yaml create mode 100644 exercises/practice/satellite/.meta/examples/success-standard/src/BinaryTree.hs create mode 100644 exercises/practice/satellite/.meta/examples/success-standard/src/Satellite.hs create mode 100644 exercises/practice/satellite/.meta/tests.toml create mode 100644 exercises/practice/satellite/package.yaml create mode 100644 exercises/practice/satellite/src/BinaryTree.hs create mode 100644 exercises/practice/satellite/src/Satellite.hs create mode 100644 exercises/practice/satellite/stack.yaml create mode 100644 exercises/practice/satellite/test/Tests.hs diff --git a/config.json b/config.json index 37d6cecc4..5ed3fc838 100644 --- a/config.json +++ b/config.json @@ -500,6 +500,17 @@ "algorithms" ] }, + { + "slug": "satellite", + "name": "Satellite", + "uuid": "22136812-8160-49f0-8a0d-f76a2086a34c", + "practices": [], + "prerequisites": [], + "difficulty": 6, + "topics": [ + "maybe" + ] + }, { "slug": "go-counting", "name": "Go Counting", diff --git a/exercises/practice/satellite/.docs/instructions.md b/exercises/practice/satellite/.docs/instructions.md new file mode 100644 index 000000000..fbbf14f43 --- /dev/null +++ b/exercises/practice/satellite/.docs/instructions.md @@ -0,0 +1,27 @@ +# Instructions + +Imagine you need to transmit a binary tree to a satellite approaching Alpha Centauri and you have limited bandwidth. +Since the tree has no repeating items it can be uniquely represented by its [pre-order and in-order traversals][wiki]. + +Write the software for the satellite to rebuild the tree from the traversals. + +A pre-order traversal reads the value of the current node before (hence "pre") reading the left subtree in pre-order. +Afterwards the right subtree is read in pre-order. + +An in-order traversal reads the left subtree in-order then the current node and finally the right subtree in-order. +So in order from left to right. + +For example the pre-order traversal of this tree is [a, i, x, f, r]. +The in-order traversal of this tree is [i, a, f, x, r] + +```text + a + / \ +i x + / \ + f r +``` + +Note: the first item in the pre-order traversal is always the root. + +[wiki]: https://en.wikipedia.org/wiki/Tree_traversal diff --git a/exercises/practice/satellite/.meta/config.json b/exercises/practice/satellite/.meta/config.json new file mode 100644 index 000000000..a90de56b3 --- /dev/null +++ b/exercises/practice/satellite/.meta/config.json @@ -0,0 +1,24 @@ +{ + "authors": [ + "tofische" + ], + "files": { + "solution": [ + "src/Satellite.hs", + "package.yaml" + ], + "test": [ + "test/Tests.hs" + ], + "example": [ + ".meta/examples/success-standard/src/Satellite.hs" + ], + "editor": [ + "src/BinaryTree.hs" + ], + "invalidator": [ + "stack.yaml" + ] + }, + "blurb": "Rebuild binary trees from pre-order and in-order traversals." +} diff --git a/exercises/practice/satellite/.meta/examples/success-standard/package.yaml b/exercises/practice/satellite/.meta/examples/success-standard/package.yaml new file mode 100644 index 000000000..11e51cf64 --- /dev/null +++ b/exercises/practice/satellite/.meta/examples/success-standard/package.yaml @@ -0,0 +1,20 @@ +name: satellite + +dependencies: + - base + - containers + +library: + exposed-modules: + - Satellite + - BinaryTree + source-dirs: src + # dependencies: + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - satellite + - hspec diff --git a/exercises/practice/satellite/.meta/examples/success-standard/src/BinaryTree.hs b/exercises/practice/satellite/.meta/examples/success-standard/src/BinaryTree.hs new file mode 100644 index 000000000..aaa1002b7 --- /dev/null +++ b/exercises/practice/satellite/.meta/examples/success-standard/src/BinaryTree.hs @@ -0,0 +1,4 @@ +module BinaryTree (BinaryTree(..)) where + +data BinaryTree a = Leaf | Branch (BinaryTree a) a (BinaryTree a) + deriving (Show, Eq) diff --git a/exercises/practice/satellite/.meta/examples/success-standard/src/Satellite.hs b/exercises/practice/satellite/.meta/examples/success-standard/src/Satellite.hs new file mode 100644 index 000000000..763832553 --- /dev/null +++ b/exercises/practice/satellite/.meta/examples/success-standard/src/Satellite.hs @@ -0,0 +1,26 @@ +module Satellite (treeFromTraversals) where + +import Data.Set (fromList, size) +import BinaryTree (BinaryTree(..)) + +treeFromTraversals :: Ord a => [a] -> [a] -> Maybe (BinaryTree a) +treeFromTraversals preorder inorder = + if (not.null) preorder && length preorder == size (fromList preorder) + then treeFromTraversals' preorder inorder + else Nothing + +treeFromTraversals' :: Ord a => [a] -> [a] -> Maybe (BinaryTree a) +treeFromTraversals' preorder inorder = Branch <$> leftChild <*> pure root <*> rightChild + where + root = head preorder + (inLeft, rest) = span (/= root) inorder + inRight = tail rest + (preLeft, preRight) = splitAt (length inLeft) $ tail preorder + leftChild + | null preLeft && null inLeft = Just Leaf + | null preLeft || null inLeft = Nothing + | otherwise = treeFromTraversals' preLeft inLeft + rightChild + | null preRight && null inRight = Just Leaf + | null preRight || null inRight = Nothing + | otherwise = treeFromTraversals' preRight inRight diff --git a/exercises/practice/satellite/.meta/tests.toml b/exercises/practice/satellite/.meta/tests.toml new file mode 100644 index 000000000..b32dc3b13 --- /dev/null +++ b/exercises/practice/satellite/.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. + +[8df3fa26-811a-4165-9286-ff9ac0850d19] +description = "Empty tree" + +[f945ccfc-05e3-47d7-825b-0270559d43ad] +description = "Tree with one item" + +[a0121d5f-37b0-48dd-9c64-cba4c4464135] +description = "Tree with many items" + +[6074041f-4891-4d81-a128-401050c2a3b0] +description = "Reject traversals of different length" + +[27916ce4-45f3-4d8b-8528-496fedc157ca] +description = "Reject inconsistent traversals of same length" + +[d86a3d72-76a9-43b5-9d3a-e64cb1216035] +description = "Reject traversals with repeated items" diff --git a/exercises/practice/satellite/package.yaml b/exercises/practice/satellite/package.yaml new file mode 100644 index 000000000..5ed670669 --- /dev/null +++ b/exercises/practice/satellite/package.yaml @@ -0,0 +1,23 @@ +name: satellite +version: 1.0.0.0 + +dependencies: + - base + +library: + exposed-modules: + - Satellite + - BinaryTree + source-dirs: src + ghc-options: -Wall + # dependencies: + # - foo # List here the packages you + # - bar # want to use in your solution. + +tests: + test: + main: Tests.hs + source-dirs: test + dependencies: + - satellite + - hspec diff --git a/exercises/practice/satellite/src/BinaryTree.hs b/exercises/practice/satellite/src/BinaryTree.hs new file mode 100644 index 000000000..aaa1002b7 --- /dev/null +++ b/exercises/practice/satellite/src/BinaryTree.hs @@ -0,0 +1,4 @@ +module BinaryTree (BinaryTree(..)) where + +data BinaryTree a = Leaf | Branch (BinaryTree a) a (BinaryTree a) + deriving (Show, Eq) diff --git a/exercises/practice/satellite/src/Satellite.hs b/exercises/practice/satellite/src/Satellite.hs new file mode 100644 index 000000000..81211efc0 --- /dev/null +++ b/exercises/practice/satellite/src/Satellite.hs @@ -0,0 +1,6 @@ +module Satellite (treeFromTraversals) where + +import BinaryTree (BinaryTree(..)) + +treeFromTraversals :: Ord a => [a] -> [a] -> Maybe (BinaryTree a) +treeFromTraversals preorder inorder = error "You need to implement this function." diff --git a/exercises/practice/satellite/stack.yaml b/exercises/practice/satellite/stack.yaml new file mode 100644 index 000000000..115878212 --- /dev/null +++ b/exercises/practice/satellite/stack.yaml @@ -0,0 +1 @@ +resolver: lts-20.18 diff --git a/exercises/practice/satellite/test/Tests.hs b/exercises/practice/satellite/test/Tests.hs new file mode 100644 index 000000000..99e9683d9 --- /dev/null +++ b/exercises/practice/satellite/test/Tests.hs @@ -0,0 +1,57 @@ +{-# LANGUAGE RecordWildCards #-} + +import Data.Foldable (for_) +import Test.Hspec (Spec, describe, it, shouldBe) +import Test.Hspec.Runner (configFailFast, defaultConfig, hspecWith) + +import Satellite (treeFromTraversals) +import BinaryTree (BinaryTree(..)) + +main :: IO () +main = hspecWith defaultConfig {configFailFast = True} specs + +specs :: Spec +specs = do + describe "treeFromTraversals" $ for_ cases $ test treeFromTraversals + where + test f Case{..} = it description $ f preorder inorder `shouldBe` expected + +data Case = Case { description :: String + , preorder :: String + , inorder :: String + , expected :: Maybe (BinaryTree Char) + } + +cases :: [Case] +cases = + [ Case { description = "Empty tree" + , preorder = "" + , inorder = "" + , expected = Nothing + } + , Case { description = "Tree with one item" + , preorder = "a" + , inorder = "a" + , expected = Just (Branch Leaf 'a' Leaf) + } + , Case { description = "Tree with many items" + , preorder = "aixfr" + , inorder = "iafxr" + , expected = Just (Branch (Branch Leaf 'i' Leaf) 'a' (Branch (Branch Leaf 'f' Leaf) 'x' (Branch Leaf 'r' Leaf))) + } + , Case { description = "Reject traversals of different length" + , preorder = "ab" + , inorder = "bar" + , expected = Nothing + } + , Case { description = "Reject inconsistent traversals of same length" + , preorder = "xyz" + , inorder = "abc" + , expected = Nothing + } + , Case { description = "Reject traversals with repeated items" + , preorder = "aba" + , inorder = "baa" + , expected = Nothing + } + ]