Skip to content

Commit 09a5ad2

Browse files
authored
Add relative-distance (#2424)
* Add `relative-distance` * Apply code review * Update generator template
1 parent a042249 commit 09a5ad2

File tree

13 files changed

+779
-0
lines changed

13 files changed

+779
-0
lines changed

config.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2731,6 +2731,22 @@
27312731
],
27322732
"difficulty": 6
27332733
},
2734+
{
2735+
"slug": "relative-distance",
2736+
"name": "Relative Distance",
2737+
"uuid": "4f4229ce-5a2a-415c-a682-6a56cf3846ac",
2738+
"practices": [
2739+
"constructors",
2740+
"dictionaries"
2741+
],
2742+
"prerequisites": [
2743+
"arrays",
2744+
"classes",
2745+
"constructors",
2746+
"dictionaries"
2747+
],
2748+
"difficulty": 5
2749+
},
27342750
{
27352751
"slug": "split-second-stopwatch",
27362752
"name": "Split-Second Stopwatch",

exercises/Exercises.sln

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "swift-scheduling", "swift-s
367367
EndProject
368368
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SwiftScheduling", "practice\swift-scheduling\SwiftScheduling.csproj", "{9A073412-4B64-48EB-A346-A56DE6847CCC}"
369369
EndProject
370+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "RelativeDistance", "practice\relative-distance\RelativeDistance.csproj", "{2C37454E-8624-47B8-A09B-ADE201C2B04C}"
371+
EndProject
370372
Global
371373
GlobalSection(SolutionConfigurationPlatforms) = preSolution
372374
Debug|Any CPU = Debug|Any CPU
@@ -2525,6 +2527,18 @@ Global
25252527
{9A073412-4B64-48EB-A346-A56DE6847CCC}.Release|x64.Build.0 = Release|Any CPU
25262528
{9A073412-4B64-48EB-A346-A56DE6847CCC}.Release|x86.ActiveCfg = Release|Any CPU
25272529
{9A073412-4B64-48EB-A346-A56DE6847CCC}.Release|x86.Build.0 = Release|Any CPU
2530+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2531+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|Any CPU.Build.0 = Debug|Any CPU
2532+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|x64.ActiveCfg = Debug|Any CPU
2533+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|x64.Build.0 = Debug|Any CPU
2534+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|x86.ActiveCfg = Debug|Any CPU
2535+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Debug|x86.Build.0 = Debug|Any CPU
2536+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|Any CPU.ActiveCfg = Release|Any CPU
2537+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|Any CPU.Build.0 = Release|Any CPU
2538+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|x64.ActiveCfg = Release|Any CPU
2539+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|x64.Build.0 = Release|Any CPU
2540+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|x86.ActiveCfg = Release|Any CPU
2541+
{2C37454E-8624-47B8-A09B-ADE201C2B04C}.Release|x86.Build.0 = Release|Any CPU
25282542
EndGlobalSection
25292543
GlobalSection(SolutionProperties) = preSolution
25302544
HideSolutionNode = FALSE
@@ -2710,6 +2724,7 @@ Global
27102724
{1BA5F72A-ED8E-48A8-8FD6-0F567BDCBD9E} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
27112725
{FA726133-BC1C-D753-28C5-C9ACB44C0776} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
27122726
{9A073412-4B64-48EB-A346-A56DE6847CCC} = {FA726133-BC1C-D753-28C5-C9ACB44C0776}
2727+
{2C37454E-8624-47B8-A09B-ADE201C2B04C} = {E276EF69-669A-43E0-88AC-8ABB17A9C026}
27132728
EndGlobalSection
27142729
GlobalSection(ExtensibilityGlobals) = postSolution
27152730
SolutionGuid = {AB4EA6C9-5461-4024-BDC7-2AE0C3A85CD1}
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+
5+
- You will be given an input, with all parent names and their children.
6+
- Each name is unique, a child _can_ have one or two parents.
7+
- The degree of separation is defined as the shortest number of connections from one person to another.
8+
- If two individuals are not connected, return a value that represents "no known relationship."
9+
Please see the test cases for the actual implementation.
10+
11+
## Example
12+
13+
Given the following family tree:
14+
15+
```text
16+
┌──────────┐ ┌──────────┐ ┌───────────┐
17+
│ Helena │ │ Erdős │ │ Shusaku │
18+
└───┬───┬──┘ └─────┬────┘ └──────┬────┘
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 3 (Tariq → Helena → Isla → Uma).
31+
There's no known relationship between Isla and [Kevin][six-bacons], 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.m.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]: http://www.islendingaapp.is/information-in-english/
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
###############################
2+
# Core EditorConfig Options #
3+
###############################
4+
5+
; This file is for unifying the coding style for different editors and IDEs.
6+
; More information at:
7+
; https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017
8+
; https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2017
9+
10+
root = true
11+
12+
[*]
13+
indent_style = space
14+
15+
[RelativeDistance.cs]
16+
indent_size = 4
17+
18+
###############################
19+
# .NET Coding Conventions #
20+
###############################
21+
22+
# Organize usings
23+
dotnet_sort_system_directives_first = true
24+
dotnet_separate_import_directive_groups = true
25+
26+
# this. preferences
27+
dotnet_style_qualification_for_field = false:suggestion
28+
dotnet_style_qualification_for_property = false:suggestion
29+
dotnet_style_qualification_for_method = false:suggestion
30+
dotnet_style_qualification_for_event = false:suggestion
31+
32+
# Language keywords vs BCL types preferences
33+
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
34+
dotnet_style_predefined_type_for_member_access = true:suggestion
35+
36+
# Parentheses preferences
37+
dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none
38+
dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none
39+
dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none
40+
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
41+
42+
# Modifier preferences
43+
dotnet_style_require_accessibility_modifiers = always:suggestion
44+
dotnet_style_readonly_field = true:suggestion
45+
46+
# Expression-level preferences
47+
dotnet_style_object_initializer = true:suggestion
48+
dotnet_style_collection_initializer = true:suggestion
49+
dotnet_style_explicit_tuple_names = true:suggestion
50+
dotnet_style_prefer_inferred_tuple_names = true:suggestion
51+
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
52+
dotnet_style_prefer_auto_properties = true:suggestion
53+
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
54+
dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
55+
dotnet_style_prefer_conditional_expression_over_return = true:suggestion
56+
dotnet_style_coalesce_expression = true:suggestion
57+
dotnet_style_null_propagation = true:suggestion
58+
59+
###############################
60+
# Naming Conventions #
61+
###############################
62+
63+
# Style Definitions
64+
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
65+
66+
# Use PascalCase for constant fields
67+
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
68+
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
69+
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
70+
dotnet_naming_symbols.constant_fields.applicable_kinds = field
71+
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
72+
dotnet_naming_symbols.constant_fields.required_modifiers = const
73+
74+
###############################
75+
# C# Code Style Rules #
76+
###############################
77+
78+
# var preferences
79+
csharp_style_var_for_built_in_types = true:none
80+
csharp_style_var_when_type_is_apparent = true:none
81+
csharp_style_var_elsewhere = true:none
82+
83+
# Expression-bodied members
84+
csharp_style_expression_bodied_methods = true:suggestion
85+
csharp_style_expression_bodied_constructors = true:suggestion
86+
csharp_style_expression_bodied_operators = true:suggestion
87+
csharp_style_expression_bodied_properties = true:suggestion
88+
csharp_style_expression_bodied_indexers = true:suggestion
89+
csharp_style_expression_bodied_accessors = true:suggestion
90+
91+
# Pattern-matching preferences
92+
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
93+
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
94+
95+
# Null-checking preferences
96+
csharp_style_throw_expression = true:suggestion
97+
csharp_style_conditional_delegate_call = true:suggestion
98+
99+
# Modifier preferences
100+
csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion
101+
102+
# Expression-level preferences
103+
csharp_prefer_braces = true:none
104+
csharp_prefer_simple_default_expression = true:suggestion
105+
csharp_style_deconstructed_variable_declaration = true:suggestion
106+
csharp_style_pattern_local_over_anonymous_function = true:suggestion
107+
csharp_style_inlined_variable_declaration = true:suggestion
108+
109+
###############################
110+
# C# Formatting Rules #
111+
###############################
112+
113+
# New line preferences
114+
csharp_new_line_before_open_brace = all
115+
csharp_new_line_before_else = true
116+
csharp_new_line_before_catch = true
117+
csharp_new_line_before_finally = true
118+
csharp_new_line_before_members_in_object_initializers = false
119+
csharp_new_line_before_members_in_anonymous_types = false
120+
csharp_new_line_between_query_expression_clauses = true
121+
122+
# Indentation preferences
123+
csharp_indent_case_contents = true
124+
csharp_indent_switch_labels = true
125+
csharp_indent_labels = flush_left
126+
127+
# Space preferences
128+
csharp_space_after_cast = false
129+
csharp_space_after_keywords_in_control_flow_statements = true
130+
csharp_space_between_method_declaration_parameter_list_parentheses = false
131+
csharp_space_between_method_call_parameter_list_parentheses = false
132+
csharp_space_before_colon_in_inheritance_clause = true
133+
csharp_space_after_colon_in_inheritance_clause = true
134+
csharp_space_around_binary_operators = before_and_after
135+
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
136+
csharp_space_between_method_call_name_and_opening_parenthesis = false
137+
csharp_space_between_method_call_empty_parameter_list_parentheses = false
138+
139+
# Wrapping preferences
140+
csharp_preserve_single_line_blocks = true
141+
csharp_preserve_single_line_statements = true
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
public class RelativeDistance
2+
{
3+
private readonly Dictionary<string, HashSet<string>> relatives;
4+
5+
public RelativeDistance(Dictionary<string, string[]> familyTree)
6+
{
7+
Dictionary<string, HashSet<string>> parsed = new();
8+
foreach (var (parent, children) in familyTree)
9+
{
10+
var parentConnections = parsed.GetValueOrDefault(parent, []);
11+
foreach (string child in children)
12+
{
13+
parentConnections.Add(child);
14+
var childConnections = parsed.GetValueOrDefault(child, [])
15+
.Union(children.Where(sibling => sibling != child)).ToHashSet();
16+
childConnections.Add(parent);
17+
parsed[child] = childConnections;
18+
}
19+
20+
parsed[parent] = parentConnections;
21+
}
22+
relatives = parsed;
23+
}
24+
25+
public int DegreeOfSeparation(string personA, string personB)
26+
{
27+
if (!relatives.ContainsKey(personA) || !relatives.ContainsKey(personB))
28+
{
29+
return -1;
30+
}
31+
32+
Queue<(string Person, int Degree)> queue = new();
33+
queue.Enqueue((personA, 0));
34+
HashSet<string> visited = [personA];
35+
36+
while (queue.Count > 0)
37+
{
38+
var (currentPerson, degree) = queue.Dequeue();
39+
40+
if (currentPerson == personB)
41+
{
42+
return degree;
43+
}
44+
45+
var unvisited = relatives[currentPerson].Except(visited).ToHashSet();
46+
foreach (string neighbor in unvisited)
47+
{
48+
queue.Enqueue((neighbor, degree + 1));
49+
}
50+
visited.UnionWith(unvisited);
51+
}
52+
53+
return -1;
54+
}
55+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
public class {{ testClass }}
2+
{
3+
{{- for test in tests }}
4+
[Fact{{ if !for.first }}(Skip = "Remove this Skip property to run this test"){{ end }}]
5+
public void {{ test.testMethod }}()
6+
{
7+
Dictionary<string, string[]> familyTree = new()
8+
{
9+
{{- for entry in test.input.familyTree }}
10+
{ "{{ entry.key }}", [{{ for name in entry.value }}"{{ name }}"{{ if !for.last }}, {{ end }}{{ end }}] }{{ if !for.last }},{{ end }}
11+
{{- end }}
12+
};
13+
RelativeDistance rd = new(familyTree);
14+
Assert.Equal({{ if test.expected }}{{ test.expected }}{{ else }}{{ -1 }}{{ end }}, rd.DegreeOfSeparation({{ test.input.personA | string.literal }}, {{ test.input.personB | string.literal }}));
15+
}
16+
{{ end -}}
17+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"RelativeDistance.cs"
8+
],
9+
"test": [
10+
"RelativeDistanceTests.cs"
11+
],
12+
"example": [
13+
".meta/Example.cs"
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: 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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
public class RelativeDistance
2+
{
3+
public RelativeDistance(Dictionary<string, string[]> familyTree)
4+
{
5+
throw new NotImplementedException("You need to implement this method.");
6+
}
7+
8+
public int DegreeOfSeparation(string personA, string personB)
9+
{
10+
throw new NotImplementedException("You need to implement this method.");
11+
}
12+
}

0 commit comments

Comments
 (0)