Compare commits
7 commits
6dc1a61792
...
main
Author | SHA1 | Date | |
---|---|---|---|
Tristan Daniël Maat | 7de9869d1c | ||
Tristan Daniël Maat | 99ec5911b7 | ||
Tristan Daniël Maat | 9abc63b97f | ||
Tristan Daniël Maat | 2c6611a020 | ||
Tristan Daniël Maat | 6723ef2021 | ||
Tristan Daniël Maat | d6739d00f6 | ||
Tristan Daniël Maat | d01e6a98d0 |
98
10/input.txt
Normal file
98
10/input.txt
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
[[{(<({[(([[([()<>][()<>])]][<{[[]<>]}<<[]{}>>>])[({<[{}[]]<{}<>>><{()[]}[{}[]]>}<<(<>[])[[]{}]>{(<
|
||||||
|
{{{[[<{<{({({(<>{})}<(()[])([]<>)>)})(<[([{}()]([]{}))[([][])([]<>)]]((<{}<>>[[]{}])({<>()}{()}))>
|
||||||
|
[(<<[(<[[[<{(([]{})){<{}{}>{()<>}})><(<[()()][<>]>([[]]))[(([]<>)(<><>))((<>)({}[]))]>]{<<{{()[]}<[]<>>}
|
||||||
|
{{({{{([<((<[[<>[]](<>[])]><<(()<>)<<><>>>{(()<>)(<>{})}>))>]({(([{{()()}>{{{}{}}{<><>}}]{({()<>
|
||||||
|
<<{(<<{<<{([{{(){}}{()()}}{<[]{}>(<>{}))][({<>{}}[[]<>])<{{}{}}{{}()}>])[<<{{}{}}[()[]]>{{
|
||||||
|
[[<{[<((<[[{{{{}{}}{{}[]}}}[[<{}<>>]]]({<([][]){{}<>}>((()<>)<<>[]>)})]><[({{<{}()>{()()}}})]{(<({[]{}}[{
|
||||||
|
<<[{([[[[[<{[([]())({}[])]{[{}[]]}}<(<[]{}>({}{})){{[]<>}[()]}>>{(<{[]}[<>[]]>)}][(([[{}[]]<[]
|
||||||
|
[(<[<{{((<{<[<{}[]>[<>{}]][<{}<>>]><<({}[])[[]<>]>}}>)<(([{<{}<>>(()[])}[[{}()]([])]]<<{<>()}({}{})>
|
||||||
|
<{{[[<(<<<([({{}())([]{})){<()<>>{<>{}}}]<{[[]{}][[]<>]}{<{}()>{[]()}}>)<<{(<>())[<><>]}[{{}[]}(<>(
|
||||||
|
{{{{<{{<{<<[[[{}()]<[][])]<{(){}}{[]{}}>][{<[]()>{<>{}}}]>><{(<<<>[]>{(){}}>{{[]()}[<><>]}){(<{}()>){[[][]](
|
||||||
|
{(<{{([[(<{[((()<>){()()})<[<>{}]{()}>]<{[()[]]}>}([{<()>{{}[]}}[([][]){()[]}]]{{<<>[]>}{([]{}){<><>}}})
|
||||||
|
[(((({[{<<{[{([]())(<>[])}[<{}()>{()()}]]}>>[<[[{{{}()}{()<>}}(<()<>>[{}[]])]{[({}<>)<<>>]}]<({<<><>
|
||||||
|
<([[[((<[<<((<[][]>))<<{[][]}>>>{<([()()>)>}><([[[()[]]({}())]({<>{}}{()[]})]{{{<><>}[[]()]}[[[]
|
||||||
|
(((<({([[({{({[][]})(({}())[()<>])}(<[[][]]>(<{}>[<>{}]))})](<{((<<><>>[()()]){<[]<>>[[]<>]})}([<
|
||||||
|
[[{[[{[[{[{{[<{}()><()[]>]}}]<<{{<<><>>{{}{}}}[(<>{})(()())]}[{([]<>)[{}()]}<[[]][()()]>]><<{{[]{}}
|
||||||
|
((<<((<(<[{[({()<>}{()()}){<{}{}>}]}[{<[<>()][[]()]>}]]{[{[<()>{[]{}}]}<{[{}{}}}[([]{})(<><>)]>](({(<>{})
|
||||||
|
[[<[<({[[<<{[[()()]{(){}}]<[{}<>](()())>>(<[()[]][[]()]>)>[{(([][])([]{}))}[<<<><>><()<>>>(<<>[]>)]
|
||||||
|
[({(<{(<{[{[{([]){{}{}}}(<[][]>(<>[]))](<{<>[]}<[]()>>{<()><{}>})}{[([<>{}]{[]()})[(<>{})<[]()>]][{[()<>
|
||||||
|
[[<<{[(<({(((([]{})[[][]])<<{}{}>{[]()}>))})<[(<<(<>[])<[]()>><((){})[()<>]>>{<({}[])>{<<>{}>{(){}}}}
|
||||||
|
<<([[({(<{<[[({}()){()[]}]]>((<<()[]>(<>{})>(([]())))(((()<>)({}[]))))}>{<{((([])<()[]>)<({}())<()<
|
||||||
|
<<({[<{<({{{{[()()]<<>[]>}[{{}<>}[()()]]}{(([]()))})})[[[{[<<>[]>[<>()]]<{[]{}}[<>{}]>}]([{{[][]}{
|
||||||
|
{((((([[([<{([<>{}]<{}[]>){({}())[{}[]]}}{(<()()>({}[]))<{<><>}(<>[])>}>([<{()<>}[()[]]><[()<>]>]{[{
|
||||||
|
{[((((({<[{<{[(){}][[]()]}[({}[])]>{[[<>{}]{{}}]{[<>[]]<<>[]>}}}({[([]{})]{[[]<>]<[]{}>}}(<(()[])[{}()]
|
||||||
|
((<<{<{{{<(<<[<>()]{{}<>}>({<>{}}[[]()])>(<<{}<>>({}<>)><[{}<>]{(){}}>))<(((()[])([]())){(<
|
||||||
|
{(<(<([{{{((([<>[]]([]<>))({<>[]}<<>[]>)}{<(<><>)<<>{}>>(({}[])(()<>))}){[{{{}{}}}]{[<{}()>(<>{})][{[]}]}
|
||||||
|
{{{([([(<[<[{<()>{()()}}<[()()]<<><>>>]{<<()<>>>(((){}){()<>})}>{<{({}[])<<><>>}((()())<{}{}>)>
|
||||||
|
{(({(<<([[({<{[][]}<<><>>>}(<({}<>){{}<>}>{<<><>>(<>())}))<{{[{}<>]<[]()>}<<{}{}>>}[{<{}[]><(){}>}{
|
||||||
|
[[[([[(([<[<{<<>{}><{}[]>}>((<[][]>[{}[]]))]{({<<><>>[()[])}[{{}()}<{}>])}>]){[{{((<<>{}>([]<>))([
|
||||||
|
([<<<[(<(<{[[({}{}](<>)]{{{}<>}({}{})}][({()}{[]()})[({})]]}{<[(<><>)({}{})]<{<>}{[]}>>}>)>){{<[(<{(()()
|
||||||
|
{{{<{(<(([<<<{{}[]}[<>{}]}>([<<>()>{<>()}]<<<><>>[{}<>]>)>{[([<>()]{()[]}){{<>{}}[<>[]]}]}][(<[(()
|
||||||
|
<<<[[{(([<<{{(()())[{}[]]}{[[]<>]<<>>}}[(<<>><{}<>>){{{}[]}[{}()])]>([(<{}()>[[]()])[(()())
|
||||||
|
{{{([[[<{(<<{[[]()](<>{})})[(<[]{}><[]{}>)[<[]{}>{{}()}]]>[[[(()()){{}{}}][[<>[]](())]]<([{}()][{
|
||||||
|
([{{([[[({[(((<>)(()<>)){[{}{}](()())}){(((){})([]()))[(<>{})<[][]>]}]([({[]()}[(){}])<[{}()>(()<>)>
|
||||||
|
[[[<<(({<<(([({}[])<(){}>][[{}]([]())])<{{[]()}[[]]><{<><>}<()[]>>>)>{<{<[[][]]<{}<>>>([[]<>]{{}<
|
||||||
|
[[[<[<([{<[{{{()<>}({}<>)}}(<{{}<>}{[]()}>[<()())(<>())])]>[[(<{()}<[]()>><[()[]]<<>{}>>){<[()<
|
||||||
|
{{(<({((<[<<[([][])<[]<>>](<<>[]>)>>{<([(){}]{[]{}})>{[({}<>)]<[(){}]{{}}}}}]>)[[[[<{<[][]>(
|
||||||
|
[[[[{{{{([(((({}<>){()()})[{()()}([]<>)])[{<{}{}><[]{}>}([()<>][[]()])])]))}(<[[[{[[()[]]<()[]>]}]{((
|
||||||
|
({{[(((([<({{(<>())<{}()>}([{}{}]<{}{}>)}[{[{}{}]}<[[]]<()[]>>])[([<{}{}><[]{}>])<<[(){}]({}{}
|
||||||
|
(<<({<({[({[{{()[]}[()<>]}<{<>{}}({}{})>](<{<>{}}>[{{}<>}{(){}}])})(({<<{}[]>{<>()}>}{{<<>()>
|
||||||
|
[[[[<<<({<({({[]}[[]{}])(<{}()>[{}{}])}[[({}())][{<>{}}{[]<>}]])>})<([<(<(()[])([]())>)<[[{}[]][{}<>]][[(
|
||||||
|
{<{<{<[[{[[<(([]{})){[()[]][{}[]]}><[{<>{}}({}{})]{({}())<<>[]>}>]]}(([<[{<>()}{(){}}]<<[]{}>(()())>>]
|
||||||
|
{<<<{<{<(<{([(<>)<[][]>][(()[]){{}<>}])}(((({}<>)<[][]>){([]<>){()<>}})<<<<>()>{{}()}>{<[]()><[]()>}>)})[<{
|
||||||
|
([<<[[{{<[{(<{[]()}>)<<<<>()>([]<>)>>}]{(({{<>()](()<>)}(({}())[[]()])))}>{(<[<(<><>)[{}<>]
|
||||||
|
[{<<{[[<[<<{{<<>()>}[[{}[]]({}{})]}([[<>[]]][(<><>)<()()>])>[({[<><>][[]<>]})({<[][]>(()<>)})]>}>][{(([<[{
|
||||||
|
{([[[<[(([[<<<()<>>[<>()]>[<()<>><(){}>]>[<<[][]>(<><>)>]][(([<>()]<<>()>))<([{}()]{{}{}}){<()[]){[]()}}>]]{[
|
||||||
|
{{<<[<{{([({[([]<>)[{}()]]{[()[]>[()()]}}<[[<>{}](<><>)]>)[<(<<><>><[]{}>)([<>{}])><<{[]}[{}()]>{<<>{}>[<>[]
|
||||||
|
{{<(<<((<[<<<[{}[]]<<><>>>[({}[]){{}()}]>>]>){(<([(<<>[]><{}>)({<><>}<{}[]>)]{{([]{}>(()())}
|
||||||
|
[(<<<{[<([[(({()()}<{}[]>){[{}<>]([]<>)})({(<>[])(()<>)}[([][])<())])]])({[<(([][]){()()})>{[[(
|
||||||
|
[<[[(({[<<([{({}[])[{}{}]}{<<>[]>[{}{}]}])[[({{}}<[]>){<[]()>{{}{}}}]<{[<>[]](<>())}<[()()][()<>]>>]>(<[[[[
|
||||||
|
{<{[([[<<<{<<({}{})(<>())>{<<><>><{}{}>}>{({()()}<{}()>)<(<>{}){<>[]}}}}({[{[]{}}{()<>}](<<><>>(
|
||||||
|
{{<<([{([[(([{()<>}<(){}>]<<()()>(()<>)>)({[{}()]}<<()[]><()()>>))][[<(((){})<[][]>)><(<<><>>
|
||||||
|
{(([{({<{[({[(<><>)(()()]]<[<>[]][{}<>]>})]}>{(([[(<()[]>(()<>)){{[]<>}(<>())}]([<[]()>[{}[
|
||||||
|
{{({{{<{{{[([[<><>]]<{[][]}[[]<>]>)(<<<><>><<><>>>[(()())({}<>)])]((<(<><>)<(){}>>[{{}{}}[{}<>]])([<()[]>
|
||||||
|
{(<<{{<<{{{{<<[]<>>[{}()]><<()[]>{{}[]}>}}}}([({<<{}{}>[()]>[[{}[]]<[]{}>]}(<{()()}<()[]>>))]{
|
||||||
|
{<<([((<<[<{({{}[]}<()()>)(([]{})<{}[]>)}<(((){})[()<>])>><(<(<><>)<<><>>>){[((){})([]<>)](([][])[<
|
||||||
|
<{[{<{<<({<<([{}()]{[]{}})[({}())<{}()>]>>[[[(()[])[()<>]](<[][]><{}()>)][(([]()]([]))]]})>>{<[<[((<{}<>>{(
|
||||||
|
[{[[[({<<[[([{<>{}}[[]]]<<{}<>><[]<>>>)(<<{}()>[()<>]>[<(){}>])][<{<()()><<>[]>}<[[][]][<>()]>><[[{}()](<>)
|
||||||
|
<{{[{[{[([[[([<><>]({}[]))([[][]](<>{})}][[{[]()}{{}()}][{[][]}<{}<>>]]][(({[]<>}[<>()])[<()<>><[][]>])<(({}
|
||||||
|
{(({[{(<[<(<[{<><>}<{}[]>]<[{}<>]((){})>>([{()}(<><>)])){<[<()<>>[{}()]]({<>{}}(<><>))>{{(<
|
||||||
|
<<[[(<{<({<<[[<>()]((){})]>{[({})<{}<>>]((<>{}){[]<>})>>})>}>({{(<<{([()[]])[{{}[]}(<>[])]}>>)}<((<<<
|
||||||
|
[[([{{((<(<({{[]<>}}<{<>()}([]())>)<[<<>()>(<>{})][[()()]<<>{}>]>>)>(<[[{[{}{}]({}[])}({{}{}}[[]()
|
||||||
|
<{[[{[([<([{<<()()>><<<>[]>>}][[((<>)(<><>))<({}{})<()<>>>]<{[<>()]<[]{}>}>])({[[{[]{}}]]}{({[<>()
|
||||||
|
<<[<{<([([<({<(){}>{[]()}}<<{}<>><[]<>>>)>{{<[(){}]{<>()}>(<<>()>[{}<>])]}](<(<(()())<<><>>
|
||||||
|
[{[<[<[<<(<[(<<>{}>)[<{}{}>({}{})]]})>[[(((<<>[]>[<>()])<{(){}}<(){}>>){{(<><>)}[(<>()){{}<>}]})
|
||||||
|
{<{<({{(<(<([[<>()][[]()]][(()[])[[]<>]])[([[]{}]{{}<>})]>[[<({}()){<><>}><{()[]}({}())>]([{<>{}}
|
||||||
|
({(([(<[[{{<([[]()]{{}{}})[{{}{}}[{}<>]]>[{([]<>)(()())}(<<><>>{<>{}})]}<<({()()}{()<>})[(<>
|
||||||
|
[<[<((({{<{([({}())([]{})]<(()())(<>())>)({<()[]>{<>[]}})}<[([()<>]{{}<>})](<{[]()}(<>())>)>>[({[([])(
|
||||||
|
({[<[(<((<{(<[()[]>[{}<>]>)<{<[]<>>{<>[]}}(({}{}))>}{{<[[]{}][{}{}]>{(())<[]()>}}}><<<{(<>[])<[]()>}({[][
|
||||||
|
(<<<({({<[[<<(<><>}<()<>>>{<{}<>><[]<>>}>[<<[]<>>(()[])>{<()()>}]]]{{(([<>[]]<[]{}>){({}{})([][]
|
||||||
|
({<[[<[({[{<{(()<>)}[(()[])<<>{}>]>}({{(<><>)[<><>]}[{[]()}<(){}>]}{{[()()]<(){}>}[[{}[]]([]{})]})]([[<{{}()}
|
||||||
|
[[[(<({(({{{<{()<>}[<>{}]><<[][]>({}[])>}[[[{}{}]<<>{}>][[(){}]]]}[<([{}{}][[]])[{<><>}[()[]]]>]}<<[({{
|
||||||
|
[<[[{[(([[<{(<{}{}>)}(<{(){}}([][])>{<(){}><<>{}>})>([([{}{}])(<[]><(){}>)])][({<<{}<>><[]<>>>[[[]{}]{[]{}}]
|
||||||
|
[{{[(<<{{{[([(()())<<><>>])<([()()]((){}))<([][]){[]<>}>>]{<<{(){}}(<><>)>({()<>}<()[]})>}}}}[{{<<
|
||||||
|
<[{[(({({<(<<<{}{}>{{}{}}>{([])({})}>{[{<>>(<>)]{[<>{}]<{}<>>}})[<({{}[]}<{}{}>)<([]())({}())>>({<[]
|
||||||
|
(<[<({[{{(((({{}[]}{{}<>}){(<>[])})[[({}<>)[[]<>]]<[{}]{[][]}>])(<[(<>()){<>()}]<(<><>){(){}}>>
|
||||||
|
[([{([{[<{<[<(<>{}){{}[]}>{([][]){()}}]{[<[]{}><<>{}>]{[(){}){[]{}}}}>([<[{}]<{}[]>>{<[][]>{()[]}}][{{<>()}{{
|
||||||
|
<{{(({({[<(({({}[]){{}<>}}[(<>()){[]{}}]))[[<{()()}[{}{}]>(<{}{}>(<>[]))]<<{()()}<{}{}>><{<><>}<<>[]
|
||||||
|
{{[[<[<[{[<{{[[]<>]<[]>}[({}{})(<>)]}>](<<((<>)<[]<>>)[<{}()><<>[]>]>[<{<>()}<(){}>>[[()<>]]]>(<[{
|
||||||
|
({[<(<{<[<<<(<<>()><[]<>>)<<()<>>({}[])>>(<[()()]{<><>}>)>>]>(<<({[<{}[]>{()}]}<<{()<>}({}())>({[]<>}([]()))>
|
||||||
|
<{<{{[({{(<{<<<><>><(){}>>[([][])([]{})]}<{([][]){{}}}<<[]()>([][])>>>[<{{[]()}[()<>]}<[<>{}]([]{})>>])
|
||||||
|
{({[{(<[<<<<(([]<>)<{}{}>)>((({}{})<{}<>>)<<{}{}>>}>{{[<()()>[{}()]]}((<<>()>[(){}])<{[]<>}[<>{}]>)}>>{<<{
|
||||||
|
((([<[[[<{{<<<{}[]><<>{}>>(([]<>)[[]])>((<{}[]><{}>)(({}[])[()[]]))}{{<(<>[])(<><>)>(<<>[]
|
||||||
|
[[([{<(<(<[({[[][]]{()<>}}{{<>[]}<[][]>})]>)<{[((((){})([]<>))[<<><>>(<><>)]>[{<{}[]><[][]>
|
||||||
|
[<<(<(({{{<((([]())[<>{}])<[[][]]{()()}>)><[<((){})<()()]>[<[]>[(){}]]]({([]())([]{})}([<>(
|
||||||
|
(<{<<{<((({(<{(){}}[()<>]>{[[]<>][()[]]})<<{[][]}{{}[]}>[(<><>)<{}{}>]>}(<[{{}<>}{[]()}]({()[]}((
|
||||||
|
<[[([<<[{{<(<[()[]]{<><>}>([<>[]]<{}[]>))[({{}()}<[]<>>)<(<>{})>]>{{{<<>{}>(<>)}<{<>()}[<>()]>}<[<<>()
|
||||||
|
[[((<({<[{{<[[[]()][<>]](<()()>[{}<>])>{<(()<>)>([()<>]{()[]})}}{[[(()<>><[]<>>]]<{(<><>){{}<>}}
|
||||||
|
[<{([{[{<<<(<[<><>]({}())>{([]<>][[]{}]})[<{[]<>}[<>{}]>[<[][]>]]>>({([(<><>){<>{}}][{{}[]}({}<>)
|
||||||
|
{({{<[([{([<<{<>()}>[{<>[]}[{}[]]]>](<{{[]{}}[{}<>]}({<>[]}[{}[]])>[<([][])({}{})><<{}()>(()<>)
|
||||||
|
(<({[<(<[<[{([[]{}][{}[]])([{}[]])}{({<>[]}{()[]})[[<><>](()<>)]}]><(({[()[]]}([{}()][{}{}]))<[(()<>)]>)[[<
|
||||||
|
<(<(<<({({[<{<<><>>[()<>]}{<[]()><<><>>}>[(([][])<{}[]>)(({}{})<<>()>)]](<<(<><>){[]<>}>([[][]][<>()])>{<(
|
||||||
|
[({<[[<{[[{[{{<>()}{{}[]}}](([{}[]}{[][]})<{<>[]}({}<>)>)}{[(([]{})<{}[]>)<<{}>{(){}}>]}]<[
|
||||||
|
<[({<<[[({{{((<><>)<[]<>>)<<{}><{}<>>>}(([(){}]{()})[{[][]}[[]<>]])}}[[<[<()[]>[{}()]]><{<{}<>><<>[]>}{[[]
|
||||||
|
<[{[[[[[<{[<([<>()]([]{}))<{[]{}}<[][]>>>([{[]<>}([]<>)]{[{}()][<>{}]}}]<[[(<><>)[{}{}]][(()(
|
||||||
|
{<{{[<({{<[([{()()}[{}<>]]{({}())<(){}>})[[{(){}}<[]<>>}<(<>()){{}{}}>]]{{(([]{})[[]()])[{{}{}}[[]{}]]}{<[
|
||||||
|
(([<([<<{[{{[({}{})][(<>{})]}}]{{([<<>{}>(<>())])}}}>[{<<(({{}<>}<<>[]>){({}())<{}()>})><(<[()<>]><{()<>}<
|
||||||
|
[<[{[[[({[{[(((){}){(){}}){{<><>}{{}[]}}]<{({}()){<>{}}}>}<{[{[]{}}({}{})])>]}{(<(((()[]){{}[]})[<()<>
|
||||||
|
({<<([{{{{({[{<>[]}[{}{}]]{<[]{}><{}{}>}}[<[<>()](<><>)><[{}{}]>])(<{[<>()]<<>()>}<(<>[])>>(([()
|
95
10/syntaxchecker.hs
Normal file
95
10/syntaxchecker.hs
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
import Data.List (foldl', sort)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
code = lines input
|
||||||
|
(putStrLn . show . solution1) code
|
||||||
|
(putStrLn . show . solution2) code
|
||||||
|
|
||||||
|
solution1 :: [String] -> Int
|
||||||
|
solution1 = sum . map charScore . map (head . fst . resolveChunks)
|
||||||
|
where
|
||||||
|
charScore :: Char -> Int
|
||||||
|
charScore ')' = 3
|
||||||
|
charScore ']' = 57
|
||||||
|
charScore '}' = 1197
|
||||||
|
charScore '>' = 25137
|
||||||
|
charScore _ = 0
|
||||||
|
|
||||||
|
solution2 :: [String] -> Int
|
||||||
|
solution2 = middle . sort . map score . completed . nonCorrupt
|
||||||
|
where
|
||||||
|
completed = map (completeChunks . fst)
|
||||||
|
nonCorrupt = filter notCorrupt . map resolveChunks
|
||||||
|
score :: [Char] -> Int
|
||||||
|
score = foldl' (\s x -> s * 5 + (charScore x)) 0
|
||||||
|
where
|
||||||
|
charScore :: Char -> Int
|
||||||
|
charScore ')' = 1
|
||||||
|
charScore ']' = 2
|
||||||
|
charScore '}' = 3
|
||||||
|
charScore '>' = 4
|
||||||
|
charScore _ = undefined
|
||||||
|
notCorrupt :: ([Char], Bool) -> Bool
|
||||||
|
notCorrupt (_, corrupt) = not corrupt
|
||||||
|
middle :: [a] -> a
|
||||||
|
middle [] = undefined
|
||||||
|
middle l = l !! (length l `quot` 2)
|
||||||
|
|
||||||
|
completeChunks :: String -> String
|
||||||
|
completeChunks = map close
|
||||||
|
where
|
||||||
|
close :: Char -> Char
|
||||||
|
close c
|
||||||
|
| c == '(' = ')'
|
||||||
|
| c == '[' = ']'
|
||||||
|
| c == '{' = '}'
|
||||||
|
| c == '<' = '>'
|
||||||
|
| otherwise = undefined
|
||||||
|
|
||||||
|
resolveChunks :: String -> ([Char], Bool)
|
||||||
|
resolveChunks = foldl' resolve ([], False)
|
||||||
|
where
|
||||||
|
resolve :: ([Char], Bool) -> Char -> ([Char], Bool)
|
||||||
|
resolve (stack, broken) c
|
||||||
|
| broken = (stack, broken)
|
||||||
|
| isOpen c = (c:stack, False)
|
||||||
|
| close c == head stack = (tail stack, False)
|
||||||
|
| close c /= head stack = (c:stack, True)
|
||||||
|
| otherwise = undefined
|
||||||
|
|
||||||
|
isOpen :: Char -> Bool
|
||||||
|
isOpen c
|
||||||
|
| c == '(' = True
|
||||||
|
| c == '[' = True
|
||||||
|
| c == '{' = True
|
||||||
|
| c == '<' = True
|
||||||
|
| otherwise = False
|
||||||
|
|
||||||
|
close :: Char -> Char
|
||||||
|
close c
|
||||||
|
| c == ')' = '('
|
||||||
|
| c == ']' = '['
|
||||||
|
| c == '}' = '{'
|
||||||
|
| c == '>' = '<'
|
||||||
|
| otherwise = undefined
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput = [
|
||||||
|
"[({(<(())[]>[[{[]{<()<>>",
|
||||||
|
"[(()[<>])]({[<{<<[]>>(",
|
||||||
|
"{([(<{}[<>[]}>{[]{[(<()>",
|
||||||
|
"(((({<>}<{<{<>}{[]{[]{}",
|
||||||
|
"[[<[([]))<([[{}[[()]]]",
|
||||||
|
"[{[{({}]{}}([{[{{{}}([]",
|
||||||
|
"{<[[]]>}<{[{[{[]{()[[[]",
|
||||||
|
"[<(<(<(<{}))><([]([]()",
|
||||||
|
"<{([([[(<>()){}]>(<<{{",
|
||||||
|
"<{([{{}}[<[[[<>{}]]]>[]]"
|
||||||
|
]
|
||||||
|
|
||||||
|
test1 = solution1 testInput -- 26397
|
||||||
|
test2 = solution2 testInput -- 288957
|
10
11/input.txt
Normal file
10
11/input.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
5421451741
|
||||||
|
3877321568
|
||||||
|
7583273864
|
||||||
|
3451717778
|
||||||
|
2651615156
|
||||||
|
6377167526
|
||||||
|
5182852831
|
||||||
|
4766856676
|
||||||
|
3437187583
|
||||||
|
3633371586
|
93
11/octoflash.hs
Normal file
93
11/octoflash.hs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
import Data.Char (digitToInt)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
octopodes = (map (map digitToInt) . lines) input
|
||||||
|
(putStrLn . show . solution1) octopodes
|
||||||
|
(putStrLn . show . solution2) octopodes
|
||||||
|
|
||||||
|
solution1 :: [[Int]] -> Int
|
||||||
|
solution1 m = snd (iterate flashSimulate (m, 0) !! 100)
|
||||||
|
|
||||||
|
solution2 :: [[Int]] -> Int
|
||||||
|
solution2 m = countUntil (all (all (==0)) . fst) flashSimulate (m, 0)
|
||||||
|
|
||||||
|
flashSimulate :: ([[Int]], Int) -> ([[Int]], Int)
|
||||||
|
flashSimulate (octopodes, flashes) =
|
||||||
|
(refreshOctopodes exhaustedOctopodes, flashes + countExhaustedOctopodes exhaustedOctopodes)
|
||||||
|
where
|
||||||
|
exhaustedOctopodes = flashStep octopodes
|
||||||
|
countExhaustedOctopodes = foldr (\l a -> length l + a) 0 . map (filter (> 9))
|
||||||
|
refreshOctopodes = map (map (\o -> if o > 9 then 0 else o))
|
||||||
|
|
||||||
|
flashStep :: [[Int]] -> [[Int]]
|
||||||
|
flashStep = propagateFlashes . map (map (+1))
|
||||||
|
where
|
||||||
|
propagateFlashes :: [[Int]] -> [[Int]]
|
||||||
|
propagateFlashes = until allExhausted flashOctopi
|
||||||
|
where
|
||||||
|
allExhausted :: [[Int]] -> Bool
|
||||||
|
allExhausted = all (all (/= 10))
|
||||||
|
flashOctopi :: [[Int]] -> [[Int]]
|
||||||
|
flashOctopi m = map (map (incrementFlashing m))
|
||||||
|
[[(x, y) | y <- [0..length (m !! x) - 1]] | x <- [0..length m - 1]]
|
||||||
|
where
|
||||||
|
incrementFlashing ::[[Int]] -> (Int, Int) -> Int
|
||||||
|
incrementFlashing m' o
|
||||||
|
| charge < 10 && newCharge > 10 = 10 -- Ensure we don't miss an increment
|
||||||
|
| otherwise = charge + numFlashingNeighbors o
|
||||||
|
where
|
||||||
|
newCharge = charge + numFlashingNeighbors o
|
||||||
|
charge = m' !!! o
|
||||||
|
numFlashingNeighbors :: (Int, Int) -> Int
|
||||||
|
numFlashingNeighbors = length . filter (\o -> (m !!! o) == 10) . (flip adjacent m)
|
||||||
|
|
||||||
|
(!!!) :: [[Int]] -> (Int, Int) -> Int
|
||||||
|
(!!!) m index = m !! (fst index) !! (snd index)
|
||||||
|
|
||||||
|
countUntil :: (a -> Bool) -> (a -> a) -> a -> Int
|
||||||
|
countUntil p f = call
|
||||||
|
where
|
||||||
|
call x
|
||||||
|
| p x = 0
|
||||||
|
| otherwise = call (f x) + 1
|
||||||
|
|
||||||
|
adjacent :: (Int, Int) -> [[Int]] -> [(Int, Int)]
|
||||||
|
adjacent (x, y) m = [(x+i, y+j) |
|
||||||
|
i <- [-1..1],
|
||||||
|
j <- [-1..1],
|
||||||
|
-- (i, j) /= (0, 0),
|
||||||
|
x+i >= 0,
|
||||||
|
y+j >= 0,
|
||||||
|
x+i < length m,
|
||||||
|
y+j < length (m !! 0)]
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput1 = [
|
||||||
|
"5483143223",
|
||||||
|
"2745854711",
|
||||||
|
"5264556173",
|
||||||
|
"6141336146",
|
||||||
|
"6357385478",
|
||||||
|
"4167524645",
|
||||||
|
"2176841721",
|
||||||
|
"6882881134",
|
||||||
|
"4846848554",
|
||||||
|
"5283751526"
|
||||||
|
]
|
||||||
|
parsedTestInput1 = map (map digitToInt) testInput1
|
||||||
|
|
||||||
|
testInput2 = [
|
||||||
|
"11111",
|
||||||
|
"19991",
|
||||||
|
"19191",
|
||||||
|
"19991",
|
||||||
|
"11111"
|
||||||
|
]
|
||||||
|
parsedTestInput2 = map (map digitToInt) testInput2
|
||||||
|
|
||||||
|
test1 = solution1 parsedTestInput1
|
||||||
|
test2 = solution2 parsedTestInput1
|
23
12/Parsing.hs
Normal file
23
12/Parsing.hs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module Parsing (
|
||||||
|
splitByString
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (isPrefixOf)
|
||||||
|
|
||||||
|
splitByString :: String -> String -> [String]
|
||||||
|
splitByString _ "" = []
|
||||||
|
splitByString splitter string =
|
||||||
|
let (chunk, rest) = spanNextSplit string
|
||||||
|
in
|
||||||
|
chunk:(splitByString splitter rest)
|
||||||
|
where
|
||||||
|
spanNextSplit :: String -> (String, String)
|
||||||
|
spanNextSplit [] = ([], [])
|
||||||
|
spanNextSplit everything@(char:rest)
|
||||||
|
| splitter `isPrefixOf` rest =
|
||||||
|
([char], (drop ((length splitter) + 1) everything))
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
(start, end) = spanNextSplit rest
|
||||||
|
in
|
||||||
|
(char:start, end)
|
122
12/cavesearcher.hs
Normal file
122
12/cavesearcher.hs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
import Data.Char (isLower)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import qualified Data.Set as Set
|
||||||
|
import Parsing (splitByString)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
caves = parseCaves input
|
||||||
|
(putStrLn . show . solution1) caves
|
||||||
|
(putStrLn . show . solution2) caves
|
||||||
|
|
||||||
|
solution1 :: Map.Map String [String] -> Int
|
||||||
|
solution1 = length . cavePaths
|
||||||
|
|
||||||
|
solution2 :: Map.Map String [String] -> Int
|
||||||
|
solution2 = length . cavePaths2
|
||||||
|
|
||||||
|
parseCaves :: String -> Map.Map String [String]
|
||||||
|
parseCaves = Map.fromListWith (++) . flatmap addReverse . map tupleFromList . map (splitByString "-") . lines
|
||||||
|
where
|
||||||
|
addReverse :: (String, [String]) -> [(String, [String])]
|
||||||
|
addReverse t@(a, b) = [t, (head b, [a])]
|
||||||
|
tupleFromList :: [String] -> (String, [String])
|
||||||
|
tupleFromList [] = undefined
|
||||||
|
tupleFromList (x:xs)
|
||||||
|
-- Since the second part is always expected to be a cave label
|
||||||
|
-- or "end", this should never be > 1
|
||||||
|
| length xs > 1 = undefined
|
||||||
|
| otherwise = (x, xs)
|
||||||
|
|
||||||
|
cavePaths :: Map.Map String [String] -> [[String]]
|
||||||
|
cavePaths caveMap = followSingle caveMap Set.empty "start"
|
||||||
|
|
||||||
|
cavePaths2 :: Map.Map String [String] -> [[String]]
|
||||||
|
cavePaths2 caveMap = followOneRepeat caveMap Set.empty "start"
|
||||||
|
|
||||||
|
followSingle :: Map.Map String [String] -> Set.Set String -> String -> [[String]]
|
||||||
|
followSingle caveMap visited node
|
||||||
|
| node == "end" = [[node]]
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
v' = Set.insert node visited
|
||||||
|
in
|
||||||
|
map ((:) node) (flatmap (followSingle caveMap v') adjacent)
|
||||||
|
where
|
||||||
|
adjacent :: [String]
|
||||||
|
adjacent = filter (not . visitedSmall) (Map.findWithDefault [] node caveMap)
|
||||||
|
visitedSmall :: String -> Bool
|
||||||
|
visitedSmall n = all isLower n && n `elem` visited
|
||||||
|
|
||||||
|
followOneRepeat :: Map.Map String [String] -> Set.Set String -> String -> [[String]]
|
||||||
|
followOneRepeat caveMap visited node
|
||||||
|
| node == "end" = [[node]]
|
||||||
|
| all isLower node && node `elem` visited =
|
||||||
|
followSingle caveMap visited node
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
v' = Set.insert node visited
|
||||||
|
in
|
||||||
|
map ((:) node) (flatmap (followOneRepeat caveMap v') adjacent)
|
||||||
|
where
|
||||||
|
adjacent :: [String]
|
||||||
|
adjacent = filter (/= "start") (Map.findWithDefault [] node caveMap)
|
||||||
|
|
||||||
|
flatmap :: (t -> [a]) -> [t] -> [a]
|
||||||
|
flatmap _ [] = []
|
||||||
|
flatmap f (x:xs) = f x ++ flatmap f xs
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput1 = unlines [
|
||||||
|
"start-A",
|
||||||
|
"start-b",
|
||||||
|
"A-c",
|
||||||
|
"A-b",
|
||||||
|
"b-d",
|
||||||
|
"A-end",
|
||||||
|
"b-end"
|
||||||
|
]
|
||||||
|
|
||||||
|
testInput2 = unlines [
|
||||||
|
"dc-end",
|
||||||
|
"HN-start",
|
||||||
|
"start-kj",
|
||||||
|
"dc-start",
|
||||||
|
"dc-HN",
|
||||||
|
"LN-dc",
|
||||||
|
"HN-end",
|
||||||
|
"kj-sa",
|
||||||
|
"kj-HN",
|
||||||
|
"kj-dc"]
|
||||||
|
|
||||||
|
testInput3 = unlines [
|
||||||
|
"fs-end",
|
||||||
|
"he-DX",
|
||||||
|
"fs-he",
|
||||||
|
"start-DX",
|
||||||
|
"pj-DX",
|
||||||
|
"end-zg",
|
||||||
|
"zg-sl",
|
||||||
|
"zg-pj",
|
||||||
|
"pj-he",
|
||||||
|
"RW-he",
|
||||||
|
"fs-DX",
|
||||||
|
"pj-RW",
|
||||||
|
"zg-RW",
|
||||||
|
"start-pj",
|
||||||
|
"he-WI",
|
||||||
|
"zg-he",
|
||||||
|
"pj-fs",
|
||||||
|
"start-RW"]
|
||||||
|
|
||||||
|
parsedTestInput1 = parseCaves testInput1
|
||||||
|
test1 = cavePaths parsedTestInput1
|
||||||
|
test2 = cavePaths2 parsedTestInput1
|
||||||
|
test3 = cavePaths2 (parseCaves testInput2)
|
||||||
|
test4 = cavePaths2 (parseCaves testInput3)
|
||||||
|
|
||||||
|
printPaths :: [[String]] -> IO ()
|
||||||
|
printPaths = putStr . unlines . (map (foldr1 (\c a -> c++"->"++a)))
|
24
12/input.txt
Normal file
24
12/input.txt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
yb-pi
|
||||||
|
jg-ej
|
||||||
|
yb-KN
|
||||||
|
LD-start
|
||||||
|
end-UF
|
||||||
|
UF-yb
|
||||||
|
yb-xd
|
||||||
|
qx-yb
|
||||||
|
xd-end
|
||||||
|
jg-KN
|
||||||
|
start-qx
|
||||||
|
start-ej
|
||||||
|
qx-LD
|
||||||
|
jg-LD
|
||||||
|
xd-LD
|
||||||
|
ej-qx
|
||||||
|
end-KN
|
||||||
|
DM-xd
|
||||||
|
jg-yb
|
||||||
|
ej-LD
|
||||||
|
qx-UF
|
||||||
|
UF-jg
|
||||||
|
qx-jg
|
||||||
|
xd-UF
|
32
13/Parsing.hs
Normal file
32
13/Parsing.hs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
module Parsing (
|
||||||
|
splitByString,
|
||||||
|
parseCoordinates
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (isPrefixOf)
|
||||||
|
|
||||||
|
splitByString :: String -> String -> [String]
|
||||||
|
splitByString _ "" = []
|
||||||
|
splitByString splitter string =
|
||||||
|
let (chunk, rest) = spanNextSplit string
|
||||||
|
in
|
||||||
|
chunk:(splitByString splitter rest)
|
||||||
|
where
|
||||||
|
spanNextSplit :: String -> (String, String)
|
||||||
|
spanNextSplit [] = ([], [])
|
||||||
|
spanNextSplit everything@(char:rest)
|
||||||
|
| splitter `isPrefixOf` rest =
|
||||||
|
([char], (drop ((length splitter) + 1) everything))
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
(start, end) = spanNextSplit rest
|
||||||
|
in
|
||||||
|
(char:start, end)
|
||||||
|
|
||||||
|
parseCoordinates :: String -> [(Int, Int)]
|
||||||
|
parseCoordinates =
|
||||||
|
map (tuplify . map read . splitByString ",") . lines
|
||||||
|
where
|
||||||
|
tuplify :: [a] -> (a, a)
|
||||||
|
tuplify [a, b] = (a, b)
|
||||||
|
tuplify _ = error "Can't parse coordinates from non-2-sized lists"
|
1035
13/input.txt
Normal file
1035
13/input.txt
Normal file
File diff suppressed because it is too large
Load diff
86
13/paperfolder.hs
Normal file
86
13/paperfolder.hs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
import Data.List (foldl', nub)
|
||||||
|
import Parsing (parseCoordinates, splitByString)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
instructions = parseInstructions input
|
||||||
|
(putStrLn . show . solution1) instructions
|
||||||
|
(putStr . solution2) instructions
|
||||||
|
|
||||||
|
solution1 :: ([(Int, Int)], [(Int, Int)]) -> Int
|
||||||
|
solution1 (paper, folds) = (length . nub) (foldPaper paper (folds !! 0))
|
||||||
|
|
||||||
|
solution2 :: ([(Int, Int)], [(Int, Int)]) -> String
|
||||||
|
solution2 (paper, folds) = printPaper (foldl' (foldPaper) paper folds)
|
||||||
|
|
||||||
|
foldPaper :: [(Int, Int)] -> (Int, Int) -> [(Int, Int)]
|
||||||
|
foldPaper paper axis = map (fold axis) paper
|
||||||
|
where
|
||||||
|
fold :: (Int, Int) -> (Int, Int) -> (Int, Int)
|
||||||
|
fold (0, a) (x, y)
|
||||||
|
| y < a = (x, y)
|
||||||
|
| y > a = (x, flipCoord y a)
|
||||||
|
fold (a, 0) (x, y)
|
||||||
|
| x < a = (x, y)
|
||||||
|
| x > a = (flipCoord x a, y)
|
||||||
|
fold _ _ = undefined -- Only axis-folds are defined
|
||||||
|
flipCoord :: Int -> Int -> Int
|
||||||
|
flipCoord c a = a - (c - a)
|
||||||
|
|
||||||
|
printPaper :: [(Int, Int)] -> String
|
||||||
|
printPaper = unlines . coordsToPaper
|
||||||
|
where
|
||||||
|
coordsToPaper :: [(Int, Int)] -> [String]
|
||||||
|
coordsToPaper dots = [[if (x, y) `elem` dots then '█' else ' ' |
|
||||||
|
x <- [0..maximum (map fst dots)]] |
|
||||||
|
y <- [0..maximum (map snd dots)]]
|
||||||
|
|
||||||
|
parseInstructions :: String -> ([(Int, Int)], [(Int, Int)])
|
||||||
|
parseInstructions input =
|
||||||
|
(dots, folds)
|
||||||
|
where
|
||||||
|
split :: [String]
|
||||||
|
split = splitByString "\n\n" input
|
||||||
|
dots :: [(Int, Int)]
|
||||||
|
dots = (parseCoordinates . head) split
|
||||||
|
folds :: [(Int, Int)]
|
||||||
|
folds = (map (tuplify . splitByString "=") . lines . last) split
|
||||||
|
tuplify :: [String] -> (Int, Int)
|
||||||
|
tuplify [] = error "Can't turn an empty list into fold instructions"
|
||||||
|
tuplify (fold:axis)
|
||||||
|
| last fold == 'x' = (read (head axis), 0)
|
||||||
|
| last fold == 'y' = (0, read (head axis))
|
||||||
|
| otherwise = error "Fold instructions must go across x or y"
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput1 = unlines [
|
||||||
|
"6,10",
|
||||||
|
"0,14",
|
||||||
|
"9,10",
|
||||||
|
"0,3",
|
||||||
|
"10,4",
|
||||||
|
"4,11",
|
||||||
|
"6,0",
|
||||||
|
"6,12",
|
||||||
|
"4,1",
|
||||||
|
"0,13",
|
||||||
|
"10,12",
|
||||||
|
"3,4",
|
||||||
|
"3,0",
|
||||||
|
"8,4",
|
||||||
|
"1,10",
|
||||||
|
"2,14",
|
||||||
|
"8,10",
|
||||||
|
"9,0",
|
||||||
|
"",
|
||||||
|
"fold along y=7",
|
||||||
|
"fold along x=5"]
|
||||||
|
|
||||||
|
testInput1Parsed = parseInstructions testInput1
|
||||||
|
test1 = solution1 testInput1Parsed
|
||||||
|
test2 = putStr (solution2 testInput1Parsed)
|
||||||
|
|
||||||
|
testPrinted1 = putStr (printPaper (foldPaper (fst testInput1Parsed) (head (snd testInput1Parsed))))
|
14
14/Itertools.hs
Normal file
14
14/Itertools.hs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
module Itertools (
|
||||||
|
flatmap,
|
||||||
|
windows
|
||||||
|
) where
|
||||||
|
|
||||||
|
windows :: Int -> [a] -> [[a]]
|
||||||
|
windows _ [] = []
|
||||||
|
windows i (x:xs)
|
||||||
|
| length xs < i-1 = []
|
||||||
|
| otherwise = (x:take (i-1) xs):windows i xs
|
||||||
|
|
||||||
|
flatmap :: (t -> [a]) -> [t] -> [a]
|
||||||
|
flatmap _ [] = []
|
||||||
|
flatmap f (x:xs) = f x ++ flatmap f xs
|
32
14/Parsing.hs
Normal file
32
14/Parsing.hs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
module Parsing (
|
||||||
|
splitByString,
|
||||||
|
parseCoordinates
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (isPrefixOf)
|
||||||
|
|
||||||
|
splitByString :: String -> String -> [String]
|
||||||
|
splitByString _ "" = []
|
||||||
|
splitByString splitter string =
|
||||||
|
let (chunk, rest) = spanNextSplit string
|
||||||
|
in
|
||||||
|
chunk:(splitByString splitter rest)
|
||||||
|
where
|
||||||
|
spanNextSplit :: String -> (String, String)
|
||||||
|
spanNextSplit [] = ([], [])
|
||||||
|
spanNextSplit everything@(char:rest)
|
||||||
|
| splitter `isPrefixOf` rest =
|
||||||
|
([char], (drop ((length splitter) + 1) everything))
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
(start, end) = spanNextSplit rest
|
||||||
|
in
|
||||||
|
(char:start, end)
|
||||||
|
|
||||||
|
parseCoordinates :: String -> [(Int, Int)]
|
||||||
|
parseCoordinates =
|
||||||
|
map (tuplify . map read . splitByString ",") . lines
|
||||||
|
where
|
||||||
|
tuplify :: [a] -> (a, a)
|
||||||
|
tuplify [a, b] = (a, b)
|
||||||
|
tuplify _ = error "Can't parse coordinates from non-2-sized lists"
|
28
14/Reducers.hs
Normal file
28
14/Reducers.hs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
module Reducers (
|
||||||
|
leastMostOcc,
|
||||||
|
leastMost,
|
||||||
|
most,
|
||||||
|
least
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (group, sortBy, sort)
|
||||||
|
import Data.Ord (comparing)
|
||||||
|
|
||||||
|
groupOccurrences :: (Ord a) => [a] -> [[a]]
|
||||||
|
groupOccurrences = sortBy (comparing length) . group . sort
|
||||||
|
|
||||||
|
leastMostOcc :: (Ord a) => [a] -> (Int, Int)
|
||||||
|
leastMostOcc list = ((length . last) occ, (length . head) occ)
|
||||||
|
where
|
||||||
|
occ = groupOccurrences list
|
||||||
|
|
||||||
|
leastMost :: (Ord a) => [a] -> (a, a)
|
||||||
|
leastMost list = ((head . last) occ, (head . head) occ)
|
||||||
|
where
|
||||||
|
occ = groupOccurrences list
|
||||||
|
|
||||||
|
least :: (Ord a) => [a] -> a
|
||||||
|
least = fst . leastMost
|
||||||
|
|
||||||
|
most :: (Ord a) => [a] -> a
|
||||||
|
most = snd . leastMost
|
102
14/input.txt
Normal file
102
14/input.txt
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
BSONBHNSSCFPSFOPHKPK
|
||||||
|
|
||||||
|
PF -> P
|
||||||
|
KO -> H
|
||||||
|
CH -> K
|
||||||
|
KN -> S
|
||||||
|
SS -> K
|
||||||
|
KB -> B
|
||||||
|
VS -> V
|
||||||
|
KV -> O
|
||||||
|
KP -> B
|
||||||
|
OF -> C
|
||||||
|
HB -> C
|
||||||
|
NP -> O
|
||||||
|
NS -> V
|
||||||
|
VO -> P
|
||||||
|
VF -> H
|
||||||
|
CK -> B
|
||||||
|
PC -> O
|
||||||
|
SK -> O
|
||||||
|
KF -> H
|
||||||
|
FV -> V
|
||||||
|
PP -> H
|
||||||
|
KS -> B
|
||||||
|
FP -> N
|
||||||
|
BV -> V
|
||||||
|
SB -> F
|
||||||
|
PB -> B
|
||||||
|
ON -> F
|
||||||
|
SF -> P
|
||||||
|
VH -> F
|
||||||
|
FC -> N
|
||||||
|
CB -> H
|
||||||
|
HP -> B
|
||||||
|
NC -> B
|
||||||
|
FH -> K
|
||||||
|
BF -> P
|
||||||
|
CN -> N
|
||||||
|
NK -> H
|
||||||
|
SC -> S
|
||||||
|
PK -> V
|
||||||
|
PV -> C
|
||||||
|
KC -> H
|
||||||
|
HN -> K
|
||||||
|
NO -> H
|
||||||
|
NN -> S
|
||||||
|
VC -> P
|
||||||
|
FF -> N
|
||||||
|
OO -> H
|
||||||
|
BK -> N
|
||||||
|
FS -> V
|
||||||
|
BO -> F
|
||||||
|
SH -> S
|
||||||
|
VK -> F
|
||||||
|
OC -> F
|
||||||
|
FN -> V
|
||||||
|
OV -> K
|
||||||
|
CF -> F
|
||||||
|
NV -> V
|
||||||
|
OP -> K
|
||||||
|
PN -> K
|
||||||
|
SO -> P
|
||||||
|
PS -> S
|
||||||
|
KK -> H
|
||||||
|
HH -> K
|
||||||
|
NH -> O
|
||||||
|
FB -> K
|
||||||
|
HS -> B
|
||||||
|
BB -> V
|
||||||
|
VB -> O
|
||||||
|
BH -> H
|
||||||
|
OK -> C
|
||||||
|
CC -> B
|
||||||
|
FK -> N
|
||||||
|
SN -> V
|
||||||
|
HK -> N
|
||||||
|
KH -> F
|
||||||
|
OS -> O
|
||||||
|
FO -> P
|
||||||
|
OH -> B
|
||||||
|
CP -> S
|
||||||
|
BN -> H
|
||||||
|
OB -> B
|
||||||
|
BP -> B
|
||||||
|
CO -> K
|
||||||
|
SP -> K
|
||||||
|
BS -> P
|
||||||
|
VV -> N
|
||||||
|
VN -> O
|
||||||
|
NF -> F
|
||||||
|
CV -> B
|
||||||
|
HC -> B
|
||||||
|
HV -> S
|
||||||
|
BC -> O
|
||||||
|
HO -> H
|
||||||
|
PO -> P
|
||||||
|
CS -> B
|
||||||
|
PH -> S
|
||||||
|
SV -> V
|
||||||
|
VP -> C
|
||||||
|
NB -> K
|
||||||
|
HF -> C
|
121
14/polymerization.hs
Normal file
121
14/polymerization.hs
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
import Data.List (maximumBy, minimumBy)
|
||||||
|
import Data.Map.Strict (Map, (!))
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
import Data.Ord (comparing)
|
||||||
|
import Itertools (flatmap, windows)
|
||||||
|
import Parsing (splitByString)
|
||||||
|
import Reducers (leastMostOcc)
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
polymer = parsePolymer input
|
||||||
|
(putStrLn . show . solution1) polymer
|
||||||
|
(putStrLn . show . solution2) polymer
|
||||||
|
|
||||||
|
parsePolymer :: String -> ([Char], Map [Char] Char)
|
||||||
|
parsePolymer input = (template input, rules input)
|
||||||
|
where
|
||||||
|
template :: String -> String
|
||||||
|
template = head . splitByString "\n\n"
|
||||||
|
rules :: String -> Map [Char] Char
|
||||||
|
rules = Map.fromList . map tupelize . map (splitByString " -> ") . lines . last . splitByString "\n\n"
|
||||||
|
tupelize :: [String] -> ([Char], Char)
|
||||||
|
tupelize untupled = (head untupled, (head . last) untupled)
|
||||||
|
|
||||||
|
solution1 :: ([Char], Map [Char] Char) -> Int
|
||||||
|
solution1 (template, rules) = uncurry (-) (leastMostOcc (polymerizeN rules template 10))
|
||||||
|
|
||||||
|
solution2 :: ([Char], Map [Char] Char) -> Int
|
||||||
|
solution2 (template, rules) = ((snd . most) polyCounts) - ((snd . least) polyCounts)
|
||||||
|
where
|
||||||
|
polyCounts :: Map Char Int
|
||||||
|
polyCounts = polyCounter rules template 40
|
||||||
|
least = minimumBy (comparing snd) . Map.assocs
|
||||||
|
most = maximumBy (comparing snd) . Map.assocs
|
||||||
|
|
||||||
|
polymerizeN :: Map [Char] Char -> [Char] -> Int -> [Char]
|
||||||
|
polymerizeN rules template i = iterate (polymerize rules) template !! i
|
||||||
|
|
||||||
|
polymerize :: Map [Char] Char -> [Char] -> [Char]
|
||||||
|
polymerize rules template = step template
|
||||||
|
where
|
||||||
|
step :: [Char] -> [Char]
|
||||||
|
step [] = []
|
||||||
|
step [final] = [final]
|
||||||
|
step (x:xs) = x:(rules ! [x, head xs]):(step xs)
|
||||||
|
|
||||||
|
-- Since we don't actually need to synthesize the polymer, but only
|
||||||
|
-- need to know how many of each elements occur, we can get around
|
||||||
|
-- having to create a ridiculously large list by operating on the rule
|
||||||
|
-- pairs instead.
|
||||||
|
--
|
||||||
|
-- E.g. NNCB -> NCNBCHB (see testInput1), in this case we turn:
|
||||||
|
--
|
||||||
|
-- - NN -> NC, CN
|
||||||
|
-- - NC -> NB, BC
|
||||||
|
-- - CB -> CH, HB
|
||||||
|
--
|
||||||
|
-- All we need to do is keep track of the counts of these
|
||||||
|
-- sub-sequences, not of the full polymer.
|
||||||
|
--
|
||||||
|
-- To get back to the individual elements, we then just need to
|
||||||
|
-- de-window it all again.
|
||||||
|
polyCounter :: Map [Char] Char -> [Char] -> Int -> Map Char Int
|
||||||
|
polyCounter rules template iterations = elCounts
|
||||||
|
where
|
||||||
|
initial :: Map [Char] Int
|
||||||
|
initial = (Map.fromListWith (+) . map (\e -> (e, 1)) . windows 2) template
|
||||||
|
step :: Map [Char] Int -> Map [Char] Int
|
||||||
|
step = Map.fromListWith (+) . flatmap resultingPolies . Map.assocs
|
||||||
|
resultingPolies :: ([Char], Int) -> [([Char], Int)]
|
||||||
|
resultingPolies (p, i) = [([head p, c], i), ([c, last p], i)]
|
||||||
|
where c = rules ! p
|
||||||
|
polyCounts :: Map [Char] Int
|
||||||
|
polyCounts = iterate step initial !! iterations
|
||||||
|
|
||||||
|
-- Because the windows are size 2, every element of a sub-binding is
|
||||||
|
-- counted twice (e.g. NBCBC -> NB, BC, CB, BC), except the first and
|
||||||
|
-- last element. We know the first and last elements (because we
|
||||||
|
-- operated on windows, they'll match the first and last of the
|
||||||
|
-- template), so we can un-window the whole batch by dividing their
|
||||||
|
-- number of occurrences by two, except for the first and last, where
|
||||||
|
-- we subtract the number by 1 first and add 1 back later.
|
||||||
|
elCounts :: Map Char Int
|
||||||
|
elCounts = Map.mapWithKey deWindow naiveSum
|
||||||
|
where
|
||||||
|
els :: ([Char], Int) -> [(Char, Int)]
|
||||||
|
els (p, i) = [(head p, i), (last p, i)]
|
||||||
|
naiveSum :: Map Char Int
|
||||||
|
naiveSum = (Map.fromListWith (+) . flatmap els . Map.assocs) polyCounts
|
||||||
|
deWindow :: Char -> Int -> Int
|
||||||
|
deWindow c i
|
||||||
|
| c == head template || c == last template = (i - 1) `quot` 2 + 1
|
||||||
|
| otherwise = i `quot` 2
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput1 = unlines [
|
||||||
|
"NNCB",
|
||||||
|
"",
|
||||||
|
"CH -> B",
|
||||||
|
"HH -> N",
|
||||||
|
"CB -> H",
|
||||||
|
"NH -> C",
|
||||||
|
"HB -> C",
|
||||||
|
"HC -> B",
|
||||||
|
"HN -> C",
|
||||||
|
"NN -> C",
|
||||||
|
"BH -> H",
|
||||||
|
"NC -> B",
|
||||||
|
"NB -> B",
|
||||||
|
"BN -> B",
|
||||||
|
"BB -> N",
|
||||||
|
"BC -> B",
|
||||||
|
"CC -> N",
|
||||||
|
"CN -> C"]
|
||||||
|
|
||||||
|
parsedTestInput1 = parsePolymer testInput1
|
||||||
|
test1 = solution1 parsedTestInput1 -- 1588
|
||||||
|
test2 = solution2 parsedTestInput1 -- 2188189693529
|
23
9/Parsing.hs
Normal file
23
9/Parsing.hs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
module Parsing (
|
||||||
|
splitByString
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.List (isPrefixOf)
|
||||||
|
|
||||||
|
splitByString :: String -> String -> [String]
|
||||||
|
splitByString _ "" = []
|
||||||
|
splitByString splitter string =
|
||||||
|
let (chunk, rest) = spanNextSplit string
|
||||||
|
in
|
||||||
|
chunk:(splitByString splitter rest)
|
||||||
|
where
|
||||||
|
spanNextSplit :: String -> (String, String)
|
||||||
|
spanNextSplit [] = ([], [])
|
||||||
|
spanNextSplit everything@(char:rest)
|
||||||
|
| splitter `isPrefixOf` rest =
|
||||||
|
([char], (drop ((length splitter) + 1) everything))
|
||||||
|
| otherwise =
|
||||||
|
let
|
||||||
|
(start, end) = spanNextSplit rest
|
||||||
|
in
|
||||||
|
(char:start, end)
|
100
9/input.txt
Normal file
100
9/input.txt
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
9987675345698765453987654321234589999899878923493212345678999998656782467898999899878301234578998787
|
||||||
|
9876543234789765322398743210123567898789767899986101239899789876543101567897898798763212355989987656
|
||||||
|
3987784014897654310987654331235679965697644998765232345997654989765212799956999679854343466799976545
|
||||||
|
2199875323998765421298776542346789434595433498754345456789543499876353489549876542975858977899876439
|
||||||
|
1012965439899896432359987667457896546789322349987656987898932445987454578932987621986767898943989598
|
||||||
|
2125976598798989943467898876589999858899910959898767898976101234598966689431298320987898999432399987
|
||||||
|
3234987987656579894578989987679998769999899898769879999965422345679298995420139434598999896543459875
|
||||||
|
4346799876545456789679877898789769878989798799656989899876563496799109989591298548999689789656598764
|
||||||
|
5956998765434345698989765679895456989678679678943496789988689989898997979989987657987565698787989543
|
||||||
|
6899898764321234567999876989954345696534598789432134679999799976987656765778998769766464989999865432
|
||||||
|
7987679653210155789999997899875456789323999899521012345899899765698943254667999898954353578999654321
|
||||||
|
9696598654323234589788998998986567898919894958933423456789999753459892123458998987893212467898765432
|
||||||
|
8543498765434545679567899987987679987898743147894934567898989432398789334767987876789101298989876543
|
||||||
|
7656789878545656789338989876598789986797654235679895678997878941987678975879896545698914345678987654
|
||||||
|
9868998989656877892129678965439899975498754346998796789986867932954569986798765434567895458989998765
|
||||||
|
8979987798787898921012567894321999874329985459876589899985457899873458987987654323469986567899869876
|
||||||
|
7899876549898959999923456789432398765909876567987678999875322987654567898998773212378997698998754987
|
||||||
|
6534997831999943987894567897543999899899987878998789789964201298765678919679654323456789799987632399
|
||||||
|
5424598942689899876789678987659899988788999989019895699865362349986989103498795434567899899996549989
|
||||||
|
4212349653498789765699989798798789877697898999999924789976457899798993212379986747698946999897998878
|
||||||
|
5334569878989678934998995679987678954545987899789935689987567987649898763467897858789235798789887867
|
||||||
|
6446878989876569976897893459876567893239876797689898789397679893234789654598998979999546999698785458
|
||||||
|
7557989199987457898956789998984348994124965323486789895498798789123569875989109989898969898598654345
|
||||||
|
8998994398796346899545699876543236789549876412345678979569987679023456989878992398767898767469643234
|
||||||
|
9999689987654235695434689987652125678956987954456789768979876568994568999867989987659999955398759345
|
||||||
|
7887578976543123489545679698983234789768998765677993457899765456789878997654878998767899843229898956
|
||||||
|
6543469998768245678956789529865445899879999896798912349998987347899989989653467899879998732019987897
|
||||||
|
7672398999875456989767895439876556789989989999899102356987798456789899878932356789989987643498976789
|
||||||
|
8954987899986567899878976546989667993498979978976212469996549567895798969991245699899998754987685698
|
||||||
|
9769876989987898901989997656898789101997768769895433498765439878934987656789346789788999869876564567
|
||||||
|
9898765778998979312397899767999893249876753656789656569976524989423976546789498997697986998765473456
|
||||||
|
3987654569789765434456976978999974756965432345678987678987734694319887635689989998456894219874321567
|
||||||
|
2198733477678978645797895989989865669876543766799998789599848789998765212678979999367975323985432378
|
||||||
|
3989821234568999756898934599878976798998754567898999897679959899899874323599867895459876434596543458
|
||||||
|
9876432347679549887969423498969987897989865698997899979898767998798765435679756899567987546987654567
|
||||||
|
9876543489789832998953210987658998996579878789876588965939989987659987546789645688979987657898785678
|
||||||
|
3987654579898721239998723976547899987467989999995477894321098765545698687895436577898998898999896789
|
||||||
|
2398766789989654359899644597656999876345697679654356965434197543434989798954323456987899939998987893
|
||||||
|
1239887894678965498788987698987999765234789598765467896545976532129879899996534567896789123976798912
|
||||||
|
0945998923567896997687898999298987653123696439876588987679876549098765945987965778945693239875459901
|
||||||
|
9896789434678999876575999899399199762064594321987678998789989698987654326599878989238789459954345899
|
||||||
|
6797898645789998767434598798989349872165689410198989769899898997898543212367989994345678998986254678
|
||||||
|
5789949756894987654323497687878959989278796521239797653998767876799654302456999965456899987432123689
|
||||||
|
4569439887893998799934598576967898995478897432345698992989545665698775212567899876697899876543234567
|
||||||
|
5678921998969899987899974475459997898567998945456789989878932124569854323498976989989965987654345678
|
||||||
|
6799990199656789876798863212349976987678999896897899879767893234698765434578965699878974598785458789
|
||||||
|
9899989989543298765987652101267895999799998789998998968456789345999879545679854598767943459987569893
|
||||||
|
3998979678932129894598543323458934889934987698999987654345895469876997656789765987659894567998678942
|
||||||
|
1987667569892099989679656445667895679899876597896596543256896567989998789899876798547689978999789531
|
||||||
|
9876553456789989878998767986898996798788995456789987752125789678998999897999987899534567899989898940
|
||||||
|
8765432345679878967999899597959789987576789347899876543234589789987899975689999987656789929876967891
|
||||||
|
8764321234698766556899995329345678987455678956789989684348678999876798764567898998769893212975456932
|
||||||
|
9863210123459654345688989910258789876323589969894398765457789998765679923459987869878999109864349894
|
||||||
|
9854525234598743234567979891345897995474567898989239878767899997654567895678996555989998919753239789
|
||||||
|
9765434545987655455679865789457896986567678967878946989878959876543456789789789434599987898954398679
|
||||||
|
9896565656898766767999954567978965497678989656567898998989245988652346799894698765679876767895976532
|
||||||
|
9987879768999879879878323489989654398789893432349899987690159899721278967923989876798965456987987699
|
||||||
|
8998989879988989998965412397898765219899762101234789996521998798754367899999878987987654347898998987
|
||||||
|
7659395989876897987654323456789898323998753242345678989439887699865456899989769999876543236789019986
|
||||||
|
8543214598765456798987654589896987536789894355456989879598754589876967999877658999997655345678998965
|
||||||
|
7654323679876578969999865678945698545678976566567898769987653479989898998766546898998786457799987654
|
||||||
|
8795498793997989657899976789234987657799987677678965657898794567998789987653234567899898568899998723
|
||||||
|
9989989932398996546789989890123498968989998788789654346789887679899678996442123458901987678999899812
|
||||||
|
9878879993989875237899999989254989979878999899898766869895998997676567894321015667892398789999798923
|
||||||
|
7767767989878943123978999878969978998967899922939878998953219876565456976534124578943469999988697654
|
||||||
|
6553459876767894234568986767898767987656789210125989987994101985432389997645234567894590129876598785
|
||||||
|
5432345985458995679799875456989659876545456991234899876789919996676569987656545678965989239988439986
|
||||||
|
4321359894346789789987654345678943965434345789546799765679898987787878998787656989879879998895321298
|
||||||
|
5430198765497899894298763234567899876521234899987987654598787999898989109898767899998967897654210129
|
||||||
|
6541679876989945999987654345678989987752345678999999766987656579999793212999878999987656789775323234
|
||||||
|
6432589989877899998998765476989978998843459789998939878996545468989654329989999998798787894989876545
|
||||||
|
7543458998965778987679976687898767898754678999987923989876432345678976498978989987659898943497987676
|
||||||
|
8654567987854567896563987798998656899865789019876894599987321238789098987967878998743989932346798888
|
||||||
|
9766779876543488997432398899987745679877892198765789998765450139989129876754568999974567895459999999
|
||||||
|
9877898765632356789543459921096434567988943989654567899986521234678998765323467899865679976598897912
|
||||||
|
9988987654521237989699567899987558978999659876543457899987634656899986544212456789877889987987656893
|
||||||
|
9999996543210357678987998998998667989431968997652346998998785667901997432101348995998994398996545789
|
||||||
|
8932987987631234589476789987689978999599878994321345997899996778929899546712467894239987469997434679
|
||||||
|
7891098876546349679345678965578899998989989989935459876979897889298778994324578943190296599989323567
|
||||||
|
6989129989865478993234567893456799987878998776896567965468789990199656989435678954989987989978934569
|
||||||
|
5678949999976569310123689932345689876569899565789778984345688999987645678945789769979999878767897698
|
||||||
|
4567898999987679453294594321017992985498765434698999993234567898765434899656899998768999765457898987
|
||||||
|
7698987898799789564989695532399891996309899323456789832125678919876325999797999887657987654346789876
|
||||||
|
8999876789654998679879989649989799876212987437899898761012348901985476789898998765431298743235689985
|
||||||
|
9899965689543249998765679998767678965429876556945987652125667899876787899979459963210139852123798954
|
||||||
|
8788754799932129879654587789656567896578987987899876543234799998989898998764349854321298764234567893
|
||||||
|
7656543458794298965443445678932456789789598998901997654345678997693939789943298765432359879876899952
|
||||||
|
6543252345679987654352237899751577899895459789212398897656889986542124599892109887545456989987896541
|
||||||
|
8432101489989999875210128932967698998901345699924569998767994987431023999789213998676569995699965430
|
||||||
|
7654312678999998996321239999878789767892396989895678989879993976545129897678954598789678934567976521
|
||||||
|
8976433589998767987542356789999891557789989978789789467998989897685398789569899989899789325679897432
|
||||||
|
9987544567899655698653468999987910345679878765678992345987878799896987667348798976949895434599789545
|
||||||
|
9999655778999543219766567899876621234598765454567891249876567689929876543237667895435976565987679656
|
||||||
|
8798789989988959309877678999765432545699654323479910134995456578912997632123456789523498878996598977
|
||||||
|
6549891299876898912988989789876547686987543212567891239984323469329876321014567898654569989985456799
|
||||||
|
1234932997764667893499995678987658798998654403459932398765012478998765432125678979866789699876345678
|
||||||
|
0356799876543456994567894567898967899019873212378993987654139989219876843336789565977896579843234589
|
||||||
|
1235789987532345789978943456899878978929764323456789398543248892101998765459895434598965498765445678
|
||||||
|
2356897698421234567899432346789989767899875435668891239654356789432789887567976323699654329876786789
|
||||||
|
3567896543210246788987541457892499848921986546879910129767568996545699998678988434789543210989897899
|
77
9/smokescreen.hs
Normal file
77
9/smokescreen.hs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
import Data.Char (digitToInt)
|
||||||
|
import Data.List (nub, sortBy)
|
||||||
|
import Data.Ord
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
input <- getContents
|
||||||
|
let
|
||||||
|
heightMap = parseHeights input
|
||||||
|
(putStrLn . show . solution1) heightMap
|
||||||
|
(putStrLn . show . solution2) heightMap
|
||||||
|
|
||||||
|
solution1 :: [[Int]] -> Int
|
||||||
|
solution1 heights = sum (map (\p -> heights !!! p + 1) (lowPoints heights))
|
||||||
|
|
||||||
|
solution2 :: [[Int]] -> Int
|
||||||
|
solution2 heights = product (take 3 (sortBy (comparing Down) (map length basins)))
|
||||||
|
where
|
||||||
|
basins :: [[(Int, Int)]]
|
||||||
|
basins = map (flip basin heights) (lowPoints heights)
|
||||||
|
|
||||||
|
basin :: (Int, Int) -> [[Int]] -> [(Int, Int)]
|
||||||
|
basin point heights
|
||||||
|
| null next = []
|
||||||
|
| otherwise = nub (point:(next)++flatmap (flip basin heights) next)
|
||||||
|
where
|
||||||
|
next = filter partOfBasin (adjacent point heights)
|
||||||
|
partOfBasin x =
|
||||||
|
let
|
||||||
|
xHeight = heights !!! x
|
||||||
|
in
|
||||||
|
xHeight > heights !!! point && xHeight /= 9
|
||||||
|
|
||||||
|
flatmap :: (t -> [a]) -> [t] -> [a]
|
||||||
|
flatmap _ [] = []
|
||||||
|
flatmap f (x:xs) = f x ++ flatmap f xs
|
||||||
|
|
||||||
|
lowPoints :: [[Int]] -> [(Int, Int)]
|
||||||
|
lowPoints heights = filter (flip isLowPoint heights) (indices heights)
|
||||||
|
where
|
||||||
|
indices :: [[Int]] -> [(Int, Int)]
|
||||||
|
indices m = [(x, y) |
|
||||||
|
x <- [0..length(m)-1],
|
||||||
|
y <- [0..length(m !! 0)-1]]
|
||||||
|
|
||||||
|
isLowPoint :: (Int, Int) -> [[Int]] -> Bool
|
||||||
|
isLowPoint point m = all (> (m !!! point)) (map ((!!!) m) (adjacent point m))
|
||||||
|
|
||||||
|
(!!!) :: [[Int]] -> (Int, Int) -> Int
|
||||||
|
(!!!) m index = m !! (fst index) !! (snd index)
|
||||||
|
|
||||||
|
adjacent :: (Int, Int) -> [[Int]] -> [(Int, Int)]
|
||||||
|
adjacent (x, y) m =
|
||||||
|
[(i+x, j+y) |
|
||||||
|
i <- [-1..1],
|
||||||
|
j <- [-1..1],
|
||||||
|
abs i /= abs j,
|
||||||
|
i+x >= 0 && i+x < length(m),
|
||||||
|
j+y >= 0 && j+y < length(m !! 0)]
|
||||||
|
|
||||||
|
parseHeights :: String -> [[Int]]
|
||||||
|
parseHeights = map (map digitToInt) . lines
|
||||||
|
|
||||||
|
-- Tests
|
||||||
|
|
||||||
|
testInput = unlines [
|
||||||
|
"2199943210",
|
||||||
|
"3987894921",
|
||||||
|
"9856789892",
|
||||||
|
"8767896789",
|
||||||
|
"9899965678"
|
||||||
|
]
|
||||||
|
|
||||||
|
testInputParsed = parseHeights testInput
|
||||||
|
|
||||||
|
test1 = solution1 testInputParsed -- 15
|
||||||
|
test2 = solution2 testInputParsed -- 1134
|
Loading…
Reference in a new issue