Skip to content

Commit f9f39dd

Browse files
authored
Add Exercise Relative Distance (#195)
1 parent ef0e50f commit f9f39dd

9 files changed

Lines changed: 466 additions & 8 deletions

File tree

config.json

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -361,14 +361,6 @@
361361
"prerequisites": [],
362362
"difficulty": 2
363363
},
364-
{
365-
"slug": "sublist",
366-
"name": "Sublist",
367-
"uuid": "374bd84a-59a0-496d-8695-a7270ad5c3f4",
368-
"practices": [],
369-
"prerequisites": [],
370-
"difficulty": 5
371-
},
372364
{
373365
"slug": "acronym",
374366
"name": "Acronym",
@@ -513,6 +505,14 @@
513505
"prerequisites": [],
514506
"difficulty": 5
515507
},
508+
{
509+
"slug": "relative-distance",
510+
"name": "Relative Distance",
511+
"uuid": "5f4a4aa8-c4ae-4260-bfd5-e97320a2bf55",
512+
"practices": [],
513+
"prerequisites": [],
514+
"difficulty": 5
515+
},
516516
{
517517
"slug": "reverse-string",
518518
"name": "Reverse String",
@@ -537,6 +537,14 @@
537537
"prerequisites": [],
538538
"difficulty": 5
539539
},
540+
{
541+
"slug": "sublist",
542+
"name": "Sublist",
543+
"uuid": "374bd84a-59a0-496d-8695-a7270ad5c3f4",
544+
"practices": [],
545+
"prerequisites": [],
546+
"difficulty": 5
547+
},
540548
{
541549
"slug": "two-bucket",
542550
"name": "Two Bucket",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Instructions append
2+
3+
In Odin, if two individuals are not connected, we will return the value -1.
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Instructions
2+
3+
Your task is to determine the degree of separation between two individuals in a family tree.
4+
This is similar to the pop culture idea that every Hollywood actor is [within six degrees of Kevin Bacon][six-bacons].
5+
6+
- You will be given an input, with all parent names and their children.
7+
- Each name is unique, a child _can_ have one or two parents.
8+
- The degree of separation is defined as the shortest number of connections from one person to another.
9+
- If two individuals are not connected, return a value that represents "no known relationship."
10+
Please see the test cases for the actual implementation.
11+
12+
## Example
13+
14+
Given the following family tree:
15+
16+
```text
17+
┌──────────┐ ┌──────────┐ ┌───────────┐
18+
│ Helena │ │ Erdős ├─────┤ Shusaku │
19+
└───┬───┬──┘ └─────┬────┘ └────┬──────┘
20+
┌───┘ └───────┐ └───────┬───────┘
21+
┌─────┴────┐ ┌────┴───┐ ┌─────┴────┐
22+
│ Isla ├─────┤ Tariq │ │ Kevin │
23+
└────┬─────┘ └────┬───┘ └──────────┘
24+
│ │
25+
┌────┴────┐ ┌────┴───┐
26+
│ Uma │ │ Morphy │
27+
└─────────┘ └────────┘
28+
```
29+
30+
The degree of separation between Tariq and Uma is 2 (Tariq → Isla → Uma).
31+
There's no known relationship between Isla and Kevin, as there is no connection in the given data.
32+
The degree of separation between Uma and Isla is 1.
33+
34+
~~~~exercism/note
35+
Isla and Tariq are siblings and have a separation of 1.
36+
Similarly, this implementation would report a separation of 2 from you to your father's brother.
37+
~~~~
38+
39+
[six-bacons]: https://en.wikipedia.org/wiki/Six_Degrees_of_Kevin_Bacon
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Introduction
2+
3+
You've been hired to develop **Noble Knots**, the hottest new dating app for nobility!
4+
With centuries of royal intermarriage, things have gotten… _complicated_.
5+
To avoid any _oops-we're-twins_ situations, your job is to build a system that checks how closely two people are related.
6+
7+
Noble Knots is inspired by Iceland's "[Islendinga-App][islendiga-app]," which is backed up by a database that traces all known family connections between Icelanders from the time of the settlement of Iceland.
8+
Your algorithm will determine the **degree of separation** between two individuals in the royal family tree.
9+
10+
Will your app help crown a perfect match?
11+
12+
[islendiga-app]: https://web.archive.org/web/20250816223614/http://www.islendingaapp.is/information-in-english/
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"rmonnet"
4+
],
5+
"files": {
6+
"solution": [
7+
"relative_distance.odin"
8+
],
9+
"test": [
10+
"relative_distance_test.odin"
11+
],
12+
"example": [
13+
".meta/example.odin"
14+
]
15+
},
16+
"blurb": "Given a family tree, calculate the degree of separation.",
17+
"source": "vaeng",
18+
"source_url": "https://github.com/exercism/problem-specifications/pull/2537"
19+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package relative_distance
2+
3+
import "core:container/queue"
4+
5+
Name :: string
6+
Children :: []Name
7+
FamilyTree :: map[Name]Children
8+
9+
Node :: struct {
10+
name: string,
11+
distance: int,
12+
}
13+
14+
Set :: map[string]bool
15+
16+
Neighbors :: map[string]Set
17+
18+
// First establish 1-degree separation between members of the family (Neighbors graph)
19+
// - parent to child
20+
// - child to parent
21+
// - child to other child
22+
// Then use BFS (Breath-First-Search) to find a path between the `from` and `to` individuals.
23+
// Because we use BFS, the path found will be the shortest path. This only works because all the
24+
// weigths in the Neighbors graph are 1.
25+
degree_of_separation :: proc(family: FamilyTree, from: string, to: string) -> int {
26+
27+
if from == to { return 0 }
28+
29+
neighbors := collect_neighbors(family)
30+
defer destroy_neighbors(neighbors)
31+
32+
visited: Set
33+
visited[from] = true
34+
defer delete(visited)
35+
36+
to_visit: queue.Queue(Node)
37+
queue.init(&to_visit)
38+
defer queue.destroy(&to_visit)
39+
queue.push_back(&to_visit, Node{from, 0})
40+
41+
for queue.len(to_visit) > 0 {
42+
node := queue.pop_front(&to_visit)
43+
for neighbor in neighbors[node.name] {
44+
if neighbor == to {
45+
return node.distance + 1
46+
}
47+
if !visited[neighbor] {
48+
visited[neighbor] = true
49+
queue.push(&to_visit, Node{neighbor, node.distance + 1})
50+
}
51+
}
52+
}
53+
// No path found
54+
return -1
55+
}
56+
57+
collect_neighbors :: proc(family: FamilyTree) -> Neighbors {
58+
59+
neighbors: Neighbors
60+
for parent, children in family {
61+
for child in children {
62+
add_neighbor(&neighbors, parent, child)
63+
add_neighbor(&neighbors, child, parent)
64+
for other_child in children {
65+
if other_child != child {
66+
add_neighbor(&neighbors, child, other_child)
67+
}
68+
}
69+
}
70+
}
71+
return neighbors
72+
}
73+
74+
add_neighbor :: proc(neighbors: ^Neighbors, name: string, neighbor: string) {
75+
76+
if name not_in neighbors {
77+
neighbors[name] = make(Set)
78+
}
79+
set := neighbors[name]
80+
set[neighbor] = true
81+
neighbors[name] = set
82+
83+
}
84+
85+
destroy_neighbors :: proc(neighbors: Neighbors) {
86+
87+
for key, _ in neighbors {
88+
set := neighbors[key]
89+
delete(set)
90+
}
91+
delete(neighbors)
92+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[4a1ded74-5d32-47fb-8ae5-321f51d06b5b]
13+
description = "Direct parent-child relation"
14+
15+
[30d17269-83e9-4f82-a0d7-8ef9656d8dce]
16+
description = "Sibling relationship"
17+
18+
[8dffa27d-a8ab-496d-80b3-2f21c77648b5]
19+
description = "Two degrees of separation, grandchild"
20+
21+
[34e56ec1-d528-4a42-908e-020a4606ee60]
22+
description = "Unrelated individuals"
23+
24+
[93ffe989-bad2-48c4-878f-3acb1ce2611b]
25+
description = "Complex graph, cousins"
26+
27+
[2cc2e76b-013a-433c-9486-1dbe29bf06e5]
28+
description = "Complex graph, no shortcut, far removed nephew"
29+
30+
[46c9fbcb-e464-455f-a718-049ea3c7400a]
31+
description = "Complex graph, some shortcuts, cross-down and cross-up, cousins several times removed, with unrelated family tree"
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package relative_distance
2+
3+
Name :: string
4+
Children :: []Name
5+
FamilyTree :: map[Name]Children
6+
7+
degree_of_separation :: proc(family: FamilyTree, from: string, to: string) -> int {
8+
// Implement this procedure.
9+
return -1
10+
}

0 commit comments

Comments
 (0)