Skip to content

Commit

Permalink
Add satellite exercise
Browse files Browse the repository at this point in the history
  • Loading branch information
ErikSchierboom committed Oct 22, 2024
1 parent 6e9b1f6 commit ac71b43
Show file tree
Hide file tree
Showing 12 changed files with 244 additions and 7 deletions.
14 changes: 14 additions & 0 deletions config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2233,6 +2233,20 @@
"result"
],
"difficulty": 5
},
{
"slug": "satellite",
"name": "Satellite",
"uuid": "bcfeb5b7-08d3-4039-95b2-ebda6b7288aa",
"practices": [
"recursion"
],
"prerequisites": [
"recursion",
"discriminated-unions",
"numbers"
],
"difficulty": 7
}
],
"foregone": [
Expand Down
7 changes: 7 additions & 0 deletions exercises/Exercises.sln
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "KillerSudokuHelper", "pract
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "StateOfTicTacToe", "practice\state-of-tic-tac-toe\StateOfTicTacToe.fsproj", "{A12FEF19-5EE8-430E-BD66-2D93ADFC1944}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Satellite", "practice\satellite\Satellite.fsproj", "{FF432193-3D08-4BD4-ADCD-1512BF67A425}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -910,6 +912,10 @@ Global
{A12FEF19-5EE8-430E-BD66-2D93ADFC1944}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A12FEF19-5EE8-430E-BD66-2D93ADFC1944}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A12FEF19-5EE8-430E-BD66-2D93ADFC1944}.Release|Any CPU.Build.0 = Release|Any CPU
{FF432193-3D08-4BD4-ADCD-1512BF67A425}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FF432193-3D08-4BD4-ADCD-1512BF67A425}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FF432193-3D08-4BD4-ADCD-1512BF67A425}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FF432193-3D08-4BD4-ADCD-1512BF67A425}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{B404AA3C-A226-409A-A035-6C1DC66940DD} = {B7E719DB-FB8D-43B4-B529-55FCF6E3DC3F}
Expand Down Expand Up @@ -1063,5 +1069,6 @@ Global
{1850FAE9-5ACB-41D0-91BB-AD17A1021248} = {391BEEC4-91A8-43F3-AE94-D5CB9A8FA611}
{FCE9E627-CFF9-4EF3-84BE-D42B354825AA} = {391BEEC4-91A8-43F3-AE94-D5CB9A8FA611}
{A12FEF19-5EE8-430E-BD66-2D93ADFC1944} = {391BEEC4-91A8-43F3-AE94-D5CB9A8FA611}
{FF432193-3D08-4BD4-ADCD-1512BF67A425} = {391BEEC4-91A8-43F3-AE94-D5CB9A8FA611}
EndGlobalSection
EndGlobal
12 changes: 12 additions & 0 deletions exercises/practice/satellite/.config/dotnet-tools.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fantomas-tool": {
"version": "4.7.9",
"commands": [
"fantomas"
]
}
}
}
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/Example.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module Satellite

type Tree =
| Empty
| Node of value: string * left: Tree * right: Tree

let rec createTree inorder preorder =
match preorder with
| [] -> Empty
| hd :: tail ->
let hdIdx = inorder |> List.findIndex (fun x -> x = hd)
let leftInorder, rightInorder = inorder[0 .. hdIdx - 1], inorder[hdIdx + 1 ..]
let leftPreorder, rightPreorder = tail[0 .. leftInorder.Length - 1], tail[leftInorder.Length ..]
Node(hd, createTree leftInorder leftPreorder, createTree rightInorder rightPreorder)

let treeFromTraversals preorder inorder =
if List.length preorder <> List.length inorder then
Error "traversals must have the same length"
elif List.sort preorder <> List.sort inorder then
Error "traversals must have the same elements"
elif List.distinct preorder <> preorder then
Error "traversals must contain unique items"
else
Ok(createTree preorder inorder)
17 changes: 17 additions & 0 deletions exercises/practice/satellite/.meta/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"authors": [
"erikschierboom"
],
"files": {
"solution": [
"Satellite.fs"
],
"test": [
"SatelliteTests.fs"
],
"example": [
".meta/Example.fs"
]
},
"blurb": "Rebuild binary trees from pre-order and in-order traversals."
}
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"
8 changes: 8 additions & 0 deletions exercises/practice/satellite/Satellite.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Satellite

type Tree =
| Empty
| Node of value: string * left: Tree * right: Tree

let treeFromTraversals preorder inorder =
failwith "Please implement the 'treeFromTraversals' function"
22 changes: 22 additions & 0 deletions exercises/practice/satellite/Satellite.fsproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<IsPackable>false</IsPackable>
<GenerateProgramFile>false</GenerateProgramFile>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<Compile Include="Satellite.fs" />
<Compile Include="SatelliteTests.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Exercism.Tests" Version="0.1.0-beta1" />
<PackageReference Include="FsUnit.xUnit" Version="4.0.4" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>
51 changes: 51 additions & 0 deletions exercises/practice/satellite/SatelliteTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module SatelliteTests

open FsUnit.Xunit
open Xunit

open Satellite

[<Fact>]
let ``Empty tree`` () =
let expected: Result<Tree,string> = Ok (
Empty
)
treeFromTraversals [] [] |> should equal expected

[<Fact>]
let ``Tree with one item`` () =
let expected: Result<Tree,string> = Ok (
Node("a", Empty, Empty)
)
treeFromTraversals ["a"] ["a"] |> should equal expected

[<Fact>]
let ``Tree with many items`` () =
let expected: Result<Tree,string> = Ok (
Node(
"a",
Node("i", Empty, Empty),
Node(
"x",
Node("f", Empty, Empty),
Node("r", Empty, Empty)
)
)
)
treeFromTraversals ["i"; "a"; "f"; "x"; "r"] ["a"; "i"; "x"; "f"; "r"] |> should equal expected

[<Fact>]
let ``Reject traversals of different length`` () =
let expected: Result<Tree,string> = Error "traversals must have the same length"
treeFromTraversals ["b"; "a"; "r"] ["a"; "b"] |> should equal expected

[<Fact>]
let ``Reject inconsistent traversals of same length`` () =
let expected: Result<Tree,string> = Error "traversals must have the same elements"
treeFromTraversals ["a"; "b"; "c"] ["x"; "y"; "z"] |> should equal expected

[<Fact>]
let ``Reject traversals with repeated items`` () =
let expected: Result<Tree,string> = Error "traversals must contain unique items"
treeFromTraversals ["b"; "a"; "a"] ["a"; "b"; "a"] |> should equal expected

34 changes: 34 additions & 0 deletions generators/Generators.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2056,3 +2056,37 @@ type KillerSudokuHelper() =

type StateOfTicTacToe() =
inherit ExerciseGenerator()

type Satellite() =
inherit ExerciseGenerator()

let renderTree (root: JToken) =
let rec render indent (node: JToken) =
let indentation = String(' ', indent * 4)

if node.HasValues then
let value = node["v"]
let left = node["l"] |> render (indent + 1)
let right = node["r"] |> render (indent + 1)

if node["l"].HasValues || node["r"].HasValues then
$"{indentation}Node(\n" +
$"{indentation} \"{value}\",\n" +
$"{left},\n" +
$"{right}\n" +
$"{indentation})"
else
$"{indentation}Node(\"{value}\", Empty, Empty)"
else
$"{indentation}Empty"

render 2 root

override _.PropertiesWithIdentifier _ = [ "expected" ]

override _.IdentifierTypeAnnotation(_, _, _) = Some "Result<Tree,string>"

override _.RenderExpected(_, _, value) =
match value.SelectToken "error" with
| null -> $"Ok (\n%s{renderTree value}\n )"
| error -> $"Error \"%s{string error}\""
7 changes: 0 additions & 7 deletions generators/Properties/launchSettings.json

This file was deleted.

0 comments on commit ac71b43

Please sign in to comment.