diff --git a/config.json b/config.json index dc508066b..1161b97c3 100644 --- a/config.json +++ b/config.json @@ -2148,6 +2148,21 @@ ], "difficulty": 4 }, + { + "slug": "prism", + "name": "Prism", + "uuid": "c52d3d36-4852-48ff-b97c-0b030a5b365d", + "practices": [ + "arrays", + "floating-point-numbers", + "while-loops" + ], + "prerequisites": [ + "arrays", + "floating-point-numbers" + ], + "difficulty": 4 + }, { "slug": "twelve-days", "name": "Twelve Days", diff --git a/exercises/Exercises.slnx b/exercises/Exercises.slnx index cdbda49b1..898746ea4 100644 --- a/exercises/Exercises.slnx +++ b/exercises/Exercises.slnx @@ -129,6 +129,7 @@ + diff --git a/exercises/practice/prism/.docs/instructions.md b/exercises/practice/prism/.docs/instructions.md new file mode 100644 index 000000000..13cefae8c --- /dev/null +++ b/exercises/practice/prism/.docs/instructions.md @@ -0,0 +1,38 @@ +# Instructions + +Before activating the laser array, you must predict the exact order in which crystals will be hit, identified by their sample IDs. + +## Example Test Case + +Consider this crystal array configuration: + +```json +{ + "start": { "x": 0, "y": 0, "angle": 0 }, + "prisms": [ + { "id": 1, "x": 10, "y": 10, "angle": -90 }, + { "id": 2, "x": 10, "y": 0, "angle": 90 }, + { "id": 3, "x": 30, "y": 10, "angle": 45 }, + { "id": 4, "x": 20, "y": 0, "angle": 0 } + ] +} +``` + +## What's Happening + +The laser starts at the origin `(0, 0)` and fires horizontally to the right at angle 0°. +Here's the step-by-step beam path: + +**Step 1**: The beam travels along the x-axis (y = 0) and first encounters **Crystal #2** at position `(10, 0)`. +This crystal has a refraction angle of 90°, which means it bends the beam perpendicular to its current path. +The beam, originally traveling at 0°, is now redirected to 90° (straight up). + +**Step 2**: The beam now travels vertically upward from position `(10, 0)` and strikes **Crystal #1** at position `(10, 10)`. +This crystal has a refraction angle of -90°, bending the beam by -90° relative to its current direction. +The beam was traveling at 90°, so after refraction it's now at 0° (90° + (-90°) = 0°), traveling horizontally to the right again. + +**Step 3**: From position `(10, 10)`, the beam travels horizontally and encounters **Crystal #3** at position `(30, 10)`. +This crystal refracts the beam by 45°, changing its direction to 45°. +The beam continues into empty space beyond the array. + +!["A graph showing the path of a laser beam refracted through three prisms."](https://assets.exercism.org/images/exercises/prism/laser_path-light.svg) diff --git a/exercises/practice/prism/.docs/introduction.md b/exercises/practice/prism/.docs/introduction.md new file mode 100644 index 000000000..bfa7ed72e --- /dev/null +++ b/exercises/practice/prism/.docs/introduction.md @@ -0,0 +1,5 @@ +# Introduction + +You're a researcher at **PRISM** (Precariously Redirected Illumination Safety Management), working with a precision laser calibration system that tests experimental crystal prisms. +These crystals are being developed for next-generation optical computers, and each one has unique refractive properties based on its molecular structure. +The lab's laser system can damage crystals if they receive unexpected illumination, so precise path prediction is critical. diff --git a/exercises/practice/prism/.editorconfig b/exercises/practice/prism/.editorconfig new file mode 100644 index 000000000..8e51769a9 --- /dev/null +++ b/exercises/practice/prism/.editorconfig @@ -0,0 +1,141 @@ +############################### +# Core EditorConfig Options # +############################### + +; This file is for unifying the coding style for different editors and IDEs. +; More information at: +; https://docs.microsoft.com/en-us/visualstudio/ide/editorconfig-code-style-settings-reference?view=vs-2017 +; https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2017 + +root = true + +[*] +indent_style = space + +[ProteinTranslation.cs] +indent_size = 4 + +############################### +# .NET Coding Conventions # +############################### + +# Organize usings +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = true + +# this. preferences +dotnet_style_qualification_for_field = false:suggestion +dotnet_style_qualification_for_property = false:suggestion +dotnet_style_qualification_for_method = false:suggestion +dotnet_style_qualification_for_event = false:suggestion + +# Language keywords vs BCL types preferences +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Parentheses preferences +dotnet_style_parentheses_in_arithmetic_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_relational_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_other_binary_operators = never_if_unnecessary:none +dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion + +# Modifier preferences +dotnet_style_require_accessibility_modifiers = always:suggestion +dotnet_style_readonly_field = true:suggestion + +# Expression-level preferences +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion +dotnet_style_prefer_inferred_tuple_names = true:suggestion +dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion +dotnet_style_prefer_auto_properties = true:suggestion +dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion +dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion +dotnet_style_prefer_conditional_expression_over_return = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion + +############################### +# Naming Conventions # +############################### + +# Style Definitions +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# Use PascalCase for constant fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields +dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style +dotnet_naming_symbols.constant_fields.applicable_kinds = field +dotnet_naming_symbols.constant_fields.applicable_accessibilities = * +dotnet_naming_symbols.constant_fields.required_modifiers = const + +############################### +# C# Code Style Rules # +############################### + +# var preferences +csharp_style_var_for_built_in_types = true:none +csharp_style_var_when_type_is_apparent = true:none +csharp_style_var_elsewhere = true:none + +# Expression-bodied members +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_expression_bodied_constructors = true:suggestion +csharp_style_expression_bodied_operators = true:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_expression_bodied_indexers = true:suggestion +csharp_style_expression_bodied_accessors = true:suggestion + +# Pattern-matching preferences +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion + +# Null-checking preferences +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Modifier preferences +csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion + +# Expression-level preferences +csharp_prefer_braces = true:none +csharp_prefer_simple_default_expression = true:suggestion +csharp_style_deconstructed_variable_declaration = true:suggestion +csharp_style_pattern_local_over_anonymous_function = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion + +############################### +# C# Formatting Rules # +############################### + +# New line preferences +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_members_in_anonymous_types = false +csharp_new_line_between_query_expression_clauses = true + +# Indentation preferences +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Space preferences +csharp_space_after_cast = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false + +# Wrapping preferences +csharp_preserve_single_line_blocks = true +csharp_preserve_single_line_statements = true diff --git a/exercises/practice/prism/.meta/Example.cs b/exercises/practice/prism/.meta/Example.cs new file mode 100644 index 000000000..b6a837dad --- /dev/null +++ b/exercises/practice/prism/.meta/Example.cs @@ -0,0 +1,54 @@ +public static class Prism +{ + public readonly record struct LaserInfo(double X, double Y, double Angle); + + public readonly record struct PrismInfo(int Id, double X, double Y, double Angle); + + public static int[] FindSequence(LaserInfo laser, PrismInfo[] prisms) + { + var x = laser.X; + var y = laser.Y; + var angle = laser.Angle; + List sequence = new(); + + while (true) + { + var rad = double.DegreesToRadians(angle); + var dirX = double.Cos(rad); + var dirY = double.Sin(rad); + + PrismInfo? nearest = null; + var nearestDist = double.PositiveInfinity; + + foreach (var prism in prisms) + { + var dx = prism.X - x; + var dy = prism.Y - y; + + var dist = dx * dirX + dy * dirY; + if (dist <= 1e-6) + continue; + + var crossSq = double.Pow(dx - dist * dirX, 2) + double.Pow(dy - dist * dirY, 2); + if (crossSq >= 1e-6 * double.Max(1, dist * dist)) + continue; + + if (dist < nearestDist) + { + nearestDist = dist; + nearest = prism; + } + } + + if (nearest is not { } hit) + break; + + sequence.Add(hit.Id); + x = hit.X; + y = hit.Y; + angle = (angle + hit.Angle) % 360; + } + + return sequence.ToArray(); + } +} diff --git a/exercises/practice/prism/.meta/Generator.tpl b/exercises/practice/prism/.meta/Generator.tpl new file mode 100644 index 000000000..95a33fc48 --- /dev/null +++ b/exercises/practice/prism/.meta/Generator.tpl @@ -0,0 +1,22 @@ +public class {{ testClass }} +{ + {{- for test in tests }} + [Fact{{ if !for.first }}(Skip = "Remove this Skip property to run this test"){{ end }}] + public void {{ test.testMethod }}() + { + Prism.LaserInfo laser = new({{ test.input.start.x }}, {{ test.input.start.y }}, {{ test.input.start.angle }}); + {{- if test.input.prisms.empty? }} + Prism.PrismInfo[] prisms = []; + {{- else }} + Prism.PrismInfo[] prisms = + [ + {{- for p in test.input.prisms }} + new({{ p.id }}, {{ p.x }}, {{ p.y }}, {{ p.angle }}){{ if !for.last }},{{ end }} + {{- end }} + ]; + {{- end }} + int[] expected = [{{ array.join test.expected.sequence ", " }}]; + Assert.Equal(expected, {{ testedClass }}.{{ test.testedMethod }}(laser, prisms)); + } + {{ end -}} +} diff --git a/exercises/practice/prism/.meta/config.json b/exercises/practice/prism/.meta/config.json new file mode 100644 index 000000000..42fb82b15 --- /dev/null +++ b/exercises/practice/prism/.meta/config.json @@ -0,0 +1,22 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "Prism.cs" + ], + "test": [ + "PrismTests.cs" + ], + "example": [ + ".meta/Example.cs" + ], + "invalidator": [ + "Prism.csproj" + ] + }, + "blurb": "Calculate the path of a laser through refractive prisms.", + "source": "FraSanga", + "source_url": "https://github.com/exercism/problem-specifications/pull/2625" +} diff --git a/exercises/practice/prism/.meta/tests.toml b/exercises/practice/prism/.meta/tests.toml new file mode 100644 index 000000000..b00222383 --- /dev/null +++ b/exercises/practice/prism/.meta/tests.toml @@ -0,0 +1,52 @@ +# 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. + +[ec65d3b3-f7bf-4015-8156-0609c141c4c4] +description = "zero prisms" + +[ec0ca17c-0c5f-44fb-89ba-b76395bdaf1c] +description = "one prism one hit" + +[0db955f2-0a27-4c82-ba67-197bd6202069] +description = "one prism zero hits" + +[8d92485b-ebc0-4ee9-9b88-cdddb16b52da] +description = "going up zero hits" + +[78295b3c-7438-492d-8010-9c63f5c223d7] +description = "going down zero hits" + +[acc723ea-597b-4a50-8d1b-b980fe867d4c] +description = "going left zero hits" + +[3f19b9df-9eaa-4f18-a2db-76132f466d17] +description = "negative angle" + +[96dacffb-d821-4cdf-aed8-f152ce063195] +description = "large angle" + +[513a7caa-957f-4c5d-9820-076842de113c] +description = "upward refraction two hits" + +[d452b7c7-9761-4ea9-81a9-2de1d73eb9ef] +description = "downward refraction two hits" + +[be1a2167-bf4c-4834-acc9-e4d68e1a0203] +description = "same prism twice" + +[df5a60dd-7c7d-4937-ac4f-c832dae79e2e] +description = "simple path" + +[8d9a3cc8-e846-4a3b-a137-4bfc4aa70bd1] +description = "multiple prisms floating point precision" + +[e077fc91-4e4a-46b3-a0f5-0ba00321da56] +description = "complex path with multiple prisms floating point precision" diff --git a/exercises/practice/prism/Prism.cs b/exercises/practice/prism/Prism.cs new file mode 100644 index 000000000..6b25c2849 --- /dev/null +++ b/exercises/practice/prism/Prism.cs @@ -0,0 +1,11 @@ +public static class Prism +{ + public readonly record struct LaserInfo(double X, double Y, double Angle); + + public readonly record struct PrismInfo(int Id, double X, double Y, double Angle); + + public static int[] FindSequence(LaserInfo laser, PrismInfo[] prisms) + { + throw new NotImplementedException("You need to implement this method."); + } +} diff --git a/exercises/practice/prism/Prism.csproj b/exercises/practice/prism/Prism.csproj new file mode 100644 index 000000000..b03c847b8 --- /dev/null +++ b/exercises/practice/prism/Prism.csproj @@ -0,0 +1,23 @@ + + + + net10.0 + Exe + enable + enable + true + Exercism + + + + + + + + + + + + + + diff --git a/exercises/practice/prism/PrismTests.cs b/exercises/practice/prism/PrismTests.cs new file mode 100644 index 000000000..b93fd4105 --- /dev/null +++ b/exercises/practice/prism/PrismTests.cs @@ -0,0 +1,293 @@ +public class PrismTests +{ + [Fact] + public void Zero_prisms() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = []; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void One_prism_one_hit() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(1, 10, 0, 0) + ]; + int[] expected = [1]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void One_prism_zero_hits() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(1, -10, 0, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Going_up_zero_hits() + { + Prism.LaserInfo laser = new(0, 0, 90); + Prism.PrismInfo[] prisms = + [ + new(3, 0, -10, 0), + new(1, -10, 0, 0), + new(2, 10, 0, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Going_down_zero_hits() + { + Prism.LaserInfo laser = new(0, 0, -90); + Prism.PrismInfo[] prisms = + [ + new(1, 10, 0, 0), + new(2, 0, 10, 0), + new(3, -10, 0, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Going_left_zero_hits() + { + Prism.LaserInfo laser = new(0, 0, 180); + Prism.PrismInfo[] prisms = + [ + new(2, 0, 10, 0), + new(3, 10, 0, 0), + new(1, 0, -10, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Negative_angle() + { + Prism.LaserInfo laser = new(0, 0, -180); + Prism.PrismInfo[] prisms = + [ + new(1, 0, -10, 0), + new(2, 0, 10, 0), + new(3, 10, 0, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Large_angle() + { + Prism.LaserInfo laser = new(0, 0, 2340); + Prism.PrismInfo[] prisms = + [ + new(1, 10, 0, 0) + ]; + int[] expected = []; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Upward_refraction_two_hits() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(1, 10, 10, 0), + new(2, 10, 0, 90) + ]; + int[] expected = [2, 1]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Downward_refraction_two_hits() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(1, 10, 0, -90), + new(2, 10, -10, 0) + ]; + int[] expected = [1, 2]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Same_prism_twice() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(2, 10, 0, 0), + new(1, 20, 0, -180) + ]; + int[] expected = [2, 1, 2]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Simple_path() + { + Prism.LaserInfo laser = new(0, 0, 0); + Prism.PrismInfo[] prisms = + [ + new(3, 30, 10, 45), + new(1, 10, 10, -90), + new(2, 10, 0, 90), + new(4, 20, 0, 0) + ]; + int[] expected = [2, 1, 3]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Multiple_prisms_floating_point_precision() + { + Prism.LaserInfo laser = new(0, 0, -6.429); + Prism.PrismInfo[] prisms = + [ + new(26, 5.8, 73.4, 6.555), + new(24, 36.2, 65.2, -0.304), + new(20, 20.4, 82.8, 45.17), + new(31, -20.2, 48.8, 30.615), + new(30, 24.0, 0.6, 28.771), + new(29, 31.4, 79.4, 61.327), + new(28, 36.4, 31.4, -18.157), + new(22, 47.0, 57.8, 54.745), + new(38, 36.4, 79.2, 49.05), + new(10, 37.8, 55.2, 11.978), + new(18, -26.0, 42.6, 22.661), + new(25, 38.8, 76.2, 51.958), + new(2, 0.0, 42.4, -21.817), + new(35, 21.4, 44.8, -171.579), + new(7, 14.2, -1.6, 19.081), + new(33, 11.2, 44.4, -165.941), + new(11, 15.4, 82.6, 66.262), + new(16, 30.8, 6.6, 35.852), + new(15, -3.0, 79.2, 53.782), + new(4, 29.0, 75.4, 17.016), + new(23, 41.6, 59.8, 70.763), + new(8, -10.0, 15.8, -9.24), + new(13, 48.6, 51.8, 45.812), + new(1, 13.2, 77.0, 17.937), + new(34, -8.8, 36.8, -4.199), + new(21, 24.4, 75.8, 20.783), + new(17, -4.4, 74.6, 24.709), + new(9, 30.8, 41.8, -165.413), + new(32, 4.2, 78.6, 40.892), + new(37, -15.8, 47.0, 33.29), + new(6, 1.0, 80.6, 51.295), + new(36, -27.0, 47.8, 92.52), + new(14, -2.0, 34.4, -52.001), + new(5, 23.2, 80.2, 31.866), + new(27, -5.6, 32.8, -75.303), + new(12, -1.0, 0.2, 0.0), + new(3, -6.6, 3.2, 46.72), + new(19, -13.8, 24.2, -9.205) + ]; + int[] expected = [7, 30, 16, 28, 13, 22, 23, 10, 9, 24, 25, 38, 29, 4, 35, 21, 5, 20, 11, 1, 33, 26, 32, 6, 15, 17, 2, 14, 27, 34, 37, 31, 36, 18, 19, 8, 3, 12]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } + + [Fact(Skip = "Remove this Skip property to run this test")] + public void Complex_path_with_multiple_prisms_floating_point_precision() + { + Prism.LaserInfo laser = new(0, 0, 0.0); + Prism.PrismInfo[] prisms = + [ + new(46, 37.4, 20.6, -88.332), + new(72, -24.2, 23.4, -90.774), + new(25, 78.6, 7.8, 98.562), + new(60, -58.8, 31.6, 115.56), + new(22, 75.2, 28.0, 63.515), + new(2, 89.8, 27.8, 91.176), + new(23, 9.8, 30.8, 30.829), + new(69, 22.8, 20.6, -88.315), + new(44, -0.8, 15.6, -116.565), + new(36, -24.2, 8.2, -90.0), + new(53, -1.2, 0.0, 0.0), + new(52, 14.2, 24.0, -143.896), + new(5, -65.2, 21.6, 93.128), + new(66, 5.4, 15.6, 31.608), + new(51, -72.6, 21.0, -100.976), + new(65, 48.0, 10.2, 87.455), + new(21, -41.8, 0.0, 68.352), + new(18, -46.2, 19.2, -128.362), + new(10, 74.4, 0.4, 90.939), + new(15, 67.6, 0.4, 84.958), + new(35, 14.8, -0.4, 89.176), + new(1, 83.0, 0.2, 89.105), + new(68, 14.6, 28.0, -29.867), + new(67, 79.8, 18.6, -136.643), + new(38, 53.0, 14.6, -90.848), + new(31, -58.0, 6.6, -61.837), + new(74, -30.8, 0.4, 85.966), + new(48, -4.6, 10.0, -161.222), + new(12, 59.0, 5.0, -91.164), + new(33, -16.4, 18.4, 90.734), + new(4, 82.6, 27.6, 71.127), + new(75, -10.2, 30.6, -1.108), + new(28, 38.0, 0.0, 86.863), + new(11, 64.4, -0.2, 92.353), + new(9, -51.4, 31.6, 67.249), + new(26, -39.8, 30.8, 61.113), + new(30, -34.2, 0.6, 111.33), + new(56, -51.0, 0.2, 70.445), + new(41, -12.0, 0.0, 91.219), + new(24, 63.8, 14.4, 86.586), + new(70, -72.8, 13.4, -87.238), + new(3, 22.4, 7.0, -91.685), + new(13, 34.4, 7.0, 90.0), + new(16, -47.4, 11.4, -136.02), + new(6, 90.0, 0.2, 90.415), + new(54, 44.0, 27.8, 85.969), + new(32, -9.0, 0.0, 91.615), + new(8, -31.6, 30.8, 0.535), + new(39, -12.0, 8.2, 90.0), + new(14, -79.6, 32.4, 92.342), + new(42, 65.8, 20.8, -85.867), + new(40, -65.0, 14.0, 87.109), + new(45, 10.6, 18.8, 23.697), + new(71, -24.2, 18.6, -88.531), + new(7, -72.6, 6.4, -89.148), + new(62, -32.0, 24.8, -140.8), + new(49, 34.4, -0.2, 89.415), + new(63, 74.2, 12.6, -138.429), + new(59, 82.8, 13.0, -140.177), + new(34, -9.4, 23.2, -88.238), + new(76, -57.6, 0.0, 1.2), + new(43, 7.0, 0.0, 116.565), + new(20, 45.8, -0.2, 1.469), + new(37, -16.6, 13.2, 84.785), + new(58, -79.0, -0.2, 89.481), + new(50, -24.2, 12.8, -86.987), + new(64, 59.2, 10.2, -92.203), + new(61, -72.0, 26.4, -83.66), + new(47, 45.4, 5.8, -82.992), + new(17, -52.2, 17.8, -52.938), + new(57, -61.8, 32.0, 84.627), + new(29, 47.2, 28.2, 92.954), + new(27, -4.6, 0.2, 87.397), + new(55, -61.4, 26.4, 94.086), + new(73, -40.4, 13.4, -62.229), + new(19, 53.2, 20.6, -87.181) + ]; + int[] expected = [43, 44, 66, 45, 52, 35, 49, 13, 3, 69, 46, 28, 20, 11, 24, 38, 19, 42, 15, 10, 63, 25, 59, 1, 6, 2, 4, 67, 22, 29, 65, 64, 12, 47, 54, 68, 23, 75, 8, 26, 18, 9, 60, 17, 31, 7, 70, 40, 5, 51, 61, 55, 57, 14, 58, 76, 56, 16, 21, 30, 73, 62, 74, 41, 39, 36, 50, 37, 33, 71, 72, 34, 32, 27, 48, 53]; + Assert.Equal(expected, Prism.FindSequence(laser, prisms)); + } +} diff --git a/exercises/practice/prism/packages.lock.json b/exercises/practice/prism/packages.lock.json new file mode 100644 index 000000000..376ba63d1 --- /dev/null +++ b/exercises/practice/prism/packages.lock.json @@ -0,0 +1,177 @@ +{ + "version": 1, + "dependencies": { + "net10.0": { + "Exercism.Tests.xunit.v3": { + "type": "Direct", + "requested": "[0.1.0-beta1, )", + "resolved": "0.1.0-beta1", + "contentHash": "XjVtQWWxmHDDj7UMdkPKpBFFKnsW0tkBhlyJSfFFh+fWwGemyyJwJYhdsvWhiKKCY7zItB+mI/o0OQtOKQxUhA==", + "dependencies": { + "xunit.v3.extensibility.core": "1.1.0" + } + }, + "Microsoft.NET.Test.Sdk": { + "type": "Direct", + "requested": "[18.3.0, )", + "resolved": "18.3.0", + "contentHash": "xW3kXuWRQtgoxJp4J+gdhHSQyK+6Wb/AZDSd7lMvuMRYlZ1tnpkojyfZlWilB5G4dmZ0Y0ZxU/M23TlubndNkw==", + "dependencies": { + "Microsoft.CodeCoverage": "18.3.0", + "Microsoft.TestPlatform.TestHost": "18.3.0" + } + }, + "xunit.runner.visualstudio": { + "type": "Direct", + "requested": "[3.1.5, )", + "resolved": "3.1.5", + "contentHash": "tKi7dSTwP4m5m9eXPM2Ime4Kn7xNf4x4zT9sdLO/G4hZVnQCRiMTWoSZqI/pYTVeI27oPPqHBKYI/DjJ9GsYgA==" + }, + "xunit.v3": { + "type": "Direct", + "requested": "[3.2.2, )", + "resolved": "3.2.2", + "contentHash": "L+4/4y0Uqcg8/d6hfnxhnwh4j9FaeULvefTwrk30rr1o4n/vdPfyUQ8k0yzH8VJx7bmFEkDdcRfbtbjEHlaYcA==", + "dependencies": { + "xunit.v3.mtp-v1": "[3.2.2]" + } + }, + "Microsoft.ApplicationInsights": { + "type": "Transitive", + "resolved": "2.23.0", + "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw==" + }, + "Microsoft.Bcl.AsyncInterfaces": { + "type": "Transitive", + "resolved": "6.0.0", + "contentHash": "UcSjPsst+DfAdJGVDsu346FX0ci0ah+lw3WRtn18NUwEqRt70HaOQ7lI72vy3+1LxtqI3T5GWwV39rQSrCzAeg==" + }, + "Microsoft.CodeCoverage": { + "type": "Transitive", + "resolved": "18.3.0", + "contentHash": "23BNy/vziREC20Wwhb50K7+kZe0m07KlLWDQv4qjJ9tt3QjpDpDIqJFrhYHmMEo9xDkuSp55U/8h4bMF7MiB+g==" + }, + "Microsoft.Testing.Extensions.Telemetry": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "No5AudZMmSb+uNXjlgL2y3/stHD2IT4uxqc5yHwkE+/nNux9jbKcaJMvcp9SwgP4DVD8L9/P3OUz8mmmcvEIdQ==", + "dependencies": { + "Microsoft.ApplicationInsights": "2.23.0", + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.Testing.Extensions.TrxReport.Abstractions": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "AL46Xe1WBi85Ntd4mNPvat5ZSsZ2uejiVqoKCypr8J3wK0elA5xJ3AN4G/Q4GIwzUFnggZoH/DBjnr9J18IO/g==", + "dependencies": { + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.Testing.Platform": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "QafNtNSmEI0zazdebnsIkDKmFtTSpmx/5PLOjURWwozcPb3tvRxzosQSL8xwYNM1iPhhKiBksXZyRSE2COisrA==" + }, + "Microsoft.Testing.Platform.MSBuild": { + "type": "Transitive", + "resolved": "1.9.1", + "contentHash": "oTUtyR4X/s9ytuiNA29FGsNCCH0rNmY5Wdm14NCKLjTM1cT9edVSlA+rGS/mVmusPqcP0l/x9qOnMXg16v87RQ==", + "dependencies": { + "Microsoft.Testing.Platform": "1.9.1" + } + }, + "Microsoft.TestPlatform.ObjectModel": { + "type": "Transitive", + "resolved": "18.3.0", + "contentHash": "AEIEX2aWdPO9XbtR96eBaJxmXRD9vaI9uQ1T/JbPEKlTAZwYx0ZrMzKyULMdh/HH9Sg03kXCoN7LszQ90o6nPQ==" + }, + "Microsoft.TestPlatform.TestHost": { + "type": "Transitive", + "resolved": "18.3.0", + "contentHash": "twmsoelXnp1uWMU3VGip9f0Jr1mZ0PZqgJdF35CIrdYgYrkHIJMV1m8uKyhcdjLdsQDESHAgkR7KhS9i1qpJag==", + "dependencies": { + "Microsoft.TestPlatform.ObjectModel": "18.3.0", + "Newtonsoft.Json": "13.0.3" + } + }, + "Microsoft.Win32.Registry": { + "type": "Transitive", + "resolved": "5.0.0", + "contentHash": "dDoKi0PnDz31yAyETfRntsLArTlVAVzUzCIvvEDsDsucrl33Dl8pIJG06ePTJTI3tGpeyHS9Cq7Foc/s4EeKcg==" + }, + "Newtonsoft.Json": { + "type": "Transitive", + "resolved": "13.0.3", + "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ==" + }, + "xunit.analyzers": { + "type": "Transitive", + "resolved": "1.27.0", + "contentHash": "y/pxIQaLvk/kxAoDkZW9GnHLCEqzwl5TW0vtX3pweyQpjizB9y3DXhb9pkw2dGeUqhLjsxvvJM1k89JowU6z3g==" + }, + "xunit.v3.assert": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "BPciBghgEEaJN/JG00QfCYDfEfnLgQhfnYEy+j1izoeHVNYd5+3Wm8GJ6JgYysOhpBPYGE+sbf75JtrRc7jrdA==" + }, + "xunit.v3.common": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "Hj775PEH6GTbbg0wfKRvG2hNspDCvTH9irXhH4qIWgdrOSV1sQlqPie+DOvFeigsFg2fxSM3ZAaaCDQs+KreFA==", + "dependencies": { + "Microsoft.Bcl.AsyncInterfaces": "6.0.0" + } + }, + "xunit.v3.core.mtp-v1": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "Ga5aA2Ca9ktz+5k3g5ukzwfexwoqwDUpV6z7atSEUvqtd6JuybU1XopHqg1oFd78QdTfZgZE9h5sHpO4qYIi5w==", + "dependencies": { + "Microsoft.Testing.Extensions.Telemetry": "1.9.1", + "Microsoft.Testing.Extensions.TrxReport.Abstractions": "1.9.1", + "Microsoft.Testing.Platform": "1.9.1", + "Microsoft.Testing.Platform.MSBuild": "1.9.1", + "xunit.v3.extensibility.core": "[3.2.2]", + "xunit.v3.runner.inproc.console": "[3.2.2]" + } + }, + "xunit.v3.extensibility.core": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "srY8z/oMPvh/t8axtO2DwrHajhFMH7tnqKildvYrVQIfICi8fOn3yIBWkVPAcrKmHMwvXRJ/XsQM3VMR6DOYfQ==", + "dependencies": { + "xunit.v3.common": "[3.2.2]" + } + }, + "xunit.v3.mtp-v1": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "O41aAzYKBT5PWqATa1oEWVNCyEUypFQ4va6K0kz37dduV3EKzXNMaV2UnEhufzU4Cce1I33gg0oldS8tGL5I0A==", + "dependencies": { + "xunit.analyzers": "1.27.0", + "xunit.v3.assert": "[3.2.2]", + "xunit.v3.core.mtp-v1": "[3.2.2]" + } + }, + "xunit.v3.runner.common": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "/hkHkQCzGrugelOAehprm7RIWdsUFVmIVaD6jDH/8DNGCymTlKKPTbGokD5czbAfqfex47mBP0sb0zbHYwrO/g==", + "dependencies": { + "Microsoft.Win32.Registry": "[5.0.0]", + "xunit.v3.common": "[3.2.2]" + } + }, + "xunit.v3.runner.inproc.console": { + "type": "Transitive", + "resolved": "3.2.2", + "contentHash": "ulWOdSvCk+bPXijJZ73bth9NyoOHsAs1ZOvamYbCkD4DNLX/Bd29Ve2ZNUwBbK0MqfIYWXHZViy/HKrdEC/izw==", + "dependencies": { + "xunit.v3.extensibility.core": "[3.2.2]", + "xunit.v3.runner.common": "[3.2.2]" + } + } + } + } +} \ No newline at end of file