From e8f9dfa7a69171643a0216af2761cfa4c24abf02 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Thu, 16 Dec 2021 17:11:53 -0800 Subject: [PATCH 1/5] test: reduce bleed of debugging logs across tests --- 2021/day-08/display.test.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/2021/day-08/display.test.js b/2021/day-08/display.test.js index fdf3439..535324e 100644 --- a/2021/day-08/display.test.js +++ b/2021/day-08/display.test.js @@ -18,15 +18,16 @@ gcafb gcf dcaebfg ecagb gf abcdeg gaef cafbge fdbac fegbdc | fgae cfgab fg bagce describe('--- Day 8: Seven Segment Search ---', () => { describe('Part 1', () => { describe('descrambleSignal()', () => { - const testData = testSingle.split('|')[0].trim() - const { segmentCodes, charCodes } = descrambleSignal(testData) - it('takes scambled string of 10 codes and identifies the letters matching each seven-digit-display segment', () => { + const testData = testSingle.split('|')[0].trim() + const { segmentCodes } = descrambleSignal(testData) expect(segmentCodes.length).to.equal(7) expect(segmentCodes.filter((code) => !['a', 'b', 'c', 'd', 'e', 'f', 'g'].includes(code)).length).to.equal(0) }) it('produces a list of character codes for each number that can be displayed', () => { + const testData = testSingle.split('|')[0].trim() + const { charCodes } = descrambleSignal(testData) // There should be exactly 10 numbers expect(charCodes.length).to.equal(10) // lengths of each code is predictable as each number has a specific count of segments @@ -35,10 +36,9 @@ describe('--- Day 8: Seven Segment Search ---', () => { }) }) describe('decodeSignal()', () => { - const testData = testMultiple[0].split('|').map((a) => a.trim()) - const { charCodes } = descrambleSignal(testData[0]) - it('decodes a display pattern using the provided map of display codes', () => { + const testData = testMultiple[0].split('|').map((a) => a.trim()) + const { charCodes } = descrambleSignal(testData[0]) const result = decodeSignal(charCodes, testData[1]) expect(result[0]).to.equal(8) expect(result[3]).to.equal(4) From 9e990a772b648b9dacb418235ceb405a29c01772 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Thu, 16 Dec 2021 17:12:39 -0800 Subject: [PATCH 2/5] fix(2021): reduce noise in runtime logs --- 2021/helpers.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 2021/helpers.js diff --git a/2021/helpers.js b/2021/helpers.js new file mode 100644 index 0000000..f1fdc6d --- /dev/null +++ b/2021/helpers.js @@ -0,0 +1,14 @@ +// Suppress logging +if (!process.env.DEBUG) { + console.debug = () => {} + console.log = () => {} +} + +module.exports = console +// module.exports = { +// debug: console.debug, +// info: console.info, +// log: console.log, +// warn: console.warn, +// error: console.error +// } From 5264b696a5b5c6db4627a96ed0cf5813d2a83eb3 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Thu, 16 Dec 2021 17:29:02 -0800 Subject: [PATCH 3/5] feat(2021-day-10): lint navigation instructions --- 2021/day-10/index.js | 3 ++ 2021/day-10/input.txt | 94 ++++++++++++++++++++++++++++++++++++ 2021/day-10/linting.js | 55 +++++++++++++++++++++ 2021/day-10/linting.test.js | 95 +++++++++++++++++++++++++++++++++++++ 2021/day-10/solution.js | 44 +++++++++++++++++ index.js | 2 +- 6 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 2021/day-10/index.js create mode 100644 2021/day-10/input.txt create mode 100644 2021/day-10/linting.js create mode 100644 2021/day-10/linting.test.js create mode 100644 2021/day-10/solution.js diff --git a/2021/day-10/index.js b/2021/day-10/index.js new file mode 100644 index 0000000..af7e035 --- /dev/null +++ b/2021/day-10/index.js @@ -0,0 +1,3 @@ +// eslint-disable-next-line no-unused-vars +const console = require('../helpers') +require('./solution') diff --git a/2021/day-10/input.txt b/2021/day-10/input.txt new file mode 100644 index 0000000..f8430ee --- /dev/null +++ b/2021/day-10/input.txt @@ -0,0 +1,94 @@ +[[<[<{[<{{<[{(()[])[[]()]}[((){})<[]{}>]}<<{[]{}}<(){}>><([]<>)>>>[[[<<>>[<><>]][<<>>(<><>)]][{ +((<[(<<(<{<((<()<>>{()()}){<<>><()[]>})([{<>{}}(()[])]{(<><>>})>(<((()())<[][]>)>([(<>{})({}())][< +<<<(<<[[((({<([]<>)[[]]>{<{}>{(){}}}}{[<[][]><<>[]>]({<><>}{()<>})})[<<({}())(()<>)>[([]{})<[]()>]>({[[] +<(<<<[((([{({((){})<<>{}>}[<(){}>[<>()]])[[<{}[]>({}{}]](<<>[]><[]<>>)]}](<[({[][]}<()<>>)<[ +{<<<{[({{(<<(<<>[]><[]()>){<[][]>{<>{}}}>((({}())([]<>))[<{}{}>({}())])>(<<<()[]>><<<>{}>(()< +{<{<<[[(<<[{<<{}[]>>([<>()]{{}{}})}]<(<{<>()}{{}()}>{({}[])<<>()>})>>>){[{[{<[[]{}][<><>]>}{(<{}( +(((([(({((<[<(<>{})[{}{}]>](<[()<>]{<><>}>)><<[<[]{}>((){})]<[()[]]>>{[{<>()}((){})]({()[]}(()[]))}>))}( +<<[(({({(<{{((<>[])[[]<>])([<>]{()()})}<<{<>[]}><<{}()>>>}>)(<(<{<()[]><(){}>}{{(){}}[{}<>]}>{ +(([[{<[<<{[<{<()[]>{<>[]}}{<{}{}>{[]<>}}>[{<{}{}>(<>[])}]]{<<({}[])>(<[]<>>[{}])>({{<>()}(< +(<{{(<<{[([<<{()[]}>{({}<>){<>[]}]>((<[]{}><{}{}>))]([{(()<>)(<>[])}]<<((){})<<>{}>>[(()[]) +{{[[<<{<{{{([{()[]}[{}()]]{(<>{}){<><>}}){<[[][]][()[]]>}}<{{<[][]>[{}[]]>(<<>{}><{}{}>)}>}}<<{[{([]( +{[<({{{[<{<{[([][])]{({}())<[][]>}}((<(){}>{()<>})<<<>{}>>)>}(((<{<>{}}<{}()>>)[((()()))[<<>{}>( +{{{[{{[(([{{[[{}<>]([]<>)]([(){}][[]()])}[{{[]<>}[{}()]}(<<><>>]]}][[([[[]<>]<<>{}>][{[]{} +<<{{{[{{[<({<<[]<>><{}<>>>}[[{()<>}{[]<>}]({(){}}{{}()})])[[(<<>[]>[[]])[{{}{}}[[]()]]]<(( +({{[{{{{<[[({[{}{}]{[]<>}}<<()<>>(()<>)>)<{{(){}]<()()>}{{(){}}[<><>]}>]<<({{}{}}<(){}>)([{} +{([[[<<([[{{[<()<>>(()<>))({<>[]}(<>{}))}{(<{}()>{()[]})}}([[{{}[]}<[]>]<([]<>){<>}>])]<{[[([]{})]{(<><>)[[]< +([<<([<[[({((({}[]){[]{}}){({}[])({}<>)})>)[(<{{{}{}}[(){}]}(([][])<{}<>>)><[[<><>]{<>{}}]{{{}[]}{[][]}}>)<[[ +{[<<{[<{[<{[[({}[])({}<>)]<<{}{}>{{}()}}]{[[<>{}]<[]{}>]}}(([(<><>){[][]}]([<>()]<()[]>))<[<()<>>(<><>) +(<[<[(({{<{<<[{}()]>(([]())<<>[]>)>}[{<[[]{}]([]<>)><{<><>}[()<>]>}{{{(){}}{[]{}}}}]>}}){{<{([<([]())({}()) +<<{({{<[<[{([{{}<>}{<><>}]([(){}](()[]))){[{()[]}<<>()>]({()()}({}()))}}]<[<<(())(()[])>>{(<{}<>>{ +{{{(<<[(<[([[[()<>]<()[]>]]{[[[]{}]{<>{}}]((<><>)({}{}))})]([(<{<>()}{[]{}}><<{}{}><<>[]>>)[<<()[]>((){ +[{(<<{[<<([{[<[][]>][{()()}({}())]}]([{([]{})<{}<>>}(<()>[{}])]{<([]<>)<{}{}>>(({}<>)<<><>>)}))>([[((<<>{} +[[(<({{(({{(<[{}<>]([]{})>{[<>[]]([][])})[(<[]<>><{}()>)[<{}()>(())]]}<[<[[]{}]<{}{}>>{<()()>({}<>)}]< +([(<({(<{{(((<[]<>>{<>()})<{[]{}>([]{})>)[<[()<>]({}[])>[(<>{})(<>[])]]){<((<>{}){()[]})><{<[]<>><<><>> +({{<({(<<({[[{<><>}]<<<><>>({}[])>]([<[]<>>[{}()]]{{<>{}}({}[])}}}<{({[]<>}({}{}))[(<>())(<>())]}((([]{}){[][ +(((({[(<([<[(<<>>[[][]])<{<><>}[{}<>]>]{({<>()}(<><>))(({}<>))}>])<([[<<()<>>{[][]}>]<[[[][ +[<<(([({((<<{({}())}[(()()){[]<>}]>>){({<[{}{}]<<>()>>{<{}()>}})})})])[[<((<[{([<>()][{}[]])((()[]) +{{{<{[[(<[{{<<{}()>[{}<>]>{({}{})<()>}}(<[(){}]>(<(){}>[[]]))}(<<[[]{}}({})><[<>[]]{<><>}>><[<[]<>>{<><>}]((( +{<[[<[{{<((<[<<>()><[]{}>][<{}()><{}{}>]>)[[[[[][]]<()[]}][([]{})(()())]]])>[[((<{[]<>}<()>><[{}[]](<><>)> +<{([{[{[{([({<{}[]>([]<>)}[[[][]]<()()>])[<[{}()]>{<<><>>(()<>)}]]){({(<[]<>>([]<>))[(<>){ +[{{<(({<{[{<{({})(<>[])}({<><>}{[]()})>(({[]<>}(<>{}))[{()()}{{}<>}])}{<{{<>()}<[]{})}(<()><( +{(<[{[[{{<(([{{}{}}<()[]>]<[<><>]>)([(<><>)])){<<{[]{}}[[][]]>{[[]<>]{<>{}}}>[<<[][]><<>()>><<{}<>>[<>()>>]}> +<[{{(<<{{{[[{<[]<>>(()<>)}<{()<>}{<>[]}>]<[<()()>]{<<>>([]())}>]{([<<>{}>({}<>)])[({{}}{[]<>})[ +<<[[<<[(<{{{[{()[]}([]())][[[]]((){})]}}(([{[][]}[()()]]<<()>[{}[]]>))}>)<{({{<[[][]]{()()}><<{}{} +{[<(([([{({([({}()){<><>}][((){})([]())])[<<()<>>(<>())>{[[]()}(()[])}]}<{{<(){}>{()[]}}((<><>){{}<>})}(( +{(({([[{{((([<()()>([][])]<<{}[]>[<>]>)(<{<><>}[{}{}]>[[<>{}]]))[{<<[][]>[()]><[{}{}]>}{<([]<>)([]<>)>}] +(({[[<<<{[{([(<>[])<()[]>])(<([])({}{})>)}[{(<<>{}>({}<>))}<<[<>[]>[(){}]>(<{}{}>)>]]{([[<<>()> +[{[[{([({[{(({()[]}[[]<>])<[[]<>]([])>)([{{}{}}[{}[]]]<{{}<>}>)][<(<<>[]>{<><>})<(()<>){[][]}>>[[{[]{}}([]()) +([[{({([({<<(<[]<>>)[{()[]}<<>()>]><<{<>()}<<>[]>>[[<>{}]<<><>>]>)<<<<<>[]><<><>>>[[[]]]>[{ +[{{([(<[[<{((([]{})[()()])[<[]{}>[<>()]])<[{()()}(<>{})]({[]}[<>{}])>}((<{[]()}>)({<{}{}>[ +[[[{{[[[<<(<(({}())[<>{}])<{{}<>}(()())>>[[((){})][[[]{}]{()}]])>>{[(<([{}{}]({}<>))([{}()]<<>[]])>({< +{<{({(({{{[{<(<>{})>{<{}<>>(<><>)}}<(<[]()>[[][]])<[{}()]>>]<{{<()[]>{{}()}}{<{}[]>{{}{}}}}{{<()<>><<> +[{[<{[<<({(<{{<>()}({}<>)}<(<>[])[()()]>>{{{<>()}{()[]}}})<{<({}()){<>{}}>({<>[]}({}())]}>}( +[[{<([((({([{{()[]}<[]{}>}({<>[]}[<><>])]{{<[]<>>[<><>]}[{()()}[<>[]]]})}[{[<{()()}(<>))<({}){()<>}>]([ +(<(<{[{<({[{{{[]()}({}{})}{<{}[]><<>{}>}}]})>}<{[[(<[<[]{}>([]())](<{}>[()()])>)][(([{[]<> +<<<<{<{<<[<({<[]>({}<>)})<[{[][]}[[]()]][[{}<>]<{}[]>])>([(([][])[[]()])<[{}[]]{[]{}}>](<[{}()]{{}()} +({[[([([<{[[({()[]}[<>[]])[<[][]><<>{}>>][(({}{})(<>[])){(<>[])}]]<{{{{}()}[<>[]]}<[[]<>]([]())>}>}{<{({ +((<{<{{[((<<<(()<>)<[]{}>>[<[][]>[(){}]]>>)){([[[[<>]({}<>)]{{{}<>}([]{})}]<[<<>()>(()())][{[]{}}{[]<>}]>] +{<<{{[({[<{{(<{}[]><<>[]>)([[]()])}<[{{}{}}{<><>}]<({})<{}()>>>}<[([{}<>][<>{}])](<<{}[]><< +{[{[[<<[(({[(((){}){<>[]})]([[<>[]]][<<>{}>[<><>]])})({<[({}[])<{}[]>]>}<(<(()<>)[[]{}]][[()()][<>< +((<<[({<{[[({<[]()>([]())}[<[]{}>(()<>)])]<<{[{}[]][<>()]}><<{<>[]}[()<>]>[<[]{}>{[]()}]>>][(({[<> +{{<[{<([({{([<<><>>{{}()}][<[][]>{[]()}])[<[[]]{[]<>}>]}(({<()[]>[{}()]}<[[]<>]{<>()}>))})])<{[{<[<[{}{}] +[(({({[[<{(<{{<>[]}[()<>]}((<>{})<<>[]>)>{[<(){}>{{}<>}]])[<{(<>[]){{}[]}}([()()][<>[]])>((({}()) +{(([<{([[{([<<{}()><[][]>>[(<>()){()[]}]]<[<()()>[{}]]([{}<>][{}[]])>){<{[[]<>]<<>{}>}{([]{})}>[([ +<{[{({([(<<{<[()<>]<(){}>>(<()>{[][]})})>{[([<{}{}>[<>()]])[{([]()){<>{}}}<<{}<>>>]]})])([<(([{<(){}>[{ +<<<(([<[{[[<{({}()>{[]()}}>]]([<[[()][{}[]]]<[()()]{(){}}>><<({}[])(()<>)>{(()[])}>]{[(<[]()>)[{[]{}} +(({(([[<{(<{[(<>[]]]}<(({}{}))([[][]]([][]))>><[{(()())[()<>]}<{(){}}>]>)((<{{()[]}{<>()}}<([ +[[[{<[{<[<[[{(<>{})<[]()>}{(()[])[<>()]}][<({}()>[<><>]>{<[]{}><[][]>}]]><<{[{(){}}{{}{}}][<<>< +((([<<((<[{(([<>[]]([]{}))([<>]{<>()})}([[(){}][[]()]][(<><>){{}()}])}{[<[()<>]({}<>)>[<{}{}>]][<(<>())<[] +{<<{([(((([{<[()]{(){}}>{{{}[]}}}[{(()[]){()<>}}{<<>>[<>{}]}]]<[{(<>())(()[])}]>){[[<({}{})[()[]]>{[{}( +([{(({([([(<<{<>[]}<{}<>>>[[[]{}]<[]{}>]>((([]<>)<<>[]>)[[(){}]]))[<{{<>{}}}[(<>}{()()}]><{<<>{}>< +{(<[<{({([{{([[][]]>({()()}[[][]])}[<(()())([]())><(<><>)([]{})>]}[(({{}{}}{{}<>})([<><>]<()[]>))] +((<(<<{{{{<{{(()<>)({}{})}{{<>[]}<()[]>}}<<<[][]>(()[])>[[()[]][[]()]]>>[[{{[]{}}[[][]]}][<[()[]]{[]<>}> +(((<(<<<{{<{<{{}{}}(()<>)>[((){})[()[]]]}{[[<>[]]{{}()}][{()[]}({}{})]}>}}>{[{<<{[{}()]}<[[]()] +({(([[<{[{<(([[]()](<><>))[<{}[]){{}()}])(<[()[]]<[]()>>[<{}<>>[()<>]])>[<[[()()]<<>[]>][([]())([]{})]>{{<<>( +[[(([((([<[[<{{}<>}({}[])>[([]<>)[()[]]]]<[(()())({}<>)](([]<>)<[]()>)>]>[{{{(()<>)}<{[]()} +(<(({[<<{((<[[[]()]{{}<>}]<<{}()>({}[])>>)<{{({}){()()}}<{[][]}>}>){[(<<[]<>>[{}{}]>{{(){}}{[ +{<(<(<<{<(<{{[{}[]]([]{})}([{}[]](<>))}[([<>()]{[]{}})<({}<>){<><>}>]>[{<[[][]]>}[<[<><>](()())>(([ +{(<(<{<(<<{{{<(){}>}({[][]}{{}{}})}}<(<<<>()>[(){}]>(<{}()>{{}}))>>[{{[{[]{}}(()[])]}[((<>())<< +([((([[{([{<<((){})>{{<>}{[]()}}>{[((){})<()[]>]<{[]{}}[(){}]>}}{((<{}()><{}>)){{<{}[]>[[] +{{{(<<{((([[{(<>{})({}())}[<[]()>({}{})]]<<[{}]>{[[]()]{()[]}}>]{({<()[]>((){})})<{<[]<>>{{}{} +(<<[[([{{(<<({{}}[{}{}])<([]{}){<>()}>>>(({<()()>({}[])}<<{}()>[(){}]>)))[{([{<>[]}([]())]([()()][<>{}])){ +<(<(<<<([[[(<{{}[]}{{}[]}>[[<>()]{()[]}])]<{({{}()}{{}<>})<({}[])([]<>)>}{(({}[])(<>{}))((()<>)<[]()>)}>](< +<<{(([<([[[[<{<>()}({}[])>{((){})[{}()]}]}[<{<<>[]><[]<>>}<[{}<>]{{}()}>>{{(()())[()[]]}{<()<> +(({<<[{([{<(([{}[]][(){}])[<[]()>(()<>)]}>}<[(<{{}()}{{}<>}><[[]()][[]()]>)]<(<(<>())>({<>[]})){[{(){}}<{}{}> +({[[{[{{<(([[[{}{}]<(){}>]((()[])(()[]))]({([]<>)({}{})}{<<>{}>{<>}}))<{(<[]{}>(()()))[[()[]](<><>) +([{[{{<{{(<[((<>){[]()})(({}())[<><>])]>({[(<><>}{{}[]}]{(()[])[()]}}{([[]{}](<><>))<<{}[]>(<>())>})) +<[(([[[<{[[(({()[]}<<>[]>){{<><>}<(){}>})<([()]{<>[]}){{<>{}}}>]]<[{{([]())({}{}>}<{[][]}<<>{}> +({(<{<([[<{[<{[]()}[{}<>>>[[(){}][[]{}]]][{[()<>][<><>]}{<()()>}]}<({{(){}}<()()>}{[<><>](<>())})[( +([({<[<[{({<<[<>{})[<><>]>{{[]{}}}>[[{()<>}([]{})](({}<>)<<>>)]}<{<<<>>{()[]}>}<{<[]()>}>>)(<<<{ +({<{[[({[([{[{[]{}}{[]<>}](((){})({}()))}]([<{<>{}}{()<>}>{({}{})(()())}])}]<{({{<()[]>{()}} +({[[{[((<[[[{<<>[]>(<>[])}]]{<({{}[]}){[{}{}]<<>()>}>[([<>()]{{}()})(<()()><<>[]>)]}]>(<([{<[]{}>(()())}<{[ +[<<<{<({({{<{[<><>]{{}<>}}{<(){}>}>}})})[<<[{[{({}{})<<>>}[{[]}(()())]]{{([]())([]())}{({}[])[<> +<<<[[((<{{<(((<>[])(()))<<<>()><<>{}>>)<[{<>[]}{(){}}]{[{}]({}())}>>}}[[((({()}{[][]}){<{}[]>} +(<[<({[[{[<<[(<>[])]([[]<>]<[]{}>)>({(<>[])([]())}<[{}<>)<<>{}>>)>[{<[[][]]><[{}<>]<[]()>>}<<[ +{[({<<<<(<([{{[][]}}]{<{<>()}<<>()>>[({}())<[]{}>]})>)>>><<<{{((([{}[]]<<><>>)[[[][]]({}[])])<{<{}{}>( +[[[({((({<([({[][]}{[]})<({}[]}[{}{}]>][([[]()]([]()))<<()<>>>])<[<<()[]><()[]>>]>>([<<{[]()}{[][]}>< +[{{<<<({<({(<<<><>>>{(<>[])[<><>]})<(<<>{}>(()()))[{{}()}{(){}}]}}[(<{[]()}<[]<>>>({<>{}}[{} +([<<{<[{([<[<{<>{}}<[]{}>><([][]>>][{([][])[()()]}<<[]<>>>]>][{<({<>()}<[][]>)[[[]<>]{()<>} +({<<[<(<<<(<((()<>)<{}<>>)>)<<([<>{}][<>[]])<<()()>({}[])>>([(()())(()<>)]{{{}<>}<[]{}>})>>>>[ +<{[{<[[<[(<{({<><>}{[]<>}){<[]{}><()>}}({({})[[]{}]})>{(<{[]<>}{<><>}>([{}[]]{<><>}))(<<{}()>[ +<{{<[[({{{<({<[]()>[{}[]]}<{<><>}{()<>}>)[<<[]{}>{{}<>}>[<<>[]>((){})]]>}}(<[[(([][])[{}<>]){(()<>)[()[]]}](( +[{[{<[(({{({<{{}{}}<()()>>(<[]<>>{<>[]})}(<<()[]>{()<>}>))<<<[{}{}]<<>[]>>>[[{[]{}}]((()<>){<> +{[[<{({[<(<((<{}[]>){[{}[]]})[{[{}{}]({}())}]>(<{{()<>}(<><>)}[(<><>)<[]{}]]><{<()[]>([][]) diff --git a/2021/day-10/linting.js b/2021/day-10/linting.js new file mode 100644 index 0000000..78600ab --- /dev/null +++ b/2021/day-10/linting.js @@ -0,0 +1,55 @@ +const pairs = { + '(': ')', + '[': ']', + '{': '}', + '<': '>' +} + +const lintLine = (line) => { + let expected = '' + let pos = 0 + while (pos < line.length) { + const char = line[pos] + + // if opening bracket, add mate to the start of expected list + if (pairs[char]) { + expected += pairs[char] + } else { // if closing bracket + // if expected closing, clear from the expected list + if (expected[expected.length - 1] === char) { + expected = expected.slice(0, -1) + } else { // otherwise, found an error to report + return { + char: pos, + expected: expected[expected.length - 1], + found: char + } + } + } + + pos++ + } + + // if we run out of line, ignore per instructions for Step 1 + if (expected.length > 0) { + // TODO - add the reporting when we need it in Step 2? + } +} + +const lintAll = (instructions) => { + const errors = instructions.map(lintLine) // lint each line + .map((error, idx) => { + return { ...error, line: idx } + }).filter((report) => !!(report.char)) // remove lines without errors + + console.log(`Linting found ${errors.length} errors in ${instructions.length} lines.`) + console.debug(instructions) + console.debug(errors) + + return errors +} + +module.exports = { + lintLine, + lintAll +} diff --git a/2021/day-10/linting.test.js b/2021/day-10/linting.test.js new file mode 100644 index 0000000..35c846c --- /dev/null +++ b/2021/day-10/linting.test.js @@ -0,0 +1,95 @@ +/* eslint-env mocha */ +const { expect } = require('chai') +const { lintLine, lintAll } = require('./linting') + +const badChunks = [ + '(]', + '{()()()>', + '(((()))}', + '<([]){()}[{}])' +] + +const testData = `[({(<(())[]>[[{[]{<()<>> +[(()[<>])]({[<{<<[]>>( +{([(<{}[<>[]}>{[]{[(<()> +(((({<>}<{<{<>}{[]{[]{} +[[<[([]))<([[{}[[()]]] +[{[{({}]{}}([{[{{{}}([] +{<[[]]>}<{[{[{[]{()[[[] +[<(<(<(<{}))><([]([]() +<{([([[(<>()){}]>(<<{{ +<{([{{}}[<[[[<>{}]]]>[]]` + +describe('--- Day 10: Syntax Scoring ---', () => { + describe('Part 1', () => { + describe('lintLine()', () => { + it('finds instnces of closing brackets that mismatch the opening brackets', () => { + expect(lintLine(badChunks[0])).to.deep.equal( + { + char: 1, + expected: ')', + found: ']' + } + ) + expect(lintLine(badChunks[1])).to.deep.equal( + { + char: 7, + expected: '}', + found: '>' + } + ) + expect(lintLine(badChunks[2])).to.deep.equal( + { + char: 7, + expected: ')', + found: '}' + } + ) + expect(lintLine(badChunks[3])).to.deep.equal( + { + char: 13, + expected: '>', + found: ')' + } + ) + }) + }) + describe('lintAll', () => { + it('finds all lines with linting errors', () => { + const errors = lintAll(testData.split('\n')) + + expect(errors.length).to.equal(5) + expect(errors[0]).to.deep.equal({ + line: 2, + char: 12, + expected: ']', + found: '}' + }) + expect(errors[1]).to.deep.equal({ + line: 4, + char: 8, + expected: ']', + found: ')' + }) + expect(errors[2]).to.deep.equal({ + line: 5, + char: 7, + expected: ')', + found: ']' + }) + expect(errors[3]).to.deep.equal({ + line: 7, + char: 10, + expected: '>', + found: ')' + }) + expect(errors[4]).to.deep.equal({ + line: 8, + char: 16, + expected: ']', + found: '>' + }) + }) + }) + }) +}) diff --git a/2021/day-10/solution.js b/2021/day-10/solution.js new file mode 100644 index 0000000..a800a92 --- /dev/null +++ b/2021/day-10/solution.js @@ -0,0 +1,44 @@ +const fs = require('fs') +const path = require('path') +const filePath = path.join(__dirname, 'input.txt') +const { linesToArray } = require('../../2018/inputParser') +const { lintAll } = require('./linting') + +fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => { + if (err) throw err + + initData = linesToArray(initData.trim()) + + const resetInput = () => { + // Deep copy to ensure we aren't mutating the original data + return JSON.parse(JSON.stringify(initData)) + } + + const part1 = () => { + const data = resetInput() + const points = { + ')': 3, + ']': 57, + '}': 1197, + '>': 25137 + } + + const errors = lintAll(data) + + return errors.reduce((total, error) => total + points[error.found], 0) + } + + const part2 = () => { + const data = resetInput() + console.debug(data) + return 'No answer yet' + } + const answers = [] + answers.push(part1()) + answers.push(part2()) + + answers.forEach((ans, idx) => { + console.info(`-- Part ${idx + 1} --`) + console.info(`Answer: ${ans}`) + }) +}) diff --git a/index.js b/index.js index f4abd84..274e3b7 100644 --- a/index.js +++ b/index.js @@ -1 +1 @@ -require('./2021/day-09/solution') +require('./2021/day-10/solution') From bb212f32019518e2db1878ac33115926db0f1f38 Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 17 Dec 2021 09:13:42 -0800 Subject: [PATCH 4/5] feat(2021-day-10): score code autocompletes --- 2021/day-10/scoring.js | 27 +++++++++++++++++++++++++++ 2021/day-10/scoring.test.js | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 2021/day-10/scoring.js create mode 100644 2021/day-10/scoring.test.js diff --git a/2021/day-10/scoring.js b/2021/day-10/scoring.js new file mode 100644 index 0000000..45c745c --- /dev/null +++ b/2021/day-10/scoring.js @@ -0,0 +1,27 @@ + +const findMiddleScore = (scores) => { + // According to specs, there's always an odd number of items in the list, + // so we're safe to divide by 2 and round down to get the desired index + return scores.sort((a, b) => a - b)[ + Math.floor(scores.length / 2) + ] +} + +// How many points each character is worth in autocomplete scoring +const pointValues = { + ')': 1, + ']': 2, + '}': 3, + '>': 4 +} + +const scoreAutocomplete = (suggestion) => { + return [...suggestion].reduce((score, char) => { + return (score * 5) + pointValues[char] + }, 0) +} + +module.exports = { + findMiddleScore, + scoreAutocomplete +} diff --git a/2021/day-10/scoring.test.js b/2021/day-10/scoring.test.js new file mode 100644 index 0000000..0ee2fe7 --- /dev/null +++ b/2021/day-10/scoring.test.js @@ -0,0 +1,36 @@ +/* eslint-env mocha */ +const { expect } = require('chai') +const { findMiddleScore, scoreAutocomplete } = require('./scoring') + +const scoreData = [ + 288957, + 5566, + 1480781, + 995444, + 294 +] + +const autocompleteSuggestions = [ + '}}]])})]', + ')}>]})', + '}}>}>))))', + ']]}}]}]}>', + '])}>' +] + +describe('--- Day 10: Syntax Scoring ---', () => { + describe('Part 2', () => { + describe('scoreAutocomplete()', () => { + it('takes a single autocomplete suggestion and scores it', () => { + autocompleteSuggestions.forEach((suggestion, idx) => { + expect(scoreAutocomplete(suggestion)).to.equal(scoreData[idx]) + }) + }) + }) + describe('findMiddleScore()', () => { + it('takes a list of scores and returns the middle entry after sorting', () => { + expect(findMiddleScore(scoreData)).to.equal(288957) + }) + }) + }) +}) From 2539be935ad609ba16a7454cf066a0c128abea8f Mon Sep 17 00:00:00 2001 From: Anthony McLin Date: Fri, 17 Dec 2021 10:02:11 -0800 Subject: [PATCH 5/5] feat(2021-day-10): find incomplete line errors solves part 2 --- 2021/day-10/linting.js | 14 +++++++++----- 2021/day-10/linting.test.js | 28 ++++++++++++++++++++++++++++ 2021/day-10/solution.js | 13 ++++++++++--- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/2021/day-10/linting.js b/2021/day-10/linting.js index 78600ab..1dc1260 100644 --- a/2021/day-10/linting.js +++ b/2021/day-10/linting.js @@ -30,9 +30,13 @@ const lintLine = (line) => { pos++ } - // if we run out of line, ignore per instructions for Step 1 + // if we run out of characters in the line, that means it is + // incomplete, and we need to provide an autocomplete suggestion if (expected.length > 0) { - // TODO - add the reporting when we need it in Step 2? + // Reversing the 'expected' string gives us the autocomplete suggestion + return { + suggestion: [...expected].reverse().join('') + } } } @@ -40,11 +44,11 @@ const lintAll = (instructions) => { const errors = instructions.map(lintLine) // lint each line .map((error, idx) => { return { ...error, line: idx } - }).filter((report) => !!(report.char)) // remove lines without errors + }).filter((report) => !!(report.char) || !!(report.suggestion)) // remove lines without errors console.log(`Linting found ${errors.length} errors in ${instructions.length} lines.`) - console.debug(instructions) - console.debug(errors) + // console.debug(instructions) + // console.debug(errors) return errors } diff --git a/2021/day-10/linting.test.js b/2021/day-10/linting.test.js index 35c846c..842107f 100644 --- a/2021/day-10/linting.test.js +++ b/2021/day-10/linting.test.js @@ -20,6 +20,14 @@ const testData = `[({(<(())[]>[[{[]{<()<>> <{([([[(<>()){}]>(<<{{ <{([{{}}[<[[[<>{}]]]>[]]` +const autocomplete = { + '[({(<(())[]>[[{[]{<()<>>': '}}]])})]', + '[(()[<>])]({[<{<<[]>>(': ')}>]})', + '(((({<>}<{<{<>}{[]{[]{}': '}}>}>))))', + '{<[[]]>}<{[{[{[]{()[[[]': ']]}}]}]}>', + '<{([{{}}[<[[[<>{}]]]>[]]': '])}>' +} + describe('--- Day 10: Syntax Scoring ---', () => { describe('Part 1', () => { describe('lintLine()', () => { @@ -57,6 +65,7 @@ describe('--- Day 10: Syntax Scoring ---', () => { describe('lintAll', () => { it('finds all lines with linting errors', () => { const errors = lintAll(testData.split('\n')) + .filter((err) => (err.char)) expect(errors.length).to.equal(5) expect(errors[0]).to.deep.equal({ @@ -90,6 +99,25 @@ describe('--- Day 10: Syntax Scoring ---', () => { found: '>' }) }) + it('provides autocomplete suggestions for incomplete lines', () => { + const data = testData.split('\n') + const errors = lintAll(data) + .filter((err) => !!err.suggestion) + + expect(errors.length).to.equal(5) + errors.forEach((err) => { + expect(err.suggestion).to.equal( + autocomplete[data[err.line]] + ) + }) + }) + it('skips lines without errors', () => { + const errors = lintAll([ + '[]', + '[()]' + ]) + expect(errors.length).to.equal(0) + }) }) }) }) diff --git a/2021/day-10/solution.js b/2021/day-10/solution.js index a800a92..c20343f 100644 --- a/2021/day-10/solution.js +++ b/2021/day-10/solution.js @@ -3,6 +3,7 @@ const path = require('path') const filePath = path.join(__dirname, 'input.txt') const { linesToArray } = require('../../2018/inputParser') const { lintAll } = require('./linting') +const { scoreAutocomplete, findMiddleScore } = require('./scoring') fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => { if (err) throw err @@ -25,13 +26,19 @@ fs.readFile(filePath, { encoding: 'utf8' }, (err, initData) => { const errors = lintAll(data) - return errors.reduce((total, error) => total + points[error.found], 0) + // Score the premature closure errors + return errors.filter((err) => !!err.char) + .reduce((total, error) => total + points[error.found], 0) } const part2 = () => { const data = resetInput() - console.debug(data) - return 'No answer yet' + // find the incomplete line errors + const errors = lintAll(data).filter((err) => !!err.suggestion) + + const scores = errors.map((err) => scoreAutocomplete(err.suggestion)) + + return findMiddleScore(scores) } const answers = [] answers.push(part1()) 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