Skip to content

Commit

Permalink
Added Satellite exercise (#1210)
Browse files Browse the repository at this point in the history
* Added Satellite exercise

* Incorporate review comment.

* Change rote tree to binary tree.

* Remove superfluous dependency.
  • Loading branch information
tofische authored Feb 20, 2024
1 parent cee99f1 commit c6c05c3
Show file tree
Hide file tree
Showing 12 changed files with 231 additions and 0 deletions.
11 changes: 11 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
27 changes: 27 additions & 0 deletions exercises/practice/satellite/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -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
24 changes: 24 additions & 0 deletions exercises/practice/satellite/.meta/config.json
Original file line number Diff line number Diff line change
@@ -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."
}
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module BinaryTree (BinaryTree(..)) where

data BinaryTree a = Leaf | Branch (BinaryTree a) a (BinaryTree a)
deriving (Show, Eq)
Original file line number Diff line number Diff line change
@@ -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
28 changes: 28 additions & 0 deletions exercises/practice/satellite/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -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"
23 changes: 23 additions & 0 deletions exercises/practice/satellite/package.yaml
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions exercises/practice/satellite/src/BinaryTree.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module BinaryTree (BinaryTree(..)) where

data BinaryTree a = Leaf | Branch (BinaryTree a) a (BinaryTree a)
deriving (Show, Eq)
6 changes: 6 additions & 0 deletions exercises/practice/satellite/src/Satellite.hs
Original file line number Diff line number Diff line change
@@ -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."
1 change: 1 addition & 0 deletions exercises/practice/satellite/stack.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
resolver: lts-20.18
57 changes: 57 additions & 0 deletions exercises/practice/satellite/test/Tests.hs
Original file line number Diff line number Diff line change
@@ -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
}
]

0 comments on commit c6c05c3

Please sign in to comment.