diff --git a/config.json b/config.json index 3f4ad36bfb..90c064066b 100644 --- a/config.json +++ b/config.json @@ -2596,6 +2596,21 @@ "logic" ] }, + { + "slug": "prism", + "name": "Prism", + "uuid": "ef463b82-bf5c-4761-a821-29eeabee3050", + "practices": [], + "prerequisites": [ + "arithmetic-operators", + "arrays", + "array-loops", + "comparison", + "conditionals", + "for-loops" + ], + "difficulty": 5 + }, { "slug": "satellite", "name": "Satellite", diff --git a/exercises/practice/prism/.docs/instructions.md b/exercises/practice/prism/.docs/instructions.md new file mode 100644 index 0000000000..a68c80defd --- /dev/null +++ b/exercises/practice/prism/.docs/instructions.md @@ -0,0 +1,36 @@ +# 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": 3, "x": 30, "y": 10, "angle": 45 }, + { "id": 1, "x": 10, "y": 10, "angle": -90 }, + { "id": 2, "x": 10, "y": 0, "angle": 90 }, + { "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. diff --git a/exercises/practice/prism/.docs/introduction.md b/exercises/practice/prism/.docs/introduction.md new file mode 100644 index 0000000000..bfa7ed72e4 --- /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/.gitignore b/exercises/practice/prism/.gitignore new file mode 100644 index 0000000000..0c88ff6ec3 --- /dev/null +++ b/exercises/practice/prism/.gitignore @@ -0,0 +1,5 @@ +/node_modules +/bin/configlet +/bin/configlet.exe +/package-lock.json +/yarn.lock diff --git a/exercises/practice/prism/.meta/config.json b/exercises/practice/prism/.meta/config.json new file mode 100644 index 0000000000..31c9ad08f8 --- /dev/null +++ b/exercises/practice/prism/.meta/config.json @@ -0,0 +1,25 @@ +{ + "authors": [ + "BNAndras" + ], + "files": { + "solution": [ + "prism.js" + ], + "test": [ + "prism.spec.js" + ], + "example": [ + ".meta/proof.ci.js" + ] + }, + "blurb": "Calculate the path of a laser through reflective prisms.", + "source": "FraSanga", + "source_url": "https://github.com/exercism/problem-specifications/pull/2625", + "custom": { + "version.tests.compatibility": "jest-27", + "flag.tests.task-per-describe": false, + "flag.tests.may-run-long": false, + "flag.tests.includes-optional": false + } +} diff --git a/exercises/practice/prism/.meta/proof.ci.js b/exercises/practice/prism/.meta/proof.ci.js new file mode 100644 index 0000000000..d327e18496 --- /dev/null +++ b/exercises/practice/prism/.meta/proof.ci.js @@ -0,0 +1,41 @@ +export const findSequence = (start, prisms) => { + let { x, y, angle } = start; + const sequence = []; + + while (true) { + const rad = (angle * Math.PI) / 180; + const dirX = Math.cos(rad); + const dirY = Math.sin(rad); + + let nearest = null; + let nearestDist = Infinity; + + for (const prism of prisms) { + const dx = prism.x - x; + const dy = prism.y - y; + + const dist = dx * dirX + dy * dirY; + const baseTolerance = 1e-6; + if (dist <= baseTolerance) continue; + + const crossProductSquared = + (dx - dist * dirX) ** 2 + (dy - dist * dirY) ** 2; + const relativeTolerance = baseTolerance * Math.max(1, dist * dist); + if (crossProductSquared >= relativeTolerance) continue; + + if (dist < nearestDist) { + nearestDist = dist; + nearest = prism; + } + } + + if (!nearest) break; + + sequence.push(nearest.id); + x = nearest.x; + y = nearest.y; + angle = (angle + nearest.angle) % 360; + } + + return sequence; +}; diff --git a/exercises/practice/prism/.meta/tests.toml b/exercises/practice/prism/.meta/tests.toml new file mode 100644 index 0000000000..b00222383a --- /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/.npmrc b/exercises/practice/prism/.npmrc new file mode 100644 index 0000000000..d26df800bb --- /dev/null +++ b/exercises/practice/prism/.npmrc @@ -0,0 +1 @@ +audit=false diff --git a/exercises/practice/prism/LICENSE b/exercises/practice/prism/LICENSE new file mode 100644 index 0000000000..90e73be03b --- /dev/null +++ b/exercises/practice/prism/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Exercism + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/exercises/practice/prism/babel.config.js b/exercises/practice/prism/babel.config.js new file mode 100644 index 0000000000..a638497df1 --- /dev/null +++ b/exercises/practice/prism/babel.config.js @@ -0,0 +1,4 @@ +module.exports = { + presets: [['@exercism/babel-preset-javascript', { corejs: '3.40' }]], + plugins: [], +}; diff --git a/exercises/practice/prism/eslint.config.mjs b/exercises/practice/prism/eslint.config.mjs new file mode 100644 index 0000000000..ca517111ed --- /dev/null +++ b/exercises/practice/prism/eslint.config.mjs @@ -0,0 +1,45 @@ +// @ts-check + +import config from '@exercism/eslint-config-javascript'; +import maintainersConfig from '@exercism/eslint-config-javascript/maintainers.mjs'; + +import globals from 'globals'; + +export default [ + ...config, + ...maintainersConfig, + { + files: maintainersConfig[1].files, + rules: { + 'jest/expect-expect': ['warn', { assertFunctionNames: ['expect*'] }], + }, + }, + { + files: ['scripts/**/*.mjs'], + languageOptions: { + globals: { + ...globals.node, + }, + }, + }, + // <> + { + ignores: [ + // # Protected or generated + '/.appends/**/*', + '/.github/**/*', + '/.vscode/**/*', + + // # Binaries + '/bin/*', + + // # Configuration + '/config', + '/babel.config.js', + + // # Typings + '/exercises/**/global.d.ts', + '/exercises/**/env.d.ts', + ], + }, +]; diff --git a/exercises/practice/prism/jest.config.js b/exercises/practice/prism/jest.config.js new file mode 100644 index 0000000000..ec8e908127 --- /dev/null +++ b/exercises/practice/prism/jest.config.js @@ -0,0 +1,22 @@ +module.exports = { + verbose: true, + projects: [''], + testMatch: [ + '**/__tests__/**/*.[jt]s?(x)', + '**/test/**/*.[jt]s?(x)', + '**/?(*.)+(spec|test).[jt]s?(x)', + ], + testPathIgnorePatterns: [ + '/(?:production_)?node_modules/', + '.d.ts$', + '/test/fixtures', + '/test/helpers', + '__mocks__', + ], + transform: { + '^.+\\.[jt]sx?$': 'babel-jest', + }, + moduleNameMapper: { + '^(\\.\\/.+)\\.js$': '$1', + }, +}; diff --git a/exercises/practice/prism/package.json b/exercises/practice/prism/package.json new file mode 100644 index 0000000000..7750c52c42 --- /dev/null +++ b/exercises/practice/prism/package.json @@ -0,0 +1,34 @@ +{ + "name": "@exercism/javascript-prism", + "description": "Exercism exercises in Javascript.", + "author": "Katrina Owen", + "private": true, + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/exercism/javascript", + "directory": "exercises/practice/prism" + }, + "devDependencies": { + "@exercism/babel-preset-javascript": "^0.5.1", + "@exercism/eslint-config-javascript": "^0.8.1", + "@jest/globals": "^29.7.0", + "@types/node": "^24.3.0", + "@types/shelljs": "^0.8.17", + "babel-jest": "^29.7.0", + "core-js": "~3.42.0", + "diff": "^8.0.2", + "eslint": "^9.28.0", + "expect": "^29.7.0", + "globals": "^16.3.0", + "jest": "^29.7.0" + }, + "dependencies": {}, + "scripts": { + "lint": "corepack pnpm eslint .", + "test": "corepack pnpm jest", + "watch": "corepack pnpm jest --watch", + "format": "corepack pnpm prettier -w ." + }, + "packageManager": "pnpm@9.15.2" +} diff --git a/exercises/practice/prism/prism.js b/exercises/practice/prism/prism.js new file mode 100644 index 0000000000..3a0dbdea69 --- /dev/null +++ b/exercises/practice/prism/prism.js @@ -0,0 +1,8 @@ +// +// This is only a SKELETON file for the 'Prism' exercise. It's been provided as a +// convenience to get you started writing code faster. +// + +export const findSequence = () => { + throw new Error('Remove this line and implement the function'); +}; diff --git a/exercises/practice/prism/prism.spec.js b/exercises/practice/prism/prism.spec.js new file mode 100644 index 0000000000..7b5c504f01 --- /dev/null +++ b/exercises/practice/prism/prism.spec.js @@ -0,0 +1,270 @@ +import { describe, expect, test, xtest } from '@jest/globals'; +import { findSequence } from './prism'; + +describe('Prism', () => { + test('zero prisms', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = []; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('one prism one hit', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [{ id: 1, x: 10, y: 0, angle: 0 }]; + const result = findSequence(start, prisms); + const expected = [1]; + expect(result).toEqual(expected); + }); + + xtest('one prism zero hits', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [{ id: 1, x: -10, y: 0, angle: 0 }]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('going up zero hits', () => { + const start = { x: 0, y: 0, angle: 90 }; + const prisms = [ + { id: 3, x: 0, y: -10, angle: 0 }, + { id: 1, x: -10, y: 0, angle: 0 }, + { id: 2, x: 10, y: 0, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('going down zero hits', () => { + const start = { x: 0, y: 0, angle: -90 }; + const prisms = [ + { id: 1, x: 10, y: 0, angle: 0 }, + { id: 2, x: 0, y: 10, angle: 0 }, + { id: 3, x: -10, y: 0, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('going left zero hits', () => { + const start = { x: 0, y: 0, angle: 180 }; + const prisms = [ + { id: 2, x: 0, y: 10, angle: 0 }, + { id: 3, x: 10, y: 0, angle: 0 }, + { id: 1, x: 0, y: -10, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('negative angle', () => { + const start = { x: 0, y: 0, angle: -180 }; + const prisms = [ + { id: 1, x: 0, y: -10, angle: 0 }, + { id: 2, x: 0, y: 10, angle: 0 }, + { id: 3, x: 10, y: 0, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('large angle', () => { + const start = { x: 0, y: 0, angle: 2340 }; + const prisms = [{ id: 1, x: 10, y: 0, angle: 0 }]; + const result = findSequence(start, prisms); + const expected = []; + expect(result).toEqual(expected); + }); + + xtest('upward refraction two hits', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [ + { id: 1, x: 10, y: 10, angle: 0 }, + { id: 2, x: 10, y: 0, angle: 90 }, + ]; + const result = findSequence(start, prisms); + const expected = [2, 1]; + expect(result).toEqual(expected); + }); + + xtest('downward refraction two hits', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [ + { id: 1, x: 10, y: 0, angle: -90 }, + { id: 2, x: 10, y: -10, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = [1, 2]; + expect(result).toEqual(expected); + }); + + xtest('same prism twice', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [ + { id: 2, x: 10, y: 0, angle: 0 }, + { id: 1, x: 20, y: 0, angle: -180 }, + ]; + const result = findSequence(start, prisms); + const expected = [2, 1, 2]; + expect(result).toEqual(expected); + }); + + xtest('simple path', () => { + const start = { x: 0, y: 0, angle: 0 }; + const prisms = [ + { id: 3, x: 30, y: 10, angle: 45 }, + { id: 1, x: 10, y: 10, angle: -90 }, + { id: 2, x: 10, y: 0, angle: 90 }, + { id: 4, x: 20, y: 0, angle: 0 }, + ]; + const result = findSequence(start, prisms); + const expected = [2, 1, 3]; + expect(result).toEqual(expected); + }); + + xtest('multiple prisms floating point precision', () => { + const start = { x: 0, y: 0, angle: -6.429 }; + const prisms = [ + { id: 26, x: 5.8, y: 73.4, angle: 6.555 }, + { id: 24, x: 36.2, y: 65.2, angle: -0.304 }, + { id: 20, x: 20.4, y: 82.8, angle: 45.17 }, + { id: 31, x: -20.2, y: 48.8, angle: 30.615 }, + { id: 30, x: 24.0, y: 0.6, angle: 28.771 }, + { id: 29, x: 31.4, y: 79.4, angle: 61.327 }, + { id: 28, x: 36.4, y: 31.4, angle: -18.157 }, + { id: 22, x: 47.0, y: 57.8, angle: 54.745 }, + { id: 38, x: 36.4, y: 79.2, angle: 49.05 }, + { id: 10, x: 37.8, y: 55.2, angle: 11.978 }, + { id: 18, x: -26.0, y: 42.6, angle: 22.661 }, + { id: 25, x: 38.8, y: 76.2, angle: 51.958 }, + { id: 2, x: 0.0, y: 42.4, angle: -21.817 }, + { id: 35, x: 21.4, y: 44.8, angle: -171.579 }, + { id: 7, x: 14.2, y: -1.6, angle: 19.081 }, + { id: 33, x: 11.2, y: 44.4, angle: -165.941 }, + { id: 11, x: 15.4, y: 82.6, angle: 66.262 }, + { id: 16, x: 30.8, y: 6.6, angle: 35.852 }, + { id: 15, x: -3.0, y: 79.2, angle: 53.782 }, + { id: 4, x: 29.0, y: 75.4, angle: 17.016 }, + { id: 23, x: 41.6, y: 59.8, angle: 70.763 }, + { id: 8, x: -10.0, y: 15.8, angle: -9.24 }, + { id: 13, x: 48.6, y: 51.8, angle: 45.812 }, + { id: 1, x: 13.2, y: 77.0, angle: 17.937 }, + { id: 34, x: -8.8, y: 36.8, angle: -4.199 }, + { id: 21, x: 24.4, y: 75.8, angle: 20.783 }, + { id: 17, x: -4.4, y: 74.6, angle: 24.709 }, + { id: 9, x: 30.8, y: 41.8, angle: -165.413 }, + { id: 32, x: 4.2, y: 78.6, angle: 40.892 }, + { id: 37, x: -15.8, y: 47.0, angle: 33.29 }, + { id: 6, x: 1.0, y: 80.6, angle: 51.295 }, + { id: 36, x: -27.0, y: 47.8, angle: 92.52 }, + { id: 14, x: -2.0, y: 34.4, angle: -52.001 }, + { id: 5, x: 23.2, y: 80.2, angle: 31.866 }, + { id: 27, x: -5.6, y: 32.8, angle: -75.303 }, + { id: 12, x: -1.0, y: 0.2, angle: 0.0 }, + { id: 3, x: -6.6, y: 3.2, angle: 46.72 }, + { id: 19, x: -13.8, y: 24.2, angle: -9.205 }, + ]; + const result = findSequence(start, prisms); + const 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, + ]; + expect(result).toEqual(expected); + }); + + xtest('complex path with multiple prisms floating point precision', () => { + const start = { x: 0, y: 0, angle: 0.0 }; + const prisms = [ + { id: 46, x: 37.4, y: 20.6, angle: -88.332 }, + { id: 72, x: -24.2, y: 23.4, angle: -90.774 }, + { id: 25, x: 78.6, y: 7.8, angle: 98.562 }, + { id: 60, x: -58.8, y: 31.6, angle: 115.56 }, + { id: 22, x: 75.2, y: 28.0, angle: 63.515 }, + { id: 2, x: 89.8, y: 27.8, angle: 91.176 }, + { id: 23, x: 9.8, y: 30.8, angle: 30.829 }, + { id: 69, x: 22.8, y: 20.6, angle: -88.315 }, + { id: 44, x: -0.8, y: 15.6, angle: -116.565 }, + { id: 36, x: -24.2, y: 8.2, angle: -90.0 }, + { id: 53, x: -1.2, y: 0.0, angle: 0.0 }, + { id: 52, x: 14.2, y: 24.0, angle: -143.896 }, + { id: 5, x: -65.2, y: 21.6, angle: 93.128 }, + { id: 66, x: 5.4, y: 15.6, angle: 31.608 }, + { id: 51, x: -72.6, y: 21.0, angle: -100.976 }, + { id: 65, x: 48.0, y: 10.2, angle: 87.455 }, + { id: 21, x: -41.8, y: 0.0, angle: 68.352 }, + { id: 18, x: -46.2, y: 19.2, angle: -128.362 }, + { id: 10, x: 74.4, y: 0.4, angle: 90.939 }, + { id: 15, x: 67.6, y: 0.4, angle: 84.958 }, + { id: 35, x: 14.8, y: -0.4, angle: 89.176 }, + { id: 1, x: 83.0, y: 0.2, angle: 89.105 }, + { id: 68, x: 14.6, y: 28.0, angle: -29.867 }, + { id: 67, x: 79.8, y: 18.6, angle: -136.643 }, + { id: 38, x: 53.0, y: 14.6, angle: -90.848 }, + { id: 31, x: -58.0, y: 6.6, angle: -61.837 }, + { id: 74, x: -30.8, y: 0.4, angle: 85.966 }, + { id: 48, x: -4.6, y: 10.0, angle: -161.222 }, + { id: 12, x: 59.0, y: 5.0, angle: -91.164 }, + { id: 33, x: -16.4, y: 18.4, angle: 90.734 }, + { id: 4, x: 82.6, y: 27.6, angle: 71.127 }, + { id: 75, x: -10.2, y: 30.6, angle: -1.108 }, + { id: 28, x: 38.0, y: 0.0, angle: 86.863 }, + { id: 11, x: 64.4, y: -0.2, angle: 92.353 }, + { id: 9, x: -51.4, y: 31.6, angle: 67.249 }, + { id: 26, x: -39.8, y: 30.8, angle: 61.113 }, + { id: 30, x: -34.2, y: 0.6, angle: 111.33 }, + { id: 56, x: -51.0, y: 0.2, angle: 70.445 }, + { id: 41, x: -12.0, y: 0.0, angle: 91.219 }, + { id: 24, x: 63.8, y: 14.4, angle: 86.586 }, + { id: 70, x: -72.8, y: 13.4, angle: -87.238 }, + { id: 3, x: 22.4, y: 7.0, angle: -91.685 }, + { id: 13, x: 34.4, y: 7.0, angle: 90.0 }, + { id: 16, x: -47.4, y: 11.4, angle: -136.02 }, + { id: 6, x: 90.0, y: 0.2, angle: 90.415 }, + { id: 54, x: 44.0, y: 27.8, angle: 85.969 }, + { id: 32, x: -9.0, y: 0.0, angle: 91.615 }, + { id: 8, x: -31.6, y: 30.8, angle: 0.535 }, + { id: 39, x: -12.0, y: 8.2, angle: 90.0 }, + { id: 14, x: -79.6, y: 32.4, angle: 92.342 }, + { id: 42, x: 65.8, y: 20.8, angle: -85.867 }, + { id: 40, x: -65.0, y: 14.0, angle: 87.109 }, + { id: 45, x: 10.6, y: 18.8, angle: 23.697 }, + { id: 71, x: -24.2, y: 18.6, angle: -88.531 }, + { id: 7, x: -72.6, y: 6.4, angle: -89.148 }, + { id: 62, x: -32.0, y: 24.8, angle: -140.8 }, + { id: 49, x: 34.4, y: -0.2, angle: 89.415 }, + { id: 63, x: 74.2, y: 12.6, angle: -138.429 }, + { id: 59, x: 82.8, y: 13.0, angle: -140.177 }, + { id: 34, x: -9.4, y: 23.2, angle: -88.238 }, + { id: 76, x: -57.6, y: 0.0, angle: 1.2 }, + { id: 43, x: 7.0, y: 0.0, angle: 116.565 }, + { id: 20, x: 45.8, y: -0.2, angle: 1.469 }, + { id: 37, x: -16.6, y: 13.2, angle: 84.785 }, + { id: 58, x: -79.0, y: -0.2, angle: 89.481 }, + { id: 50, x: -24.2, y: 12.8, angle: -86.987 }, + { id: 64, x: 59.2, y: 10.2, angle: -92.203 }, + { id: 61, x: -72.0, y: 26.4, angle: -83.66 }, + { id: 47, x: 45.4, y: 5.8, angle: -82.992 }, + { id: 17, x: -52.2, y: 17.8, angle: -52.938 }, + { id: 57, x: -61.8, y: 32.0, angle: 84.627 }, + { id: 29, x: 47.2, y: 28.2, angle: 92.954 }, + { id: 27, x: -4.6, y: 0.2, angle: 87.397 }, + { id: 55, x: -61.4, y: 26.4, angle: 94.086 }, + { id: 73, x: -40.4, y: 13.4, angle: -62.229 }, + { id: 19, x: 53.2, y: 20.6, angle: -87.181 }, + ]; + const result = findSequence(start, prisms); + const 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, + ]; + expect(result).toEqual(expected); + }); +});