From 93a7aeaa818e478680aeab695e1fed6b496d4351 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 13 Dec 2019 10:52:33 -0800 Subject: [PATCH 1/9] test(2019-day-03): tests for wire crossings --- 2019/day-03/wires.test.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 2019/day-03/wires.test.js diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js new file mode 100644 index 0000000..6e225ba --- /dev/null +++ b/2019/day-03/wires.test.js @@ -0,0 +1,30 @@ +/* eslint-env mocha */ +const expect = require('chai').expect +const { elfWireToSVGPath, findWireIntersections } = require('./wires') + +describe('--- 2019 Day 3: Crossed Wires ---', () => { + describe('Part 1', () => { + describe('elfWiresToSVGPath()', () => { + it('converts elfwire syntax to svg path syntax', () => { + const wire = 'R75,D30,R83,U83,L12,D49,R71,U7,L72' + const expected = 'M0,0 h75 v30 h83 v-83 h-12 v49 h71 v-7 h-72' + const actual = elfWireToSVGPath(wire) + expect(actual).to.equal(expected) + }) + }) + describe('findWireIntersections()', () => { + it('finds the intersection points of multiple wires', () => { + const wires = [ + 'R8,U5,L5,D3', + 'U7,R6,D4' + ] + const expected = [ + [3, 3], + [6, 9] + ] + const actual = findWireIntersections(wires) + expect(actual).to.deep.equal(expected) + }) + }) + }) +}) From 020e93ffefa848ae45198bb696c9a4e6f5650a14 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 13 Dec 2019 10:53:58 -0800 Subject: [PATCH 2/9] test(2019-day-03): tests for closest wire intersection --- 2019/day-03/wires.test.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js index 6e225ba..8f0227e 100644 --- a/2019/day-03/wires.test.js +++ b/2019/day-03/wires.test.js @@ -1,6 +1,6 @@ /* eslint-env mocha */ const expect = require('chai').expect -const { elfWireToSVGPath, findWireIntersections } = require('./wires') +const { elfWireToSVGPath, findWireIntersections, getClosesetIntersection } = require('./wires') describe('--- 2019 Day 3: Crossed Wires ---', () => { describe('Part 1', () => { @@ -16,15 +16,29 @@ describe('--- 2019 Day 3: Crossed Wires ---', () => { it('finds the intersection points of multiple wires', () => { const wires = [ 'R8,U5,L5,D3', - 'U7,R6,D4' + 'U7,R6,D4,L4' ] const expected = [ - [3, 3], - [6, 9] + { x: 0, y: 0, distance: 0 }, + { x: 3, y: -3, distance: 6 }, + { x: 6, y: -5, distance: 11 } ] const actual = findWireIntersections(wires) expect(actual).to.deep.equal(expected) }) }) + describe('getClosestIntersection()', () => { + it('finds the closest intersection in a list of intersections', () => { + const intersections = [ + { x: 23, y: 45 }, + { x: 48, y: -10 }, + { x: 3, y: 3 }, + { x: 3, y: 3 } + ] + const expected = { x: 3, y: 3, distance: 6 } + const actual = getClosesetIntersection(intersections) + expect(actual).to.deep.equal(expected) + }) + }) }) }) From 5c567f689990a57d6ed5132c409f7b1f56a6c329 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 13 Dec 2019 10:59:22 -0800 Subject: [PATCH 3/9] feat(2019-day-03): utilities for finding wire intersections --- 2019/day-03/wires.js | 58 ++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 5 ++++ package.json | 4 +++ 3 files changed, 67 insertions(+) create mode 100644 2019/day-03/wires.js diff --git a/2019/day-03/wires.js b/2019/day-03/wires.js new file mode 100644 index 0000000..34721e8 --- /dev/null +++ b/2019/day-03/wires.js @@ -0,0 +1,58 @@ +const intersection = require('path-intersection') +const { distance } = require('../../2018/day-06/coordinates') // Manhattan distance function from last year + +const elfWireToSVGPath = (path) => { + const replacements = { + R: 'h', // R(ight) becomes relative positive horizontal lineto + L: 'h-', // L(eft) becomes relative negative horizontal lineto + U: 'v-', // U(p) becomes relative negative vertical line + D: 'v', // D(own) becomes relative positive vertical line + ',': ' ' // Separators are done with whitespace + } + path = path.trim() + + const pattern = new RegExp(Object.keys(replacements).join('|'), 'gi') + path = path.replace(pattern, (match) => { + return replacements[match] + }) + + return `M0,0 ${path}` +} + +const findWireIntersections = (wires) => { + wires = wires.map(elfWireToSVGPath) + const ints = intersection( + ...wires + ).map((point) => { + return { x: parseInt(point.x), y: parseInt(point.y) } + }) + + return ints.sort(isCloser) +} + +const isCloser = (intA, intB) => { + const origin = { x: 0, y: 0 } + intA.distance = distance(origin, intA) + intB.distance = distance(origin, intB) + if (intA.distance < intB.distance) { + return -1 + } + if (intA.distance > intB.distance) { + return 1 + } + if (intA.distance === intB.distance) { + return 0 + } +} + +const getClosesetIntersection = (intersections) => { + intersections.sort(isCloser) + // Skip the origin since all wires start at origin + return intersections[1] +} + +module.exports = { + elfWireToSVGPath, + findWireIntersections, + getClosesetIntersection +} diff --git a/package-lock.json b/package-lock.json index 3bc796e..b2be39e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7854,6 +7854,11 @@ "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", "dev": true }, + "path-intersection": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-intersection/-/path-intersection-2.0.1.tgz", + "integrity": "sha512-tvqxG1oZoq1q7QidC5REg6tafAA38X4VvB5ZLzPAl/nIoh05dmYegTJUwNXOyJ7D3Qk/rN6KsZrbSPAyHx/AiA==" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "http://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", diff --git a/package.json b/package.json index dacdf9a..7eee33d 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "private": true, "scripts": { + "start": "node index.js", "pretest": "npm run lint", "test": "nyc mocha \"./20*/**/*.test.js\"", "posttest": "nyc report --reporter=html --reporter=text-lcov > coverage.lcov", @@ -35,5 +36,8 @@ "nyc": "^14.1.1", "semantic-release": "^15.13.31", "standard": "^14.3.1" + }, + "dependencies": { + "path-intersection": "^2.0.1" } } From 5c169158df106e21e8849d93020e8a688aa9a3a9 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 13 Dec 2019 12:04:38 -0800 Subject: [PATCH 4/9] fix(2019-day-03): inconsistent wire intersection lists Shared origin of two wires does not consistently show up in the list of intersections when wires are longer and more complex. See https://github.com/bpmn-io/path-intersection/issues/10 --- 2019/day-03/wires.js | 12 ++++++++++-- 2019/day-03/wires.test.js | 15 +++++++++++++++ index.js | 2 +- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/2019/day-03/wires.js b/2019/day-03/wires.js index 34721e8..0c068d3 100644 --- a/2019/day-03/wires.js +++ b/2019/day-03/wires.js @@ -47,8 +47,16 @@ const isCloser = (intA, intB) => { const getClosesetIntersection = (intersections) => { intersections.sort(isCloser) - // Skip the origin since all wires start at origin - return intersections[1] + + // TODO: Remove workaround for bug in SVG intersection library + // https://github.com/bpmn-io/path-intersection/issues/10 + // + // The shared origin inconsistently shows up in the intersection list + if (parseInt(intersections[0].x) === 0 && parseInt(intersections[0].y) === 0) { + // Skip the shared origin since all wires start at origin + return intersections[1] + } + return intersections[0] } module.exports = { diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js index 8f0227e..f5cb959 100644 --- a/2019/day-03/wires.test.js +++ b/2019/day-03/wires.test.js @@ -40,5 +40,20 @@ describe('--- 2019 Day 3: Crossed Wires ---', () => { expect(actual).to.deep.equal(expected) }) }) + it('can be used to find the distance to the closest intersection', () => { + const wiresets = [ + [ + 'R75,D30,R83,U83,L12,D49,R71,U7,L72', + 'U62,R66,U55,R34,D71,R55,D58,R83' + ], [ + 'R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51', + 'U98,R91,D20,R16,D67,R40,U7,R15,U6,R7' + ] + ] + const distances = [159, 135] + wiresets.forEach((wires, idx) => { + expect(getClosesetIntersection(findWireIntersections(wires)).distance).to.equal(distances[idx]) + }) + }) }) }) diff --git a/index.js b/index.js index 8bc439d..0314d0a 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -require('./2019/day-02/solution') +require('./2019/day-03/solution') From 5df7932c44782376c77f1756b785c1486768a333 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 13 Dec 2019 12:05:56 -0800 Subject: [PATCH 5/9] feat(2019-day-03): solution for part one - find closest wire crossing --- 2019/day-03/input.txt | 2 ++ 2019/day-03/solution.js | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) create mode 100644 2019/day-03/input.txt create mode 100644 2019/day-03/solution.js diff --git a/2019/day-03/input.txt b/2019/day-03/input.txt new file mode 100644 index 0000000..4c3baef --- /dev/null +++ b/2019/day-03/input.txt @@ -0,0 +1,2 @@ +R1000,D940,L143,D182,L877,D709,L253,U248,L301,U434,R841,U715,R701,U92,R284,U115,R223,U702,R969,U184,L992,U47,L183,U474,L437,D769,L71,U96,R14,U503,R144,U432,R948,U96,L118,D696,R684,U539,L47,D851,L943,U606,L109,D884,R157,U946,R75,U702,L414,U347,R98,D517,L963,D177,R467,D142,L845,U427,R357,D528,L836,D222,L328,U504,R237,U99,L192,D147,L544,D466,R765,U845,L267,D217,L138,U182,R226,U466,R785,U989,R55,D822,L101,U292,R78,U962,R918,U218,L619,D324,L467,U885,L658,U890,L764,D747,R369,D930,L264,D916,L696,U698,R143,U537,L922,U131,R141,D97,L76,D883,R75,D657,R859,U503,R399,U33,L510,D318,L455,U128,R146,D645,L147,D651,L388,D338,L998,U321,L982,U150,R123,U834,R913,D200,L455,D479,L38,U860,L471,U945,L946,D365,L377,U816,R988,D597,R181,D253,R744,U472,L345,U495,L187,D443,R924,D536,R847,U430,L145,D827,L152,D831,L886,D597,R699,D751,R638,D580,L488,D566,L717,D220,L965,D587,L638,D880,L475,D165,L899,U388,R326,D568,R940,U550,R788,D76,L189,D641,R629,D383,L272,D840,L441,D709,L424,U158,L831,D576,R96,D401,R425,U525,L378,D907,L645,U609,L336,D232,L259,D280,L523,U938,R190,D9,L284,U941,L254,D657,R572,U443,L850,U508,L742,D661,L977,U910,L190,U626,R140,U762,L673,U741,R317,D518,R111,U28,R598,D403,R465,D684,R79,U725,L556,U302,L367,U306,R632,D550,R89,D292,R561,D84,L923,D109,L865,D880,L387,D24,R99,U934,L41,U29,L225,D12,L818,U696,R652,U327,L69,D773,L618,U803,L433,D467,R840,D281,R161,D400,R266,D67,L205,D94,R551,U332,R938,D759,L437,D515,L480,U774,L373,U478,R963,D863,L735,U138,L580,U72,L770,U968,L594 +L990,D248,L833,U137,L556,U943,R599,U481,R963,U812,L825,U421,R998,D847,R377,D19,R588,D657,R197,D354,L548,U849,R30,D209,L745,U594,L168,U5,L357,D135,R94,D686,R965,U838,R192,U428,L861,U354,R653,U543,L633,D508,R655,U575,R709,D53,L801,D709,L92,U289,L466,D875,R75,D448,R576,D972,L77,U4,L267,D727,L3,D687,R743,D830,L803,D537,L180,U644,L204,U407,R866,U886,R560,D848,R507,U470,R38,D652,R806,D283,L836,D629,R347,D679,R609,D224,L131,D616,L687,U181,R539,D829,L598,D55,L806,U208,R886,U794,L268,D365,L145,U690,R50,D698,L140,D512,L551,U845,R351,U724,R405,D245,L324,U181,L824,U351,R223,D360,L687,D640,L653,U158,R786,D962,R931,D151,R939,D34,R610,U684,L694,D283,R402,D253,R388,D195,R732,U809,R246,D571,L820,U742,L507,U967,L886,D693,L273,U558,L914,D122,R146,U788,R83,U149,R241,U616,R326,U40,L192,D845,L577,U803,L668,D443,R705,D793,R443,D883,L715,U757,R767,D360,L289,D756,R696,D236,L525,U872,L332,U203,L152,D234,R559,U191,R340,U926,L746,D128,R867,D562,L100,U445,L489,D814,R921,D286,L378,D956,L36,D998,R158,D611,L493,U542,R932,U957,R55,D608,R790,D388,R414,U670,R845,D394,L572,D612,R842,U792,R959,U7,L285,U769,L410,D940,L319,D182,R42,D774,R758,D457,R10,U82,L861,D901,L310,D217,R644,U305,R92,U339,R252,U460,R609,D486,R553,D798,R809,U552,L183,D238,R138,D147,L343,D597,L670,U237,L878,U872,R789,U268,L97,D313,R22,U343,R907,D646,L36,D516,L808,U622,L927,D982,L810,D149,R390,U101,L565,U488,L588,U426,L386,U305,R503,U227,R969,U201,L698,D850,R800,D961,R387,U632,R543,D541,R750,D174,R543,D237,R487,D932,R220 \ No newline at end of file diff --git a/2019/day-03/solution.js b/2019/day-03/solution.js new file mode 100644 index 0000000..e923220 --- /dev/null +++ b/2019/day-03/solution.js @@ -0,0 +1,16 @@ +const fs = require('fs') +const path = require('path') +const filePath = path.join(__dirname, 'input.txt') +const { findWireIntersections, getClosesetIntersection } = require('./wires') +const { linesToArray } = require('../../2018/inputParser') + +fs.readFile(filePath, { encoding: 'utf8' }, (err, data) => { + if (err) throw err + + data = linesToArray(data.trim()) + + const answer = getClosesetIntersection(findWireIntersections(data)).distance + + console.log('-- Part 1 --') + console.log(`Answer: ${answer}`) +}) From aa83c0bc4ad03f70c27c3dc45d8c4354b02f782a Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 16 Dec 2019 10:43:01 -0800 Subject: [PATCH 6/9] test(20190-day-03): specs for finding closest wire intersection by wire distance --- 2019/day-03/wires.test.js | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js index f5cb959..9d738e0 100644 --- a/2019/day-03/wires.test.js +++ b/2019/day-03/wires.test.js @@ -55,5 +55,37 @@ describe('--- 2019 Day 3: Crossed Wires ---', () => { expect(getClosesetIntersection(findWireIntersections(wires)).distance).to.equal(distances[idx]) }) }) + describe('getIntersectionWireDistance()', () => { + it('calculates the summed total wire length to reach the specified intersection', () => { + const wires = [ + 'R8,U5,L5,D3', + 'U7,R6,D4,L4' + ] + const expected = [ + 40, 30 + ] + const intersections = findWireIntersections(...wires) + const actual = intersections.map((inter) => getIntersectionWireDistance({wires, intersection:inter})) + expect(actual).to.deep.equal(expected) + }) + }) + describe('getClosestIntersectionByWire()', () => { + it('can be used to find the wire distance to the closest intersection', () => { + const wiresets = [ + [ + 'R75,D30,R83,U83,L12,D49,R71,U7,L72', + 'U62,R66,U55,R34,D71,R55,D58,R83' + ], [ + 'R98,U47,R26,D63,R33,U87,L62,D20,R33,U53,R51', + 'U98,R91,D20,R16,D67,R40,U7,R15,U6,R7' + ] + ] + const distances = [610, 410] + wiresets.forEach((wires, idx) => { + const intersections = findWireIntersections(wires) + expect(getClosesetIntersectionByWire({ intersections, wires }).distance).to.equal(distances[idx]) + }) + }) + }) }) }) From 7a6c55bf55387fa695966561cfe9516c46ef9bee Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 16 Dec 2019 10:43:39 -0800 Subject: [PATCH 7/9] style(2019-day-03): standard linting --- 2019/day-03/wires.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js index 9d738e0..96d0922 100644 --- a/2019/day-03/wires.test.js +++ b/2019/day-03/wires.test.js @@ -65,7 +65,7 @@ describe('--- 2019 Day 3: Crossed Wires ---', () => { 40, 30 ] const intersections = findWireIntersections(...wires) - const actual = intersections.map((inter) => getIntersectionWireDistance({wires, intersection:inter})) + const actual = intersections.map((inter) => getIntersectionWireDistance({ wires, intersection: inter })) expect(actual).to.deep.equal(expected) }) }) From 173ab6daf1494ae97625ef57f15b96e8e5bf6d78 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 16 Dec 2019 15:30:14 -0600 Subject: [PATCH 8/9] refactor(2019-day-03): support multiple ways of finding closest intersection --- 2019/day-03/wires.js | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/2019/day-03/wires.js b/2019/day-03/wires.js index 0c068d3..fda21a4 100644 --- a/2019/day-03/wires.js +++ b/2019/day-03/wires.js @@ -27,26 +27,33 @@ const findWireIntersections = (wires) => { return { x: parseInt(point.x), y: parseInt(point.y) } }) - return ints.sort(isCloser) + return ints.sort(isCloser.manhattan) } -const isCloser = (intA, intB) => { - const origin = { x: 0, y: 0 } - intA.distance = distance(origin, intA) - intB.distance = distance(origin, intB) - if (intA.distance < intB.distance) { - return -1 +const isCloser = { + manhattan: (intA, intB) => { + const origin = { x: 0, y: 0 } + intA.distance = distance(origin, intA) + intB.distance = distance(origin, intB) + if (intA.distance < intB.distance) { + return -1 + } + if (intA.distance > intB.distance) { + return 1 + } + if (intA.distance === intB.distance) { + return 0 + } } - if (intA.distance > intB.distance) { - return 1 - } - if (intA.distance === intB.distance) { - return 0 +} } } -const getClosesetIntersection = (intersections) => { - intersections.sort(isCloser) +const getClosesetIntersection = ({ + intersections, + method = 'manhattan' +}) => { + intersections.sort(isCloser[method]) // TODO: Remove workaround for bug in SVG intersection library // https://github.com/bpmn-io/path-intersection/issues/10 From c60f6ea555f96075a81080478bf1019a07692273 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Mon, 16 Dec 2019 15:31:10 -0600 Subject: [PATCH 9/9] feat(2019-day-03): trace wires to find their length at intersections --- 2019/day-03/wires.js | 50 ++++++++++++++++++++++++++++++++++++++- 2019/day-03/wires.test.js | 4 ++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/2019/day-03/wires.js b/2019/day-03/wires.js index fda21a4..5337af8 100644 --- a/2019/day-03/wires.js +++ b/2019/day-03/wires.js @@ -46,7 +46,49 @@ const isCloser = { } } } + +const advance = ({ segment, remaining, distance, current }) => { + // Track the step + switch (direction) { + case 'U': // Up + current.y += -dimension + break + case 'D': // Down + current.y += dimension + break + case 'R': // Right + current.x += dimension + break + case 'L': // Left + current.x += -dimension } + remaining += -1 + distance++ +} + +const getIntersectionWireDistance = ({ intersection, wires }) => { + intersection.wireDistance = 0 + + wires.reduce((wire) => { + const segments = wire.split(',') + const current = { x: 0, y: 0 } + const distance = 0 + + segments.forEach((segment, idx) => { + const direction = segment.slice(0, 1) + const length = parseInt(segment.slice(1)) + for (let d = 0; d < length; d++) { + advance({ direction, remaining, distance, current }) + // Reached the desired intersection, stop counting and track result + if (current.x === intersection.x && current.y === intersection.y) { + intersection.wireDistance += distance + break + } + } + }) + }, 0) + + return intersection.wireDistance } const getClosesetIntersection = ({ @@ -66,8 +108,14 @@ const getClosesetIntersection = ({ return intersections[0] } +const getClosesetIntersectionByWire = (intersections) => { + intersections.sort(isCloserByWire) +} + module.exports = { elfWireToSVGPath, findWireIntersections, - getClosesetIntersection + getClosesetIntersection, + getIntersectionWireDistance, + getClosestIntersectionByWireDistance } diff --git a/2019/day-03/wires.test.js b/2019/day-03/wires.test.js index 96d0922..dc7ab23 100644 --- a/2019/day-03/wires.test.js +++ b/2019/day-03/wires.test.js @@ -1,6 +1,6 @@ /* eslint-env mocha */ const expect = require('chai').expect -const { elfWireToSVGPath, findWireIntersections, getClosesetIntersection } = require('./wires') +const { elfWireToSVGPath, findWireIntersections, getClosesetIntersection, getIntersectionWireDistance, getClosesetIntersectionByWire } = require('./wires') describe('--- 2019 Day 3: Crossed Wires ---', () => { describe('Part 1', () => { @@ -69,7 +69,7 @@ describe('--- 2019 Day 3: Crossed Wires ---', () => { expect(actual).to.deep.equal(expected) }) }) - describe('getClosestIntersectionByWire()', () => { + describe('getClosestIntersectionByWireDistance()', () => { it('can be used to find the wire distance to the closest intersection', () => { const wiresets = [ [ pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy