Skip to content

Commit

Permalink
[exercism#726] New practice exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
jiegillet committed Jun 12, 2021
1 parent c25ca49 commit 3ddbb32
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 0 deletions.
15 changes: 15 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2380,6 +2380,21 @@
],
"difficulty": 9
},
{
"slug": "satellite",
"name": "Satellite",
"uuid": "a07e01e6-7cea-4db9-a514-7c95788e90a9",
"prerequisites": [
"pattern-matching",
"tuple",
"cond",
"recursion"
],
"practices": [
"recusrion"
],
"difficulty": 6
},
{
"slug": "zebra-puzzle",
"name": "Zebra Puzzle",
Expand Down
29 changes: 29 additions & 0 deletions exercises/practice/satellite/.docs/instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Description

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]

```
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
4 changes: 4 additions & 0 deletions exercises/practice/satellite/.formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
18 changes: 18 additions & 0 deletions exercises/practice/satellite/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"blurb": "Rebuild binary trees from pre-order and in-order traversals.",
"authors": [
"jiegillet"
],
"contributors": [],
"files": {
"solution": [
"lib/satellite.ex"
],
"test": [
"test/satellite_test.exs"
],
"example": [
".meta/example.ex"
]
}
}
41 changes: 41 additions & 0 deletions exercises/practice/satellite/.meta/example.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
defmodule Satellite do
@typedoc """
A tree, which can be empty, or made from a left branch, a node and a right branch
"""
@type tree :: {} | {tree, any, tree}

@doc """
Build a tree from the elements given in a pre-order and in-order style
"""
@spec build_tree(preorder :: [any], inorder :: [any]) :: tree | {:error, String.t()}

def build_tree(preorder, inorder) do
p_length = length(preorder)
i_length = length(inorder)
p_set = MapSet.new(preorder)
i_set = MapSet.new(inorder)

cond do
p_length != i_length -> {:error, "traversals must have the same length"}
p_set != i_set -> {:error, "traversals must have the same elements"}
p_length != MapSet.size(p_set) -> {:error, "traversals must contain unique items"}
true -> build_tree(preorder, inorder, :safe)
end
end

def build_tree([], [], :safe), do: {}

def build_tree([root | preorder], inorder, :safe) do
{in_left, in_right, pre_left, pre_right} = split(root, inorder, preorder)

{build_tree(pre_left, in_left, :safe), root, build_tree(pre_right, in_right, :safe)}
end

defp split(root, [root | inorder], preorder), do: {[], inorder, [], preorder}

defp split(root, [i | inorder], [p | preorder]) do
{in_left, in_right, pre_left, pre_right} = split(root, inorder, preorder)

{[i | in_left], in_right, [p | pre_left], pre_right}
end
end
22 changes: 22 additions & 0 deletions exercises/practice/satellite/.meta/tests.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# This is an auto-generated file. Regular comments will be removed when this
# file is regenerated. Regenerating will not touch any manually added keys,
# so comments can be added in 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"

14 changes: 14 additions & 0 deletions exercises/practice/satellite/lib/satellite.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
defmodule Satellite do
@typedoc """
A tree, which can be empty, or made from a left branch, a node and a right branch
"""
@type tree :: {} | {tree, any, tree}

@doc """
Build a tree from the elements given in a pre-order and in-order style
"""
@spec build_tree(preorder :: [any], inorder :: [any]) :: tree | {:error, String.t()}

def build_tree(preorder, inorder) do
end
end
28 changes: 28 additions & 0 deletions exercises/practice/satellite/mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Satellite.MixProject do
use Mix.Project

def project do
[
app: :satellite,
version: "0.1.0",
# elixir: "~> 1.8",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

# Run "mix help deps" to learn about dependencies.
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
]
end
end
52 changes: 52 additions & 0 deletions exercises/practice/satellite/test/satellite_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
defmodule SatelliteTest do
use ExUnit.Case

# @tag :pending
test "Empty tree" do
preorder = []
inorder = []
tree = {}
assert Satellite.build_tree(preorder, inorder) == tree
end

@tag :pending
test "Tree with one item" do
preorder = [:a]
inorder = [:a]
tree = {{}, :a, {}}
assert Satellite.build_tree(preorder, inorder) == tree
end

@tag :pending
test "Tree with many items" do
preorder = ~w(a i x f r)a
inorder = ~w(i a f x r)a
tree = {{{}, :i, {}}, :a, {{{}, :f, {}}, :x, {{}, :r, {}}}}

assert Satellite.build_tree(preorder, inorder) == tree
end

@tag :pending
test "Reject traversals of different length" do
preorder = [:a, :b]
inorder = [:b, :a, :r]
error = {:error, "traversals must have the same length"}
assert Satellite.build_tree(preorder, inorder) == error
end

@tag :pending
test "Reject inconsistent traversals of same length" do
preorder = [:x, :y, :z]
inorder = [:a, :b, :c]
error = {:error, "traversals must have the same elements"}
assert Satellite.build_tree(preorder, inorder) == error
end

@tag :pending
test "Reject traversals with repeated items" do
preorder = [:a, :b, :a]
inorder = [:b, :a, :a]
error = {:error, "traversals must contain unique items"}
assert Satellite.build_tree(preorder, inorder) == error
end
end
2 changes: 2 additions & 0 deletions exercises/practice/satellite/test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ExUnit.start()
ExUnit.configure(exclude: :pending, trace: true)

0 comments on commit 3ddbb32

Please sign in to comment.