Skip to content

Commit 3f4a058

Browse files
authored
add prism (#2472)
1 parent e14d997 commit 3f4a058

13 files changed

Lines changed: 854 additions & 0 deletions

File tree

config.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2148,6 +2148,21 @@
21482148
],
21492149
"difficulty": 4
21502150
},
2151+
{
2152+
"slug": "prism",
2153+
"name": "Prism",
2154+
"uuid": "c52d3d36-4852-48ff-b97c-0b030a5b365d",
2155+
"practices": [
2156+
"arrays",
2157+
"floating-point-numbers",
2158+
"while-loops"
2159+
],
2160+
"prerequisites": [
2161+
"arrays",
2162+
"floating-point-numbers"
2163+
],
2164+
"difficulty": 4
2165+
},
21512166
{
21522167
"slug": "twelve-days",
21532168
"name": "Twelve Days",

exercises/Exercises.slnx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
<Project Path="practice/pov/Pov.csproj" />
130130
<Project Path="practice/prime-factors/PrimeFactors.csproj" />
131131
<Project Path="practice/protein-translation/ProteinTranslation.csproj" />
132+
<Project Path="practice/prism/Prism.csproj" />
132133
<Project Path="practice/proverb/Proverb.csproj" />
133134
<Project Path="practice/pythagorean-triplet/PythagoreanTriplet.csproj" />
134135
<Project Path="practice/queen-attack/QueenAttack.csproj" />
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Instructions
2+
3+
Before activating the laser array, you must predict the exact order in which crystals will be hit, identified by their sample IDs.
4+
5+
## Example Test Case
6+
7+
Consider this crystal array configuration:
8+
9+
```json
10+
{
11+
"start": { "x": 0, "y": 0, "angle": 0 },
12+
"prisms": [
13+
{ "id": 1, "x": 10, "y": 10, "angle": -90 },
14+
{ "id": 2, "x": 10, "y": 0, "angle": 90 },
15+
{ "id": 3, "x": 30, "y": 10, "angle": 45 },
16+
{ "id": 4, "x": 20, "y": 0, "angle": 0 }
17+
]
18+
}
19+
```
20+
21+
## What's Happening
22+
23+
The laser starts at the origin `(0, 0)` and fires horizontally to the right at angle 0°.
24+
Here's the step-by-step beam path:
25+
26+
**Step 1**: The beam travels along the x-axis (y = 0) and first encounters **Crystal #2** at position `(10, 0)`.
27+
This crystal has a refraction angle of 90°, which means it bends the beam perpendicular to its current path.
28+
The beam, originally traveling at 0°, is now redirected to 90° (straight up).
29+
30+
**Step 2**: The beam now travels vertically upward from position `(10, 0)` and strikes **Crystal #1** at position `(10, 10)`.
31+
This crystal has a refraction angle of -90°, bending the beam by -90° relative to its current direction.
32+
The beam was traveling at 90°, so after refraction it's now at 0° (90° + (-90°) = 0°), traveling horizontally to the right again.
33+
34+
**Step 3**: From position `(10, 10)`, the beam travels horizontally and encounters **Crystal #3** at position `(30, 10)`.
35+
This crystal refracts the beam by 45°, changing its direction to 45°.
36+
The beam continues into empty space beyond the array.
37+
38+
!["A graph showing the path of a laser beam refracted through three prisms."](https://assets.exercism.org/images/exercises/prism/laser_path-light.svg)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Introduction
2+
3+
You're a researcher at **PRISM** (Precariously Redirected Illumination Safety Management), working with a precision laser calibration system that tests experimental crystal prisms.
4+
These crystals are being developed for next-generation optical computers, and each one has unique refractive properties based on its molecular structure.
5+
The lab's laser system can damage crystals if they receive unexpected illumination, so precise path prediction is critical.
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+
[ProteinTranslation.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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
public static class Prism
2+
{
3+
public readonly record struct LaserInfo(double X, double Y, double Angle);
4+
5+
public readonly record struct PrismInfo(int Id, double X, double Y, double Angle);
6+
7+
public static int[] FindSequence(LaserInfo laser, PrismInfo[] prisms)
8+
{
9+
var x = laser.X;
10+
var y = laser.Y;
11+
var angle = laser.Angle;
12+
List<int> sequence = new();
13+
14+
while (true)
15+
{
16+
var rad = double.DegreesToRadians(angle);
17+
var dirX = double.Cos(rad);
18+
var dirY = double.Sin(rad);
19+
20+
PrismInfo? nearest = null;
21+
var nearestDist = double.PositiveInfinity;
22+
23+
foreach (var prism in prisms)
24+
{
25+
var dx = prism.X - x;
26+
var dy = prism.Y - y;
27+
28+
var dist = dx * dirX + dy * dirY;
29+
if (dist <= 1e-6)
30+
continue;
31+
32+
var crossSq = double.Pow(dx - dist * dirX, 2) + double.Pow(dy - dist * dirY, 2);
33+
if (crossSq >= 1e-6 * double.Max(1, dist * dist))
34+
continue;
35+
36+
if (dist < nearestDist)
37+
{
38+
nearestDist = dist;
39+
nearest = prism;
40+
}
41+
}
42+
43+
if (nearest is not { } hit)
44+
break;
45+
46+
sequence.Add(hit.Id);
47+
x = hit.X;
48+
y = hit.Y;
49+
angle = (angle + hit.Angle) % 360;
50+
}
51+
52+
return sequence.ToArray();
53+
}
54+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
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+
Prism.LaserInfo laser = new({{ test.input.start.x }}, {{ test.input.start.y }}, {{ test.input.start.angle }});
8+
{{- if test.input.prisms.empty? }}
9+
Prism.PrismInfo[] prisms = [];
10+
{{- else }}
11+
Prism.PrismInfo[] prisms =
12+
[
13+
{{- for p in test.input.prisms }}
14+
new({{ p.id }}, {{ p.x }}, {{ p.y }}, {{ p.angle }}){{ if !for.last }},{{ end }}
15+
{{- end }}
16+
];
17+
{{- end }}
18+
int[] expected = [{{ array.join test.expected.sequence ", " }}];
19+
Assert.Equal(expected, {{ testedClass }}.{{ test.testedMethod }}(laser, prisms));
20+
}
21+
{{ end -}}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"authors": [
3+
"BNAndras"
4+
],
5+
"files": {
6+
"solution": [
7+
"Prism.cs"
8+
],
9+
"test": [
10+
"PrismTests.cs"
11+
],
12+
"example": [
13+
".meta/Example.cs"
14+
],
15+
"invalidator": [
16+
"Prism.csproj"
17+
]
18+
},
19+
"blurb": "Calculate the path of a laser through refractive prisms.",
20+
"source": "FraSanga",
21+
"source_url": "https://github.com/exercism/problem-specifications/pull/2625"
22+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
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+
[ec65d3b3-f7bf-4015-8156-0609c141c4c4]
13+
description = "zero prisms"
14+
15+
[ec0ca17c-0c5f-44fb-89ba-b76395bdaf1c]
16+
description = "one prism one hit"
17+
18+
[0db955f2-0a27-4c82-ba67-197bd6202069]
19+
description = "one prism zero hits"
20+
21+
[8d92485b-ebc0-4ee9-9b88-cdddb16b52da]
22+
description = "going up zero hits"
23+
24+
[78295b3c-7438-492d-8010-9c63f5c223d7]
25+
description = "going down zero hits"
26+
27+
[acc723ea-597b-4a50-8d1b-b980fe867d4c]
28+
description = "going left zero hits"
29+
30+
[3f19b9df-9eaa-4f18-a2db-76132f466d17]
31+
description = "negative angle"
32+
33+
[96dacffb-d821-4cdf-aed8-f152ce063195]
34+
description = "large angle"
35+
36+
[513a7caa-957f-4c5d-9820-076842de113c]
37+
description = "upward refraction two hits"
38+
39+
[d452b7c7-9761-4ea9-81a9-2de1d73eb9ef]
40+
description = "downward refraction two hits"
41+
42+
[be1a2167-bf4c-4834-acc9-e4d68e1a0203]
43+
description = "same prism twice"
44+
45+
[df5a60dd-7c7d-4937-ac4f-c832dae79e2e]
46+
description = "simple path"
47+
48+
[8d9a3cc8-e846-4a3b-a137-4bfc4aa70bd1]
49+
description = "multiple prisms floating point precision"
50+
51+
[e077fc91-4e4a-46b3-a0f5-0ba00321da56]
52+
description = "complex path with multiple prisms floating point precision"

exercises/practice/prism/Prism.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
public static class Prism
2+
{
3+
public readonly record struct LaserInfo(double X, double Y, double Angle);
4+
5+
public readonly record struct PrismInfo(int Id, double X, double Y, double Angle);
6+
7+
public static int[] FindSequence(LaserInfo laser, PrismInfo[] prisms)
8+
{
9+
throw new NotImplementedException("You need to implement this method.");
10+
}
11+
}

0 commit comments

Comments
 (0)