This repository has been archived by the owner on May 30, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
d307a66
commit cc4dda8
Showing
8 changed files
with
325 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Instructions | ||
|
||
Reparent a tree on a selected node. | ||
|
||
A [tree][wiki-tree] is a special type of [graph][wiki-graph] where all nodes are connected but there are no cycles. | ||
That means, there is exactly one path to get from one node to another for any pair of nodes. | ||
|
||
This exercise is all about re-orientating a tree to see things from a different point of view. | ||
For example family trees are usually presented from the ancestor's perspective: | ||
|
||
```text | ||
+------0------+ | ||
| | | | ||
+-1-+ +-2-+ +-3-+ | ||
| | | | | | | ||
4 5 6 7 8 9 | ||
``` | ||
|
||
But there is no inherent direction in a tree. | ||
The same information can be presented from the perspective of any other node in the tree, by pulling it up to the root and dragging its relationships along with it. | ||
So the same tree from 6's perspective would look like: | ||
|
||
```text | ||
6 | ||
| | ||
+-----2-----+ | ||
| | | ||
7 +-----0-----+ | ||
| | | ||
+-1-+ +-3-+ | ||
| | | | | ||
4 5 8 9 | ||
``` | ||
|
||
This lets us more simply describe the paths between two nodes. | ||
So for example the path from 6-9 (which in the first tree goes up to the root and then down to a different leaf node) can be seen to follow the path 6-2-0-3-9. | ||
|
||
This exercise involves taking an input tree and re-orientating it from the point of view of one of the nodes. | ||
|
||
[wiki-graph]: https://en.wikipedia.org/wiki/Tree_(graph_theory) | ||
[wiki-tree]: https://en.wikipedia.org/wiki/Graph_(discrete_mathematics) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
{ | ||
"authors": [ | ||
"ErikSchierboom" | ||
], | ||
"files": { | ||
"solution": [ | ||
"src/pov.cljs" | ||
], | ||
"test": [ | ||
"test/pov_test.cljs" | ||
], | ||
"example": [ | ||
".meta/src/example.cljs" | ||
] | ||
}, | ||
"blurb": "Reparent a graph on a selected node.", | ||
"source": "Adaptation of exercise from 4clojure", | ||
"source_url": "https://www.4clojure.com/" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
(ns pov | ||
(:require [clojure.zip :as zip])) | ||
|
||
(defn- remove-child | ||
"Remove a child from a node" | ||
[parent child] | ||
(filter #(not= child %) parent)) | ||
|
||
(defn- reparent | ||
"Take a node, and make it the parent of its parent" | ||
[loc] | ||
(let [current (zip/node loc) | ||
parent (zip/up loc) | ||
belonged-to (when parent | ||
(-> parent | ||
(zip/edit remove-child current) | ||
reparent | ||
list))] | ||
(vec (concat current belonged-to)))) | ||
|
||
(defn- find-node | ||
"Find the node whose identifier matches the given value" | ||
[v tree] | ||
(loop [loc (-> tree zip/vector-zip zip/next)] | ||
(cond (= v (zip/node loc)) (zip/up loc) | ||
(zip/end? loc) nil | ||
:else (recur (zip/next loc))))) | ||
|
||
(defn of | ||
"Find a node by its identifier and raise to the root" | ||
[s tree] | ||
(when-let [loc (find-node s tree)] | ||
(reparent loc))) | ||
|
||
(defn path-from-to | ||
"Find a path from src node to dest node" | ||
[src dest graph] | ||
(when-let [loc (find-node dest (of src graph))] | ||
(let [dest-node (zip/node loc) | ||
path (concat (zip/path loc) [dest-node])] | ||
(map first path)))) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# 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. | ||
|
||
[1b3cd134-49ad-4a7d-8376-7087b7e70792] | ||
description = "Results in the same tree if the input tree is a singleton" | ||
|
||
[0778c745-0636-40de-9edd-25a8f40426f6] | ||
description = "Can reroot a tree with a parent and one sibling" | ||
|
||
[fdfdef0a-4472-4248-8bcf-19cf33f9c06e] | ||
description = "Can reroot a tree with a parent and many siblings" | ||
|
||
[cbcf52db-8667-43d8-a766-5d80cb41b4bb] | ||
description = "Can reroot a tree with new root deeply nested in tree" | ||
|
||
[e27fa4fa-648d-44cd-90af-d64a13d95e06] | ||
description = "Moves children of the new root to same level as former parent" | ||
|
||
[09236c7f-7c83-42cc-87a1-25afa60454a3] | ||
description = "Can reroot a complex tree with cousins" | ||
|
||
[f41d5eeb-8973-448f-a3b0-cc1e019a4193] | ||
description = "Errors if target does not exist in a singleton tree" | ||
|
||
[9dc0a8b3-df02-4267-9a41-693b6aff75e7] | ||
description = "Errors if target does not exist in a large tree" | ||
|
||
[02d1f1d9-428d-4395-b026-2db35ffa8f0a] | ||
description = "Can find path to parent" | ||
|
||
[d0002674-fcfb-4cdc-9efa-bfc54e3c31b5] | ||
description = "Can find path to sibling" | ||
|
||
[c9877cd1-0a69-40d4-b362-725763a5c38f] | ||
description = "Can find path to cousin" | ||
|
||
[9fb17a82-2c14-4261-baa3-2f3f234ffa03] | ||
description = "Can find path not involving root" | ||
|
||
[5124ed49-7845-46ad-bc32-97d5ac7451b2] | ||
description = "Can find path from nodes other than x" | ||
|
||
[f52a183c-25cc-4c87-9fc9-0e7f81a5725c] | ||
description = "Errors if destination does not exist" | ||
|
||
[f4fe18b9-b4a2-4bd5-a694-e179155c2149] | ||
description = "Errors if source does not exist" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{:deps | ||
{org.clojure/clojure {:mvn/version "1.10.1"} | ||
org.clojure/clojurescript {:mvn/version "1.10.773"}} | ||
|
||
:aliases | ||
{:test | ||
{:extra-paths ["test"] | ||
:extra-deps | ||
{olical/cljs-test-runner {:mvn/version "3.8.0"}} | ||
:main-opts ["-m" "cljs-test-runner.main"]}}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
(ns pov) | ||
|
||
(defn of [] ;; <- arglist goes here | ||
;; your code goes here | ||
) | ||
|
||
(defn path-from-to [] ;; <- arglist goes here | ||
;; your code goes here | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
(ns pov-test | ||
(:require [clojure.test :refer [deftest is]] | ||
pov)) | ||
|
||
;;; Inputs. | ||
|
||
(def singleton [:x]) | ||
|
||
(def simple-tree [:parent [:sibling] [:x]]) | ||
|
||
(def large-flat | ||
[:parent [:sib-a] | ||
[:sib-b] | ||
[:x] | ||
[:sib-c] | ||
[:sib-d]]) | ||
|
||
(def deeply-nested | ||
[:level-0 | ||
[:level-1 | ||
[:level-2 | ||
[:level-3 | ||
[:level-4 | ||
[:x]]]]]]) | ||
|
||
(def cousins | ||
[:grand-parent | ||
[:parent | ||
[:sib-1] | ||
[:x] | ||
[:sib-2]] | ||
[:uncle | ||
[:cousin-1] | ||
[:cousin-2]]]) | ||
|
||
(def target-with-children | ||
[:grand-parent | ||
[:parent | ||
[:x | ||
[:child-1] | ||
[:child-2]] | ||
[:sibling | ||
[:nephew] | ||
[:niece]]] | ||
[:aunt | ||
[:cousin-1 | ||
[:2nd-cousin-1] | ||
[:2nd-cousin-2]] | ||
[:cousin-2 | ||
[:2nd-cousin-3] | ||
[:2nd-cousin-4]]]]) | ||
|
||
;;; Expected results. | ||
|
||
(def simple-pulled [:x [:parent [:sibling]]]) | ||
|
||
(def flat-pulled | ||
[:x [:parent | ||
[:sib-a] | ||
[:sib-b] | ||
[:sib-c] | ||
[:sib-d]]]) | ||
|
||
(def nested-pulled | ||
[:x | ||
[:level-4 | ||
[:level-3 | ||
[:level-2 | ||
[:level-1 | ||
[:level-0]]]]]]) | ||
|
||
(def cousins-pulled | ||
[:x | ||
[:parent | ||
[:sib-1] | ||
[:sib-2] | ||
[:grand-parent | ||
[:uncle | ||
[:cousin-1] | ||
[:cousin-2]]]]]) | ||
|
||
(def with-kids-pulled | ||
[:x | ||
[:child-1] | ||
[:child-2] | ||
[:parent | ||
[:sibling | ||
[:nephew] | ||
[:niece]] | ||
[:grand-parent | ||
[:aunt | ||
[:cousin-1 | ||
[:2nd-cousin-1] | ||
[:2nd-cousin-2]] | ||
[:cousin-2 | ||
[:2nd-cousin-3] | ||
[:2nd-cousin-4]]]]]]) | ||
|
||
(deftest singletons | ||
(is (= singleton | ||
(pov/of :x singleton)))) | ||
|
||
(deftest simple-trees | ||
(is (= simple-pulled | ||
(pov/of :x simple-tree)))) | ||
|
||
(deftest nested-trees | ||
(is (= nested-pulled | ||
(pov/of :x deeply-nested)))) | ||
|
||
(deftest extract-node-from-siblings | ||
(is (= flat-pulled | ||
(pov/of :x large-flat)))) | ||
|
||
(deftest moderate-trees | ||
(is (= cousins-pulled | ||
(pov/of :x cousins)))) | ||
|
||
(deftest complex-trees | ||
(is (= with-kids-pulled | ||
(pov/of :x target-with-children)))) | ||
|
||
(deftest not-found-cannot-reparent | ||
(is (nil? (pov/of :not-found! target-with-children)))) | ||
|
||
(deftest not-found-input-empty | ||
(is (nil? (pov/of :x [])))) | ||
|
||
(deftest not-found-input-nil | ||
(is (nil? (pov/of :x nil)))) | ||
|
||
(deftest path-from-target-to-parent | ||
(is (= [:x :parent] | ||
(pov/path-from-to :x :parent simple-tree)))) | ||
|
||
(deftest path-from-target-to-sibling | ||
(is (= [:x :parent :sib-c] | ||
(pov/path-from-to :x :sib-c large-flat)))) | ||
|
||
(deftest path-from-x-to-2nd-cousin-1 | ||
(is (= [:x :parent :grand-parent :aunt :cousin-1 :2nd-cousin-1] | ||
(pov/path-from-to :x :2nd-cousin-1 target-with-children)))) | ||
|
||
(deftest no-path | ||
(is (nil? (pov/path-from-to :x :not-there! cousins)))) |