├── 2015 ├── Haskell │ ├── .gitignore │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2015.cabal │ ├── app │ │ └── Main.hs │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06-old.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ └── Tuple.hs │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── Python │ ├── 01.py │ ├── 02.py │ ├── 03.py │ ├── 04.py │ ├── 05.py │ ├── 06.py │ ├── 07.py │ ├── 08.py │ ├── 09.py │ ├── 10.py │ ├── 11.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ ├── 24.py │ └── 25.py └── README.md ├── 2016 ├── Haskell │ ├── .gitignore │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2016.cabal │ ├── app │ │ └── Main.hs │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ ├── Other │ │ │ └── Day16.hs │ │ └── Template.hs │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── Python │ ├── 01.py │ ├── 02.py │ ├── 03.py │ ├── 04.py │ ├── 05.py │ ├── 06.py │ ├── 07.py │ ├── 08.py │ ├── 09.py │ ├── 10.py │ ├── 12.py │ ├── 13.py │ ├── 14.py │ ├── 15.py │ ├── 16.py │ ├── 17.py │ ├── 18.py │ ├── 19.py │ ├── 20.py │ ├── 21.py │ ├── 22.py │ ├── 23.py │ └── 24.py └── README.md ├── 2017 ├── Haskell │ ├── 01.hs │ ├── 02.hs │ ├── 03.hs │ ├── 04.hs │ ├── 05.hs │ ├── 06.hs │ ├── 07.hs │ ├── 08.hs │ ├── 09.hs │ ├── 10.hs │ ├── 11.hs │ ├── 12.hs │ ├── 13.hs │ ├── 14.hs │ ├── 15.hs │ ├── 16.hs │ ├── 17.hs │ ├── 18.hs │ ├── 19.hs │ ├── 20.hs │ ├── 21.hs │ ├── 22.hs │ ├── 23.hs │ ├── 24-rec.hs │ ├── 24.hs │ └── 25.hs ├── Python │ ├── 01.py │ ├── 02.py │ ├── 03.py │ ├── 04.py │ ├── 05.py │ ├── 06.py │ └── 07.py └── rec-scheme │ ├── 24-lib.hs │ ├── 24-rec.hs │ ├── 24.in │ └── Knot.hs ├── 2018 ├── Haskell │ ├── .ghcid │ ├── .gitignore │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2018.cabal │ ├── app │ │ └── Main.hs │ ├── hie.yaml │ ├── old.ca │ ├── package.yaml │ ├── src │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day16.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ └── Lib.hs │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── Python │ ├── data │ │ ├── day06.in │ │ └── day07.in │ ├── day01.py │ ├── day02.py │ ├── day03.py │ ├── day04.py │ ├── day05.py │ ├── day06.py │ ├── day07.py │ ├── day08.py │ ├── day09.py │ ├── day10.py │ ├── day11-alt.py │ ├── day11.py │ ├── day12.py │ ├── day13.py │ ├── day14.py │ ├── day15.py │ ├── day16.py │ ├── day17.py │ ├── day18.py │ ├── day19.py │ ├── day20.py │ ├── day21.py │ ├── day22.py │ ├── day23.py │ ├── day24.py │ ├── day25.py │ └── out ├── README.md ├── aoc_18 │ ├── Cargo.toml │ ├── data │ │ ├── day01.in │ │ ├── day02.in │ │ ├── day03.in │ │ ├── day04.in │ │ ├── day04_mod.in │ │ ├── day05.in │ │ └── day06.in │ ├── day04_mod.in │ └── src │ │ ├── day01.rs │ │ ├── day02.rs │ │ ├── day03.rs │ │ ├── day04.rs │ │ ├── day05.rs │ │ ├── day06.rs │ │ ├── main.rs │ │ └── out ├── fixx.hs └── various │ ├── day01.c │ ├── day01.hs │ ├── day02.hs │ └── day11.c ├── 2019 ├── Haskell │ ├── .gitignore │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2019.cabal │ ├── app │ │ └── Main.hs │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11-lazy.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18-1.hs │ │ ├── Day18-old.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Intcode.hs │ │ └── Lib.hs │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── Python │ ├── day02.py │ └── day03.py └── README.md ├── 2020 ├── Haskell │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── app │ │ └── Main.hs │ ├── bench │ │ └── Bench.hs │ ├── bu.txt │ ├── get │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Advent │ │ │ └── Coord.hs │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day04HKD.hs │ │ ├── Day04regex.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day07knot.hs │ │ ├── Day08.hs │ │ ├── Day08hylo.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── DayTest.hs │ │ ├── Lib.hs │ │ ├── gen │ │ └── manual_16 │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs └── README.md ├── 2021 ├── Haskell │ ├── .gitignore │ ├── ChangeLog.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2021.cabal │ ├── app │ │ └── Main.hs │ ├── get │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Advent │ │ │ └── Coord.hs │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day16State.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ └── gen │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── README.md └── Scheme │ ├── day01.scm │ ├── day02.scm │ ├── day03.scm │ ├── day04.scm │ ├── day05.scm │ ├── day06.scm │ ├── day07.scm │ ├── day08.scm │ ├── day09.scm │ ├── day10.scm │ ├── day11.scm │ ├── day12.scm │ ├── day13.scm │ ├── day14.scm │ ├── day24.scm │ ├── main.scm │ ├── point-map.scm │ └── utils.scm ├── 2022 ├── Haskell │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2022.cabal │ ├── app │ │ └── Main.hs │ ├── day22.txt │ ├── get │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Advent │ │ │ └── Coord.hs │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ └── gen │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs └── README.md ├── 2023 ├── Haskell │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2023.cabal │ ├── app │ │ └── Main.hs │ ├── get │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Advent │ │ │ ├── Coord.hs │ │ │ └── Search.hs │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ └── gen │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs └── README.md ├── 2024 ├── Haskell │ ├── .gitignore │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── Setup.hs │ ├── aoc2024.cabal │ ├── app │ │ └── Main.hs │ ├── bench │ ├── get │ ├── hie.yaml │ ├── package.yaml │ ├── run │ ├── src │ │ ├── Advent │ │ │ ├── Coord.hs │ │ │ ├── Parsers.hs │ │ │ └── Search.hs │ │ ├── Day01.hs │ │ ├── Day02.hs │ │ ├── Day03.hs │ │ ├── Day04.hs │ │ ├── Day05.hs │ │ ├── Day06.hs │ │ ├── Day07.hs │ │ ├── Day08.hs │ │ ├── Day09.hs │ │ ├── Day10.hs │ │ ├── Day11.hs │ │ ├── Day12.hs │ │ ├── Day13.hs │ │ ├── Day14.hs │ │ ├── Day15.hs │ │ ├── Day16.hs │ │ ├── Day17.hs │ │ ├── Day18.hs │ │ ├── Day19.hs │ │ ├── Day20.hs │ │ ├── Day21.hs │ │ ├── Day22.hs │ │ ├── Day23.hs │ │ ├── Day24.hs │ │ ├── Day25.hs │ │ ├── Lib.hs │ │ └── gen │ ├── stack.yaml │ ├── stack.yaml.lock │ └── test │ │ └── Spec.hs ├── README.md └── data │ ├── day01.in │ ├── day02.in │ ├── day03.in │ ├── day04.in │ ├── day05.in │ ├── day06.in │ ├── day07.in │ ├── day08.in │ ├── day09.in │ ├── day10.in │ ├── day11.in │ ├── day12.in │ ├── day13.in │ ├── day14.in │ ├── day15.in │ ├── day16.in │ └── day17.in ├── .gitignore └── README.md /2015/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2015/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2015 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2015/Haskell/README.md: -------------------------------------------------------------------------------- 1 | # aoc2015 2 | -------------------------------------------------------------------------------- /2015/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2015/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | stack: 3 | - path: "./src" 4 | component: "aoc2015:lib" 5 | 6 | - path: "./app/Main.hs" 7 | component: "aoc2015:exe:aoc2015-exe" 8 | 9 | - path: "./app/Paths_aoc2015.hs" 10 | component: "aoc2015:exe:aoc2015-exe" 11 | 12 | - path: "./test" 13 | component: "aoc2015:test:aoc2015-test" 14 | -------------------------------------------------------------------------------- /2015/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2015:exe:aoc2015-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | left :: Int -> Char -> Int 4 | left n '(' = n + 1 5 | left n ')' = n - 1 6 | 7 | part1 :: String -> Int 8 | part1 = foldl left 0 9 | 10 | part2 :: String -> Int 11 | part2 = length . takeWhile (0 <=) . scanl left 0 12 | 13 | main :: IO () 14 | main = do 15 | input <- init <$> readFile "../data/01.in" 16 | print $ part1 input 17 | print $ part2 input 18 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Data.List.Extra ( splitOn 4 | , sort 5 | ) 6 | 7 | type Gift = [Int] 8 | 9 | paper :: Gift -> Int 10 | paper [l, w, h] = sum xs + (minimum xs `div` 2) 11 | where xs = [2 * l * w, 2 * w * h, 2 * h * l] 12 | 13 | ribbon :: Gift -> Int 14 | ribbon g = dimension + bow 15 | where 16 | dimension = sum (take 2 $ sort g) * 2 17 | bow = product g 18 | 19 | parse :: String -> Gift 20 | parse = map read . splitOn "x" 21 | 22 | main :: IO () 23 | main = do 24 | input <- map parse . lines <$> readFile "../data/02.in" 25 | print . sum $ map paper input 26 | print . sum $ map ribbon input 27 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | module Day03 where 2 | 3 | import Linear.V2 4 | import Data.List ( nub ) 5 | import Control.Lens 6 | 7 | type Point = V2 Int 8 | 9 | move :: String -> [Point] 10 | move = nub . scanl go (V2 0 0) 11 | where 12 | go p '^' = p + V2 1 0 13 | go p 'v' = p + V2 (-1) 0 14 | go p '<' = p + V2 0 (-1) 15 | go p '>' = p + V2 0 1 16 | 17 | part1 :: String -> Int 18 | part1 = length . move 19 | 20 | part2 :: String -> Int 21 | part2 input = length . nub $ santa ++ robot 22 | where 23 | santa = move $ input ^.. (traversed . indices even) 24 | robot = move $ input ^.. (traversed . indices odd) 25 | 26 | main :: IO () 27 | main = do 28 | input <- init <$> readFile "../data/03.in" 29 | print $ part1 input 30 | print $ part2 input 31 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day04.hs: -------------------------------------------------------------------------------- 1 | module Day04 where 2 | 3 | import Data.Hash.MD5 4 | import Data.List (find) 5 | 6 | input :: String 7 | input = "ckczppom" 8 | 9 | leadingZeroes :: Int -> String -> Maybe (Int, String) 10 | leadingZeroes n str = find (all (=='0') . take n . snd) . zip [1..] . map (md5s . Str . (str++) . show) $ [1..] 11 | 12 | main :: IO () 13 | main = do 14 | print $ leadingZeroes 5 input 15 | print $ leadingZeroes 6 input 16 | 17 | -- Just (117946,"00000fe1c139a2c710e9a5c03ec1af03") 18 | -- Just (3938038,"00000028023e3b4729684757f8dc3fbf") 19 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Data.List ( isInfixOf, tails,) 4 | import Data.Monoid ( All(All, getAll) ) 5 | 6 | allPass :: [a -> Bool] -> a -> Bool 7 | allPass ps = getAll . foldMap (All .) ps 8 | 9 | -- Filters 10 | bad, row, threeVowels, twicePair, oneSep :: String -> Bool 11 | bad = not . flip any ["ab", "cd", "pq", "xy"] . flip isInfixOf 12 | row = any (uncurry (==)) . (zip <*> tail) 13 | threeVowels = (3 <=) . length . filter (`elem` "aeiou") 14 | twicePair = any (\(x : y : xs) -> [x, y] `isInfixOf` xs) . takeWhile ((> 2) . length) . tails 15 | oneSep = any (\(x : _ : z : _) -> x == z) . takeWhile ((> 2) . length) . tails 16 | 17 | part1 :: [String] -> Int 18 | part1 = length . filter (allPass [bad, row, threeVowels]) 19 | 20 | part2 :: [String] -> Int 21 | part2 = length . filter (allPass [twicePair, oneSep]) 22 | 23 | main :: IO () 24 | main = do 25 | input <- lines <$> readFile "../data/05.in" 26 | print $ part1 input 27 | print $ part2 input 28 | 29 | -- 255 30 | -- 55 31 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day08.hs: -------------------------------------------------------------------------------- 1 | module Day08 where 2 | 3 | simplify :: String -> Int 4 | simplify txt = length txt - memChars txt 5 | where 6 | memChars [] = 0 7 | memChars ('"' : xs) = memChars xs 8 | memChars ('\\' : '\\' : xs) = 1 + memChars xs 9 | memChars ('\\' : 'x' : _ : _ : xs) = 1 + memChars xs 10 | memChars ('\\' : '"' : xs) = 1 + memChars xs 11 | memChars (_ : xs) = 1 + memChars xs 12 | 13 | encode :: String -> Int 14 | encode str = length (show str) - length str 15 | 16 | fileDiff :: (String -> Int) -> [String] -> Int 17 | fileDiff f = sum . map f 18 | 19 | main :: IO () 20 | main = do 21 | input <- lines <$> readFile "../data/08.in" 22 | print $ fileDiff simplify input 23 | print $ fileDiff encode input 24 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | import qualified Data.Map as Map 4 | import Data.Map ( Map ) 5 | import Data.List ( permutations 6 | , nub 7 | ) 8 | import Data.Maybe (mapMaybe) 9 | 10 | parse :: [String] -> Map (String, String) Int 11 | parse = Map.fromList . concatMap (go . words) 12 | where 13 | go [from, "to", to, "=", dist] = [((from, to), read dist), ((to, from), read dist)] 14 | 15 | paths :: Map (String, String) Int -> [Int] 16 | paths m = let perms = map (zip <*> tail) . permutations . nub . map fst $ Map.keys m 17 | in map (sum . map (m Map.!)) perms 18 | 19 | main :: IO () 20 | main = do 21 | input <- parse . lines <$> readFile "../data/09.in" 22 | print . minimum $ paths input 23 | print . maximum $ paths input 24 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day10.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module Day10 where 3 | 4 | import Control.Arrow 5 | import Data.List (group) 6 | import qualified Data.Text as T 7 | import Data.Text ( Text ) 8 | 9 | puzzleInput :: Text 10 | puzzleInput = "3113322113" 11 | 12 | lookAndSay :: Text -> Text 13 | lookAndSay = T.concat . map ((\(l, c) -> T.pack (show l ++ [c])) . (T.length &&& T.head)) . T.group 14 | 15 | play :: Int -> Text -> Int 16 | play n = T.length . (!! n) . iterate lookAndSay 17 | 18 | main :: IO () 19 | main = do 20 | print $ play 40 puzzleInput 21 | print $ play 50 puzzleInput 22 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day11.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module Day11 where 3 | 4 | import qualified Data.Text as T 5 | import Data.Text ( Text ) 6 | import Data.Char 7 | import Data.List ( find ) 8 | import Data.Foldable 9 | 10 | puzzleInput :: Text 11 | puzzleInput = "cqjxjnds" 12 | 13 | inc :: Text -> Text 14 | inc t = case T.last t of 15 | 'z' -> inc (T.init t) <> T.singleton 'a' 16 | c -> T.init t <> T.singleton (chr (ord c + 1)) 17 | 18 | triples :: [Text] 19 | triples = go "abc" 20 | where 21 | go :: Text -> [Text] 22 | go "xyz" = ["xyz"] 23 | go xs = [xs] <> go (T.map (chr . (+ 1) . ord) xs) 24 | 25 | pairs :: [Text] 26 | pairs = [ T.singleton a <> T.singleton a | a <- ['a' .. 'z']] 27 | 28 | good :: Text -> Bool 29 | good t = and $ pair t : three t : (xs <*> pure t) 30 | where 31 | xs = [not . T.any (== 'i'), not . T.any (== 'l'), not . T.any (== 'o')] 32 | three t = or $ (`T.isInfixOf` t) <$> triples 33 | pair t = (>1) . length . filter id $ (`T.isInfixOf` t) <$> pairs 34 | 35 | main :: IO () 36 | main = do 37 | print . head . filter good . iterate inc $ puzzleInput 38 | print . (!! 1) . filter good . iterate inc $ puzzleInput 39 | 40 | -- "cqjxxyzz" 41 | -- "cqkaabcc" 42 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day12.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module Day12 where 3 | 4 | import Data.Aeson.Lens 5 | import Data.Aeson 6 | import Control.Lens 7 | 8 | main :: IO () 9 | main = do 10 | input <- (read :: String -> Object) <$> readFile "../data/12.in" 11 | print input 12 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day15.hs: -------------------------------------------------------------------------------- 1 | module Day15 where 2 | 3 | import Control.Arrow 4 | import Text.Regex.TDFA 5 | import qualified Data.Map as Map 6 | import Data.Map ( Map ) 7 | import Data.List.Extra ( splitOn 8 | , transpose 9 | , permutations 10 | ) 11 | 12 | parse :: String -> [[Int]] 13 | parse = map go . lines 14 | where 15 | go :: String -> [Int] 16 | go s = map read $ getAllTextMatches (s =~ "-*[0-9]+") 17 | 18 | score :: [Int] -> [[Int]] -> (Int, Int) 19 | score v = (product . init &&& last) . map (max 0 . sum . zipWith (*) v) . transpose 20 | 21 | genNums :: Int -> [[Int]] 22 | genNums n = concatMap permutations $ 23 | [ [a, b, c, d] 24 | | a <- [0 .. n] 25 | , b <- [a .. n] 26 | , c <- [b .. n] 27 | , d <- [c .. n] 28 | , a + b + c + d == n 29 | ] 30 | 31 | main :: IO () 32 | main = do 33 | input <- parse <$> readFile "../data/15.in" 34 | let nums = map (`score` input) $ genNums 100 35 | print . fst $ maximum nums 36 | print . fst . maximum . filter ((== 500) . snd) $ nums 37 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day17.hs: -------------------------------------------------------------------------------- 1 | -- https://adventofcode.com/2015/day/17 2 | {-# LANGUAGE DeriveFunctor #-} 3 | module Day17 where 4 | 5 | import Data.Functor.Foldable 6 | import Data.List ( nub 7 | , delete 8 | , sort 9 | , group 10 | , sortOn 11 | ) 12 | 13 | parse :: String -> [Int] 14 | parse = map read . lines 15 | 16 | data TreeF a r = NodeF a [r] 17 | deriving (Functor, Show) 18 | 19 | type Tree a = Fix (TreeF a) 20 | 21 | solve :: (Int, [Int]) -> [[Int]] 22 | solve = map nub . hylo cat an 23 | where 24 | an (n, []) = NodeF n [] 25 | an (n, xs) = let m = minimum xs in NodeF n [(n - m, delete m xs), (n, delete m xs)] 26 | cat (NodeF 0 []) = [[0]] 27 | cat (NodeF n []) = [] 28 | cat (NodeF n xs) = map ((n:) . nub) . concat $ xs 29 | 30 | 31 | 32 | part1 :: (Int, [Int]) -> Int 33 | part1 = length . solve 34 | 35 | part2 :: (Int, [Int]) -> Int 36 | part2 x = length . filter ((== m) . length) $ xs 37 | where xs = solve x 38 | m = minimum . map length $ xs 39 | 40 | main :: IO () 41 | main = do 42 | input <- parse <$> readFile "../data/17.in" 43 | print $ part1 (150, input) 44 | print $ part2 (150, input) 45 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day19.hs: -------------------------------------------------------------------------------- 1 | module Day19 where 2 | 3 | import Lib ( tuple ) 4 | import Data.List.Extra ( intercalate, splitOn ) 5 | import qualified Data.Set as Set 6 | import Data.Set ( Set ) 7 | import Data.Tuple (swap) 8 | 9 | parseInput :: String -> (String, [(String, String)]) 10 | parseInput input = (x, rules) 11 | where 12 | (x : xs) = lines input 13 | rules = map (tuple . splitOn " => ") xs 14 | 15 | replace :: String -> (String, String) -> Set String 16 | replace str (rule, rep) = Set.fromList $ go (head parts) (tail parts) 17 | where 18 | parts = splitOn rule str 19 | go _ [] = [] 20 | go pre (x:xs) = new : go (pre ++ rule ++ x) xs 21 | where new = pre ++ rep ++ intercalate rule (x:xs) 22 | 23 | part1 :: [(String, String)] -> String -> Int 24 | part1 rules str = Set.size . Set.unions $ map (replace str) rules 25 | 26 | part2 :: [(String, String)] -> String -> Int 27 | part2 rules = length . takeWhile ((> 1) . length) . iterate (reduce rules) 28 | where 29 | reduce rules str = Set.findMax . Set.unions $ map (replace str . swap) rules 30 | 31 | main :: IO () 32 | main = do 33 | (line, rules) <- parseInput <$> readFile "../data/19.in" 34 | mapM_ (print . swap) rules 35 | print $ part1 rules line 36 | print $ part2 rules line 37 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day20.hs: -------------------------------------------------------------------------------- 1 | module Day20 where 2 | 3 | import Lib 4 | import Control.Lens 5 | import Data.List.Extra 6 | import qualified Data.Set as Set 7 | import Data.Set ( Set ) 8 | import qualified Data.Map as Map 9 | import Data.Map ( Map ) 10 | import Data.Foldable (foldl') 11 | import Control.Monad.State 12 | 13 | import Math.NumberTheory.ArithmeticFunctions 14 | 15 | input :: Int 16 | input = 34000000 17 | 18 | part1 :: Maybe Int 19 | part1 = (+1) <$> findIndex test [1..] 20 | where 21 | test n = (>= input) . foldl' (+) 0 . Set.map (*10) $ divisors n 22 | 23 | part2 :: Maybe Int 24 | part2 = fmap (+1) . findIndex (>= input) $ evalState (traverse test [1..]) Map.empty 25 | where 26 | test :: Int -> State (Map Int Int) Int 27 | test n = do 28 | seen <- get 29 | let divs = divisors n 30 | seen' = Map.unionWith (+) seen (freqs divs) 31 | divs' = Set.filter ((<= Just 50) . (`Map.lookup` seen')) divs 32 | put seen' 33 | pure $ foldl' (+) 0 . Set.map (*11) $ divs' 34 | 35 | main :: IO () 36 | main = do 37 | print part1 38 | print part2 39 | 40 | -- 786240 41 | -- 831600 42 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day23.hs: -------------------------------------------------------------------------------- 1 | module Day23 where 2 | 3 | import Lib 4 | import Control.Lens 5 | import Data.List.Extra 6 | 7 | parseInput = id 8 | 9 | part1 input = undefined 10 | 11 | part2 input = undefined 12 | 13 | main :: IO () 14 | main = do 15 | input <- parseInput <$> readFile "../data/day01.in" 16 | print input 17 | -- print $ part1 input 18 | -- print $ part2 input 19 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day24.hs: -------------------------------------------------------------------------------- 1 | module Day24 where 2 | 3 | import Lib 4 | import Control.Lens 5 | import Data.List.Extra 6 | 7 | parseInput = id 8 | 9 | part1 input = undefined 10 | 11 | part2 input = undefined 12 | 13 | main :: IO () 14 | main = do 15 | input <- parseInput <$> readFile "../data/day01.in" 16 | print input 17 | -- print $ part1 input 18 | -- print $ part2 input 19 | -------------------------------------------------------------------------------- /2015/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Lib 4 | import Control.Lens 5 | import Data.List.Extra 6 | 7 | parseInput = id 8 | 9 | part1 input = undefined 10 | 11 | part2 input = undefined 12 | 13 | main :: IO () 14 | main = do 15 | input <- parseInput <$> readFile "../data/day01.in" 16 | print input 17 | -- print $ part1 input 18 | -- print $ part2 input 19 | -------------------------------------------------------------------------------- /2015/Haskell/src/Tuple.hs: -------------------------------------------------------------------------------- 1 | module Tuple where 2 | 3 | import Data.Monoid 4 | import qualified Data.Set as Set 5 | import Data.Set ( Set ) 6 | import Control.Lens 7 | 8 | toTuple :: Char -> (Sum Int, Sum Int) 9 | toTuple '^' = (Sum 1, Sum 0) 10 | toTuple 'v' = (Sum (-1), Sum 0) 11 | toTuple '<' = (Sum 0, Sum (-1)) 12 | toTuple '>' = (Sum 0, Sum 1) 13 | 14 | findHouses :: [(Sum Int, Sum Int)] -> Set (Sum Int, Sum Int) 15 | findHouses = Set.fromList . scanl (<>) (Sum 0, Sum 0) 16 | 17 | main :: IO () 18 | main = do 19 | contents <- map toTuple . init <$> readFile "data/03.in" 20 | let path = findHouses contents 21 | print . length $ path 22 | let f p = toListOf (traversed . indices p) contents 23 | print . length $ Set.union (findHouses (f even)) (findHouses (f odd)) 24 | -------------------------------------------------------------------------------- /2015/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2015/Python/01.py: -------------------------------------------------------------------------------- 1 | 2 | def solveA(line): 3 | return line.count('(') - line.count(')') 4 | 5 | def solveB(line): 6 | count = 0 7 | pos = 0 8 | while count != -1: 9 | pos += 1 10 | c, line = line[0], line[1:] 11 | if c == '(': 12 | count += 1 13 | if c == ')': 14 | count -= 1 15 | return pos 16 | 17 | def main(): 18 | line = open('../data/01.in').read() 19 | print(f'Part 1: {solveA(line)}') 20 | print(f'Part 2: {solveB(line)}') 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /2015/Python/02.py: -------------------------------------------------------------------------------- 1 | 2 | # Part 1 3 | with open('../data/02.in') as f: 4 | total = 0 5 | for line in f: 6 | x, y, z = map(int, line.split('x')) 7 | a = 2 * x * y 8 | b = 2 * x * z 9 | c = 2 * y * z 10 | total += a + b + c + min([x*y, x*z, y*z]) 11 | print('Part 1:', total) 12 | 13 | # Part 2 14 | with open('../data/02.in') as f: 15 | total = 0 16 | for line in f: 17 | x, y, z = map(int, line.split('x')) 18 | a = [x, y, z] 19 | a.remove(max([x, y, z])) 20 | total += sum(a) * 2 21 | total += x * y * z 22 | print('Part 2:', total) 23 | -------------------------------------------------------------------------------- /2015/Python/03.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | 3 | with open('../data/03.in') as f: 4 | line = f.read().strip() 5 | 6 | def move(pos, c): 7 | x, y = pos 8 | if c == '>': 9 | return (x + 1, y) 10 | if c == '<': 11 | return (x - 1, y) 12 | if c == '^': 13 | return (x, y - 1) 14 | if c == 'v': 15 | return (x, y + 1) 16 | 17 | houses = defaultdict(int) 18 | pos = (0, 0) 19 | robo_pos = (0, 0) 20 | houses[pos] += 1 21 | houses[robo_pos] += 1 22 | line = iter(line) 23 | for c in line: 24 | pos = move(pos, c) 25 | houses[pos] += 1 26 | robo_pos = move(robo_pos, next(line)) 27 | houses[robo_pos] += 1 28 | 29 | print(len(houses)) 30 | -------------------------------------------------------------------------------- /2015/Python/04.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | import hashlib 3 | 4 | key = 'ckczppom' 5 | 6 | for i in count(): 7 | if hashlib.md5((key + str(i)).encode()).hexdigest()[:6] == '000000': 8 | print(f'Part 1: {i}') 9 | break 10 | -------------------------------------------------------------------------------- /2015/Python/05.py: -------------------------------------------------------------------------------- 1 | def is_nice(line): 2 | if len([i for i in line if i in 'aeiou']) < 3: 3 | return False 4 | if not any(a == b for a, b in zip(line, line[1:])): 5 | return False 6 | if 'ab' in line: 7 | return False 8 | if 'cd' in line: 9 | return False 10 | if 'pq' in line: 11 | return False 12 | if 'xy' in line: 13 | return False 14 | return True 15 | 16 | def is_nice_2(line): 17 | for i in [a+b for a, b in zip(line, line[1:])]: 18 | if line.count(i) >= 2: 19 | break 20 | else: 21 | return False 22 | for a,b,c in zip(line, line[1:], line[2:]): 23 | if a == c: 24 | return True 25 | return False 26 | 27 | count = 0 28 | 29 | for line in open('../data/05.in'): 30 | if is_nice(line): 31 | count += 1 32 | print('Part 1:', count) 33 | 34 | count = 0 35 | for line in open('../data/05.in'): 36 | if is_nice_2(line): 37 | count += 1 38 | print('Part 2:', count) 39 | -------------------------------------------------------------------------------- /2015/Python/06.py: -------------------------------------------------------------------------------- 1 | 2 | grid = [[0 for _ in range(1000)] for _ in range(1000)] 3 | 4 | for line in open('../data/06.in'): 5 | line = line.split() 6 | if line[0] == 'toggle': 7 | x, y = map(int, line[1].split(',')) 8 | a, b = map(int, line[3].split(',')) 9 | for i in range(x, a + 1): 10 | for j in range(y, b + 1): 11 | grid[i][j] += 2 12 | else: 13 | new = {'on': 1, 'off': -1}[line[1]] 14 | x, y = map(int, line[2].split(',')) 15 | a, b = map(int, line[4].split(',')) 16 | for i in range(x, a + 1): 17 | for j in range(y, b + 1): 18 | if new == -1 and grid[i][j] == 0: 19 | continue 20 | grid[i][j] += new 21 | 22 | count = 0 23 | for row in grid: 24 | for i in row: 25 | count += i 26 | 27 | print(count) 28 | 29 | # Attempts: 13396307 (Too low) 30 | 31 | -------------------------------------------------------------------------------- /2015/Python/07.py: -------------------------------------------------------------------------------- 1 | from functools import lru_cache 2 | 3 | def read_file(filename): 4 | lines = {} 5 | with open(filename) as f: 6 | for line in f: 7 | cmd, to = line.split(' -> ') 8 | lines[to.strip()] = cmd 9 | return lines 10 | 11 | data = read_file('../data/07.in') 12 | 13 | @lru_cache() 14 | def calc(val): 15 | try: 16 | return int(val) 17 | except ValueError: 18 | pass 19 | 20 | cmd = data[val].split(' ') 21 | 22 | if 'NOT' in cmd: 23 | return ~calc(cmd[1]) 24 | elif 'AND' in cmd: 25 | return calc(cmd[0]) & calc(cmd[2]) 26 | elif 'OR' in cmd: 27 | return calc(cmd[0]) | calc(cmd[2]) 28 | elif 'RSHIFT' in cmd: 29 | return calc(cmd[0]) >> calc(cmd[2]) 30 | elif 'LSHIFT' in cmd: 31 | return calc(cmd[0]) << calc(cmd[2]) 32 | else: 33 | return calc(cmd[0]) 34 | 35 | def main(): 36 | a = calc('a') 37 | print('Part 1:', a) 38 | data['b'] = str(a) 39 | calc.cache_clear() 40 | a = calc('a') 41 | print('Part 2:', a) 42 | 43 | if __name__ == "__main__": 44 | main() 45 | -------------------------------------------------------------------------------- /2015/Python/08.py: -------------------------------------------------------------------------------- 1 | from ast import literal_eval 2 | from itertools import zip_longest 3 | from subprocess import check_output 4 | import sys 5 | 6 | def get_code(filename): 7 | l, c = map(int, check_output(['wc', '-l', '-c', filename]).split()[:2]) 8 | return c - l 9 | 10 | def encode(string): 11 | string = repr(string) 12 | chars = 2 13 | for a, b in zip_longest(string, string[1:]): 14 | if a == '"': 15 | chars += 2 16 | else: 17 | chars += 1 18 | 19 | def solveA(filename): 20 | lines = open(filename).read().splitlines() 21 | chars = sum(len(literal_eval(line)) for line in lines) 22 | code = get_code(filename) 23 | print('Part 1:', code - chars) 24 | return code - chars 25 | 26 | def solveB(filename): 27 | lines = open(filename).read().splitlines() 28 | ext_code = sum(encode(s) for s in lines) 29 | code = get_code(filename) 30 | print('Part 2:', ext_code - code) 31 | return ext_code - code 32 | 33 | def main(): 34 | filename = '../data/08.in' 35 | solveA(filename) 36 | 37 | if __name__ == "__main__": 38 | main() 39 | -------------------------------------------------------------------------------- /2015/Python/09.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from collections import deque 3 | from itertools import permutations 4 | 5 | def read_file(filename): 6 | data = defaultdict(dict) 7 | with open(filename) as f: 8 | for line in f: 9 | a, _, b, _, dist = line.split() 10 | data[a][b] = int(dist) 11 | data[b][a] = int(dist) 12 | return data 13 | 14 | def max_distance(data): 15 | dist = max(sum(data[a][b] for a, b in zip(perm, perm[1:])) for perm in create_perms(data)) 16 | print(f'Part 2: {dist}') 17 | return dist 18 | 19 | def min_distance(data): 20 | min_dist = min(sum(data[a][b] for a, b in zip(perm, perm[1:])) for perm in create_perms(data)) 21 | print(f'Part 1: {min_dist}') 22 | return min_dist 23 | 24 | def create_perms(data): 25 | cities = list(data.keys()) 26 | yield from (perm for perm in permutations(cities)) 27 | 28 | def main(): 29 | cities = read_file('../data/09.in') 30 | min_distance(cities) 31 | max_distance(cities) 32 | 33 | if __name__ == "__main__": 34 | main() 35 | 36 | # Attemps: 464 37 | # 269 (Too high) 38 | -------------------------------------------------------------------------------- /2015/Python/10.py: -------------------------------------------------------------------------------- 1 | 2 | def play(key): 3 | new = '' 4 | while key: 5 | f = key[0] 6 | l = 1 7 | key = key[1:] 8 | while key and key[0] == f: 9 | l += 1 10 | key = key[1:] 11 | new += str(l) + f 12 | return new 13 | 14 | def run(times=40): 15 | key = '3113322113' 16 | for _ in range(times): 17 | key = play(key) 18 | print(len(key)) 19 | 20 | def main(): 21 | # It's slow, but it works 22 | run() 23 | run(times=50) 24 | 25 | if __name__ == "__main__": 26 | main() 27 | -------------------------------------------------------------------------------- /2015/Python/11.py: -------------------------------------------------------------------------------- 1 | from string import ascii_lowercase 2 | import re 3 | 4 | def legal(string): 5 | return req1(string) and req2(string) and req3(string) 6 | 7 | def req1(string): 8 | return any(a+b+c in ascii_lowercase for a, b, c in zip(string, string[1:], string[2:])) 9 | 10 | def req2(string): 11 | return not any(c in string for c in 'iol') 12 | 13 | def req3(string): 14 | return len(re.findall(r'(\w{1})(\1)', string)) >= 2 15 | 16 | def iterate_pw(string): 17 | # Can be a lot more efficient if it skips illegal characters 18 | string = list(string) 19 | curr = -1 20 | while True: 21 | if string[curr] == 'z': 22 | string[curr] = 'a' 23 | curr -= 1 24 | else: 25 | string[curr] = ascii_lowercase[ascii_lowercase.index(string[curr]) + 1] 26 | return ''.join(string) 27 | 28 | def main(): 29 | a = 'cqjxjnds' 30 | while not legal(a): 31 | a = iterate_pw(a) 32 | print('Part 1:', a) 33 | a = iterate_pw(a) 34 | while not legal(a): 35 | a = iterate_pw(a) 36 | print('Part 2:', a) 37 | 38 | if __name__ == "__main__": 39 | main() 40 | -------------------------------------------------------------------------------- /2015/Python/12.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pprint import pprint 3 | import json 4 | 5 | def solveA(filename): 6 | lines = open(filename).read().strip() 7 | print('Part 1:', sum(int(i) for i in re.findall(r'-*\d+', lines))) 8 | 9 | def solveB(filename): 10 | lines = open(filename).read().strip() 11 | data = json.loads(lines) 12 | total = parse(data) 13 | print('Part 2:', total) 14 | 15 | def parse(data): 16 | total = 0 17 | if isinstance(data, dict): 18 | data = list(data.values()) 19 | if 'red' in data: 20 | return 0 21 | if isinstance(data, list): 22 | for i in data: 23 | total += parse(i) 24 | 25 | try: 26 | total += data 27 | except (ValueError,TypeError): 28 | pass 29 | 30 | return total 31 | 32 | def main(): 33 | solveA('../data/12.in') 34 | solveB('../data/12.in') 35 | 36 | 37 | if __name__ == "__main__": 38 | main() 39 | 40 | 41 | # Attempts: 38885 (Too low) 42 | -------------------------------------------------------------------------------- /2015/Python/13.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from itertools import permutations 3 | 4 | def read_file(filename): 5 | data = defaultdict(dict) 6 | with open(filename) as f: 7 | for line in f: 8 | name, _, sign, n, _, _, _, _, _, _, other = line.split() 9 | sign = {'gain': 1, 'lose': -1}[sign] 10 | data[name][other[:-1]] = int(n) * sign 11 | return data 12 | 13 | def happiness(data, perm): 14 | happy = 0 15 | for i, name in enumerate(perm): 16 | l = i - 1 17 | r = i + 1 if i != (len(perm) - 1) else 0 18 | l, r = perm[l], perm[r] 19 | happy += data[name][l] 20 | happy += data[name][r] 21 | return happy 22 | 23 | 24 | def best_perm(data): 25 | return max(happiness(data, p) for p in permutations(data.keys())) 26 | 27 | def solveA(data): 28 | rv = best_perm(data) 29 | print('Part 1:', rv) 30 | return rv 31 | 32 | def solveB(data): 33 | for k in list(data.keys()): 34 | data['Me'][k] = 0 35 | data[k]['Me'] = 0 36 | rv = best_perm(data) 37 | print('Part 2:', rv) 38 | return rv 39 | 40 | def main(): 41 | data = read_file('../data/13.in') 42 | solveA(data) 43 | solveB(data) 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /2015/Python/14.py: -------------------------------------------------------------------------------- 1 | """Advent of Code 2015 Day 14""" 2 | from collections import defaultdict 3 | from collections import namedtuple 4 | import re 5 | 6 | Deer = namedtuple('Deer', ['speed', 'sec', 'rest']) 7 | 8 | def read_file(filename): 9 | lines = open(filename).read().splitlines() 10 | data = {} 11 | for line in lines: 12 | speed, sec, rest = map(int, re.findall(r'\d+', line)) 13 | data[line.split()[0]] = Deer(speed, sec, rest) 14 | return data 15 | 16 | def distance(name, deer, time): 17 | speed, sec, rest = deer 18 | dist = 0 19 | for _ in range(time): 20 | if sec: 21 | sec -= 1 22 | dist += speed 23 | continue 24 | if rest: 25 | rest -= 1 26 | if rest == 0: 27 | sec = deer.sec 28 | rest = deer.rest 29 | return dist, name 30 | 31 | def solveA(data, time): 32 | return max(distance(r, data[r], time) for r in data.keys()) 33 | 34 | def solveB(data, time): 35 | score = defaultdict(int) 36 | for i in range(time): 37 | dist, name = solveA(data, i) 38 | score[name] += 1 39 | return max(score.values()) 40 | 41 | def main(): 42 | data = read_file('../data/14.in') 43 | print('Part 1:', solveA(data, 2503)[0]) 44 | print('Part 2:', solveB(data, 2503)) 45 | 46 | if __name__ == "__main__": 47 | main() 48 | 49 | # Attempts: 2640 50 | -------------------------------------------------------------------------------- /2015/Python/17.py: -------------------------------------------------------------------------------- 1 | from itertools import combinations 2 | 3 | with open('../data/../data/17.in') as f: 4 | CONTAINERS = [int(i) for i in f.read().splitlines()] 5 | 6 | def find_count(part2=False): 7 | count = 0 8 | for i in range(1, len(CONTAINERS)): 9 | for c in combinations(CONTAINERS, i): 10 | if sum(c) == 150: 11 | count += 1 12 | if part2 and count > 0: 13 | return count 14 | return count 15 | 16 | 17 | print('Part 1:', find_count()) 18 | print('Part 2:', find_count(part2=True)) 19 | 20 | # 1638 21 | # 17 22 | -------------------------------------------------------------------------------- /2015/Python/20.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | goal = 34_000_000 4 | 5 | NUM = 1_000_000 6 | 7 | houses_a = np.zeros(NUM) 8 | houses_b = np.zeros(NUM) 9 | 10 | for i in range(1, NUM): 11 | houses_a[i::i] += 10 * i 12 | houses_b[i:(i + 1) * 50:i] += 11 * i 13 | 14 | print('Part 1:', np.nonzero(houses_a >= goal)[0][0]) 15 | print('Part 2:', np.nonzero(houses_b >= goal)[0][0]) 16 | -------------------------------------------------------------------------------- /2015/Python/23.py: -------------------------------------------------------------------------------- 1 | def read_file(filename): 2 | rv = [] 3 | with open(filename) as f: 4 | for line in f: 5 | line = line.replace(',', '') 6 | line = line.replace('a', '1') 7 | line = line.replace('b', '2') 8 | rv.append(line.split()) 9 | return rv 10 | 11 | def func(regs, func, v, w=0): 12 | v = int(v) 13 | w = int(w) 14 | if func == 'hlf': 15 | regs[v] = regs[v] // 2 16 | elif func == 'tpl': 17 | regs[v] *= 3 18 | elif func == 'inc': 19 | regs[v] += 1 20 | elif func == 'jmp': 21 | regs[0] += int(v) 22 | elif func == 'jie': 23 | if regs[v] % 2 == 0: 24 | regs[0] += int(w) 25 | elif func == 'jio': 26 | if regs[v] == 1: 27 | regs[0] += int(w) 28 | 29 | def run_program(regs, data): 30 | counter = 0 31 | while 0 <= counter < len(data): 32 | line = data[counter] 33 | func(regs, line[0], *line[1:]) 34 | if counter == regs[0]: 35 | regs[0] += 1 36 | counter = regs[0] 37 | 38 | def main(): 39 | data = read_file('../data/23.in') 40 | regs = [0, 0, 0] 41 | run_program(regs, data) 42 | print('Part 1:', regs[2]) 43 | regs = [0, 1, 0] 44 | run_program(regs, data) 45 | print('Part 2:', regs[2]) 46 | 47 | if __name__ == "__main__": 48 | main() 49 | -------------------------------------------------------------------------------- /2015/Python/25.py: -------------------------------------------------------------------------------- 1 | from itertools import islice 2 | from math import factorial 3 | 4 | FIRST = 20151125 5 | 6 | def n_code(): 7 | n = FIRST 8 | while True: 9 | yield n 10 | n = code(n) 11 | 12 | def code(previous): 13 | return (previous * 252533) % 33554393 14 | 15 | def top_of_column(n): 16 | return factorial(n + 1) // (factorial(n - 1) * factorial((n + 1) - (n - 1))) 17 | 18 | def place(col, row): 19 | return top_of_column(col) + sum(range(col, col + (row - 1))) 20 | 21 | # Part 1: Code at row 2981, col 3075 22 | def main(): 23 | col = 3075 24 | row = 2981 25 | n = place(col, row) 26 | print(n) 27 | print('Part 1:', next(islice(n_code(), n - 1, n))) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | 32 | # 12322222 (Too high) 33 | # 390292 (Too low) 34 | -------------------------------------------------------------------------------- /2016/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2016/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2016 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2016/Haskell/README.md: -------------------------------------------------------------------------------- 1 | # aoc2016 2 | -------------------------------------------------------------------------------- /2016/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2016/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | stack: 3 | - path: "./src" 4 | component: "aoc2016:lib" 5 | 6 | - path: "./app/Main.hs" 7 | component: "aoc2016:exe:aoc2016-exe" 8 | 9 | - path: "./app/Paths_aoc2016.hs" 10 | component: "aoc2016:exe:aoc2016-exe" 11 | 12 | - path: "./test" 13 | component: "aoc2016:test:aoc2016-test" 14 | -------------------------------------------------------------------------------- /2016/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2016:exe:aoc2016-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Lib 4 | ( Point, firstRepeat, Dir(North, East, West), dirPoint ) 5 | import Linear 6 | 7 | 8 | data Move = Turn Dir 9 | | Walk 10 | deriving (Show) 11 | 12 | data Sleigh = (:@) Dir Point 13 | deriving (Eq, Show) 14 | 15 | instance Ord Sleigh where 16 | (_ :@ p) `compare` (_ :@ p') = p `compare` p' 17 | 18 | parseInput :: String -> [Move] 19 | parseInput = concatMap parse . words . filter (/= ',') 20 | where 21 | parse ('R' : xs) = let i = read xs in Turn East : replicate (i - 1) Walk 22 | parse ('L' : xs) = let i = read xs in Turn West : replicate (i - 1) Walk 23 | 24 | move :: Sleigh -> Move -> Sleigh 25 | move (d :@ p) Walk = d :@ (p + dirPoint d) 26 | move (d :@ p) (Turn dir) = 27 | let d' = d <> dir 28 | in d' :@ (p + dirPoint d') 29 | 30 | part1 :: Foldable t => t Move -> Int 31 | part1 input = 32 | let _ :@ p = foldl move (North :@ V2 0 0) input 33 | in sum p 34 | 35 | part2 :: [Move] -> Int 36 | part2 input = case firstRepeat $ scanl move (North :@ V2 0 0) input of 37 | Nothing -> error "No repeating point" 38 | Just (_ :@ p) -> sum p 39 | 40 | main :: IO () 41 | main = do 42 | input <- parseInput <$> readFile "../data/day01.in" 43 | print $ part1 input 44 | print $ part2 input 45 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ViewPatterns #-} 2 | module Day03 where 3 | 4 | import Control.Lens 5 | import Data.Maybe (fromJust) 6 | import Linear (V2 (..)) 7 | import Lib ( count ) 8 | import Data.List (sort) 9 | import Data.List.Extra 10 | 11 | import Debug.Trace 12 | 13 | parseInput :: String -> [[Int]] 14 | parseInput = map (map read . words) . lines 15 | 16 | type Triple = (Int, Int, Int) 17 | 18 | part1 :: [[Int]] -> Int 19 | part1 = count valid 20 | where 21 | valid (sort -> [a, b, c]) = a + b > c 22 | 23 | part2 :: [[Int]] -> Int 24 | part2 = part1 . concatMap transpose . chunksOf 3 25 | 26 | main :: IO () 27 | main = do 28 | let run file = do 29 | input <- parseInput <$> readFile file 30 | putStrLn ("\nInput file: " ++ show file) 31 | print $ part1 input 32 | print $ part2 input 33 | 34 | run "../data/day03.in" 35 | 36 | -- 1032 37 | -- 1838 38 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day06.hs: -------------------------------------------------------------------------------- 1 | module Day06 where 2 | 3 | import Control.Lens 4 | import Lib 5 | import Data.List.Extra 6 | import Text.ParserCombinators.Parsec 7 | import qualified Data.Map as Map 8 | 9 | parseInput = lines 10 | 11 | part1 :: [String] -> Maybe String 12 | part1 = fmap (map fst) . traverse (maximumVal . freqs) . transpose 13 | 14 | part2 :: [String] -> Maybe String 15 | part2 = fmap (map fst) . traverse (minimumVal . freqs) . transpose 16 | 17 | main :: IO () 18 | main = do 19 | let run file = do 20 | input <- parseInput <$> readFile file 21 | putStrLn ("\nInput file: " ++ show file ++ "\n") 22 | print $ part1 input 23 | print $ part2 input 24 | 25 | run "../data/day06.in" 26 | 27 | -- Just "dzqckwsd" 28 | -- Just "lragovly" 29 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day11.hs: -------------------------------------------------------------------------------- 1 | module Day11 where 2 | 3 | main :: IO () 4 | main = undefined 5 | 6 | -- Solved by hand 7 | 8 | -- The first floor contains a strontium generator, a strontium-compatible microchip, a plutonium generator, and a plutonium-compatible microchip. 9 | -- The second floor contains a thulium generator, a ruthenium generator, a ruthenium-compatible microchip, a curium generator, and a curium-compatible microchip. 10 | -- The third floor contains a thulium-compatible microchip. 11 | -- The fourth floor contains nothing relevant. 12 | -- 13 | -- To move x items one floor up: 14 | -- 2 moves per item 15 | -- - 2 because the last two items take one trip 16 | -- - 1 becauce the first item took one trip 17 | -- = 2 * x - 3 18 | -- 19 | -- 5 steps to get everything but T on lvl 2 20 | -- 15 steps to move from 2 -> 3 21 | -- 17 steps for 3 -> 4 22 | -- = 37 23 | -- 24 | -- -- Part 2 25 | -- 26 | -- 13 for 1 -> 2 27 | -- 23 for 2 -> 3 28 | -- 25 for 3 -> 4 29 | -- = 61 30 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day14.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Day14 where 4 | 5 | import Control.Monad (guard) 6 | import Crypto.Hash 7 | import qualified Crypto.Hash.MD5 as MD5 8 | import Data.ByteString (ByteString) 9 | import qualified Data.ByteString as BS 10 | import Data.ByteString.Char8 (pack) 11 | import Data.Byteable 12 | import Data.List 13 | import Lib 14 | 15 | genHash :: ByteString -> ByteString 16 | genHash = digestToHexByteString . md5 17 | where 18 | md5 :: ByteString -> Digest MD5 19 | md5 = hash 20 | 21 | run :: (ByteString -> ByteString) -> ByteString -> Int 22 | run strat salt = fst . (!! 63) $ do 23 | ((ix, x) : xs) <- tails hashes 24 | ts <- take 1 $ do 25 | s <- sliding 3 x 26 | guard $ BS.all (== BS.head s) s 27 | pure $ BS.head s 28 | guard $ any ((BS.replicate 5 ts `BS.isInfixOf`) . snd) $ take 1000 xs 29 | pure (ix, x) 30 | where 31 | hashes :: [(Int, ByteString)] 32 | hashes = zip [0 ..] $ map (strat . (salt <>) . pack . show) [0 ..] 33 | sliding n bs = takeWhile ((== n) . BS.length) . map (BS.take 3) $ BS.tails bs 34 | 35 | part1 :: ByteString -> Int 36 | part1 = run genHash 37 | 38 | part2 :: ByteString -> Int 39 | part2 = run (genHash . (!! 2015) . iterate MD5.hash) 40 | 41 | main :: IO () 42 | main = do 43 | print $ part1 "ahsbgdzn" 44 | print $ part2 "ahsbgdzn" 45 | 46 | -- 23890 47 | -- 22696 (92 s) 48 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day16.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | module Day16 where 3 | 4 | import Control.Lens 5 | import Lib 6 | import Data.List.Extra (chunksOf) 7 | import Text.ParserCombinators.Parsec 8 | import qualified Data.Map as Map 9 | import qualified Data.ByteString as BS 10 | import Data.ByteString (ByteString) 11 | import Data.Word (Word8) 12 | import Data.Bool (bool) 13 | 14 | 15 | solve :: Int -> [Bool] -> [Bool] 16 | solve len = checksum . take len . until ((>= len) . length) genData 17 | where 18 | genData a = a <> [False] <> map not (reverse a) 19 | checksum = until (odd . length) run 20 | where 21 | run = map (foldl1 (==)) . chunksOf 2 22 | 23 | part1 :: Int -> [Bool] -> String 24 | part1 n = map (bool '0' '1') . solve n 25 | 26 | part2 :: Int -> [Bool] -> String 27 | part2 n = map (bool '0' '1') . solve n 28 | 29 | toRep :: Bool -> Char 30 | toRep a = if a then '1' else '0' 31 | 32 | main :: IO () 33 | main = do 34 | let run str = do 35 | putStrLn str 36 | let input = map (== '1') "01110110101001000" 37 | print $ part1 272 input 38 | print $ part2 35651584 input 39 | 40 | run "\nActual:\n" 41 | 42 | -- "11100111011101111" 43 | -- "10001110010000110" (~100 s) 44 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day18.hs: -------------------------------------------------------------------------------- 1 | module Day18 where 2 | 3 | import Control.Lens 4 | import Lib 5 | import Data.List.Extra 6 | import qualified Data.Map as Map 7 | 8 | parseInput = init 9 | 10 | sliding :: Int -> [a] -> [[a]] 11 | sliding n str = filter ((== n) . length) . map (take n) $ tails str 12 | 13 | gen :: String -> String 14 | gen str = map next . sliding 3 $ "." <> str <> "." 15 | where 16 | next "^^." = '^' 17 | next ".^^" = '^' 18 | next "^.." = '^' 19 | next "..^" = '^' 20 | next _ = '.' 21 | 22 | runN :: Int -> String -> Int 23 | runN n = count (== '.') . concat . take n . iterate gen 24 | 25 | part1 :: String -> Int 26 | part1 = runN 40 27 | 28 | part2 :: String -> Int 29 | part2 = runN 400000 30 | 31 | main :: IO () 32 | main = do 33 | let run file = do 34 | input <- parseInput <$> readFile file 35 | print $ part1 input 36 | print $ part2 input 37 | 38 | run "../data/day18.in" 39 | 40 | -- 2035 41 | -- 20000577 42 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day19.hs: -------------------------------------------------------------------------------- 1 | module Day19 where 2 | 3 | import Data.Sequence ( Seq(..) ) 4 | import qualified Data.Sequence as S 5 | 6 | n :: Int 7 | n = 3012210 8 | 9 | type Elves = Seq Int 10 | 11 | steal :: (Elves -> Int) -> Elves -> Elves 12 | steal _ es@(_ :<| Empty) = es 13 | steal f es = 14 | let (e :<| rest) = S.deleteAt (f es) es 15 | in rest S.|> e 16 | 17 | run :: (Elves -> Int) -> Elves -> Int 18 | run f = flip S.index 0 . head . dropWhile ((>1) . length) . iterate (steal f) 19 | 20 | part1 :: Elves -> Int 21 | part1 = run (const 1) 22 | 23 | part2 :: Elves -> Int 24 | part2 = run ((`div` 2) . length) 25 | 26 | main :: IO () 27 | main = do 28 | print $ part1 (S.fromList [1 .. n]) 29 | print $ part2 (S.fromList [1 .. n]) 30 | 31 | -- 1830117 32 | -- 1417887 33 | -------------------------------------------------------------------------------- /2016/Haskell/src/Day20.hs: -------------------------------------------------------------------------------- 1 | module Day20 where 2 | 3 | import Control.Lens 4 | import Data.List.Extra (sort) 5 | import qualified Data.Map as Map 6 | import Data.Maybe (listToMaybe) 7 | import Lib 8 | import Text.ParserCombinators.Parsec 9 | 10 | parseInput :: String -> [(Int, Int)] 11 | parseInput = either (error . show) id . traverse (parse nums "") . lines 12 | where 13 | nums = do 14 | from <- read @Int <$> many1 digit 15 | char '-' 16 | to <- read @Int <$> many1 digit 17 | pure (from, to) 18 | 19 | type Pair = (Int, Int) 20 | 21 | merge :: [Pair] -> [Pair] 22 | merge [] = [] 23 | merge [x] = [x] 24 | merge ((x, y) : (a, b) : rest) 25 | | y > b = merge $ (x, y) : rest 26 | | y > a = merge $ (x, b) : rest 27 | | otherwise = (x, y) : merge ((a, b) : rest) 28 | 29 | part1 :: [Pair] -> Maybe Int 30 | part1 = fmap ((+ 1) . snd) . listToMaybe . merge . sort 31 | 32 | part2 :: [Pair] -> Int 33 | part2 = 34 | sum 35 | . map (uncurry diff) 36 | . (zip <*> tail) 37 | . merge 38 | . ((0, 0) :) 39 | . (++ [(4294967295, 0)]) 40 | . sort 41 | where 42 | diff (_, x) (y, _) = max (y - x - 1) 0 43 | 44 | main :: IO () 45 | main = do 46 | let run file = do 47 | input <- parseInput <$> readFile file 48 | print $ part1 input 49 | print $ part2 input 50 | 51 | run "../data/day20.in" 52 | 53 | -- Just 753115 54 | -- 113 55 | -------------------------------------------------------------------------------- /2016/Haskell/src/Template.hs: -------------------------------------------------------------------------------- 1 | module Template where 2 | 3 | import Control.Lens 4 | import Lib 5 | import Data.List.Extra 6 | import Text.ParserCombinators.Parsec 7 | import qualified Data.Map as Map 8 | 9 | parseInput = lines 10 | 11 | part1 = undefined 12 | 13 | part2 = undefined 14 | 15 | main :: IO () 16 | main = do 17 | let run file = do 18 | input <- parseInput <$> readFile file 19 | putStrLn ("\nInput file: " ++ show file ++ "\n") 20 | print input 21 | -- print $ part1 input 22 | -- print $ part2 input 23 | 24 | run "../data/test" 25 | -- run "../data/day05.in" 26 | 27 | -- 409147 28 | -- Just 991 29 | -------------------------------------------------------------------------------- /2016/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2016/Python/01.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | import re 3 | 4 | def read_file(filename): 5 | with open(filename) as f: 6 | return f.read().split(', ') 7 | 8 | class Point(namedtuple('Point', ['x', 'y'])): 9 | def __add__(self, other): 10 | return Point(self.x + other.x, self.y + other.y) 11 | 12 | def dist(self): 13 | return abs(self.x) + abs(self.y) 14 | 15 | next_move = {'N': {'R': 'E', 'L': 'W'}, 16 | 'S': {'R': 'W', 'L': 'E'}, 17 | 'W': {'R': 'N', 'L': 'S'}, 18 | 'E': {'R': 'S', 'L': 'N'}} 19 | 20 | move = {'N': (-1, 0), 21 | 'S': (1, 0), 22 | 'W': (0, -1), 23 | 'E': (0, 1)} 24 | 25 | def main(): 26 | data = read_file('input/01.in') 27 | direction = 'N' 28 | seen = set() 29 | repeat = [] 30 | pos = Point(0, 0) 31 | for i in data: 32 | direction = next_move[direction][i[0]] 33 | a = int(i[1:]) 34 | while a: 35 | if pos in seen: 36 | repeat.append(pos) 37 | else: 38 | seen.add(pos) 39 | pos += Point(*move[direction]) 40 | a -= 1 41 | 42 | print('Part 1:', pos.dist()) 43 | print('Part 2:', repeat[0].dist()) 44 | 45 | if __name__ == "__main__": 46 | main() 47 | -------------------------------------------------------------------------------- /2016/Python/02.py: -------------------------------------------------------------------------------- 1 | from collections import namedtuple 2 | 3 | def read_file(filename): 4 | return open(filename).read().splitlines() 5 | 6 | class Point(namedtuple('Point', ['x', 'y'])): 7 | def __add__(self, other): 8 | return Point(self.x + other.x, self.y + other.y) 9 | 10 | PAD = [[1,2,3], 11 | [4,5,6], 12 | [7,8,9]] 13 | 14 | PAD2 = [[0,0,1,0,0], 15 | [0,2,3,4,0], 16 | [5,6,7,8,9], 17 | [0,'A','B','C',0], 18 | [0,0,'D',0,0]] 19 | 20 | MOVE = {'L': Point(-1, 0), 21 | 'R': Point(1, 0), 22 | 'U': Point(0, -1), 23 | 'D': Point(0, 1)} 24 | 25 | def find_pos(lines, pad, start): 26 | ans = '' 27 | pos = Point(*start) 28 | for line in lines: 29 | for c in line: 30 | new = pos + MOVE[c] 31 | if (0 <= new.y < len(pad)) and (0 <= new.x < len(pad[new.y])) and (pad[new.y][new.x] != 0): 32 | pos = new 33 | ans += str(pad[pos.y][pos.x]) 34 | return ans 35 | 36 | def main(): 37 | lines = read_file('input/02.in') 38 | print('Part 1:', find_pos(lines, PAD, (1, 1))) 39 | print('Part 2:', find_pos(lines, PAD2, (2, 2))) 40 | 41 | if __name__ == "__main__": 42 | main() 43 | -------------------------------------------------------------------------------- /2016/Python/03.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def read_file(filename): 4 | with open(filename) as f: 5 | triangles = [] 6 | for line in f: 7 | triangles.append(tuple(int(i) for i in re.findall(r'\d+', line))) 8 | return triangles 9 | 10 | def legal_triangle(a, b, c): 11 | return a + b > c and a + c > b and b + c > a 12 | 13 | def solveA(triangles): 14 | return sum(legal_triangle(*a) for a in triangles) 15 | 16 | def solveB(triangles): 17 | ts = iter(triangles) 18 | count = 0 19 | for a in ts: 20 | b = next(ts) 21 | c = next(ts) 22 | count += sum(legal_triangle(*i) for i in zip(a, b, c)) 23 | return count 24 | 25 | def main(): 26 | triangles = read_file('input/03.in') 27 | print('Part 1:', solveA(triangles)) 28 | print('Part 2:', solveB(triangles)) 29 | 30 | if __name__ == "__main__": 31 | main() 32 | 33 | # Attempts: 1067 (Too low) 34 | -------------------------------------------------------------------------------- /2016/Python/05.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | import hashlib 3 | 4 | 5 | def md5_hex(key): 6 | for i in count(): 7 | val = hashlib.md5((key + str(i)).encode()).hexdigest() 8 | if val[:5] == '0' * 5: 9 | yield val 10 | 11 | def solveA(key, length=8, zeros=5): 12 | password = '' 13 | for val in md5_hex(key): 14 | password += val[zeros] 15 | print('Processing ... :', ''.join(password)) 16 | if len(password) == length: 17 | return password 18 | 19 | def solveB(key): 20 | password = [''] * 8 21 | for val in md5_hex(key): 22 | try: 23 | i = int(val[5]) 24 | except ValueError: 25 | continue 26 | if 0 > i or i > 7: 27 | continue 28 | if password[i] == '': 29 | password[i] = val[6] 30 | print('Processing: ... :', ''.join(password)) 31 | if '' not in password: 32 | return ''.join(password) 33 | 34 | def main(): 35 | key = 'wtnhxymk' 36 | print('Part 1:', solveA(key)) 37 | print('Part 2:', solveB(key)) 38 | 39 | if __name__ == "__main__": 40 | main() 41 | -------------------------------------------------------------------------------- /2016/Python/06.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | def read_file(filename): 4 | return open(filename).read().splitlines() 5 | 6 | def solve(lines): 7 | lines = list(map(list, zip(*lines))) 8 | first = '' 9 | last = '' 10 | for line in lines: 11 | count = Counter(line).most_common() 12 | first += count[0][0] 13 | last += count[-1][0] 14 | print('Part 1:', first) 15 | print('Part 2:', last) 16 | 17 | def main(): 18 | lines = read_file('input/06.in') 19 | solve(lines) 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /2016/Python/09.py: -------------------------------------------------------------------------------- 1 | """Advent of Code 2016 Day 9""" 2 | import re 3 | 4 | def read_file(filename): 5 | return open(filename).read().strip() 6 | 7 | def decompress(string, part2=False): 8 | new = '' 9 | while string: 10 | if string[0] != '(': 11 | new += string[0] 12 | string = string[1:] 13 | continue 14 | index = string.find(')') 15 | code = string[1:index] 16 | chars, repeat = [int(i) for i in code.split('x')] 17 | string = string[index + 1:] 18 | substring = string[:chars] 19 | if part2: 20 | while re.findall(r'\(\d+x\d+\)', substring): 21 | substring = decompress(substring, part2=True) 22 | string = string[chars:] 23 | new += substring * repeat 24 | return new 25 | 26 | def main(): 27 | line = read_file('input/09.in') 28 | print('Part 1:', len(decompress(line))) 29 | print('Part 2:', len(decompress(line, part2=True))) 30 | 31 | if __name__ == "__main__": 32 | main() 33 | -------------------------------------------------------------------------------- /2016/Python/13.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | KEY = 1352 4 | 5 | def space(key, loc): 6 | x, y = loc 7 | num = x*x + 3*x + 2*x*y + y + y*y + key 8 | num = str(bin(num)).count('1') 9 | return num % 2 == 0 10 | 11 | def shortest_path(key, target=None, steps=0): 12 | queue = deque([((1,1), 0)]) 13 | data = {} 14 | while queue: 15 | loc, dist = queue.popleft() 16 | if target is not None and loc == target: 17 | return dist 18 | data[loc] = True 19 | for x, y in ((-1, 0), (1, 0), (0, -1), (0, 1)): 20 | new = (loc[0] + x, loc[1] + y) 21 | if new[0] < 0 or new[1] < 0: 22 | continue 23 | if new in data or not space(key, new): 24 | continue 25 | if steps and dist >= steps: 26 | continue 27 | queue.append((new, dist + 1)) 28 | return len(data) 29 | 30 | def main(): 31 | print('Part 1:', shortest_path(KEY, target=(31, 39))) 32 | print('Part 2:', shortest_path(KEY, steps=50)) 33 | 34 | if __name__ == "__main__": 35 | main() 36 | -------------------------------------------------------------------------------- /2016/Python/15.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | from itertools import count 3 | import re 4 | 5 | @dataclass 6 | class Disc: 7 | num: int 8 | n_pos: int 9 | pos: int 10 | 11 | def read_file(filename): 12 | discs = [] 13 | with open(filename) as f: 14 | for line in f: 15 | num, n_pos, time, pos = map(int, re.findall(r'\d+', line)) 16 | discs.append(Disc(num, n_pos, pos)) 17 | return discs 18 | 19 | def simulate(discs): 20 | for i in count(): 21 | for d in discs: 22 | if ((d.pos + i + d.num) % d.n_pos) != 0: 23 | break 24 | else: 25 | return i 26 | 27 | def main(): 28 | discs = read_file('input/15.in') 29 | print('Part 1:', simulate(discs)) 30 | discs.append(Disc(len(discs) + 1, 11, 0)) 31 | print('Part 2:', simulate(discs)) 32 | 33 | if __name__ == "__main__": 34 | main() 35 | -------------------------------------------------------------------------------- /2016/Python/16.py: -------------------------------------------------------------------------------- 1 | 2 | INIT = '01110110101001000' 3 | 4 | def gen(a): 5 | b = ''.join('1' if i == '0' else '0' for i in reversed(a)) 6 | return a + '0' + b 7 | 8 | assert gen('111100001010') == '1111000010100101011110000' 9 | 10 | def checksum(string): 11 | new = '' 12 | for a, b in list(zip(string, string[1:]))[::2]: 13 | new += '1' if a == b else '0' 14 | return new 15 | 16 | def gen_checksum(data, length): 17 | cs = '' 18 | while len(data) < length: 19 | data = gen(data) 20 | cs = checksum(data[:length]) 21 | while len(cs) % 2 == 0: 22 | if len(cs) > length: 23 | cs = cs[:length] 24 | cs = checksum(cs) 25 | return cs 26 | 27 | def main(): 28 | print('Part 1:', gen_checksum(INIT, 272)) 29 | print('Part 1:', gen_checksum(INIT, 35651584)) 30 | 31 | if __name__ == "__main__": 32 | main() 33 | 34 | -------------------------------------------------------------------------------- /2016/Python/17.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | from collections import deque 3 | 4 | KEY = 'ioramepc' 5 | 6 | def md5_hex(key): 7 | return tuple(hashlib.md5(key.encode()).hexdigest()[:4]) 8 | 9 | def shortest_path(key, longest=False): 10 | longest_path = 0 11 | target = (6, 6) 12 | dists = {} 13 | queue = deque([((0, 0), '')]) 14 | while queue: 15 | coord, path = queue.popleft() 16 | if coord == target: 17 | if not longest: 18 | return path 19 | longest_path = len(path) 20 | continue 21 | for d, i in zip(['U', 'D', 'L', 'R'], md5_hex(key + path)): 22 | if i in 'bcdef': 23 | x, y = coord 24 | a, b = {'U': (0, -2), 25 | 'D': (0, 2), 26 | 'L': (-2, 0), 27 | 'R': (2, 0)}[d] 28 | new = (x + a, y + b) 29 | if not new[0] in range(8) or not new[1] in range(8): 30 | continue 31 | queue.append((new, path + d)) 32 | return longest_path 33 | 34 | def main(): 35 | print('Part 1:', shortest_path(KEY)) 36 | print('Part 2:', shortest_path(KEY, longest=True)) 37 | 38 | if __name__ == "__main__": 39 | main() 40 | -------------------------------------------------------------------------------- /2016/Python/18.py: -------------------------------------------------------------------------------- 1 | 2 | def safe_tiles(line, rows=10): 3 | count = line.count('.') 4 | for _ in range(rows - 1): 5 | line = '.' + line + '.' 6 | new = '' 7 | for a, b, c in zip(line, line[1:], line[2:]): 8 | if '^' == a == b != c: 9 | new += '^' 10 | elif '^' == b == c != a: 11 | new += '^' 12 | elif '^' == a != b == c: 13 | new += '^' 14 | elif a == b != c == '^': 15 | new += '^' 16 | else: 17 | new += '.' 18 | line = new 19 | count += line.count('.') 20 | return count 21 | 22 | assert safe_tiles('.^^.^.^^^^', rows=10) == 38 23 | 24 | def main(): 25 | line = '.^..^....^....^^.^^.^.^^.^.....^.^..^...^^^^^^.^^^^.^.^^^^^^^.^^^^^..^.^^^.^^..^.^^.^....^.^...^^.^.' 26 | print('Part 1:', safe_tiles(line, rows=40)) 27 | print('Part 2:', safe_tiles(line, rows=400000)) 28 | 29 | if __name__ == "__main__": 30 | main() 31 | -------------------------------------------------------------------------------- /2016/Python/20.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | # 4294967295 3 | 4 | def read_file(filename): 5 | data = [] 6 | with open(filename) as f: 7 | for line in f: 8 | data.append(list(map(int, line.split('-')))) 9 | return sorted(data) 10 | 11 | 12 | def solveA(lines): 13 | smallest = 0 14 | for a, b in zip(lines, lines[1:]): 15 | if b[0] in range(a[0], a[1] + 2): 16 | continue 17 | return a[1] + 1 18 | 19 | def solveB(lines): 20 | MAX = 4294967295 21 | arr = np.ones(MAX + 1, dtype=np.bool_) 22 | for a, b in lines: 23 | arr[a:b + 1] = False 24 | return np.count_nonzero(arr) 25 | 26 | def main(): 27 | lines = read_file('input/20.in') 28 | print('Part 1:', solveA(lines)) 29 | print('Part 2:', solveB(lines)) 30 | 31 | if __name__ == "__main__": 32 | main() 33 | 34 | # 834840788 (Too high) 35 | -------------------------------------------------------------------------------- /2016/Python/22.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | import re 3 | 4 | @dataclass 5 | class Node: 6 | x: int 7 | y: int 8 | size: int 9 | used: int 10 | avail: int 11 | use_percent: int 12 | 13 | def read_file(filename): 14 | nodes = {} 15 | with open(filename) as f: 16 | for line in f: 17 | x, y, size, used, avail, use_percent = list(map(int, re.findall(r'\d+', line))) 18 | nodes[(x, y)] = Node(x, y, size, used, avail, use_percent) 19 | return nodes 20 | 21 | def is_viable(node, nodes): 22 | if node.used == 0: 23 | return False 24 | for comp in nodes.values(): 25 | if comp == node: 26 | continue 27 | if node.used <= comp.avail: 28 | return True 29 | return False 30 | 31 | 32 | """ 33 | Node A is not empty (its Used is not zero). 34 | Nodes A and B are not the same node. 35 | The data on node A (its Used) would fit on node B (its Avail). 36 | """ 37 | 38 | def find_viable_pairs(nodes): 39 | return sum(is_viable(node, nodes) for node in nodes.values()) 40 | 41 | def main(): 42 | nodes = read_file('input/22.in') 43 | print(len(nodes)) 44 | print('Part 1:', find_viable_pairs(nodes)) 45 | 46 | if __name__ == "__main__": 47 | main() 48 | -------------------------------------------------------------------------------- /2017/Haskell/01.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeApplications #-} 2 | {-# LANGUAGE ViewPatterns #-} 3 | module Main where 4 | 5 | import Data.Digits ( digits ) 6 | import Data.Monoid 7 | import Data.Coerce 8 | import qualified Data.Vector as V 9 | 10 | import Debug.Trace 11 | 12 | part1 :: [Int] -> Int 13 | part1 = coerce . foldMap (Sum . fst) . filter (uncurry (==)) . (zip <*> tail) . ((:) =<< last) 14 | 15 | part2 :: [Int] -> Int 16 | part2 (V.fromList -> xs) = getSum $ foldMap test [0..(len - 1)] 17 | where 18 | len = V.length xs `div` 2 19 | test x = if xs V.! x == xs V.! (x + len) 20 | then Sum (2 * (xs V.! x)) 21 | else Sum 0 22 | 23 | main :: IO () 24 | main = do 25 | input <- map (read @Int . pure) . init <$> readFile "../data/01.in" 26 | print $ part1 input 27 | print $ part2 input 28 | -------------------------------------------------------------------------------- /2017/Haskell/02.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeApplications #-} 2 | module Main where 3 | 4 | import Data.Digits ( digits ) 5 | import Data.Semigroup 6 | import Data.List 7 | 8 | pairs :: [Int] -> [(Int, Int)] 9 | pairs xs = do 10 | (x:xs) <- tails xs 11 | y <- xs 12 | pure (x, y) 13 | 14 | part1 :: [[Int]] -> Int 15 | part1 = getSum . foldMap (Sum . diff . foldMap tup) 16 | where 17 | tup x = (Max x, Min x) 18 | diff (Max x, Min y) = abs (x - y) 19 | 20 | part2 :: [[Int]] -> Int 21 | part2 = getSum . foldMap (foldMap tup . pairs) 22 | where 23 | tup (x, y) = let (a, b) = (max x y, min x y) 24 | in if rem a b == 0 25 | then Sum (a `div` b) 26 | else Sum 0 27 | 28 | main :: IO () 29 | main = do 30 | input <- map ((map (read @Int)) . words) . lines <$> readFile "../data/02.in" 31 | print $ part1 input 32 | print $ part2 input 33 | -------------------------------------------------------------------------------- /2017/Haskell/04.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Data.List (sort, tails, nub) 4 | import Data.Function (on) 5 | 6 | part1 :: [[String]] -> Int 7 | part1 = length . filter (((==) `on` length) <*> nub) 8 | 9 | part2 :: [[String]] -> Int 10 | part2 = length . filter (not . any (uncurry ((==) `on` sort)) . pairs) 11 | where pairs xs = [ (t, c) | t:ts <- tails xs, c <- ts ] 12 | 13 | main :: IO () 14 | main = do 15 | input <- map words . lines <$> readFile "../data/04.in" 16 | print $ part1 input 17 | print $ part2 input 18 | -------------------------------------------------------------------------------- /2017/Haskell/05.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TypeApplications #-} 2 | module Main where 3 | 4 | import Data.List.PointedList (PointedList) 5 | import qualified Data.List.PointedList as PL 6 | import Control.Lens 7 | import Control.Monad.Extra 8 | 9 | type Tape = PointedList Int 10 | 11 | iterateMaybe :: (a -> Maybe a) -> a -> [a] 12 | iterateMaybe f a = a : case f a of 13 | Nothing -> [] 14 | Just v -> iterateMaybe f v 15 | 16 | 17 | step :: (Int -> Int) -> Tape -> Maybe Tape 18 | step f tape = PL.moveN curr $ over PL.focus f tape 19 | where 20 | curr = view PL.focus tape 21 | 22 | part1 :: Tape -> Int 23 | part1 = length . iterateMaybe (step (+1)) 24 | 25 | part2 :: Tape -> Int 26 | part2 = length . iterateMaybe (step (\x -> if x >= 3 then (x - 1) else (x + 1))) 27 | 28 | main :: IO () 29 | main = do 30 | Just input <- PL.fromList . map (read @Int) . lines <$> readFile "../data/05.in" 31 | print $ part1 input 32 | print $ part2 input 33 | -------------------------------------------------------------------------------- /2017/Haskell/06.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BangPatterns #-} 2 | {-# LANGUAGE TupleSections #-} 3 | module Main where 4 | 5 | import Data.IntMap (IntMap) 6 | import qualified Data.IntMap as IMap 7 | import Data.Map (Map) 8 | import qualified Data.Map as Map 9 | import Data.List.Extra 10 | import Control.Lens 11 | 12 | findLoop :: Ord a => [a] -> (Int, Int) -- first loop, size of loop, shift 13 | findLoop (x:xs) = go (Map.singleton x 0) 1 xs 14 | where 15 | go !seen !i (w:ws) = case Map.lookup w seen of 16 | Nothing -> go (Map.insert w i seen) (i + 1) ws 17 | Just seenI -> (seenI, i - seenI) 18 | 19 | run :: IntMap Int -> (Int, Int) 20 | run = findLoop . map (map snd . IMap.toList) . iterate step 21 | where 22 | step mp = 23 | let (i, v) = maximumOn snd $ IMap.toList mp 24 | new = IMap.fromListWith (+) . map ((,1) . (`mod` IMap.size mp)) $ [i + 1 .. (i + v)] 25 | in IMap.unionWith (+) new (IMap.insert i 0 mp) 26 | 27 | main :: IO () 28 | main = do 29 | input <- IMap.fromList . zip [0..] . map read . words <$> readFile "../data/06.in" 30 | print . uncurry (+) . run $ input 31 | print . snd . run $ input 32 | 33 | -- 6681 34 | -- 2392 35 | -------------------------------------------------------------------------------- /2017/Haskell/09.hs: -------------------------------------------------------------------------------- 1 | import Text.ParserCombinators.Parsec 2 | import Data.Maybe (catMaybes) 3 | 4 | data Tree = Group [Tree] 5 | | Garbage String 6 | deriving Show 7 | 8 | parseTree :: String -> Tree 9 | parseTree = either (error $ "Bad parse") id . parse parse' "Group" 10 | where parse' = parseGroup <|> parseGarbage 11 | parseGroup = Group <$> between (char '{') (char '}') (sepBy parse' (char ',')) 12 | parseGarbage = Garbage <$> between (char '<') (char '>') (catMaybes <$> many garbageChar) 13 | garbageChar = 14 | Nothing <$ (char '!' *> anyChar) <|> Just <$> noneOf ">" 15 | 16 | score :: Tree -> Int 17 | score = go 1 18 | where go n (Garbage _) = 0 19 | go n (Group xs) = n + (sum $ map (go (n+1)) xs) 20 | 21 | countGarbage (Group xs) = sum $ map part2 xs 22 | countGarbage (Garbage x) = length x 23 | 24 | part1 :: Tree -> Int 25 | part1 = score 26 | 27 | part2 :: Tree -> Int 28 | part2 = countGarbage 29 | 30 | main = do 31 | input <- parseTree <$> readFile "../data/09.in" 32 | print $ part1 input 33 | print $ part2 input 34 | 35 | -- 11089 36 | -- 5288 37 | -------------------------------------------------------------------------------- /2017/Haskell/10.hs: -------------------------------------------------------------------------------- 1 | import Numeric 2 | import Text.Printf 3 | import Data.Char 4 | import Data.Bits 5 | import Data.Word 6 | import Control.Lens 7 | import Data.List.Extra 8 | import qualified Data.Vector as V 9 | 10 | data Knot = K { _vec :: V.Vector Word8 11 | , _pos :: Word8 12 | , _skip :: Word8 13 | } 14 | 15 | tie :: Knot -> Word8 -> Knot 16 | tie (K v p s) n = K v' p' s' 17 | where 18 | ixs = fromIntegral . (+ p) <$> init [0..n] 19 | vals = map (v V.!) ixs 20 | v' = v V.// zip ixs (reverse vals) 21 | p' = p + s + n 22 | s' = s + 1 23 | 24 | process :: [Word8] -> V.Vector Word8 25 | process = _vec . foldl tie (K (V.fromList [0..255]) 0 0) 26 | 27 | knot :: String -> [Word8] 28 | knot = map (foldr1 xor) 29 | . chunksOf 16 30 | . V.toList 31 | . process 32 | . concat . replicate 64 33 | . (++ [17, 31, 73, 47, 23]) 34 | . map (fromIntegral . ord) . init 35 | 36 | part1 :: String -> Int 37 | part1 = product 38 | . V.map fromIntegral . V.take 2 39 | . process 40 | . map read . splitOn "," . init 41 | 42 | part2 :: String -> String 43 | part2 = concatMap (printf "%02x") . knot 44 | 45 | main = do 46 | input <- readFile "../data/10.in" 47 | 48 | print $ part1 input 49 | print $ part2 input 50 | -------------------------------------------------------------------------------- /2017/Haskell/11.hs: -------------------------------------------------------------------------------- 1 | import Data.Maybe 2 | import Data.List.Extra 3 | import Math.Geometry.Grid (distance, neighbour) 4 | import Math.Geometry.Grid.Hexagonal2 (UnboundedHexGrid(..)) 5 | import Math.Geometry.Grid.HexagonalInternal2 (HexDirection(..)) 6 | import Text.ParserCombinators.Parsec 7 | 8 | parseInput :: String -> [HexDirection] 9 | parseInput = map (\x -> case x of 10 | "nw" -> Northwest 11 | "ne" -> Northeast 12 | "n" -> North 13 | "se" -> Southeast 14 | "sw" -> Southwest 15 | "s" -> South) 16 | . splitOn "," 17 | . init 18 | 19 | move :: (Int, Int) -> HexDirection -> (Int, Int) 20 | move pos = fromJust . neighbour UnboundedHexGrid pos 21 | 22 | part1 :: String -> Int 23 | part1 = distance UnboundedHexGrid (0,0) . foldl move (0,0) . parseInput 24 | 25 | part2 :: String -> Int 26 | part2 = maximum . map (distance UnboundedHexGrid (0,0)) . scanl move (0,0) . parseInput 27 | 28 | main = do 29 | input <- readFile "../data/11.in" 30 | print $ part1 input 31 | print $ part2 input 32 | 33 | -- 705 34 | -- 1469 35 | -------------------------------------------------------------------------------- /2017/Haskell/12.hs: -------------------------------------------------------------------------------- 1 | import Data.Maybe 2 | import Control.Arrow 3 | import Data.List.Extra 4 | import qualified Data.Set as S 5 | import qualified Data.Map as M 6 | 7 | type Id = Int 8 | type Nodes = M.Map Id [Id] 9 | 10 | parse' :: String -> Nodes 11 | parse' = M.fromList 12 | . map (((read . head) &&& (map read . drop 2)) 13 | . splitOn " ") 14 | . lines 15 | . filter (','/=) 16 | 17 | count :: Int -> Nodes -> S.Set Id 18 | count start nodes = go S.empty $ M.findWithDefault [] start nodes 19 | where go seen [] = seen 20 | go seen xs = go (foldl (flip S.insert) seen xs) 21 | $ concatMap (\x -> M.findWithDefault [] x nodes) 22 | $ filter (not . flip S.member seen) xs 23 | 24 | part1 :: String -> Int 25 | part1 = length . count 0 . parse' 26 | 27 | part2 :: String -> Int 28 | part2 = go 0 . parse' 29 | where 30 | go n keys 31 | | M.null keys = n 32 | | otherwise = let new = fst . head $ M.toList keys 33 | in go (n + 1) . foldl (flip M.delete) keys . S.toList $ count new keys 34 | 35 | main = do 36 | input <- readFile "../data/12.in" 37 | print $ part1 input 38 | print $ part2 input 39 | 40 | -- 115 41 | -- 221 42 | -------------------------------------------------------------------------------- /2017/Haskell/13.hs: -------------------------------------------------------------------------------- 1 | import Data.Maybe 2 | import Data.List.Extra 3 | 4 | parse :: String -> [(Int, Int)] 5 | parse = map (\[a,b] -> (read a, read b)) . map (splitOn ": ") . lines 6 | 7 | caught :: Int -> (Int, Int) -> Bool 8 | caught delay (depth, range) = (depth + delay) `mod` (2 * (range - 1)) == 0 9 | 10 | part1 :: String -> Int 11 | part1 = sum . map (uncurry (*)) . filter (caught 0) . parse 12 | 13 | part2 :: [(Int, Int)] -> Int 14 | part2 input = fromJust $ find notCaught [0..] 15 | where 16 | notCaught delay = all (not . caught delay) input 17 | 18 | main = do 19 | input <- readFile "../data/13.in" 20 | print $ part1 input 21 | print $ part2 $ parse input 22 | 23 | -- 1876 24 | -- 3964778 25 | -------------------------------------------------------------------------------- /2017/Haskell/15.hs: -------------------------------------------------------------------------------- 1 | import Data.Bits 2 | import Data.Maybe 3 | import Data.List.Extra 4 | 5 | parse :: String -> [Int] 6 | parse = map (read . last . words) . lines 7 | 8 | judge :: Int -> Int -> Bool 9 | judge a b = (a .&. 65535) == (b .&. 65535) 10 | 11 | generate :: Int -> Int -> Int 12 | generate seed val = val * seed `mod` 2147483647 13 | 14 | part1 :: Int -> Int -> Int 15 | part1 a b = length . filter id . take 40000000 $ zipWith judge as bs 16 | where 17 | as = iterate (generate 16807) a 18 | bs = iterate (generate 48271) b 19 | 20 | part2 :: Int -> Int -> Int 21 | part2 a b = length . filter id . take 5000000 $ zipWith judge as bs 22 | where 23 | as = filter ((==0) . (`mod` 4)) $ iterate (generate 16807) a 24 | bs = filter ((==0) . (`mod` 8)) $ iterate (generate 48271) b 25 | 26 | main = do 27 | [a, b] <- parse <$> readFile "../data/15.in" 28 | 29 | print $ part1 a b 30 | print $ part2 a b 31 | 32 | -------------------------------------------------------------------------------- /2017/Haskell/17.hs: -------------------------------------------------------------------------------- 1 | import Data.Maybe 2 | import Control.Lens 3 | import Data.List.Extra 4 | 5 | data State = S { _step :: Int 6 | , _next :: Int 7 | , _ix :: Int 8 | , _buffer :: [Int] 9 | } 10 | deriving Show 11 | 12 | simulate :: State -> State 13 | simulate (S s next ix xs) = S s next' ix' xs' 14 | where 15 | ix' = 1 + ((ix + s) `mod` next) 16 | xs' = (take ix' xs ++ [next] ++ drop ix' xs) 17 | next' = next + 1 18 | 19 | part1 :: Int -> Int 20 | part1 n = (!! 1) . dropWhile (/=2017) . _buffer . fromJust . find ((==2018) . _next) . iterate simulate $ S n 1 0 [0] 21 | 22 | part2 :: Int -> Int 23 | part2 n = last 24 | . elemIndices 1 25 | $ scanl f 0 [1..50000000] 26 | where 27 | f ix next = 1 + ((ix + n) `mod` next) 28 | 29 | 30 | main = do 31 | input <- (read :: String -> Int) <$> readFile "../data/17.in" 32 | print $ part1 3 33 | print $ part1 input 34 | print $ part2 input 35 | 36 | -- 1306 37 | -- 20430489 38 | -------------------------------------------------------------------------------- /2017/Haskell/21.hs: -------------------------------------------------------------------------------- 1 | import Data.Maybe 2 | import Control.Monad 3 | import Data.List.Extra 4 | import qualified Data.Map.Strict as M 5 | 6 | type Rules = (Grid -> Maybe Grid) 7 | type Grid = [String] 8 | 9 | parse :: String -> Rules 10 | parse = rules' . M.fromList . map (\(x:_:y:_) -> (slash x, slash y)) . map (splitOn " ") . lines 11 | where slash = splitOn "/" 12 | rules' input = flip M.lookup input 13 | 14 | findNext :: Rules -> Grid -> Grid 15 | findNext rules str = head . mapMaybe rules $ rotations str 16 | where rotations x = foldr (liftM2 ($)) [x] $ map (:[id]) [reverse, map reverse, transpose] 17 | 18 | transform :: Rules -> Grid -> Grid 19 | transform rules grid = combine . map (map $ findNext rules) $ zoom grid 20 | where l len = 2 + mod (length len) 2 21 | zoom grid = map (transpose . map (chunksOf (l grid))) $ chunksOf (l grid) grid 22 | combine = map concat . concatMap transpose 23 | 24 | solve :: Rules -> Int -> Int 25 | solve rules n = count (=='#') . concat . (!! n) . iterate (transform rules) $ [".#.","..#","###"] 26 | where count f xs = length $ filter f xs 27 | 28 | part1 :: Rules -> Int 29 | part1 r = solve r 5 30 | 31 | part2 :: Rules -> Int 32 | part2 r = solve r 18 33 | 34 | main = do 35 | input <- parse <$> readFile "../data/21.in" 36 | 37 | print $ part1 input 38 | print $ part2 input 39 | 40 | -- 142 41 | -- 1879071 42 | -------------------------------------------------------------------------------- /2017/Python/01.py: -------------------------------------------------------------------------------- 1 | """Advent of Code 2017 Day 1.""" 2 | 3 | def find_captcha(line): 4 | line = list(line) 5 | line.append(line[0]) 6 | return sum(a for a, b in zip(line, line[1:]) if a == b) 7 | 8 | def solveB(line): 9 | l = len(line) // 2 10 | total = 0 11 | for i, a in enumerate(line): 12 | if a == (line[(i + l) % len(line)]): 13 | total += a 14 | return total 15 | 16 | def main(): 17 | line = list(int(i) for i in list(open('input/01.in').readline().strip())) 18 | print('Part 1:', find_captcha(line)) 19 | print('Part 2:', solveB(line)) 20 | 21 | if __name__ == "__main__": 22 | main() 23 | 24 | # 1081 (Too low) 25 | -------------------------------------------------------------------------------- /2017/Python/02.py: -------------------------------------------------------------------------------- 1 | 2 | def read_file(filename): 3 | with open(filename) as f: 4 | return [[int(i) for i in line.split()] for line in f] 5 | 6 | def checksum(lines): 7 | return sum(max(i) - min(i) for i in lines) 8 | 9 | def evenly_divisible(lines): 10 | total = 0 11 | for line in lines: 12 | for a in line: 13 | for b in line: 14 | if a == b: 15 | continue 16 | if a % b == 0: 17 | total += (a // b) 18 | return total 19 | 20 | def main(): 21 | lines = read_file('input/02.in') 22 | print('Part 1:', checksum(lines)) 23 | print('Part 2:', evenly_divisible(lines)) 24 | 25 | if __name__ == "__main__": 26 | main() 27 | 28 | # 541 (Too high) 29 | -------------------------------------------------------------------------------- /2017/Python/03.py: -------------------------------------------------------------------------------- 1 | 2 | KEY = 289326 3 | 4 | def find_steps(key): 5 | if key == 1: 6 | return 0 7 | for ring, n in enumerate(range(1, 30000, 2)): 8 | if n ** 2 >= key: 9 | break 10 | a = n ** 2 - (n // 2) 11 | axes = [a - (i * (n - 1)) for i in range(4)] 12 | return min(abs(key - i) for i in axes) + ring 13 | 14 | assert find_steps(12) == 3 15 | assert find_steps(23) == 2 16 | assert find_steps(1024) == 31 17 | 18 | def main(): 19 | print('Part 1:', find_steps(KEY)) 20 | 21 | if __name__ == "__main__": 22 | main() 23 | -------------------------------------------------------------------------------- /2017/Python/04.py: -------------------------------------------------------------------------------- 1 | def valid_passphrases(lines): 2 | return sum(1 for line in lines if (len(line) == len(set(line)))) 3 | 4 | def anagrams(lines): 5 | lines = [[''.join(sorted(l)) for l in line] for line in lines] 6 | return sum(1 for line in lines if len(line) == len(set(line))) 7 | 8 | def main(): 9 | lines = [line.split() for line in open('input/04.in').read().splitlines()] 10 | print('Part 1:', valid_passphrases(lines)) 11 | print('Part 2:', anagrams(lines)) 12 | 13 | if __name__ == "__main__": 14 | main() 15 | -------------------------------------------------------------------------------- /2017/Python/05.py: -------------------------------------------------------------------------------- 1 | import re 2 | 3 | def find_exit(nums, negative=False): 4 | nums = list(nums) 5 | i = 0 6 | steps = 0 7 | while i < len(nums): 8 | steps += 1 9 | new = i + nums[i] 10 | nums[i] += -1 if (negative and nums[i] >= 3) else 1 11 | i = new 12 | return steps 13 | 14 | def main(): 15 | nums = [int(i) for i in re.findall(r'-*\d+', open('input/05.in').read())] 16 | print('Part 1:', find_exit(nums)) 17 | print('Part 2:', find_exit(nums, negative=True)) 18 | 19 | if __name__ == "__main__": 20 | main() 21 | -------------------------------------------------------------------------------- /2017/Python/06.py: -------------------------------------------------------------------------------- 1 | from itertools import count 2 | 3 | def redistribute(banks): 4 | m = banks.index(max(banks)) 5 | num = banks[m] 6 | banks[m] = 0 7 | m += 1 8 | while num > 0: 9 | banks[m % len(banks)] += 1 10 | num -= 1 11 | m += 1 12 | 13 | def count_shifts(banks, repeat=False): 14 | seen = set() 15 | while True: 16 | if tuple(banks) in seen: 17 | if repeat: 18 | return find_repeat(banks) 19 | return len(seen) 20 | seen.add(tuple(banks)) 21 | redistribute(banks) 22 | 23 | def find_repeat(banks): 24 | target = list(banks) 25 | print(target) 26 | for i in count(1): 27 | redistribute(banks) 28 | if target == banks: 29 | print(banks) 30 | return i 31 | 32 | def main(): 33 | banks = [int(i) for i in open('input/06.in').readline().split()] 34 | print('Part 1:', count_shifts(banks)) 35 | print('Part 2:', count_shifts(banks, repeat=True)) 36 | 37 | if __name__ == "__main__": 38 | main() 39 | 40 | # 2394 Too high 41 | -------------------------------------------------------------------------------- /2017/rec-scheme/24.in: -------------------------------------------------------------------------------- 1 | 32/31 2 | 2/2 3 | 0/43 4 | 45/15 5 | 33/24 6 | 20/20 7 | 14/42 8 | 2/35 9 | 50/27 10 | 2/17 11 | 5/45 12 | 3/14 13 | 26/1 14 | 33/38 15 | 29/6 16 | 50/32 17 | 9/48 18 | 36/34 19 | 33/50 20 | 37/35 21 | 12/12 22 | 26/13 23 | 19/4 24 | 5/5 25 | 14/46 26 | 17/29 27 | 45/43 28 | 5/0 29 | 18/18 30 | 41/22 31 | 50/3 32 | 4/4 33 | 17/1 34 | 40/7 35 | 19/0 36 | 33/7 37 | 22/48 38 | 9/14 39 | 50/43 40 | 26/29 41 | 19/33 42 | 46/31 43 | 3/16 44 | 29/46 45 | 16/0 46 | 34/17 47 | 31/7 48 | 5/27 49 | 7/4 50 | 49/49 51 | 14/21 52 | 50/9 53 | 14/44 54 | 29/29 55 | 13/38 56 | 31/11 57 | -------------------------------------------------------------------------------- /2017/rec-scheme/Knot.hs: -------------------------------------------------------------------------------- 1 | module Knot where 2 | 3 | import qualified Data.Map as M 4 | import Data.Functor 5 | 6 | nums :: M.Map Int Int 7 | nums = M.fromList [(i, i `mod` 5) | i <- [10..200]] 8 | 9 | -- How to count the number of parents (keys) for each value? 10 | -- i.e. how many keys point to 3, or 4? 11 | 12 | 13 | countNums :: M.Map Int Int 14 | countNums = nums <&> \par -> case M.lookup par countNums of 15 | Nothing -> 0 16 | Just n -> n + 1 17 | 18 | 19 | main :: IO () 20 | main = do 21 | -- print nums 22 | print countNums 23 | -------------------------------------------------------------------------------- /2018/Haskell/.ghcid: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sondresl/AdventOfCode/9b562153445f4eba523fb2ac713fd7f20c2c5fbc/2018/Haskell/.ghcid -------------------------------------------------------------------------------- /2018/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2018/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2018 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2018/Haskell/README.md: -------------------------------------------------------------------------------- 1 | # aoc2018 2 | 3 | ### Running ghcid 4 | 5 | > ghcid -c "stack ghci --main-is aoc2018:exe:aoc2018-exe" --test="Main.main" 6 | 7 | Rather than `Main.main`, pick the `main` function of whatever day you want to run, or 8 | change the main function in `app/Main.hs` 9 | -------------------------------------------------------------------------------- /2018/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2018/Haskell/app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | -- import Lib() 4 | import qualified Day01 5 | import qualified Day02 6 | import qualified Day03 7 | import qualified Day04 8 | import qualified Day05 9 | import qualified Day06 10 | import qualified Day07 11 | import qualified Day08 12 | import qualified Day09 13 | import qualified Day10 14 | import qualified Day11 15 | import qualified Day12 16 | import qualified Day13 17 | import qualified Day14 18 | import qualified Day18 19 | import qualified Day19 20 | import qualified Day20 21 | import qualified Day21 22 | import qualified Day23 23 | 24 | run day f = putStrLn ("Day " ++ day) >> f 25 | 26 | main :: IO () 27 | main = do 28 | -- run "01:" Day01.main 29 | -- run "02:" Day02.main 30 | -- run "03:" Day03.main 31 | -- run "04:" Day04.main 32 | -- run "05:" Day05.main 33 | -- run "06:" Day06.main 34 | -- run "07:" Day07.main 35 | -- run "08:" Day08.main 36 | -- run "09:" Day09.main 37 | -- run "10:" Day10.main 38 | -- run "11:" Day11.main 39 | -- run "12:" Day12.main 40 | -- run "13:" Day13.main 41 | -- run "14:" Day14.main 42 | -- run "18:" Day18.main 43 | -- run "19:" Day19.main 44 | -- run "20:" Day20.main 45 | -- run "21:" Day21.main 46 | run "23:" Day23.main 47 | -------------------------------------------------------------------------------- /2018/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | stack: 3 | - path: "./src" 4 | component: "aoc2018:lib" 5 | 6 | - path: "./app/Main.hs" 7 | component: "aoc2018:exe:aoc2018-exe" 8 | 9 | - path: "./app/Paths_aoc2018.hs" 10 | component: "aoc2018:exe:aoc2018-exe" 11 | 12 | - path: "./test" 13 | component: "aoc2018:test:aoc2018-test" 14 | -------------------------------------------------------------------------------- /2018/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Data.Set (Set) 4 | import qualified Data.Set as Set 5 | 6 | parse :: String -> [Int] 7 | parse = map read . lines . filter (/= '+') 8 | 9 | firstRepeat :: Set Int -> [Int] -> Int 10 | firstRepeat _ [] = undefined 11 | firstRepeat seen (x : xs) = 12 | if Set.member x seen 13 | then x 14 | else firstRepeat (Set.insert x seen) xs 15 | 16 | main :: IO () 17 | main = do 18 | input <- parse <$> readFile "../data/day01.in" 19 | print $ sum input 20 | print $ firstRepeat Set.empty . scanl (+) 0 $ cycle input 21 | 22 | -- 533 23 | -- 73272 24 | -------------------------------------------------------------------------------- /2018/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Data.List (find, group, sort) 4 | import Data.Monoid (Sum (..)) 5 | 6 | parse :: String -> [String] 7 | parse = lines 8 | 9 | pairTwoThree :: (Num a1, Num a2, Ord a3) => [a3] -> (Sum a1, Sum a2) 10 | pairTwoThree str = (counts 2, counts 3) 11 | where 12 | els = group . sort $ str 13 | counts n = 14 | if any ((== n) . length) els 15 | then Sum 1 16 | else Sum 0 17 | 18 | part2 :: Eq b => [[b]] -> Maybe [b] 19 | part2 strs = map fst . filter (uncurry (==)) <$> find oneDiff [zip a b | a <- strs, b <- strs] 20 | where 21 | oneDiff = (== 1) . length . filter (uncurry (/=)) 22 | 23 | main :: IO () 24 | main = do 25 | input <- parse <$> readFile "../data/day02.in" 26 | print $ getSum . uncurry (*) . foldMap pairTwoThree $ input 27 | print $ part2 input 28 | 29 | -- 8715 30 | -- fvstwblgqkhpuixdrnevmaycd 31 | -------------------------------------------------------------------------------- /2018/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Data.Char ( isLower, toLower ) 4 | import qualified Data.Group.Free as F 5 | import Data.Algebra.Free ( FreeAlgebra(returnFree, foldMapFree) ) 6 | import Data.Group ( invert ) 7 | 8 | inject :: Char -> F.FreeGroupL Char 9 | inject c 10 | | isLower c = returnFree c 11 | | otherwise = invert $ returnFree (toLower c) 12 | 13 | part1 :: [Char] -> Int 14 | part1 = length . F.toList . foldMap inject 15 | 16 | clean :: Char -> (F.FreeGroupL Char -> F.FreeGroupL Char) 17 | clean c = foldMapFree $ \d -> 18 | if d == c 19 | then mempty 20 | else returnFree d 21 | 22 | part2 :: [Char] -> Int 23 | part2 string = minimum [ length $ F.toList $ clean c poly 24 | | c <- ['a' .. 'z'] 25 | ] 26 | where 27 | poly = foldMap inject string 28 | 29 | main :: IO () 30 | main = do 31 | input <- init <$> readFile "../data/day05.in" 32 | print $ part1 input 33 | print $ part2 input 34 | 35 | -- 9686 36 | -- 5524 37 | -------------------------------------------------------------------------------- /2018/Haskell/src/Day14.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE BangPatterns #-} 2 | module Day14 where 3 | 4 | import qualified Data.Digits as D 5 | import qualified Data.Sequence as S 6 | import Data.List.Utils 7 | 8 | input :: Int 9 | input = 409551 10 | 11 | generate :: [Int] 12 | generate = 3 : 7 : go 0 1 (S.fromList [3,7]) 13 | where 14 | go !a !b !s = new ++ go a' b' s' 15 | where x = S.index s a 16 | y = S.index s b 17 | new = digits $ x + y 18 | s' = s <> S.fromList new 19 | a' = (a + 1 + x) `mod` length s' 20 | b' = (b + 1 + y) `mod` length s' 21 | 22 | -- Data.Digits.digits fails for 0 -> [] rather than [0] 23 | digits :: Int -> [Int] 24 | digits n = case n `divMod` 10 of 25 | (0, n) -> [n] 26 | (n, m) -> [n, m] 27 | 28 | part1 :: Int -> Int 29 | part1 n = D.unDigits 10 . take 10 $ drop n generate 30 | 31 | part2 :: Int -> Maybe Int 32 | part2 n = subIndex (D.digits 10 n) generate 33 | 34 | main :: IO () 35 | main = do 36 | print $ part1 input 37 | print $ part2 input 38 | 39 | -- 1631191756 40 | -- 20219475 41 | -------------------------------------------------------------------------------- /2018/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Lib ( commaNums 4 | , unionFind 5 | ) 6 | import Linear ( V4(..) ) 7 | import qualified Data.Set as Set 8 | import Data.Set ( Set ) 9 | 10 | type Point = V4 Int 11 | 12 | parseInput :: String -> [Point] 13 | parseInput = map ((\[a,b,c,d] -> V4 a b c d) . commaNums) . lines 14 | 15 | sameConstellation :: Point -> Point -> Bool 16 | sameConstellation p q = sum (abs (p - q)) <= 3 17 | 18 | inConstellation :: Point -> Set Point -> Bool 19 | inConstellation p = not . null . Set.filter (sameConstellation p) 20 | 21 | main :: IO () 22 | main = do 23 | input <- parseInput <$> readFile "../data/day25.in" 24 | print . length $ unionFind inConstellation input 25 | 26 | -- 390 27 | -------------------------------------------------------------------------------- /2018/Haskell/stack.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: 7 | - completed: 8 | hackage: free-algebras-0.1.0.0@sha256:59c6496581fef0483f4eb42ab2fc637dffa8dfeb692d00ced8070a80c2be6013,2485 9 | pantry-tree: 10 | size: 1139 11 | sha256: bc586bc74af137489399aed36ff845a27cacdb9df0ad9002c90eb2bf8fe07b53 12 | original: 13 | hackage: free-algebras-0.1.0.0 14 | - completed: 15 | hackage: sbv-8.9@sha256:efb0f16c671869805e57d11e269793d5e5ae512e8e626582cf76b8e46a63e9c6,28985 16 | pantry-tree: 17 | size: 62515 18 | sha256: 9bb3bb8dbb26363388e013c795e60e81f9b243ecac6e28b3e9d7079c083ebdf4 19 | original: 20 | hackage: sbv-8.9 21 | snapshots: 22 | - completed: 23 | size: 532414 24 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/16/22.yaml 25 | sha256: e483fb88549fc0f454c190979bf35ac91c7aceff2c0e71e7d8edd11842d772d8 26 | original: 27 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/16/22.yaml 28 | -------------------------------------------------------------------------------- /2018/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2018/Python/data/day06.in: -------------------------------------------------------------------------------- 1 | 181, 47 2 | 337, 53 3 | 331, 40 4 | 137, 57 5 | 200, 96 6 | 351, 180 7 | 157, 332 8 | 113, 101 9 | 285, 55 10 | 189, 188 11 | 174, 254 12 | 339, 81 13 | 143, 61 14 | 131, 155 15 | 239, 334 16 | 357, 291 17 | 290, 89 18 | 164, 149 19 | 248, 73 20 | 311, 190 21 | 54, 217 22 | 285, 268 23 | 354, 113 24 | 318, 191 25 | 182, 230 26 | 156, 252 27 | 114, 232 28 | 159, 299 29 | 324, 280 30 | 152, 155 31 | 295, 293 32 | 194, 214 33 | 252, 345 34 | 233, 172 35 | 272, 311 36 | 230, 82 37 | 62, 160 38 | 275, 96 39 | 335, 215 40 | 185, 347 41 | 134, 272 42 | 58, 113 43 | 112, 155 44 | 220, 83 45 | 153, 244 46 | 279, 149 47 | 302, 167 48 | 185, 158 49 | 72, 91 50 | 264, 67 51 | -------------------------------------------------------------------------------- /2018/Python/data/day07.in: -------------------------------------------------------------------------------- 1 | B G 2 | G J 3 | J F 4 | U Z 5 | C M 6 | Y I 7 | Q A 8 | N L 9 | O A 10 | Z T 11 | I H 12 | L W 13 | F W 14 | T X 15 | A X 16 | K X 17 | S P 18 | M E 19 | E W 20 | D P 21 | P W 22 | X H 23 | V W 24 | R H 25 | H W 26 | N I 27 | X R 28 | D V 29 | V R 30 | F K 31 | P R 32 | P V 33 | S X 34 | I S 35 | J N 36 | T S 37 | T R 38 | K P 39 | N R 40 | G T 41 | I V 42 | G Q 43 | D H 44 | V H 45 | T K 46 | T W 47 | E H 48 | C R 49 | L K 50 | G Y 51 | Y O 52 | O E 53 | U S 54 | X W 55 | C D 56 | E P 57 | B R 58 | F R 59 | A D 60 | G M 61 | B Q 62 | Q V 63 | B W 64 | S H 65 | P X 66 | I M 67 | A S 68 | M X 69 | L S 70 | S W 71 | L V 72 | Z X 73 | M R 74 | T A 75 | N V 76 | M H 77 | E D 78 | F V 79 | B O 80 | G U 81 | J C 82 | G F 83 | Y M 84 | F D 85 | M P 86 | F T 87 | G A 88 | G Z 89 | K V 90 | J Z 91 | O Z 92 | B E 93 | Z V 94 | Q O 95 | J D 96 | Y E 97 | D R 98 | I F 99 | M V 100 | I D 101 | O P 102 | -------------------------------------------------------------------------------- /2018/Python/day01.py: -------------------------------------------------------------------------------- 1 | # Advent of Code 2018 - Day 1 2 | from itertools import accumulate 3 | from itertools import cycle 4 | 5 | 6 | # -- Part 1 7 | with open('data/day01.txt') as f: 8 | print('Part 1:', sum(int(i) for i in f)) 9 | 10 | # -- Part 2 11 | with open('data/day01.txt') as f: 12 | nums = [int(i) for i in f] 13 | 14 | seen = {0} 15 | 16 | for i in accumulate(cycle(nums)): 17 | if i not in seen: 18 | seen.add(i) 19 | else: 20 | print('Part 2:', i) 21 | break 22 | -------------------------------------------------------------------------------- /2018/Python/day02.py: -------------------------------------------------------------------------------- 1 | # Advent of Code 2018 - Day 2 2 | # www.github.com/SondreSL 3 | 4 | # -- Part 1 5 | from collections import Counter 6 | 7 | with open('day02.txt') as f: 8 | twos = 0 9 | threes = 0 10 | for line in f: 11 | count = Counter(line).values() 12 | if 2 in count: 13 | twos += 1 14 | if 3 in count: 15 | threes += 1 16 | print('Part 1: ', twos * threes) 17 | 18 | 19 | # -- Part 2 20 | from itertools import combinations 21 | 22 | with open('day02.txt') as f: 23 | lines = f.read().split() 24 | for a, b in combinations(lines, 2): 25 | eqs = [v != h for h, v in zip(a,b)] 26 | if sum(eqs) == 1: 27 | i = eqs.index(1) 28 | print('Part 2: ', a[:i] + a[i + 1:]) 29 | break 30 | -------------------------------------------------------------------------------- /2018/Python/day03.py: -------------------------------------------------------------------------------- 1 | # Advent of Code 2018 - Day 3 2 | # www.github.com/SondreSL 3 | import re 4 | 5 | GRID = [[0 for i in range(3000)] for j in range(3000)] 6 | 7 | 8 | def new_read(filename): 9 | data = {} 10 | with open(filename) as f: 11 | for line in f: 12 | num, row, col, dx, dy = map(int, re.findall(r'\d+', line)) 13 | data[num] = [(row, col), (dx, dy)] 14 | count_overlaps(data) 15 | return data 16 | 17 | 18 | def count_overlaps(data): 19 | for (col, row), end in data.values(): 20 | for i in range(end[1]): 21 | for j in range(end[0]): 22 | GRID[row + i][col + j] += 1 23 | 24 | 25 | def findUnique(coords): 26 | (col, row), end = coords 27 | return not any((GRID[row + i][col + j] != 1) for i in range(end[1]) for j in range(end[0])) 28 | 29 | 30 | def find_overlapping(data): 31 | return sum(1 for line in GRID for cell in line if cell > 1) 32 | 33 | 34 | def solveB(data): 35 | return [line for line in data if findUnique(data[line])][0] 36 | 37 | 38 | def main(): 39 | data = new_read('../data/day03.in') 40 | print('Part 1:', find_overlapping(data)) 41 | print('Part 2:', solveB(data)) 42 | 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /2018/Python/day04.py: -------------------------------------------------------------------------------- 1 | from collections import Counter 2 | 3 | data = Counter() 4 | mins = {} 5 | 6 | with open('day04.txt') as f: 7 | for line in f: 8 | line = line.split() 9 | if len(line) == 1: 10 | id = line[0] 11 | else: 12 | if id not in mins: 13 | mins[id] = [0] * 60 14 | time, key, _ = line 15 | time = int(time[3:]) 16 | end_time = int(next(f).split()[0][3:]) 17 | data[id] += end_time - time 18 | for i in range(time, end_time): 19 | mins[id][i] += 1 20 | 21 | 22 | id = data.most_common(1)[0][0] 23 | minute = mins[id].index(max(mins[id])) 24 | 25 | print(int(id) * minute) 26 | 27 | # Part 2 28 | curr_max = 0 29 | 30 | for guard in mins: 31 | if max(mins[guard]) > curr_max: 32 | curr_max = max(mins[guard]) 33 | id = guard 34 | 35 | print(mins[id].index(max(mins[id])) * int(id)) 36 | -------------------------------------------------------------------------------- /2018/Python/day05.py: -------------------------------------------------------------------------------- 1 | from string import ascii_lowercase 2 | from string import ascii_uppercase 3 | 4 | with open('day05.txt') as f: 5 | line = f.read().strip() 6 | 7 | 8 | def reaction(string): 9 | new = "" 10 | string += " " 11 | it = zip(string, string[1:]) 12 | for a, b in it: 13 | if a.lower() != b.lower(): 14 | new += a 15 | continue 16 | if a == b: 17 | new += a 18 | continue 19 | try: 20 | next(it) 21 | except: 22 | pass 23 | string = string[:-1] 24 | if string == new: 25 | return False 26 | else: 27 | return new 28 | 29 | # new = line 30 | # while new: 31 | # line = new 32 | # new = reaction(line) 33 | 34 | # print(len(line)) 35 | 36 | # Part 2 37 | letters = zip(ascii_uppercase, ascii_lowercase) 38 | orig = line 39 | for a, b in letters: 40 | line = orig 41 | while a in line: 42 | i = line.index(a) 43 | line = line[:i] + line[i + 1:] 44 | while b in line: 45 | i = line.index(b) 46 | line = line[:i] + line[i + 1:] 47 | new = line 48 | while new: 49 | line = new 50 | new = reaction(line) 51 | print(len(line)) 52 | 53 | -------------------------------------------------------------------------------- /2018/Python/day08.py: -------------------------------------------------------------------------------- 1 | # Advent of Code 2018 - Day 8 2 | 3 | # Part 1 4 | 5 | with open('day08.txt') as f: 6 | data = list(int(i) for i in f.read().split()) 7 | 8 | 9 | def find_metadata(nums): 10 | children = nums[0] 11 | n_metadata = nums[1] 12 | total = 0 13 | while children: 14 | meta, sub_nums = find_metadata(nums[2:]) 15 | total += meta 16 | nums = nums[:2] + sub_nums 17 | children -= 1 18 | return total + sum(nums[2:2 + n_metadata]), nums[2 + n_metadata:] 19 | 20 | 21 | print(find_metadata(data)) 22 | 23 | # Part 2 24 | 25 | 26 | def find_value(nums): 27 | children = nums[0] 28 | n_metadata = nums[1] 29 | value = 0 30 | cs = [0] 31 | if not children: 32 | return sum(nums[2:2 + n_metadata]), nums[2 + n_metadata:] 33 | while children: 34 | val, sub_sums = find_value(nums[2:]) 35 | cs.append(val) 36 | nums = nums[:2] + sub_sums 37 | children -= 1 38 | for v in nums[2:2 + n_metadata]: 39 | if v >= len(cs): 40 | continue 41 | value += cs[v] 42 | return value, nums[2 + n_metadata:] 43 | 44 | 45 | print(find_value(data)) 46 | -------------------------------------------------------------------------------- /2018/Python/day09.py: -------------------------------------------------------------------------------- 1 | """Advent of Code 2018 Day 9""" 2 | # Input: 455 players; last marble is worth 71223 points 3 | from collections import deque 4 | from itertools import cycle 5 | 6 | 7 | def marble_game(players, max_marble): 8 | cont = deque([0]) 9 | score = {n: 0 for n in range(1, players + 1)} 10 | players = cycle(score.keys()) 11 | 12 | for i in range(1, max_marble + 1): 13 | player = next(players) 14 | if i % 23 == 0: 15 | for _ in range(6): 16 | cont.appendleft(cont.pop()) 17 | score[player] += cont.pop() + i 18 | else: 19 | cont.append(cont.popleft()) 20 | cont.append(cont.popleft()) 21 | cont.appendleft(i) 22 | 23 | return max(score.values()) 24 | 25 | 26 | print("Part 1: ", marble_game(455, 71223)) 27 | print("Part 2: ", marble_game(455, 71223 * 100)) 28 | -------------------------------------------------------------------------------- /2018/Python/day11.py: -------------------------------------------------------------------------------- 1 | """Advent of Code 2018 Day 11""" 2 | # Input: 3628 3 | import numpy as np 4 | from numba import jit 5 | 6 | PUZZLE_INPUT = 3628 7 | # PUZZLE_INPUT = 42 8 | 9 | @jit 10 | def power_level(x, y, grid_serial): 11 | return ((((x + 10) * (((x + 10) * y) + grid_serial)) // 100) % 10) - 5 12 | 13 | # grid = [[power_level(j, i, PUZZLE_INPUT) for j in range(1, 301)] for i in range(1, 301)] 14 | 15 | grid = np.zeros((300, 300)) 16 | for j in range(1, 301): 17 | for i in range(1, 301): 18 | grid[j - 1, i - 1] = power_level(i, j, PUZZLE_INPUT) 19 | 20 | 21 | # Casual quintuple for loop 22 | @jit 23 | def find_max(): 24 | maximum = 0 25 | for s in range(1, 301): 26 | print(s) 27 | for i in range(len(grid) - (s - 1)): 28 | for j in range(len(grid[0]) - (s - 1)): 29 | val = 0 30 | for y in range(s): 31 | for x in range(s): 32 | val += grid[i + y][x + j] 33 | if val >= maximum: 34 | maximum = val 35 | coord = (j + 1, i + 1) 36 | size = s 37 | return coord, maximum, size 38 | 39 | coord, maximum, size = find_max() 40 | print("Max:", maximum) 41 | print("Coordinates:", coord) 42 | print("Size of sub-grid:", size) 43 | -------------------------------------------------------------------------------- /2018/Python/out: -------------------------------------------------------------------------------- 1 | Part 1: 384288 2 | Part 2: 3189426841 3 | -------------------------------------------------------------------------------- /2018/README.md: -------------------------------------------------------------------------------- 1 | ## Advent of Code 2018 2 | 3 | Quite a mix of different stuff, poorly organized. 4 | -------------------------------------------------------------------------------- /2018/aoc_18/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aoc_18" 3 | version = "0.1.0" 4 | authors = ["sondrelunde "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | regex = "1" 9 | -------------------------------------------------------------------------------- /2018/aoc_18/data/day06.in: -------------------------------------------------------------------------------- 1 | 181, 47 2 | 337, 53 3 | 331, 40 4 | 137, 57 5 | 200, 96 6 | 351, 180 7 | 157, 332 8 | 113, 101 9 | 285, 55 10 | 189, 188 11 | 174, 254 12 | 339, 81 13 | 143, 61 14 | 131, 155 15 | 239, 334 16 | 357, 291 17 | 290, 89 18 | 164, 149 19 | 248, 73 20 | 311, 190 21 | 54, 217 22 | 285, 268 23 | 354, 113 24 | 318, 191 25 | 182, 230 26 | 156, 252 27 | 114, 232 28 | 159, 299 29 | 324, 280 30 | 152, 155 31 | 295, 293 32 | 194, 214 33 | 252, 345 34 | 233, 172 35 | 272, 311 36 | 230, 82 37 | 62, 160 38 | 275, 96 39 | 335, 215 40 | 185, 347 41 | 134, 272 42 | 58, 113 43 | 112, 155 44 | 220, 83 45 | 153, 244 46 | 279, 149 47 | 302, 167 48 | 185, 158 49 | 72, 91 50 | 264, 67 51 | -------------------------------------------------------------------------------- /2018/aoc_18/src/day01.rs: -------------------------------------------------------------------------------- 1 | pub mod day01 { 2 | use std::collections::HashSet; 3 | 4 | fn read_file() -> Vec { 5 | std::fs::read_to_string("data/day01.in") 6 | .expect("Invalid file") 7 | .lines() 8 | .map(|line| line.parse::().unwrap()) 9 | .collect() 10 | } 11 | 12 | fn solve_a(data: &Vec) -> i32 { 13 | data.iter().sum() 14 | } 15 | 16 | fn solve_b(data: &Vec) -> i32 { 17 | let mut seen = HashSet::new(); 18 | let mut sum = 0; 19 | 20 | for v in data.iter().cycle() { 21 | sum += v; 22 | if !seen.insert(sum) { 23 | break; 24 | } 25 | } 26 | sum 27 | } 28 | 29 | pub fn run01() -> () { 30 | let data = read_file(); 31 | let a = solve_a(&data); 32 | let b = solve_b(&data); 33 | println!("Day 01 - Part 1: {} | Part 2: {}", a, b); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /2018/aoc_18/src/main.rs: -------------------------------------------------------------------------------- 1 | use crate::day01::day01::run01; 2 | mod day01; 3 | use crate::day02::day02::run02; 4 | mod day02; 5 | use crate::day03::day03::run03; 6 | mod day03; 7 | use crate::day04::day04::run04; 8 | mod day04; 9 | use crate::day05::day05::run05; 10 | mod day05; 11 | use crate::day06::day06::run06; 12 | mod day06; 13 | 14 | fn main() { 15 | run01(); 16 | run02(); 17 | run03(); 18 | run04(); 19 | run05(); 20 | run06(); 21 | } 22 | -------------------------------------------------------------------------------- /2018/aoc_18/src/out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sondresl/AdventOfCode/9b562153445f4eba523fb2ac713fd7f20c2c5fbc/2018/aoc_18/src/out -------------------------------------------------------------------------------- /2018/fixx.hs: -------------------------------------------------------------------------------- 1 | module Fixx where 2 | 3 | import Control.Lens 4 | 5 | _Factor :: (Choice p, Applicative f, Integral a) => a -> p a (f a) -> p a (f a) 6 | _Factor n = prism' embed match 7 | where 8 | embed i = i * n 9 | match i = case i `mod` n of 10 | 0 -> Just (i `div` n) 11 | _ -> Nothing 12 | 13 | prismFizzBuzz :: Int -> String 14 | prismFizzBuzz n 15 | | has (_Factor 3 . _Factor 5) n = "FizzBuzz" 16 | | has (_Factor 3) n = "Fizz" 17 | | has (_Factor 5) n = "Buzz" 18 | | otherwise = show n 19 | 20 | _Conss :: Prism [a] [b] (a, [a]) (b, [b]) 21 | _Conss = prism embed match 22 | where 23 | match [] = Left [] 24 | match (x:xs) = Right (x, xs) 25 | embed (x, xs) = x : xs 26 | 27 | main :: IO () 28 | main = do 29 | mapM_ (putStrLn . prismFizzBuzz) [1..20] 30 | print $ review _Conss (0, [1..10]) 31 | print $ toListOf (worded . (_Show :: Prism' String Int)) "1 2 3 4 56" 32 | -------------------------------------------------------------------------------- /2018/various/day01.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void sumFile(char *filename); 4 | void firstRepeat(char *filename); 5 | 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | char *filename = "day01.txt"; 10 | 11 | sumFile(filename); 12 | firstRepeat(filename); 13 | 14 | return 0; 15 | } 16 | 17 | 18 | void sumFile(char filename[]) 19 | { 20 | 21 | FILE *fp; 22 | fp = fopen(filename, "r"); 23 | 24 | char str[100]; 25 | long i; 26 | long sum = 0; 27 | 28 | while (fgets(str, 20, fp) != NULL) { 29 | sscanf(str, "%li", &i); 30 | sum = sum + i; 31 | } 32 | fclose(fp); 33 | 34 | printf("Sum: %li\n", sum); 35 | } 36 | 37 | 38 | void firstRepeat(char *filename) 39 | { 40 | FILE *fp; 41 | fp = fopen(filename, "r"); 42 | 43 | char str[100]; 44 | long i; 45 | long sum = 0; 46 | 47 | char index[1000000]; 48 | 49 | for (unsigned int i = 0; i <= 1000000; i++) { 50 | index[i] = 0; 51 | } 52 | 53 | while (index[500000 + sum] != 1) { 54 | if (fgets(str, 20, fp) != NULL) { 55 | index[500000 + sum] = 1; 56 | sscanf(str, "%li", &i); 57 | sum = sum + i; 58 | } else { 59 | fclose(fp); 60 | fp = fopen(filename, "r"); 61 | } 62 | } 63 | printf("First repeated sum: %li\n", sum); 64 | } 65 | -------------------------------------------------------------------------------- /2018/various/day01.hs: -------------------------------------------------------------------------------- 1 | -- Works, but the second part is very slow. 2 | module Main where 3 | 4 | import qualified Data.Set as Set 5 | import Data.Set ( Set ) 6 | 7 | parseFile :: String -> [Int] 8 | parseFile = map read . lines . filter (/= '+') 9 | 10 | solveA :: String -> Int 11 | solveA = sum . parseFile 12 | 13 | solveB :: String -> Int 14 | solveB = findFirst Set.empty . scanl (+) 0 . cycle . parseFile 15 | where 16 | findFirst seen (new : xs) = if Set.member new seen 17 | then new 18 | else findFirst (Set.insert new seen) xs 19 | 20 | main :: IO () 21 | main = do 22 | contents <- readFile "data/day01.in" 23 | print $ solveA contents 24 | print $ solveB contents 25 | 26 | -------------------------------------------------------------------------------- /2018/various/day02.hs: -------------------------------------------------------------------------------- 1 | -- Advent of Code 2018 - Day 2 2 | -- www.github.com/SondreSL 3 | 4 | -- Part 1 5 | 6 | count :: String -> Int 7 | count (x:xs) = length (filter (x==) xs) + 1 8 | 9 | findN :: Int -> String -> Int 10 | findN _ "" = 0 11 | findN n xs = if count xs == n 12 | then 1 13 | else findN n (tail xs) 14 | 15 | solveA xs = res2 xs * res3 xs 16 | where 17 | res2 = sum . map (findN 2) . lines 18 | res3 = sum . map (findN 3) . lines 19 | 20 | -- Not the correct answer. Off by 35, 8750 should be 8715. 21 | 22 | -- Part 2 23 | 24 | 25 | 26 | -- Main 27 | main :: IO () 28 | main = do 29 | contents <- readFile "day02.txt" 30 | print $ solveA contents 31 | -------------------------------------------------------------------------------- /2019/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2019/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2019 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2019/Haskell/README.md: -------------------------------------------------------------------------------- 1 | # aoc2019 2 | -------------------------------------------------------------------------------- /2019/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2019/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | stack: 3 | - path: "./src" 4 | component: "aoc2019:lib" 5 | 6 | - path: "./app/Main.hs" 7 | component: "aoc2019:exe:aoc2019-exe" 8 | 9 | - path: "./app/Paths_aoc2019.hs" 10 | component: "aoc2019:exe:aoc2019-exe" 11 | 12 | - path: "./test" 13 | component: "aoc2019:test:aoc2019-test" 14 | -------------------------------------------------------------------------------- /2019/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2019:exe:aoc2019-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | -- Advent of Code 2019 Day 1 3 | -- Sondre Lunde 4 | 5 | strToInts :: String -> [Int] 6 | strToInts = map read . lines 7 | 8 | calcFuel :: Int -> Int 9 | calcFuel = subtract 2 . (`div` 3) 10 | 11 | solve :: [Int] -> Int 12 | solve = sum . map calcFuel 13 | 14 | solve2 :: [Int] -> Int 15 | solve2 = sum . map calcFuelFuel 16 | where calcFuelFuel = sum . takeWhile (> 0) . iterate calcFuel . calcFuel 17 | 18 | main :: IO () 19 | main = do 20 | contents <- strToInts <$> readFile "data/input-2019-1.txt" 21 | print $ solve contents 22 | print $ solve2 contents 23 | 24 | -- Part 1: 3497998 25 | -- Part 2: 5244112 26 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Data.List 4 | import Data.Vector (Vector, (//), (!), fromList) 5 | import Data.Bool 6 | 7 | -- I preprossesed the file to remove commas and allow for simple splitting 8 | -- using 'words' 9 | 10 | strToInts :: String -> Vector Int 11 | strToInts = fromList . map read . words 12 | 13 | compute :: Int -> Vector Int -> Int 14 | compute i vec 15 | | vec ! i == 99 = vec ! 0 16 | | otherwise = 17 | let code = bool (*) (+) (vec ! i == 1) 18 | a = vec ! (vec ! (i + 1)) 19 | b = vec ! (vec ! (i + 2)) 20 | c = vec ! (i + 3) 21 | new = code a b 22 | in compute (i + 4) (vec // [(c, new)]) 23 | 24 | solveA :: Vector Int -> Int 25 | solveA = compute 0 . (// [(1, 12), (2, 2)]) 26 | 27 | solveB :: Vector Int -> Int 28 | solveB vec = 29 | let xs = [[i, j] | i <- [0..99], j <- [0..99]] 30 | f [a,b] = compute 0 (vec // [(1, a), (2, b)]) == 19690720 31 | Just (a:b:_) = find f xs 32 | in 100 * a + b 33 | 34 | main = do 35 | contents <- strToInts <$> readFile "data/input-2019-2.txt" 36 | print $ solveA contents 37 | print $ solveB contents 38 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day08.hs: -------------------------------------------------------------------------------- 1 | module Day08 where 2 | 3 | import Data.Ord 4 | import Data.List 5 | import Data.List.Extra (chunksOf) 6 | 7 | color :: String -> String -> String 8 | color "" "" = "" 9 | color ('2':xs) (y:ys) = y : color xs ys 10 | color (x:xs) (_:ys) = x : color xs ys 11 | 12 | solveA :: Int -> Int -> String -> Int 13 | solveA w h str = (occ '1' xs) * (occ '2' xs) 14 | where occ n ls = length $ filter (== n) ls 15 | xs = minimumBy (comparing (occ '0')) $ chunksOf (w * h) str 16 | 17 | solveB :: Int -> Int -> String -> IO () 18 | solveB w h str = 19 | let res = foldr1 color $ chunksOf (w * h) str 20 | f '1' = '🔴' 21 | f '0' = '🖤' 22 | in mapM_ putStrLn $ chunksOf w $ map f res 23 | 24 | main = do 25 | str <- init <$> readFile "data/input-2019-8.txt" 26 | print $ solveA 25 6 str 27 | solveB 25 6 str 28 | 29 | -- 1620 30 | -- BCYEF 31 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | import Data.Char 4 | import Intcode 5 | 6 | solveA :: Memory -> Int 7 | solveA memory = head . untilHalt $ compute (Intcode 0 0 [chr 1] [] memory) 8 | 9 | solveB :: Memory -> Int 10 | solveB memory = head . untilHalt $ compute (Intcode 0 0 [chr 2] [] memory) 11 | 12 | main :: IO () 13 | main = do 14 | contents <- parseIntcode <$> readFile "../data/input-2019-9.txt" 15 | print $ solveA contents 16 | print $ solveB contents 17 | 18 | -- 3241900951 19 | -- 83089 20 | 21 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day16.hs: -------------------------------------------------------------------------------- 1 | module Day16 where 2 | 3 | import Data.List 4 | import Data.Char 5 | 6 | type State = [Int] 7 | type Pattern = [Int] 8 | 9 | strToInts :: String -> State 10 | strToInts = map (read . pure) 11 | 12 | pattern :: [Int] -> [Pattern] 13 | pattern base = map (drop 1 . inner) [1..] 14 | where inner n = cycle $ concatMap (replicate n) base 15 | 16 | phase :: State -> [Pattern] -> State 17 | phase base patterns = take (length base) $ map (applyInput base) $ zip [0..] patterns 18 | where applyInput state (i, pat) = (`rem` 10) . abs . sum $ zipWith (*) (drop i state) (drop i pat) 19 | 20 | rev :: [Int] -> [Int] 21 | rev num = inner 0 [] $ reverse num 22 | where inner acc xs [] = xs 23 | inner acc xs (n:ns) = let new = (acc + n) `mod` 10 24 | in inner new (new : xs) ns 25 | 26 | solveA :: [Int] -> [Int] 27 | solveA base = take 8 . (!! 100) . scanl phase base $ repeat (pattern [0,1,0,-1]) 28 | 29 | solveB :: [Int] -> [Int] 30 | solveB base = 31 | let offset = foldl ((+) . (*10)) 0 $ take 7 base 32 | rest = drop offset (concat $ replicate 10000 base) 33 | in take 8 . (!! 100) $ iterate rev rest 34 | 35 | main = do 36 | contents <- strToInts . head . lines <$> readFile "data/input-2019-16.txt" 37 | 38 | putStrLn $ concatMap show $ solveA contents 39 | putStrLn $ concatMap show $ solveB contents 40 | 41 | -- 76795888 42 | -- 84024125 43 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day17.hs: -------------------------------------------------------------------------------- 1 | module Day17 where 2 | 3 | import Lib 4 | import Intcode 5 | import Data.Char 6 | import qualified Data.Map as Map 7 | import qualified Data.Set as Set 8 | 9 | findMap :: Intcode -> String 10 | findMap ic = init . map chr $ untilHalt (Wait ic) 11 | 12 | calibrate :: String -> Int 13 | calibrate input = sum . map product . filter (all (`Set.member` points) . neighbours4) $ Set.toList points 14 | where 15 | points = Map.keysSet $ parseAsciiMap f input 16 | f '#' = Just () 17 | f _ = Nothing 18 | 19 | part1 :: Intcode -> Int 20 | part1 = calibrate . findMap 21 | 22 | part2 :: ProgramState -> Int 23 | part2 = last . untilHalt 24 | 25 | main :: IO () 26 | main = do 27 | inp <- parseIntcode <$> readFile "../data/input-2019-17.txt" 28 | print $ part1 $ Intcode 0 0 [] [] inp 29 | let cmd = "A,B,A,C,A,B,C,A,B,C\n" 30 | a = "R,8,R,10,R,10\n" 31 | b = "R,4,R,8,R,10,R,12\n" 32 | c = "R,12,R,4,L,12,L,12\n" 33 | n = "n\n" 34 | let inp' = Map.insert 0 2 inp 35 | print $ part2 $ Wait (Intcode 0 0 (cmd ++ a ++ b ++ c ++ n) [] inp') 36 | 37 | -- 3608 38 | -- 897426 39 | -------------------------------------------------------------------------------- /2019/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Intcode 4 | ( Intcode(Intcode), 5 | ProgramState(Wait, Halt, Input), 6 | input, 7 | output, 8 | run, 9 | untilInput, 10 | parseIntcode ) 11 | import Control.Lens ( (&), (.~) ) 12 | 13 | -- Actually play the game. 14 | -- You need to hold the coin, cake, hologram and hypercube 15 | -- to pass through the checkpoint in the south-east corner of the map. 16 | 17 | play :: ProgramState -> IO () 18 | play (Halt ic) = print (Halt ic) 19 | play (Input ic) = do 20 | print (Input ic) 21 | cmd <- getLine 22 | let new = Wait $ ic & input .~ (cmd ++ "\n") & output .~ [] 23 | putStrLn "\n ========= \n" 24 | play new 25 | play ic = play $ untilInput $ iterate run ic 26 | 27 | main :: IO () 28 | main = do 29 | memory <- parseIntcode <$> readFile "../data/input-2019-25.txt" 30 | let ic = Intcode 0 0 [] [] memory 31 | play (Wait ic) 32 | 33 | -- 4362 34 | -------------------------------------------------------------------------------- /2019/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2019/Python/day02.py: -------------------------------------------------------------------------------- 1 | import re 2 | from operator import mul 3 | from operator import add 4 | 5 | def read_file(filename): 6 | with open(filename) as f: 7 | return list(map(int, re.findall("\d+", f.read()))) 8 | 9 | def compute(data): 10 | index = 0 11 | while data[index] != 99: 12 | data[data[index + 3]] = {1: add, 2: mul}[data[index]](data[data[index + 1]], data[data[index + 2]]) 13 | index += 4 14 | return data[0] 15 | 16 | def solveA(data): 17 | return compute(data[:1] + [12, 2] + data[3:]) 18 | 19 | def solveB(data): 20 | for i in range(0, 100): 21 | for j in range(0, 100): 22 | if compute(data[:1] + [i, j] + data[3:]) == 19690720: 23 | return 100 * i + j 24 | 25 | def main(): 26 | data = read_file("data/input-2019-2.txt") 27 | print('Part A: ', solveA(data[:])) 28 | print('Part B: ', solveB(data)) 29 | 30 | if __name__ == "__main__": 31 | main() 32 | 33 | # Part A: 3306701 34 | # Part B: 7621 35 | -------------------------------------------------------------------------------- /2019/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2019 2 | 3 | * [x] Day 1: [Haskell](Haskell/src/Day01.hs) 4 | * [x] Day 2: [Haskell](Haskell/src/Day02.hs) 5 | * [x] Day 3: [Haskell](Haskell/src/Day03.hs) 6 | * [x] Day 4: [Haskell](Haskell/src/Day04.hs) 7 | * [x] Day 5: [Haskell](Haskell/src/Day05.hs) 8 | * [x] Day 6: [Haskell](Haskell/src/Day06.hs) 9 | * [x] Day 7: [Haskell](Haskell/src/Day07.hs) 10 | * [x] Day 8: [Haskell](Haskell/src/Day08.hs) 11 | * [x] Day 9: [Haskell](Haskell/src/Day09.hs) 12 | * [x] Day 10: [Haskell](Haskell/src/Day10.hs) 13 | * [x] Day 11: [Haskell](Haskell/src/Day11.hs) 14 | * [x] Day 12: [Haskell](Haskell/src/Day12.hs) 15 | * [x] Day 13: [Haskell](Haskell/src/Day13.hs) 16 | * [x] Day 14: [Haskell](Haskell/src/Day14.hs) 17 | * [x] Day 15: [Haskell](Haskell/src/Day15.hs) 18 | * [x] Day 16: [Haskell](Haskell/src/Day16.hs) 19 | * [x] Day 17: [Haskell](Haskell/src/Day17.hs) 20 | * [ ] Day 18: [Haskell](Haskell/src/Day18.hs) 21 | * [x] Day 19: [Haskell](Haskell/src/Day19.hs) 22 | * [x] Day 20: [Haskell](Haskell/src/Day20.hs) 23 | * [x] Day 21: [Haskell](Haskell/src/Day21.hs) 24 | * [x] Day 22: [Haskell](Haskell/src/Day22.hs) 25 | * [x] Day 23: [Haskell](Haskell/src/Day23.hs) 26 | * [ ] Day 24: [Haskell](Haskell/src/Day24.hs) 27 | * [ ] Day 25: [Haskell](Haskell/src/Day25.hs) 28 | -------------------------------------------------------------------------------- /2020/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2020 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2020/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2020/Haskell/bu.txt: -------------------------------------------------------------------------------- 1 | - free-algebras-0.1.0.1 2 | - sbv-8.15 3 | - lens-regex-pcre-1.1.0.0 4 | - libBF-0.6.2@sha256:7bffc0e4dbc9bd9e851ba5c29255b62fd2c288dbc9a401cd3761b740f013775e,1770 5 | -------------------------------------------------------------------------------- /2020/Haskell/get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -r "../.cookie" ]; then 4 | source "../.cookie" 5 | fi 6 | 7 | export TZ=CET 8 | thisyear="$(date +%Y)" 9 | thismonth="$(date +%m)" 10 | thisday="$(date +%d)" 11 | 12 | day=$(expr $thisday + 0) # Strip leading zero 13 | 14 | year=2020 15 | 16 | if [ "$thisyear" -ne "$year" ] || [ "$thismonth" -ne 12 ] || [ "$thisday" -gt 25 ]; then 17 | echo "Not a valid date: $thisday / $thismonth / $thisyear" 18 | exit 0 19 | fi 20 | 21 | filename="../data/day$thisday.in" 22 | 23 | if [ -r "$filename" ]; then 24 | echo "Filename $filename already exists!" 25 | exit 0 26 | fi 27 | 28 | curl -sS -o "$filename" -b "$AOC_COOKIE" https://adventofcode.com/$year/day/$day/input 29 | echo "Curled into $filename" 30 | -------------------------------------------------------------------------------- /2020/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | cabal: 3 | - path: "src" 4 | component: "lib:aoc2020" 5 | 6 | - path: "app/Main.hs" 7 | component: "aoc2020:exe:aoc2020-exe" 8 | 9 | - path: "app/Paths_aoc2020.hs" 10 | component: "aoc2020:exe:aoc2020-exe" 11 | 12 | - path: "test" 13 | component: "aoc2020:test:aoc2020-test" 14 | 15 | - path: "app/Main.hs" 16 | component: "aoc2020:bench:aoc2020-bench" 17 | 18 | - path: "app/Paths_aoc2020.hs" 19 | component: "aoc2020:bench:aoc2020-bench" 20 | -------------------------------------------------------------------------------- /2020/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2020:exe:aoc2020-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2020/Haskell/src/Advent/Coord.hs: -------------------------------------------------------------------------------- 1 | module Advent.Coord where 2 | 3 | import Linear 4 | 5 | type Coord = V2 Int 6 | type Dir = V2 Int 7 | 8 | origin, up, down, left, right :: V2 Int 9 | origin= V2 0 0 10 | up = V2 0 1 11 | down = V2 0 (-1) 12 | left = V2 (-1) 0 13 | right = V2 1 0 14 | 15 | turnAround, turnLeft, turnRight :: V2 Int -> V2 Int 16 | turnLeft = perp 17 | turnRight = perp . perp . perp 18 | turnAround = negate 19 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Lib (linedNums) 4 | import Data.Maybe (listToMaybe) 5 | 6 | part1 :: [Int] -> Maybe Int 7 | part1 input = 8 | listToMaybe 9 | [ x * y 10 | | x <- input 11 | , y <- input 12 | , x + y == 2020 13 | ] 14 | 15 | part2 :: [Int] -> Maybe Int 16 | part2 input = 17 | listToMaybe 18 | [ x * y * z 19 | | x <- input 20 | , y <- input 21 | , z <- input 22 | , x + y + z == 2020 23 | ] 24 | 25 | main :: IO () 26 | main = do 27 | input <- linedNums <$> readFile "../data/day01.in" 28 | print $ part1 input 29 | print $ part2 input 30 | 31 | -- 793524 32 | -- 61515678 33 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Lib (count) 4 | import Control.Lens (Ixed (ix), (^?)) 5 | import Text.ParserCombinators.Parsec (alphaNum, char, digit, letter, many1, parse, space, string) 6 | 7 | data Password = P Int Int Char String 8 | 9 | parseInput :: String -> [Password] 10 | parseInput = either (error . show) id . traverse (parse parsePassword "") . lines 11 | where 12 | num = read <$> many1 digit 13 | parsePassword = 14 | P <$> num <* char '-' 15 | <*> num <* space 16 | <*> letter <* string ": " 17 | <*> many1 alphaNum 18 | 19 | part1 :: [Password] -> Int 20 | part1 = count valid 21 | where 22 | valid (P a b l str) = a <= le && le <= b 23 | where 24 | le = count (== l) str 25 | 26 | part2 :: [Password] -> Int 27 | part2 = count valid 28 | where 29 | valid (P a b l str) = aa /= bb 30 | where 31 | aa = str ^? ix (a - 1) == Just l 32 | bb = str ^? ix (b - 1) == Just l 33 | 34 | main :: IO () 35 | main = do 36 | input <- parseInput <$> readFile "../data/day02.in" 37 | print $ part1 input 38 | print $ part2 input 39 | 40 | -- 517 41 | -- 284 42 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | module Day03 where 2 | 3 | import Control.Lens (bimap) 4 | import qualified Data.Map as Map 5 | import Data.Semigroup ( Max(Max) ) 6 | import Data.Set (Set) 7 | import qualified Data.Set as Set 8 | import Lib (count, parseAsciiMap, pointToTuple) 9 | 10 | type Tuple = (Int, Int) 11 | 12 | parseInput :: String -> Set Tuple 13 | parseInput = Set.map pointToTuple . Map.keysSet . parseAsciiMap f 14 | where 15 | f '#' = Just () 16 | f _ = Nothing 17 | 18 | toboggan :: Set Tuple -> Tuple -> Int 19 | toboggan input = count (`Set.member` input) . slope 20 | where 21 | (Max maxX, Max maxY) = foldMap (bimap Max Max) input 22 | slope p = takeWhile ((<= maxY) . snd) $ iterate (addMod p) (0, 0) 23 | addMod (x, y) (x', y') = ((x + x') `mod` succ maxX, y + y') 24 | 25 | part1 :: Set Tuple -> Tuple -> Int 26 | part1 = toboggan 27 | 28 | part2 :: Set Tuple -> Int 29 | part2 = product . (<$> [(1, 1), (3, 1), (5, 1), (7, 1), (1, 2)]) . toboggan 30 | 31 | main :: IO () 32 | main = do 33 | input <- parseInput <$> readFile "../data/day03.in" 34 | print $ part1 input (3, 1) 35 | print $ part2 input 36 | 37 | -- 299 38 | -- 3621285278 39 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day04regex.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE QuasiQuotes #-} 3 | 4 | module Day04regex where 5 | 6 | import Control.Lens ((^..)) 7 | import Control.Lens.Regex.Text (match, regex) 8 | import qualified Data.Text as T 9 | import Lib (count) 10 | 11 | -- Solutions with regex are supposed to be unreadable anyway, right? 12 | main :: IO () 13 | main = do 14 | input <- T.splitOn "\n\n" . T.pack <$> readFile "../data/day04.in" 15 | let passports r = count ((== 7) . length) $ map r input 16 | r1 s = s ^.. [regex|byr:|iyr:|eyr:|hgt:|hcl:|ecl:|pid:|] . match 17 | r2 s = 18 | s 19 | ^.. ( [regex|byr:(19[2-9][0-9]|200[0-2])|] 20 | <> [regex|iyr:(201[0-9]|2020)|] 21 | <> [regex|eyr:(202[0-9]|2030)|] 22 | <> [regex|hgt:(1[5-8][0-9]|19[0-3])cm|] 23 | <> [regex|hgt:(5[8-9]|6[0-9]|7[0-6])in|] 24 | <> [regex|hcl:#[0-9a-f]{6}|] 25 | <> [regex|ecl:(amb|blu|brn|gry|grn|hzl|oth)|] 26 | <> [regex|pid:[0-9]{9}\b|] 27 | ) 28 | . match 29 | print $ passports r1 30 | print $ passports r2 31 | 32 | -- 219 33 | -- 127 34 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Data.List (find, sort) 4 | import Data.Digits ( unDigits ) 5 | 6 | seat :: [Char] -> Int 7 | seat = unDigits 2 . map f 8 | where f 'F' = 0 9 | f 'B' = 1 10 | f 'L' = 0 11 | f 'R' = 1 12 | 13 | part1 :: [String] -> Int 14 | part1 = maximum . map seat 15 | 16 | part2 :: [String] -> Maybe Int 17 | part2 = 18 | fmap snd 19 | . find (uncurry (/=)) 20 | . (zip <*> (tail . map pred)) 21 | . sort 22 | . map seat 23 | 24 | main :: IO () 25 | main = do 26 | input <- lines <$> readFile "../data/day05.in" 27 | print $ part1 input 28 | print $ part2 input 29 | 30 | -- 883 31 | -- 532 32 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day06.hs: -------------------------------------------------------------------------------- 1 | module Day06 where 2 | 3 | import Data.List.Extra ( splitOn ) 4 | import qualified Data.Set as Set 5 | import Data.Set ( Set ) 6 | 7 | parseInput :: String -> [[Set Char]] 8 | parseInput = map (map Set.fromList . lines) . splitOn "\n\n" 9 | 10 | main :: IO () 11 | main = do 12 | input <- parseInput <$> readFile "../data/day06.in" 13 | print . sum . map (length . Set.unions) $ input 14 | print . sum . map (length . foldl Set.intersection (Set.fromList ['a'..'z'])) $ input 15 | 16 | -- 6799 17 | -- 3354 18 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | import Lib ( linedNums ) 4 | import Data.Maybe ( listToMaybe ) 5 | import Data.List.Extra ( inits, tails ) 6 | import Control.Monad (guard) 7 | 8 | part1 :: [Int] -> Int -> Maybe Int 9 | part1 input n = listToMaybe $ do 10 | ts <- tails input 11 | let xs = take n ts 12 | target = ts !! n 13 | pairs = do 14 | y : ys <- tails xs 15 | z <- ys 16 | pure $ y + z 17 | guard $ target `notElem` pairs 18 | pure target 19 | 20 | part2 :: [Int] -> Int -> Maybe Int 21 | part2 input n = listToMaybe $ do 22 | xs <- dropWhile ((< n) . sum) $ inits input 23 | candidate <- take 1 . dropWhile ((n <) . sum) $ tails xs 24 | guard $ sum candidate == n 25 | pure $ minimum candidate + maximum candidate 26 | 27 | main :: IO () 28 | main = do 29 | input <- linedNums <$> readFile "../data/day09.in" 30 | let i = part1 input 25 31 | print i 32 | print $ i >>= part2 input 33 | 34 | -- 2089807806 35 | -- 245848639 36 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day10.hs: -------------------------------------------------------------------------------- 1 | module Day10 where 2 | 3 | import Data.Functor.Foldable 4 | import Data.List.Extra (sort) 5 | import Data.Maybe (listToMaybe) 6 | import Lib (freqs, linedNums, zipWithTail) 7 | import qualified Data.Map as Map 8 | 9 | part1 :: [Int] -> Maybe Int 10 | part1 = adapterProduct . freqs . map (uncurry subtract) . zipWithTail 11 | where 12 | adapterProduct input = (*) <$> Map.lookup 1 input <*> Map.lookup 3 input 13 | 14 | part2 :: [Int] -> Maybe Integer 15 | part2 = listToMaybe . para f 16 | where 17 | f Nil = [] 18 | f (Cons x (xs, res)) = next : res 19 | where 20 | next = max 1 . sum . zipWith const res . takeWhile (<= x + 3) $ xs 21 | 22 | main :: IO () 23 | main = do 24 | input <- sort . (\xs -> maximum xs + 3 : 0 : xs) . linedNums <$> readFile "../data/day10.in" 25 | print $ part1 input 26 | print $ part2 input 27 | 28 | -- Just 2030 29 | -- Just 42313823813632 30 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day12.hs: -------------------------------------------------------------------------------- 1 | module Day12 where 2 | 3 | import Advent.Coord 4 | ( down, left, origin, right, turnLeft, turnRight, up,) 5 | import Control.Lens (Lens', view, (%~), (&), (+~), _1, _2) 6 | import Data.List (foldl') 7 | import Lib (Point, mannDist) 8 | import Linear (V2 (..), (*^)) 9 | 10 | data Command = N | S | E | W | L | R | F 11 | deriving (Show, Read, Eq, Ord) 12 | 13 | parseInput :: String -> [(Command, Int)] 14 | parseInput = map (\x -> (read [head x], read $ tail x)) . lines 15 | 16 | move :: Lens' (Point, Point) Point -> (Point, Point) -> (Command, Int) -> (Point, Point) 17 | move l ship c = ship & case c of 18 | (N, n ) -> l +~ n *^ up 19 | (E, n ) -> l +~ n *^ right 20 | (S, n ) -> l +~ n *^ down 21 | (W, n ) -> l +~ n *^ left 22 | (F, n ) -> _2 +~ n *^ view _1 ship 23 | (L, n ) -> _1 %~ (!! mod (div n 90) 4) . iterate turnLeft 24 | (R, n ) -> _1 %~ (!! mod (div n 90) 4) . iterate turnRight 25 | 26 | run :: Lens' (Point, Point) Point -> Point -> [(Command, Int)] -> Int 27 | run l start = mannDist origin . snd . foldl' (move l) (start, origin) 28 | 29 | main :: IO () 30 | main = do 31 | input <- parseInput <$> readFile "../data/day12.in" 32 | print $ run _2 right input 33 | print $ run _1 (V2 10 1) input 34 | 35 | -- 1424 36 | -- 63447 37 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day13.hs: -------------------------------------------------------------------------------- 1 | module Day13 where 2 | 3 | import Data.List.Extra (foldl1', minimumOn, splitOn) 4 | 5 | parseInput :: String -> (Integer, [(Integer, Integer)]) 6 | parseInput = (\x -> (read $ head x, concatMap f . zip [0 ..] . splitOn "," $ x !! 1)) . lines 7 | where 8 | f (_, "x") = [] 9 | f (n, x) = [(n, read x)] 10 | 11 | part1 :: Integer -> [(Integer, Integer)] -> Integer 12 | part1 n xs = uncurry (*) . minimumOn snd $ do 13 | (_, x) <- xs 14 | pure (x, x - n `mod` x) 15 | 16 | part2 :: [(Integer, Integer)] -> Integer 17 | part2 = fst . foldl1' firstCommon 18 | where 19 | firstCommon (x, stepx) (y, stepy) = (next, lcm stepx stepy) 20 | where 21 | next = until ((== 0) . (`mod` stepy) . (+ y)) (+ stepx) x 22 | 23 | main :: IO () 24 | main = do 25 | (n, times) <- parseInput <$> readFile "../data/day13.in" 26 | print $ part1 n times 27 | print $ part2 times 28 | 29 | -- 2165 30 | -- 534035653563227 31 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day15.hs: -------------------------------------------------------------------------------- 1 | module Day15 where 2 | 3 | import Control.Monad.ST (runST) 4 | import qualified Data.Vector.Unboxed.Mutable as MV 5 | import Control.Monad (forM_) 6 | 7 | run :: Int -> [Int] -> Int 8 | run target xs = runST $ do 9 | vec <- MV.replicate (target + 1) 0 10 | 11 | forM_ (zip [1 ..] (init xs)) $ \(i, x) -> do 12 | MV.write vec x i 13 | 14 | let runMut current turn 15 | | turn == target = pure current 16 | | otherwise = do 17 | next <- MV.read vec current >>= \case 18 | 0 -> pure 0 19 | prev -> pure $ turn - prev 20 | MV.write vec current turn 21 | if turn == target 22 | then pure current 23 | else runMut next (turn + 1) 24 | 25 | runMut (last xs) (length xs) 26 | 27 | main :: IO () 28 | main = do 29 | let input = [1, 20, 11, 6, 12, 0] 30 | print $ run 2020 input 31 | print $ run 30000000 input 32 | 33 | -- 1085 34 | -- 10652 35 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day17.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE FlexibleContexts #-} 2 | module Day17 where 3 | 4 | import qualified Data.Map as Map 5 | import Data.Set (Set) 6 | import qualified Data.Set as Set 7 | import Linear (V2 (..), V3 (..), V4 (..)) 8 | import Lib (parseAsciiMap, count, neighbours, conway) 9 | 10 | parseInput :: String -> Set (V2 Int) 11 | parseInput = Map.keysSet . parseAsciiMap f 12 | where 13 | f '#' = Just () 14 | f _ = Nothing 15 | 16 | solve :: (Ord (t a), Traversable t, Applicative t, Num a) => Set (t a) -> Int 17 | solve = Set.size . (!! 6) . iterate (conway neighbours f) 18 | where 19 | f :: (Bool, Int) -> Bool 20 | f (True, 2) = True 21 | f (True, 3) = True 22 | f (False, 3) = True 23 | f _ = False 24 | 25 | main :: IO () 26 | main = do 27 | input <- parseInput <$> readFile "../data/day17.in" 28 | let v2tov3 (V2 x y) = V3 x y 0 29 | v2tov4 (V2 x y) = V4 x y 0 0 30 | print $ solve (Set.map v2tov3 input) 31 | print $ solve (Set.map v2tov4 input) 32 | 33 | -- 240 34 | -- 1180 35 | -------------------------------------------------------------------------------- /2020/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Data.Finite (Finite, finite, getFinite) 4 | import Data.List.Extra (elemIndex) 5 | import Lib (tuple) 6 | 7 | part1 :: Finite 20201227 -> Finite 20201227 -> Maybe Integer 8 | part1 card door = getFinite . (card ^) <$> doorIx 9 | where 10 | doorIx = elemIndex door $ iterate (*7) 1 11 | 12 | main :: IO () 13 | main = do 14 | (card, door) <- tuple . map read . lines <$> readFile "../data/day25.in" 15 | print $ part1 (finite card) (finite door) 16 | 17 | -- 19924389 18 | -------------------------------------------------------------------------------- /2020/Haskell/src/DayTest.hs: -------------------------------------------------------------------------------- 1 | module DayTest where 2 | 3 | sumOrOdd :: [Int] -> Either Int Int 4 | sumOrOdd = foldMon f 0 5 | where 6 | f acc n 7 | | odd n = Left n 8 | | otherwise = Right $ acc + n 9 | 10 | sumEven :: [Int] -> Maybe Int 11 | sumEven = foldMon f 0 12 | where 13 | f acc n 14 | | odd n = Nothing 15 | | otherwise = Just $ acc + n 16 | 17 | squareEven :: [Integer] -> [Integer] 18 | squareEven = foldMon f 0 19 | where 20 | f acc n 21 | | odd n = [acc + n] 22 | | otherwise = [acc + n^2, acc + n] 23 | 24 | foldMon :: Monad m => (a -> b -> m a) -> a -> [b] -> m a 25 | foldMon _ def [] = pure def 26 | foldMon f def (x:xs) = do 27 | v <- f def x 28 | foldMon f v xs 29 | 30 | 31 | main :: IO () 32 | main = do 33 | -- Maybe 34 | print $ sumEven [2,4..50] 35 | print $ sumEven $ [2,4..50] ++ [17] ++ [2,4..50] 36 | 37 | putStrLn "\n ------- \n" 38 | 39 | -- Either 40 | print $ sumOrOdd [2,4..50] 41 | print $ sumOrOdd $ [2,4..50] ++ [17] ++ [2,4..50] 42 | 43 | putStrLn "\n ------- \n" 44 | 45 | print $ squareEven [2,4..6] 46 | print $ squareEven [0..6] 47 | 48 | -------------------------------------------------------------------------------- /2020/Haskell/src/gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq -f "%02g" 09 25); do 4 | echo "module Day$i where 5 | 6 | import Lib 7 | import Data.Maybe 8 | import Data.List.Extra 9 | import Text.ParserCombinators.Parsec 10 | 11 | parseInput = id 12 | 13 | part1 input = undefined 14 | 15 | part2 input = undefined 16 | 17 | main :: IO () 18 | main = do 19 | input <- parseInput <$> readFile \"../data/day$i.in\" 20 | print input 21 | -- print $ part1 input 22 | -- print $ part2 input" >Day$i.hs 23 | done 24 | -------------------------------------------------------------------------------- /2020/Haskell/src/manual_16: -------------------------------------------------------------------------------- 1 | (0,fromList row 2 | (1,fromList departure track 3 | (2,fromList duration 4 | (3,fromList arrival station 5 | (4,fromList departure date 6 | (5,fromList class 7 | (6,fromList type 8 | (7,fromList arrival location 9 | (8,fromList price 10 | (9,fromList train 11 | (10,fromList seat 12 | (11,fromList arrival platform 13 | (12,fromList zone 14 | (13,fromList departure location 15 | (14,fromList departure station 16 | (15,fromList departure platform 17 | (16,fromList route 18 | (17,fromList departure time 19 | (18,fromList arrival track 20 | (19,fromList wagon 21 | 22 | 1 4 13 14 15 17 23 | 24 | [("row",157),("departure track",73),("duration",79),("arrival station",191),("departure date",113),("class",59),("type",109),("arrival location",61),("price",103),("train",101),("seat",67),("arrival platform",193),("zone",97),("departure location",179),("departure station",107),("departure platform",89),("route",53),("departure time",71),("arrival track",181),("wagon",83)] 25 | -------------------------------------------------------------------------------- /2020/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2020/README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2020 2 | 3 | * [x] Day 1: [Haskell](Haskell/src/Day01.hs) 4 | * [x] Day 2: [Haskell](Haskell/src/Day02.hs) 5 | * [x] Day 3: [Haskell](Haskell/src/Day03.hs) 6 | * [x] Day 4: [Haskell](Haskell/src/Day04.hs) | [Haskell w/ HKD](Haskell/src/Day04HKD.hs) 7 | * [x] Day 5: [Haskell](Haskell/src/Day05.hs) 8 | * [x] Day 6: [Haskell](Haskell/src/Day06.hs) 9 | * [x] Day 7: [Haskell](Haskell/src/Day07.hs) 10 | * [x] Day 8: [Haskell](Haskell/src/Day08.hs) 11 | * [x] Day 9: [Haskell](Haskell/src/Day09.hs) 12 | * [x] Day 10: [Haskell](Haskell/src/Day10.hs) 13 | * [x] Day 11: [Haskell](Haskell/src/Day11.hs) 14 | * [x] Day 12: [Haskell](Haskell/src/Day12.hs) 15 | * [x] Day 13: [Haskell](Haskell/src/Day13.hs) 16 | * [x] Day 14: [Haskell](Haskell/src/Day14.hs) 17 | * [x] Day 15: [Haskell](Haskell/src/Day15.hs) 18 | * [x] Day 16: [Haskell](Haskell/src/Day16.hs) 19 | * [x] Day 17: [Haskell](Haskell/src/Day17.hs) 20 | * [x] Day 18: [Haskell](Haskell/src/Day18.hs) 21 | * [x] Day 19: [Haskell](Haskell/src/Day19.hs) 22 | * [x] Day 20: [Haskell](Haskell/src/Day20.hs) 23 | * [x] Day 21: [Haskell](Haskell/src/Day21.hs) 24 | * [x] Day 22: [Haskell](Haskell/src/Day22.hs) 25 | * [x] Day 23: [Haskell](Haskell/src/Day23.hs) 26 | * [x] Day 24: [Haskell](Haskell/src/Day24.hs) 27 | * [x] Day 25: [Haskell](Haskell/src/Day25.hs) 28 | -------------------------------------------------------------------------------- /2021/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2021/Haskell/ChangeLog.md: -------------------------------------------------------------------------------- 1 | # Changelog for aoc2021 2 | 3 | ## Unreleased changes 4 | -------------------------------------------------------------------------------- /2021/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2021/Haskell/get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -r "../.cookie" ]; then 4 | source "../.cookie" 5 | fi 6 | 7 | export TZ=CET 8 | thisyear="$(date +%Y)" 9 | thismonth="$(date +%m)" 10 | thisday="$(date +%d)" 11 | 12 | day=$(expr $thisday + 0) # Strip leading zero 13 | 14 | year=2021 15 | 16 | if [ "$thisyear" -ne "$year" ] || [ "$thismonth" -ne 12 ] || [ "$thisday" -gt 25 ]; then 17 | echo "Not a valid date: $thisday / $thismonth / $thisyear" 18 | exit 0 19 | fi 20 | 21 | filename="../data/day$thisday.in" 22 | 23 | if [ -r "$filename" ]; then 24 | echo "Filename $filename already exists!" 25 | exit 0 26 | fi 27 | 28 | curl -sS -o "$filename" -b "$aoc_cookie" https://adventofcode.com/$year/day/$day/input && echo "Curled into $filename" 29 | -------------------------------------------------------------------------------- /2021/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | stack: 3 | - path: "./src" 4 | component: "aoc2021:lib" 5 | 6 | - path: "./app/Main.hs" 7 | component: "aoc2021:exe:aoc2021-exe" 8 | 9 | - path: "./app/Paths_aoc2021.hs" 10 | component: "aoc2021:exe:aoc2021-exe" 11 | 12 | - path: "./test" 13 | component: "aoc2021:test:aoc2021-test" 14 | -------------------------------------------------------------------------------- /2021/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2021:exe:aoc2021-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2021/Haskell/src/Advent/Coord.hs: -------------------------------------------------------------------------------- 1 | module Advent.Coord where 2 | 3 | import Linear 4 | 5 | type Coord = V2 Int 6 | type Dir = V2 Int 7 | 8 | origin, up, down, left, right :: V2 Int 9 | origin= V2 0 0 10 | up = V2 0 1 11 | down = V2 0 (-1) 12 | left = V2 (-1) 0 13 | right = V2 1 0 14 | 15 | turnAround, turnLeft, turnRight :: V2 Int -> V2 Int 16 | turnLeft = perp 17 | turnRight = perp . perp . perp 18 | turnAround = negate 19 | 20 | invert :: V2 a -> V2 a 21 | invert (V2 x y) = V2 y x 22 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Lib (count, linedNums) 4 | 5 | main :: IO () 6 | main = do 7 | input <- linedNums <$> readFile "../data/day01.in" 8 | 9 | let solve f = count (uncurry (<)) . (zip <*> f) 10 | 11 | print $ solve tail input 12 | print $ solve (drop 3) input 13 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE ViewPatterns #-} 2 | module Day02 where 3 | 4 | import Lib (tuple, intoEndo) 5 | import Data.Monoid (Endo(..), Dual(..), appEndo) 6 | import Linear (V3(..), _xy, _xz) 7 | import Control.Lens (productOf, each) 8 | 9 | encode :: (String, String) -> V3 Int -> V3 Int 10 | encode (str, read -> v) = 11 | case str of 12 | "up" -> (+ V3 0 0 (-v)) 13 | "down" -> (+ V3 0 0 v) 14 | "forward" -> \(V3 x y z) -> V3 (x + v) (y + v * z) z 15 | 16 | main :: IO () 17 | main = do 18 | input <- intoEndo (encode . tuple . words) . lines <$> readFile "../data/day02.in" 19 | let run f = productOf (f . each) . (`appEndo` V3 0 0 0) 20 | print $ run _xz input 21 | print $ run _xy input 22 | 23 | -- 2039256 24 | -- 1856459736 25 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | module Day03 where 2 | 3 | import Lib (count, binToInt) 4 | import Data.Function (on) 5 | import Data.List.Extra (transpose) 6 | import Data.Tuple.Extra (both, (&&&)) 7 | 8 | gammaEpsilon :: [String] -> (String, String) 9 | gammaEpsilon = foldMap go . transpose 10 | where 11 | go str 12 | | count (== '1') str >= count (== '0') str = ("1", "0") 13 | | otherwise = ("0", "1") 14 | 15 | keep :: ((String, String) -> String) -> [String] -> String 16 | keep _ [x] = x 17 | keep f strs = 18 | let val = head . f $ gammaEpsilon strs 19 | in val : keep f (map tail $ filter ((== val) . head) strs) 20 | 21 | main :: IO () 22 | main = do 23 | input <- lines <$> readFile "../data/day03.in" 24 | let run f = uncurry (*) . both binToInt . f 25 | print $ run gammaEpsilon input 26 | print $ run (keep fst &&& keep snd) input 27 | 28 | -- 693486 29 | -- 3379326 30 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day04.hs: -------------------------------------------------------------------------------- 1 | module Day04 where 2 | 3 | import Lib (takeUntil, commaNums) 4 | import Data.List.Extra (transpose, splitOn, maximumOn, minimumOn, sortOn) 5 | import Data.Tuple.Extra ((&&&), second, both) 6 | 7 | type Board = [[Int]] 8 | type Result = (Int, Int) 9 | 10 | playAll :: [Int] -> [Board] -> Result 11 | playAll xs = both (uncurry (*)) 12 | . (head &&& last) 13 | . map (second (xs !!)) 14 | . sortOn snd 15 | . map ((play xs) . ((<>) <*> transpose)) 16 | 17 | play :: [Int] -> Board -> (Int, Int) -- Score, turns 18 | play nums board = (score . last &&& subtract 1 . length) 19 | . tail 20 | . takeUntil (any null) 21 | $ scanl (flip $ map . filter . (/=)) board nums 22 | where 23 | score = sum . map sum . take 5 24 | 25 | main :: IO () 26 | main = do 27 | (nums, boards) <- parseInput <$> readFile "../data/day04.in" 28 | let (part1, part2) = playAll nums boards 29 | print part1 30 | print part2 31 | 32 | parseInput :: String -> ([Int], [Board]) 33 | parseInput input = (nums, grids) 34 | where (x:xs) = splitOn "\n\n" input 35 | nums = commaNums x 36 | grids = map ((map (map read . words)) . lines) xs 37 | 38 | -- 38594 39 | -- 21184 40 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Lib (count, lineSegment, (.:), freqs) 4 | import Linear (V2(..)) 5 | import Data.List (partition) 6 | import Control.Applicative (liftA2) 7 | import Text.ParserCombinators.Parsec (parse, many1, digit, char, string) 8 | import qualified Data.Map as Map 9 | 10 | main :: IO () 11 | main = do 12 | input <- parseInput <$> readFile "../data/day05.in" 13 | let run = freqs . concatMap (uncurry lineSegment) 14 | (straight, diags) = partition (uncurry $ foldr1 (||) .: liftA2 (==)) input 15 | hor = run straight 16 | all = Map.unionWith (+) hor $ run diags 17 | print $ count (> 1) hor 18 | print $ count (> 1) all 19 | 20 | parseInput :: String -> [(V2 Int, V2 Int)] 21 | parseInput = either (error . show) id . traverse (parse line "") . lines 22 | where 23 | num = read <$> many1 digit 24 | tuple = V2 <$> (num <* char ',') <*> num 25 | line = (,) <$> tuple <* string " -> " <*> tuple 26 | 27 | -- 6666 28 | -- 19081 29 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day06.hs: -------------------------------------------------------------------------------- 1 | module Day06 where 2 | 3 | import Lib 4 | import Data.List.Extra 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | 8 | step :: Map Int Int -> Map Int Int 9 | step (Map.mapKeysMonotonic (subtract 1) -> input) = 10 | Map.insert 8 negs 11 | . Map.insertWith (+) 6 negs 12 | $ Map.insert (-1) 0 input 13 | where 14 | negs = Map.findWithDefault 0 (-1) input 15 | 16 | main :: IO () 17 | main = do 18 | input <- freqs . sort . commaNums <$> readFile "../data/day06.in" 19 | let run n = sum . iterateN n step 20 | print $ run 80 input 21 | print $ run 256 input 22 | 23 | -- 350917 24 | -- 1592918715629 25 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day07.hs: -------------------------------------------------------------------------------- 1 | module Day07 where 2 | 3 | import Lib (commaNums) 4 | import Data.List (sort) 5 | 6 | main :: IO () 7 | main = do 8 | input <- sort . commaNums <$> readFile "../data/day07.in" 9 | let run f val = sum . map (f . abs . subtract val) $ input 10 | digitSum x = x * (x + 1) `div` 2 11 | median = input !! (length input `div` 2) 12 | mean = map ((+) $ sum input `div` length input) [0, 1] 13 | print $ run id median 14 | print $ minimum $ map (run digitSum) mean 15 | 16 | -- 348996 17 | -- 98231647 18 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | import Lib (bfs, parseAsciiMap, neighbours4) 4 | import Linear (V2(..)) 5 | import Data.Maybe (mapMaybe) 6 | import Data.List.Extra (sortBy) 7 | import Data.Map (Map) 8 | import qualified Data.Map as Map 9 | 10 | lowPoints :: Map (V2 Int) Int -> [(V2 Int, Int)] 11 | lowPoints input = Map.toList $ Map.filterWithKey lowPoint input 12 | where lowPoint k v = all (v <) . mapMaybe (`Map.lookup` input) $ neighbours4 k 13 | 14 | basin :: Map (V2 Int) Int -> (V2 Int, Int) -> Int 15 | basin input (pos, val) = length $ bfs [pos] f id 16 | where 17 | f = filter ((/= 9) . flip (Map.findWithDefault 9) input) . neighbours4 18 | 19 | main :: IO () 20 | main = do 21 | input <- parseAsciiMap (Just . read . pure) <$> readFile "../data/day09.in" 22 | let lps = lowPoints input 23 | print . sum . map ((+1) . snd) $ lps 24 | print . product . take 3 . sortBy (flip compare) $ map (basin input) lps 25 | 26 | -- 545 27 | -- 950600 28 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day10.hs: -------------------------------------------------------------------------------- 1 | module Day10 where 2 | 3 | import Lib (middle, (.:)) 4 | import Data.List.Extra (sort) 5 | import Control.Monad (foldM) 6 | import Data.Either (partitionEithers) 7 | 8 | par :: String -> Char -> Either Char String 9 | par [] c = Right [c] 10 | par stack c | c `elem` "([{<" = Right (c : stack) 11 | par (x:xs) c 12 | | (x,c) `elem` [('(', ')'), ('{', '}'), ('[', ']'), ('<', '>')] = Right xs 13 | | otherwise = Left c 14 | 15 | main :: IO () 16 | main = do 17 | input <- lines <$> readFile "../data/day10.in" 18 | let (errors, remaining) = partitionEithers $ map (foldM par []) input 19 | print $ sum $ map score1 errors 20 | print . middle . sort $ map (foldl (\acc new -> acc * 5 + score2 new) 0) remaining 21 | 22 | score1, score2 :: Char -> Int 23 | score1 x = let Just val = lookup x [(')', 3), (']', 57), ('}', 1197), ('>', 25137)] in val 24 | score2 x = let Just val = lookup x [('(', 1), ('[', 2), ('{', 3), ('<', 4)] in val 25 | 26 | -- 411471 27 | -- 3122628974 28 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day11.hs: -------------------------------------------------------------------------------- 1 | module Day11 where 2 | 3 | import Lib (iterateMaybe, count, parseAsciiMap, neighbours, Point, takeUntil) 4 | import Data.Maybe (listToMaybe) 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | 8 | type Coordinates = Map Point Int 9 | 10 | flash :: Coordinates -> Maybe Coordinates 11 | flash input = do 12 | (k, v) <- listToMaybe $ Map.toList $ Map.filter (> 9) input 13 | let f x = if x == 0 then 0 else x + 1 14 | new = foldr (Map.adjust f) input 15 | . filter (`Map.member` input) 16 | $ neighbours k 17 | pure $ Map.insert k 0 new 18 | 19 | main :: IO () 20 | main = do 21 | input <- parseAsciiMap (Just . read . pure) <$> readFile "../data/day11.in" 22 | let run = map (count (== 0)) 23 | . tail 24 | . iterate (last . iterateMaybe flash . Map.map (+1)) 25 | $ input 26 | 27 | print . sum $ take 100 run 28 | print . length $ takeUntil (== 100) run 29 | 30 | -- 1655 31 | -- 337 32 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day12.hs: -------------------------------------------------------------------------------- 1 | module Day12 where 2 | 3 | import Control.Monad (guard) 4 | import Data.List.Extra (delete, splitOn) 5 | import Data.Char (isUpper, isLower) 6 | import Data.Map (Map) 7 | import qualified Data.Map as Map 8 | 9 | move :: (String -> Map String Int -> Bool) -> Map String [String] -> Int 10 | move pred mp = length $ go Map.empty "start" 11 | where 12 | go seen pos = do 13 | next <- mp Map.! pos 14 | guard $ isUpper (head next) || pred next seen 15 | let seen' = if isLower (head next) then Map.insertWith (+) next 1 seen else seen 16 | case next of 17 | "end" -> pure () 18 | _ -> go seen' next 19 | 20 | main :: IO () 21 | main = do 22 | input <- fmap (delete "start") . parseInput <$> readFile "../data/day12.in" 23 | let part2 x seen = (Map.notMember x seen || not (any (== 2) seen)) 24 | print $ move Map.notMember input 25 | print $ move part2 input 26 | 27 | parseInput :: String -> Map String [String] 28 | parseInput = Map.fromListWith (<>) . concatMap (f . splitOn "-") . lines 29 | where f [x,y] = [(x, [y]), (y, [x])] 30 | 31 | -- 3563 32 | -- 105453 33 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day13.hs: -------------------------------------------------------------------------------- 1 | module Day13 where 2 | 3 | import Lib (display, findBounds) 4 | import Linear (V2(..), _x, _y) 5 | import Control.Lens (over, each, Lens', view) 6 | import Data.List.Extra (splitOn, union, partition) 7 | 8 | fold :: [V2 Int] -> (String, Int) -> [V2 Int] 9 | fold points (dir, val) = 10 | let (keep, toFold) = partition ((< val) . view lens) points 11 | in keep `union` over (each . lens) (dist val) toFold 12 | where 13 | dist val x = val - abs (val - x) 14 | (_, _, mx, my) = findBounds points 15 | lens :: Lens' (V2 Int) Int 16 | lens = if dir == "x" then _x else _y 17 | 18 | main :: IO () 19 | main = do 20 | (coords, folds) <- parseInput <$> readFile "../data/day13.in" 21 | print . length $ fold coords (head folds) 22 | let pattern = foldl fold coords folds 23 | putStrLn $ display pattern 24 | 25 | parseInput :: String -> ([V2 Int], [(String, Int)]) 26 | parseInput = f . splitOn "\n\n" 27 | where f [x,y] = (coords x, folds y) 28 | coords = map ((\[x,y] -> (V2 (read x) (read y))) . splitOn ",") . lines 29 | folds = concat . map (map ((\[x,y] -> (x, read y)) . splitOn "=") . drop 2 . words) . lines 30 | 31 | -- 810 32 | -- HLBUBGFR 33 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day17.hs: -------------------------------------------------------------------------------- 1 | module Day17 where 2 | 3 | import Lib (takeUntil, allNums) 4 | import Data.Maybe (fromJust, mapMaybe) 5 | import Control.Lens (maximumOf, _1, _2, each) 6 | import Text.ParserCombinators.Parsec (many1, digit, char, parse, string, (<|>)) 7 | 8 | type Point = (Int, Int) 9 | type Bound = (Point, Point) 10 | 11 | shoot :: Bound -> Point -> Maybe [Bound] 12 | shoot ((tx,tx'), (ty, ty')) (dx,dy) = path 13 | where 14 | step ((x, y), (dx, dy)) = ((x + dx, y + dy), (max 0 (dx - 1), dy - 1)) 15 | between x tx ty = x >= min tx ty && x <= max tx ty 16 | path = (\x -> if length x == bound then Nothing else Just x) 17 | . take bound 18 | . takeUntil (\((x,y),(dx,dy)) -> between x tx tx' && between y ty ty') 19 | $ iterate step ((0,0), (dx, dy)) 20 | where bound = 400 21 | 22 | main :: IO () 23 | main = do 24 | input@((_, mx), (miy, mxy)) <- parseInput <$> readFile "../data/day17.in" 25 | 26 | let paths = mapMaybe (fmap . (,) <*> shoot input) $ do 27 | x <- [0..mx + 1] 28 | y <- [min miy mxy..(abs (min miy mxy) - 1)] 29 | pure (x,y) 30 | 31 | print . maximumOf (each . _2 . each . _1 . _2) $ paths 32 | print $ length paths 33 | 34 | parseInput :: String -> ((Int, Int), (Int, Int)) 35 | parseInput str = let [x1,x2,y1,y2] = allNums str in ((x1,x2), (y1, y2)) 36 | 37 | -- Just 3160 38 | -- 1928 39 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day20.hs: -------------------------------------------------------------------------------- 1 | module Day20 where 2 | 3 | import Lib (toMapIndexed, Point, tuple, count, parseAsciiMap, findBounds, neighbours) 4 | import Linear (V2(..)) 5 | import Data.Digits (unDigits) 6 | import Data.Tuple.Extra ((***)) 7 | import Data.List.Extra (splitOn, sortBy) 8 | import Data.Map (Map) 9 | import qualified Data.Map as Map 10 | 11 | step :: Int -> Map Int Int -> Map Point Int -> Map (V2 Int) Int 12 | step n algo input = foldMap f expanded 13 | where 14 | (minx,miny,maxx,maxy) = findBounds $ Map.keys input 15 | expanded = [ V2 x y | x <- [minx - 1..maxx + 1], y <- [miny - 1..maxy + 1]] 16 | f v2 = Map.singleton v2 $ algo Map.! num 17 | where num = unDigits 2 18 | . map (\v2 -> Map.findWithDefault n v2 input) 19 | . sortBy (\(V2 x y) (V2 x' y') -> compare y y' <> compare x x') 20 | . (v2:) 21 | $ neighbours v2 22 | 23 | main :: IO () 24 | main = do 25 | (code, input) <- parseInput <$> readFile "../data/day20.in" 26 | let run n = count (== 1) . (!! (n `div` 2)) 27 | $ iterate (step 1 code . step 0 code) input 28 | print $ run 2 29 | print $ run 50 30 | 31 | parseInput :: String -> (Map Int Int, Map Point Int) 32 | parseInput = f . splitOn "\n\n" 33 | where 34 | f = (toMapIndexed . map g *** parseAsciiMap (Just . g)) . tuple 35 | g '#' = 1 36 | g '.' = 0 37 | 38 | -- 5391 39 | -- 16383 40 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day21.hs: -------------------------------------------------------------------------------- 1 | module Day21 where 2 | 3 | import Lib (tuple, freqs, memo4) 4 | import Linear (_x, V2(..)) 5 | import Advent.Coord (invert) 6 | import Control.Lens (view) 7 | import Control.Applicative (liftA3) 8 | import Data.Map (Map) 9 | import qualified Data.Map as Map 10 | 11 | play :: (Int, Int) -> (Int, Int) -> Int -> [Int] -> Int 12 | play (score1, pos1) (score2, pos2) cnt rolls 13 | | score' >= 1000 = score2 * (cnt + 3) 14 | | otherwise = play (score2, pos2) (score', pos') (cnt + 3) (drop 3 rolls) 15 | where 16 | pos' = (pos1 + sum (take 3 rolls)) `mod` 10 17 | score' = score1 + pos' + 1 18 | 19 | solve :: Int -> Int -> Int -> Int -> V2 Int 20 | solve = memo4 $ \p1 s1 p2 s2 -> sum $ do 21 | (v, freq) <- Map.toList (freqs (liftA3 (\a b c -> a + b + c) [1,2,3] [1,2,3] [1,2,3])) 22 | let p1' = (p1 + v) `mod` 10 23 | s1' = s1 + p1' + 1 24 | pure $ if s1' >= 21 25 | then V2 freq 0 26 | else (* V2 freq freq) . invert $ solve p2 s2 p1' s1' 27 | 28 | main :: IO () 29 | main = do 30 | (one, two) <- parseInput <$> readFile "../data/day21.in" 31 | print $ play (0, one - 1) (0, two - 1) 0 (cycle [1..100]) 32 | print $ view _x $ solve (one - 1) 0 (two - 1) 0 33 | 34 | parseInput :: String -> (Int, Int) 35 | parseInput = tuple . map (read . pure . last) . lines 36 | 37 | -- 752745 38 | -- 309196008717909 39 | -------------------------------------------------------------------------------- /2021/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Lib (count, Point, findBounds, parseAsciiMap, zipWithTail) 4 | import Linear (V2(..)) 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | 8 | type Oceanfloor = Map Point Cucumber 9 | data Cucumber = South | East | Space 10 | deriving (Show, Eq, Ord) 11 | 12 | step :: Oceanfloor -> Oceanfloor 13 | step mp = go South south (go East east mp) 14 | where 15 | (_,_,mx,my) = findBounds (Map.keys mp) 16 | south (V2 x y) = V2 x ((y + 1) `mod` (my + 1)) 17 | east (V2 x y) = V2 ((x + 1) `mod` (1 + mx)) y 18 | go dir add mp = foldr (uncurry Map.insert) mp $ concatMap (\k -> [(k, Space), (add k, dir)]) 19 | $ Map.keys $ Map.filterWithKey (\k v -> v == dir && (mp Map.! add k == Space)) mp 20 | 21 | main :: IO () 22 | main = do 23 | input <- parseInput <$> readFile "../data/day25.in" 24 | print $ (+1) . length . takeWhile (uncurry (/=)) . zipWithTail $ iterate step input 25 | 26 | parseInput :: String -> Oceanfloor 27 | parseInput = parseAsciiMap f 28 | where 29 | f '>' = Just East 30 | f 'v' = Just South 31 | f '.' = Just Space 32 | 33 | -- 568 34 | -------------------------------------------------------------------------------- /2021/Haskell/src/gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq -f "%02g" 08 25); do 4 | echo "module Day$i where 5 | 6 | import Lib 7 | import Advent.Coord 8 | import Data.Maybe 9 | import Control.Lens 10 | import Control.Monad 11 | import Control.Monad.State 12 | import Data.List.Extra 13 | import Data.Map (Map) 14 | import qualified Data.Map as Map 15 | import Text.ParserCombinators.Parsec hiding (count) 16 | 17 | part1 input = undefined 18 | 19 | part2 input = undefined 20 | 21 | main :: IO () 22 | main = do 23 | 24 | let run str file = do 25 | input <- parseInput <$> readFile file 26 | putStrLn str 27 | print input 28 | 29 | -- print $ part1 input 30 | -- print $ part2 input 31 | 32 | run \"\nTest:\n\n\" \"../data/test.in\" 33 | -- run \"\nActual:\n\n\" \"../data/day$i.in\" 34 | 35 | parseInput = id 36 | 37 | -- parseInput = either (error . show) id . traverse (parse p \"\") . lines 38 | -- where 39 | -- p = undefined" >Day$i.hs 40 | 41 | done 42 | -------------------------------------------------------------------------------- /2021/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2021/Scheme/day01.scm: -------------------------------------------------------------------------------- 1 | (load "utils.scm") 2 | 3 | (define lines (read-input "../data/day01.in")) 4 | 5 | (define ((solve input) dist) 6 | (->> input 7 | (map > (drop dist input)) 8 | (filter id) 9 | length)) 10 | 11 | (define (main) 12 | (let ((f (solve lines))) 13 | (cons (f 1) (f 3)))) 14 | 15 | (main) 16 | -------------------------------------------------------------------------------- /2021/Scheme/day02.scm: -------------------------------------------------------------------------------- 1 | (load "utils.scm") 2 | 3 | (define symbols (read-input "../data/day02.in")) 4 | 5 | (define (solve input) 6 | (let loop ((pos 0) (aim 0) (depth 0) (input input)) 7 | (if (null? input) 8 | (cons (* pos aim) (* depth pos)) 9 | (let ((value (cadr input)) 10 | (rest (cddr input))) 11 | (case (car input) 12 | ((up) (loop pos (- aim value) depth rest)) 13 | ((down) (loop pos (+ aim value) depth rest)) 14 | ((forward) (loop (+ pos value) aim (+ depth (* aim value)) rest))))))) 15 | 16 | (define (main) (solve symbols)) 17 | 18 | (main) 19 | -------------------------------------------------------------------------------- /2021/Scheme/day03.scm: -------------------------------------------------------------------------------- 1 | (load "utils.scm") 2 | 3 | (define symbols (map string->list (read-line-string "../data/day03.in"))) 4 | 5 | (define (gamma-epsilon items) 6 | (define (inner item) 7 | (let ((ones (count (partial eq? #\1) item)) 8 | (zeros (count (partial eq? #\0) item))) 9 | (if (>= ones zeros) 10 | (list #\1 #\0) 11 | (list #\0 #\1)))) 12 | (transpose (map inner (transpose items)))) 13 | 14 | (define (oxygen-carbon f items) 15 | (define (inner items) 16 | (if (= 1 (length items)) 17 | (car items) 18 | (let ((val (car (f (gamma-epsilon items))))) 19 | (->> items 20 | (filter (compose (partial eq? val) car)) 21 | (map cdr) 22 | inner 23 | (cons val))))) 24 | (inner items)) 25 | 26 | (define (run f items) 27 | (->> items 28 | f 29 | (map binToInt) 30 | (apply *))) 31 | 32 | (define (part2 items) 33 | (list (oxygen-carbon car items) 34 | (oxygen-carbon cadr items))) 35 | 36 | (define (main) 37 | (cons (run gamma-epsilon symbols) 38 | (run part2 symbols))) 39 | 40 | (main) 41 | -------------------------------------------------------------------------------- /2021/Scheme/day06.scm: -------------------------------------------------------------------------------- 1 | (load "utils.scm") 2 | 3 | (define (parse filename) 4 | (let ((line (car (read-line-string filename)))) 5 | (map (compose string->number list->string) (split-on #\, (string->list line))))) 6 | 7 | (define (mk-vec input) 8 | (let ((vec (make-vector 10 0))) 9 | (for-each (lambda (x) 10 | (vector-set! vec x (+ 1 (vector-ref vec x)))) 11 | input) 12 | vec)) 13 | 14 | 15 | (define (run-vec turns vec) 16 | (let loop ((turn 0)) 17 | (if (= turn turns) 18 | (sum (vector->list vec)) 19 | (begin 20 | (vector-set! vec 7 (+ (vector-ref vec 0) 21 | (vector-ref vec 7))) 22 | (vector-set! vec 9 (vector-ref vec 0)) 23 | (for-each (lambda (ix) (vector-set! vec ix (vector-ref vec (+ 1 ix)))) (range 0 8)) 24 | (vector-set! vec 9 0) 25 | (loop (+ turn 1)))))) 26 | 27 | (define (main) 28 | (let ((vec (mk-vec (parse "../data/day06.in")))) 29 | (cons (run-vec 80 vec) 30 | (run-vec (- 256 80) vec)))) ; Vec has been mutated. 31 | 32 | (main) 33 | 34 | ;; (350917 . 1592918715629) 35 | -------------------------------------------------------------------------------- /2021/Scheme/day07.scm: -------------------------------------------------------------------------------- 1 | (load "utils.scm") 2 | 3 | (define (parse filename) 4 | (let ((line (car (read-line-string filename)))) 5 | (map (compose string->number list->string) (split-on #\, (string->list line))))) 6 | 7 | (define (run f val items) 8 | (foldl (lambda (acc new) (+ acc (f (abs (- new val))))) 0 items)) 9 | 10 | (define (gauss n) 11 | (floor (/ (* n (+ 1 n)) 2))) 12 | 13 | (define (main) 14 | (let* ((input (sort (parse "../data/day07.in"))) 15 | (len (length input)) 16 | (total (sum input)) 17 | (median (car (drop (floor (/ len 2)) input))) 18 | (mean (/ total len))) 19 | (cons (run id median input) 20 | (min (run gauss mean input) 21 | (run gauss (+ 1 mean) input))))) 22 | 23 | (main) 24 | 25 | ;; (348996 . 98231647) 26 | -------------------------------------------------------------------------------- /2021/Scheme/main.scm: -------------------------------------------------------------------------------- 1 | 2 | (load "utils.scm") 3 | 4 | (define (run-main str) 5 | (load str) 6 | (print (list str (main)))) 7 | 8 | (for-each run-main 9 | '("day01.scm" 10 | "day02.scm" 11 | "day03.scm" 12 | "day04.scm" 13 | "day05.scm" 14 | "day06.scm" 15 | "day07.scm" 16 | "day08.scm" 17 | "day09.scm" 18 | "day10.scm" 19 | "day11.scm")) 20 | -------------------------------------------------------------------------------- /2021/Scheme/point-map.scm: -------------------------------------------------------------------------------- 1 | 2 | (define ((point-map x y start-element) input) 3 | (let ((data (make-vector (* (+ 1 x) (+ 1 y)) start-element))) 4 | (let loop ((input input)) 5 | (if (null? input) 6 | data 7 | (let* ((x0 (caar input)) 8 | (y0 (cdar input)) 9 | (ix (+ x0 (* y0 (+ x 1)))) 10 | (curr (vector-ref data ix))) 11 | (vector-set! data ix (+ curr 1)) 12 | (loop (cdr input))))))) 13 | 14 | -------------------------------------------------------------------------------- /2022/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2022/Haskell/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for `aoc2022` 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to the 7 | [Haskell Package Versioning Policy](https://pvp.haskell.org/). 8 | 9 | ## Unreleased 10 | 11 | ## 0.1.0.0 - YYYY-MM-DD 12 | -------------------------------------------------------------------------------- /2022/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2022/Haskell/get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -r "../.cookie" ]; then 4 | source "../.cookie" 5 | fi 6 | 7 | export TZ=CET 8 | thisyear="$(date +%Y)" 9 | thismonth="$(date +%m)" 10 | thisday="$(date +%d)" 11 | 12 | day=$(expr $thisday + 0) # Strip leading zero 13 | 14 | year=2022 15 | 16 | if [ "$thisyear" -ne "$year" ] || [ "$thismonth" -ne 12 ] || [ "$thisday" -gt 25 ]; then 17 | echo "Not a valid date: $thisday / $thismonth / $thisyear" 18 | exit 0 19 | fi 20 | 21 | filename="../data/day$thisday.in" 22 | 23 | if [ -r "$filename" ]; then 24 | echo "Filename $filename already exists!" 25 | exit 0 26 | fi 27 | 28 | curl -sS -o "$filename" -b "$AOC_COOKIE" https://adventofcode.com/$year/day/$day/input && echo "Curled into $filename" 29 | -------------------------------------------------------------------------------- /2022/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2022:exe:aoc2022-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2022/Haskell/src/Advent/Coord.hs: -------------------------------------------------------------------------------- 1 | module Advent.Coord where 2 | 3 | import Linear 4 | import Control.Lens (over) 5 | 6 | type Coord = V2 Int 7 | type Dir = V2 Int 8 | 9 | origin, up, down, left, right :: (Traversable t, Applicative t, Num a, Eq (t a), R2 t) => 10 | t a 11 | origin = pure 0 12 | up = over _y (+1) $ pure 0 13 | down = over _y (subtract 1) $ pure 0 14 | left = over _x (subtract 1) $ pure 0 15 | right = over _x (+ 1) $ pure 0 16 | 17 | above, below :: (Traversable t, Applicative t, Num a, Eq (t a), R3 t) => 18 | t a 19 | above = over _z (+1) $ pure 0 20 | below = over _z (subtract 1) $ pure 0 21 | 22 | turnAround, turnLeft, turnRight :: V2 Int -> V2 Int 23 | turnLeft = perp 24 | turnRight = perp . perp . perp 25 | turnAround = negate 26 | 27 | invert :: V2 a -> V2 a 28 | invert (V2 x y) = V2 y x 29 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Data.List.Extra (splitOn, sortOn) 4 | import Data.Ord (Down(Down)) 5 | 6 | main :: IO () 7 | main = do 8 | input <- sortOn Down . map (sum . map read . lines) . splitOn "\n\n" <$> readFile "../data/day01.in" 9 | print $ head input 10 | print . sum . take 3 $ input 11 | 12 | -- 69206 13 | -- 197400 14 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Lib (tuple, safeSucc, safePred) 4 | 5 | data RPS = Rock | Paper | Scissors 6 | deriving (Enum, Show, Eq, Ord, Bounded) 7 | 8 | part1 :: RPS -> RPS -> Int 9 | part1 a b = outcome a b + score b 10 | where 11 | score r = let Just v = lookup r [(Rock, 1), (Paper, 2), (Scissors, 3)] in v 12 | outcome a b 13 | | b == safeSucc a = 6 14 | | a == b = 3 15 | | otherwise = 0 16 | 17 | part2 :: RPS -> RPS -> Int 18 | part2 a b = part1 a (action b a) 19 | where 20 | action = \case 21 | Rock -> safePred 22 | Paper -> id 23 | Scissors -> safeSucc 24 | 25 | main :: IO () 26 | main = do 27 | input <- map (tuple . map parseInput . words) . lines <$> readFile "../data/day02.in" 28 | let run f = print . sum . map (uncurry f) 29 | run part1 input 30 | run part2 input 31 | where 32 | parseInput a 33 | | a `elem` ["X", "A"] = Rock 34 | | a `elem` ["Y", "B"] = Paper 35 | | a `elem` ["Z", "C"] = Scissors 36 | | otherwise = error a 37 | 38 | -- 12740 39 | -- 11980 40 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | module Day03 where 2 | 3 | import Data.List.Extra (intersect, nub, chunksOf) 4 | import Data.Maybe (fromJust) 5 | 6 | main :: IO () 7 | main = do 8 | input <- lines <$> readFile "../data/day03.in" 9 | 10 | let halve str = [a,b] where (a,b) = splitAt (length str `div` 2) str 11 | scoreCommon = sum . map priority . nub . foldl1 intersect 12 | priority = fromJust . (`lookup` zip (['a'..'z'] <> ['A'..'Z']) [1..]) 13 | 14 | print . sum . map (scoreCommon . halve) $ input 15 | print . sum . map scoreCommon . chunksOf 3 $ input 16 | 17 | -- 8349 18 | -- 2681 19 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day04.hs: -------------------------------------------------------------------------------- 1 | module Day04 where 2 | 3 | import Lib (count) 4 | import Data.List.Extra (splitOn) 5 | import Data.IntSet (IntSet, isSubsetOf, disjoint, fromList) 6 | 7 | main :: IO () 8 | main = do 9 | input <- map parseInput . lines <$> readFile "../data/day04.in" 10 | print $ count ((||) <$> uncurry isSubsetOf <*> uncurry (flip isSubsetOf)) input 11 | print $ count (not . uncurry disjoint) input 12 | 13 | parseInput :: String -> (IntSet, IntSet) 14 | parseInput str = (fromList [a..b], fromList [c..d]) 15 | where 16 | [[a,b], [c,d]] = map (map read . splitOn "-") . splitOn "," $ str 17 | 18 | -- 580 19 | -- 895 20 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Data.List.Extra (transpose, splitOn) 4 | import Data.IntMap (IntMap) 5 | import qualified Data.IntMap as IM 6 | 7 | type Stacks = IntMap String 8 | type Cmd = (Int, Int, Int) 9 | 10 | main :: IO () 11 | main = do 12 | (stack, cmds) <- parseInput <$> readFile "../data/day05.in" 13 | let score = map head . IM.elems 14 | putStrLn . score $ foldl (rearrange reverse) stack cmds 15 | putStrLn . score $ foldl (rearrange id ) stack cmds 16 | 17 | rearrange :: (String -> String) -> Stacks -> Cmd -> Stacks 18 | rearrange f stack (n, from, to) = IM.adjust (new <>) to $ IM.adjust (drop n) from stack 19 | where new = f . take n $ stack IM.! from 20 | 21 | parseInput :: String -> (Stacks, [Cmd]) 22 | parseInput input = (out top, cmds bottom) 23 | where 24 | (map lines -> [top, bottom]) = splitOn "\n\n" input 25 | cmds = map (parse . words) 26 | parse ["move", read -> n, "from", read -> from, "to", read -> to] = (n, from, to) 27 | parse e = error ("Bad input: " <> show e) 28 | out = foldMap f 29 | . filter (not . null) 30 | . map (dropWhile (`notElem` "123456789")) 31 | . transpose 32 | . reverse 33 | f (x:xs) = IM.singleton (read [x]) (reverse $ filter (/= ' ') xs) 34 | f e = error ("Bad input: " <> show e) 35 | 36 | -- MQSHJMWNH 37 | -- LLWJRBHVZ 38 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day06.hs: -------------------------------------------------------------------------------- 1 | module Day06 where 2 | 3 | import Lib (slidingWindow, ordNub) 4 | import Data.List.Extra (findIndex) 5 | 6 | main :: IO () 7 | main = do 8 | input <- init <$> readFile "../data/day06.in" 9 | let solve n = fmap (+n) . findIndex ((== n) . length . ordNub) . slidingWindow n 10 | print $ solve 4 input 11 | print $ solve 14 input 12 | 13 | -- Just 1655 14 | -- Just 2665 15 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | import Lib (mannDist, ordNub) 4 | import Linear (V2(..)) 5 | import Advent.Coord (origin, right, left, up, down, Coord) 6 | 7 | runTail :: [Coord] -> [Coord] 8 | runTail = scanl go origin 9 | where 10 | oneAway x y = abs (x - y) < 2 11 | go p@(V2 px py) x@(V2 xx xy) 12 | | oneAway px xx, oneAway py xy = p 13 | | otherwise = p + signum (x - p) 14 | 15 | main :: IO () 16 | main = do 17 | input <- parseInput <$> readFile "../data/day09.in" 18 | let headPos = scanl (+) origin input 19 | tailPos n = length . ordNub . (!! n) . iterate runTail $ headPos 20 | print $ tailPos 1 21 | print $ tailPos 9 22 | 23 | parseInput :: String -> [Coord] 24 | parseInput = concatMap (f . words) . lines 25 | where 26 | f ["R", read -> n] = replicate n right 27 | f ["L", read -> n] = replicate n left 28 | f ["U", read -> n] = replicate n up 29 | f ["D", read -> n] = replicate n down 30 | f e = error (show e) 31 | 32 | -- 6197 33 | -- 2562 34 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day10.hs: -------------------------------------------------------------------------------- 1 | module Day10 where 2 | 3 | import Lib (display) 4 | import Linear (V2(..)) 5 | import Data.Maybe (maybe, mapMaybe) 6 | import Text.Read (readMaybe) 7 | import Control.Monad (guard) 8 | 9 | lightCRT :: (Int, Int) -> Maybe (V2 Int) 10 | lightCRT (cycle, val) = guard inSprite *> Just (V2 col row) 11 | where 12 | (row, col) = (cycle - 1) `divMod` 40 13 | inSprite = col `elem` [pred val, val, succ val] 14 | 15 | main :: IO () 16 | main = do 17 | input <- parseInput <$> readFile "../data/day10.in" 18 | let res = scanl (flip ($)) 1 input 19 | print . sum . map ((*) <*> (res !!)) $ [20,60,100,140,180,220] 20 | putStrLn . display . mapMaybe lightCRT $ zip [0..] res 21 | 22 | parseInput :: String -> [Int -> Int] 23 | parseInput = (id:) . concatMap (map (maybe id (+) . readMaybe) . words) . lines 24 | 25 | -- 14560 26 | -- ▓▓▓▓ ▓ ▓ ▓▓▓ ▓ ▓ ▓▓▓▓ ▓▓▓ ▓ ▓ ▓▓▓▓ 27 | -- ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ 28 | -- ▓▓▓ ▓▓ ▓ ▓ ▓▓▓▓ ▓▓▓ ▓ ▓ ▓ ▓ ▓ 29 | -- ▓ ▓ ▓ ▓▓▓ ▓ ▓ ▓ ▓▓▓ ▓ ▓ ▓ 30 | -- ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓ 31 | -- ▓▓▓▓ ▓ ▓ ▓ ▓ ▓ ▓ ▓▓▓▓ ▓ ▓▓ ▓▓▓▓ 32 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day12.hs: -------------------------------------------------------------------------------- 1 | module Day12 where 2 | 3 | import Lib (parseAsciiMap, bfs, ordinalNeighbours) 4 | import Linear (V2(..)) 5 | import Data.List.Extra (find) 6 | import Data.Map (Map) 7 | import qualified Data.Map as Map 8 | import Data.Maybe 9 | 10 | type GPS = Map (V2 Int) Char 11 | type Pos = (V2 Int, Int) -- Position, length to that position 12 | 13 | move :: GPS -> (GPS -> [Pos]) -> Maybe Int 14 | move input start = listToMaybe [ v | (k, v) <- bfs (start input) ns fst, input Map.! k == 'E'] 15 | where 16 | ns (pos, dist) = map (,dist + 1) 17 | . filter ((&&) <$> (`Map.member` input) <*> ((<= succ next) . convert . (input Map.!))) 18 | $ ordinalNeighbours pos 19 | where next = convert $ input Map.! pos 20 | convert 'S' = 'a' 21 | convert 'E' = 'z' 22 | convert c = c 23 | 24 | main :: IO () 25 | main = do 26 | input <- parseAsciiMap Just <$> readFile "../data/day12.in" 27 | let start str = map (,0) . Map.keys . Map.filter (`elem` str) 28 | run = move input 29 | print $ run (start "S") 30 | print $ run (start "Sa") 31 | 32 | -- 462 33 | -- 451 34 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day13.hs: -------------------------------------------------------------------------------- 1 | module Day13 where 2 | 3 | import Lib (tuple) 4 | import Data.List.Extra (splitOn, elemIndex, sort) 5 | import Text.ParserCombinators.Parsec (between, char, sepBy, many1, digit, parse, (<|>)) 6 | 7 | data Tree = Node [Tree] | Leaf Int 8 | deriving (Show, Eq) 9 | 10 | instance Ord Tree where 11 | compare (Leaf l ) (Leaf r ) = l `compare` r 12 | compare (Node ls) (Node rs) = compare ls rs 13 | compare (Leaf l ) (Node rs) = compare (Node [Leaf l]) (Node rs) 14 | compare (Node ls) (Leaf r ) = compare (Node ls) (Node [Leaf r]) 15 | 16 | part2trees :: [Tree] 17 | part2trees = [Node [Node [Leaf 2]], Node [Node [Leaf 6]]] 18 | 19 | main :: IO () 20 | main = do 21 | input <- parseInput <$> readFile "../data/day13.in" 22 | print $ sum . map snd $ filter ((==LT) . fst) . flip zip [1..] $ map (uncurry compare) input 23 | let part2 = sort $ concatMap (\(x,y) -> [x,y]) input <> part2trees 24 | print $ product . map (+1) <$> traverse (`elemIndex` part2) part2trees 25 | 26 | parseInput :: String -> [(Tree, Tree)] 27 | parseInput = map (tuple . either (error . show) id . traverse (parse p "") . lines) . splitOn "\n\n" 28 | where 29 | p = Node <$> between (char '[') (char ']') f 30 | f = sepBy (p <|> (Leaf . read <$> many1 digit)) (char ',') 31 | 32 | -- 5659 33 | -- 22110 34 | -------------------------------------------------------------------------------- /2022/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | fromSnafu :: Char -> Int 4 | fromSnafu = \case 5 | '=' -> -2 6 | '-' -> -1 7 | '0' -> 0 8 | '1' -> 1 9 | '2' -> 2 10 | 11 | toSnafu :: Int -> Char 12 | toSnafu = \case 13 | (-2) -> '=' 14 | (-1) -> '-' 15 | 0 -> '0' 16 | 1 -> '1' 17 | 2 -> '2' 18 | 19 | dMod :: Int -> (Int, Int) -- (value, rest) 20 | dMod n 21 | | n <= -3 = (n + 5, -1) 22 | | n >= 3 = (n - 5, 1) 23 | | otherwise = (n , 0) 24 | 25 | addSnafu :: [Int] -> [Int] -> [Int] 26 | addSnafu a b = go 0 (combine a b) 27 | where 28 | go mente [] = if mente == 0 then [] else [mente] 29 | go mente (x:xs) = let (y, mente') = dMod (x + mente) in y : go mente' xs 30 | combine [] ys = ys 31 | combine xs [] = xs 32 | combine (x:xs) (y:ys) = (x + y) : combine xs ys 33 | 34 | main :: IO () 35 | main = do 36 | input <- map (map fromSnafu . reverse) . lines <$> readFile "../data/day25.in" 37 | putStrLn . map toSnafu . reverse $ foldr1 addSnafu input 38 | 39 | -- 2-20=01--0=0=0=2-120 40 | -------------------------------------------------------------------------------- /2022/Haskell/src/gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq -f "%02g" 01 25); do 4 | echo "module Day$i where 5 | 6 | import Lib 7 | import Advent.Coord 8 | import Data.Maybe 9 | import Control.Lens 10 | import Control.Monad 11 | import Control.Monad.State 12 | import Data.List.Extra 13 | import Data.Map (Map) 14 | import qualified Data.Map as Map 15 | import Text.ParserCombinators.Parsec hiding (count) 16 | 17 | part1 input = undefined 18 | 19 | part2 input = undefined 20 | 21 | main :: IO () 22 | main = do 23 | 24 | let run str file = do 25 | input <- parseInput <$> readFile file 26 | putStrLn str 27 | print input 28 | 29 | -- print $ part1 input 30 | -- print $ part2 input 31 | 32 | run \"\nTest:\n\n\" \"../data/test.in\" 33 | -- run \"\nActual:\n\n\" \"../data/day$i.in\" 34 | 35 | parseInput = id 36 | 37 | -- parseInput = either (error . show) id . traverse (parse p \"\") . lines 38 | -- where 39 | -- p = undefined" >Day$i.hs 40 | 41 | done 42 | -------------------------------------------------------------------------------- /2022/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2023/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2023/Haskell/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for `aoc2023` 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to the 7 | [Haskell Package Versioning Policy](https://pvp.haskell.org/). 8 | 9 | ## Unreleased 10 | 11 | ## 0.1.0.0 - YYYY-MM-DD 12 | -------------------------------------------------------------------------------- /2023/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2023/Haskell/get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -r "../.cookie" ]; then 4 | source "../.cookie" 5 | fi 6 | 7 | export TZ=CET 8 | thisyear="$(date +%Y)" 9 | thismonth="$(date +%m)" 10 | thisday="$(date +%d)" 11 | 12 | day=$(expr $thisday + 0) # Strip leading zero 13 | 14 | year=2023 15 | 16 | if [ "$thisyear" -ne "$year" ] || [ "$thismonth" -ne 12 ] || [ "$thisday" -gt 25 ]; then 17 | echo "Not a valid date: $thisday / $thismonth / $thisyear" 18 | exit 0 19 | fi 20 | 21 | # Include leading zero for days 1 - 9 22 | daystring=$(printf "%02d" $thisday) 23 | filename="../data/day$daystring.in" 24 | 25 | if [ -r "$filename" ]; then 26 | echo "Filename $filename already exists!" 27 | exit 0 28 | fi 29 | 30 | curl -sS -o "$filename" -b "$AOC_COOKIE" https://adventofcode.com/$year/day/$day/input && echo "Curled into $filename" 31 | -------------------------------------------------------------------------------- /2023/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ghcid -c "stack ghci --main-is aoc2023:exe:aoc2023-exe" --test="Day${1}.main" 4 | -------------------------------------------------------------------------------- /2023/Haskell/src/Advent/Coord.hs: -------------------------------------------------------------------------------- 1 | module Advent.Coord where 2 | 3 | import Linear (V2(..), R2(_y), R3(_z), perp, R1(_x)) 4 | import Control.Lens (over) 5 | 6 | type Coord = V2 Int 7 | type Dir = V2 Int 8 | 9 | origin, up, down, left, right :: (Traversable t, Applicative t, Num a, Eq (t a), R2 t) => 10 | t a 11 | origin = pure 0 12 | up = over _y (+1) $ pure 0 13 | down = over _y (subtract 1) $ pure 0 14 | left = over _x (subtract 1) $ pure 0 15 | right = over _x (+ 1) $ pure 0 16 | 17 | -- Similar to above but north is V2 0 (-1) due to how 18 | -- parseAsciiMap parses top left as 0 0 19 | north, south, west, east :: (Traversable t, Applicative t, Num a, Eq (t a), R2 t) => 20 | t a 21 | north = over _y (subtract 1) $ pure 0 22 | south = over _y (+1) $ pure 0 23 | west = over _x (subtract 1) $ pure 0 24 | east = over _x (+ 1) $ pure 0 25 | 26 | above, below :: (Traversable t, Applicative t, Num a, Eq (t a), R3 t) => 27 | t a 28 | above = over _z (+1) $ pure 0 29 | below = over _z (subtract 1) $ pure 0 30 | 31 | turnAround, turnLeft, turnRight :: V2 Int -> V2 Int 32 | turnLeft = perp 33 | turnRight = perp . perp . perp 34 | turnAround = negate 35 | 36 | invert :: V2 a -> V2 a 37 | invert (V2 x y) = V2 y x 38 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Data.Maybe (mapMaybe) 4 | import Data.List.Extra (isPrefixOf, find, tails) 5 | 6 | ints, numbers :: [String] 7 | ints = map show [1..9] 8 | numbers = ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"] <> ints 9 | 10 | convert :: String -> Int 11 | convert str = let Just v = lookup str (zip numbers (cycle [1..9])) in v 12 | 13 | solve :: [String] -> String -> Int 14 | solve comps input = head opts * 10 + last opts 15 | where opts = mapMaybe findNumber $ tails input 16 | findNumber str = convert <$> find (`isPrefixOf` str) comps 17 | 18 | main :: IO () 19 | main = do 20 | input <- lines <$> readFile "../data/day01.in" 21 | let run f = sum $ map (solve f) input 22 | print $ run ints 23 | print $ run numbers 24 | 25 | -- 55477 26 | -- 54431 27 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Lib (combineWith) 4 | import Control.Monad (guard) 5 | import Data.Functor (($>)) 6 | import Data.Maybe (mapMaybe) 7 | import Linear (V3 (..)) 8 | import Text.ParserCombinators.Parsec 9 | (alphaNum, char, digit, many1, parse, sepBy, space, string) 10 | 11 | type RGB = V3 Int 12 | 13 | part1 :: [(Int, [RGB])] -> Int 14 | part1 = sum . mapMaybe possible 15 | where 16 | test (V3 r g b) = r <= 12 && g <= 13 && b <= 14 17 | possible (cId, xs) = guard (all test xs) $> cId 18 | 19 | main :: IO () 20 | main = do 21 | input <- parseInput <$> readFile "../data/day02.in" 22 | print $ part1 input 23 | print $ sum $ map (product . combineWith max . snd) input 24 | 25 | parseInput :: String -> [(Int, [RGB])] 26 | parseInput = either (error . show) id . traverse (parse p "") . lines 27 | where 28 | cube = do 29 | cnt <- read <$> (space *> many1 digit <* space) 30 | colour <- many1 alphaNum 31 | case colour of 32 | "red" -> pure (V3 cnt 0 0) 33 | "green" -> pure (V3 0 cnt 0) 34 | "blue" -> pure (V3 0 0 cnt) 35 | cubes = combineWith (+) <$> sepBy cube (string ",") 36 | p = do 37 | gameId <- read <$> (string "Game " *> many1 digit <* string ":") 38 | cs <- sepBy cubes (char ';') 39 | pure (gameId, cs) 40 | 41 | -- 2377 42 | -- 71220 43 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day04.hs: -------------------------------------------------------------------------------- 1 | module Day04 where 2 | 3 | import Lib (tuple, allNums) 4 | import Data.List.Extra (intersect, splitOn, unfoldr) 5 | import Data.Tuple.Extra (first) 6 | 7 | accumulate :: [(Int, Int)] -> Maybe (Int, [(Int, Int)]) 8 | accumulate [] = Nothing 9 | accumulate ((c, wins):xs) = Just (c, map (first (+ c)) (take wins xs) <> drop wins xs) 10 | 11 | main :: IO () 12 | main = do 13 | input <- parseInput <$> readFile "../data/day04.in" 14 | let winCount = length . uncurry intersect 15 | print . sum . map ((2^) . subtract 1) . filter (>0) . map winCount $ input 16 | print . sum . unfoldr accumulate . map ((1,) . winCount) $ input 17 | 18 | parseInput :: String -> [([Int], [Int])] 19 | parseInput = map (first tail . tuple . map allNums . splitOn "|") . lines 20 | 21 | -- 26914 22 | -- 13080971 23 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day06.hs: -------------------------------------------------------------------------------- 1 | module Day06 where 2 | 3 | import Lib (allNums, binaryMinSearch, tuple) 4 | import Data.Tuple.Extra (both) 5 | 6 | run :: (Int, Int) -> Int 7 | run (t, rec) = ub - lb 8 | where 9 | beat n = n * (t - n) > rec 10 | Just lb = binaryMinSearch beat 1 t 11 | Just ub = binaryMinSearch (not . beat) lb t 12 | 13 | main :: IO () 14 | main = do 15 | input <- parseInput <$> readFile "../data/day06.in" 16 | print . product $ map run input 17 | print . run . both (read . concatMap show) $ unzip input 18 | 19 | parseInput :: String -> [(Int, Int)] 20 | parseInput = uncurry zip . tuple . map allNums . lines 21 | 22 | -- 800280 23 | -- 45128024 24 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day09.hs: -------------------------------------------------------------------------------- 1 | module Day09 where 2 | 3 | solve :: [Int] -> Int 4 | solve = foldr ((-) . head) 0 5 | . takeWhile (any (/= 0)) 6 | . iterate (zipWith subtract <*> tail) 7 | 8 | main :: IO () 9 | main = do 10 | input <- map (map read . words) . lines <$> readFile "../data/day09.in" 11 | print $ sum $ map (solve . reverse) input 12 | print $ sum $ map solve input 13 | 14 | -- 1939607039 15 | -- 1041 16 | 17 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day11.hs: -------------------------------------------------------------------------------- 1 | module Day11 where 2 | 3 | import Lib (tuple, mannDist, Point, parseAsciiMap, combinations) 4 | import Control.Monad (guard) 5 | import Data.List.Extra (transpose, mapAccumL) 6 | import qualified Data.Map as Map 7 | import Linear (V2(..)) 8 | 9 | expand :: String -> Int -> [Point] 10 | expand input addRows = map (\(V2 x y) -> V2 (cs x) (rs y)) $ parseInput input 11 | where 12 | rs y = let Just y' = lookup y (rows addRows $ lines input) in y + y' 13 | cs x = let Just x' = lookup x (rows addRows $ transpose $ lines input) in x + x' 14 | rows inc = zip [0..] . snd . mapAccumL f 0 15 | where f st row = (if all (== '.') row then st + inc else st, st) 16 | parseInput = Map.keys . parseAsciiMap f 17 | where f x = guard (x == '#') *> Just () 18 | 19 | main :: IO () 20 | main = do 21 | input <- readFile "../data/day11.in" 22 | let findSum = sum . map (uncurry mannDist . tuple) . combinations 2 23 | print . findSum $ expand input 1 24 | print . findSum $ expand input 999999 25 | 26 | -- 10154062 27 | -- 553083047914 28 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day13.hs: -------------------------------------------------------------------------------- 1 | module Day13 where 2 | 3 | import Lib (perturbations) 4 | import Data.List.Extra (transpose, splitOn) 5 | 6 | solve :: String -> [Int] 7 | solve (lines -> x) = reflect (transpose x) <> ((100 *) <$> reflect x) 8 | 9 | reflect :: [String] -> [Int] 10 | reflect ls = filter findMirror [1..length ls - 1] 11 | where 12 | findMirror n = and (zipWith (==) l r) 13 | where 14 | l = reverse $ take n ls 15 | r = take n $ drop n ls 16 | 17 | part2 :: Int -> String -> Int 18 | part2 old = head . concatMap (filter (old /=) . solve) . change 19 | 20 | change :: String -> [String] 21 | change = perturbations $ \case 22 | '.' -> "#" 23 | '#' -> "." 24 | '\n' -> "" 25 | 26 | main :: IO () 27 | main = do 28 | input <- splitOn "\n\n" <$> readFile "../data/day13.in" 29 | let p1 = concatMap solve input 30 | print $ sum p1 31 | print $ sum $ zipWith part2 p1 input 32 | 33 | -- 27664 34 | -- 33991 35 | -------------------------------------------------------------------------------- /2023/Haskell/src/Day14.hs: -------------------------------------------------------------------------------- 1 | module Day14 where 2 | 3 | import Lib (iterateN, skipLoop) 4 | import Data.List.Extra (intercalate, sortOn, transpose, splitOn) 5 | import Data.Ord (Down(Down)) 6 | 7 | roll :: [String] -> [String] 8 | roll = map (intercalate "#" . map (sortOn Down) . splitOn "#") 9 | 10 | part2 :: [String] -> Int 11 | part2 = score . skipLoop (0,) (const $ const id) 1000000000 . iterate oneCycle 12 | where oneCycle = iterateN 4 (transpose . map reverse . roll) 13 | 14 | score :: [String] -> Int 15 | score = sum . concatMap (f . reverse) 16 | where f line = [ v | (v,'O') <- zip [1..] line] 17 | 18 | main :: IO () 19 | main = do 20 | input <- transpose . lines <$> readFile "../data/day14.in" 21 | print $ score $ roll input 22 | print $ part2 input 23 | 24 | -- 112773 25 | -- 98894 26 | -------------------------------------------------------------------------------- /2023/Haskell/src/gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq -f "%02g" 01 25); do 4 | echo "module Day$i where 5 | 6 | import Lib 7 | import Advent.Coord 8 | import Data.Maybe 9 | import Control.Lens 10 | import Control.Monad 11 | import Control.Monad.State 12 | import Data.List.Extra 13 | import Data.Map (Map) 14 | import qualified Data.Map as Map 15 | import Text.RawString.QQ 16 | import Text.ParserCombinators.Parsec hiding (count) 17 | 18 | part1 input = undefined 19 | 20 | part2 input = undefined 21 | 22 | main :: IO () 23 | main = do 24 | 25 | let run str input = do 26 | putStrLn str 27 | print input 28 | 29 | -- print $ part1 input 30 | -- print $ part2 input 31 | 32 | run \"\nTest:\n\n\" testInput 33 | 34 | -- input <- parseInput <$> readFile \"../data/day$i.in\" 35 | -- run \"\nActual:\n\n\" input 36 | 37 | parseInput = id 38 | 39 | -- parseInput = either (error . show) id . traverse (parse p \"\") . lines 40 | -- where 41 | -- p = undefined 42 | 43 | testInput = [r| 44 | |]" >Day$i.hs 45 | 46 | done 47 | -------------------------------------------------------------------------------- /2023/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2024/Haskell/.gitignore: -------------------------------------------------------------------------------- 1 | .stack-work/ 2 | *~ -------------------------------------------------------------------------------- /2024/Haskell/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog for `aoc2024` 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to the 7 | [Haskell Package Versioning Policy](https://pvp.haskell.org/). 8 | 9 | ## Unreleased 10 | 11 | ## 0.1.0.0 - YYYY-MM-DD 12 | -------------------------------------------------------------------------------- /2024/Haskell/Setup.hs: -------------------------------------------------------------------------------- 1 | import Distribution.Simple 2 | main = defaultMain 3 | -------------------------------------------------------------------------------- /2024/Haskell/bench: -------------------------------------------------------------------------------- 1 | 2 | hyperfine -m 20 .stack-work/dist/aarch64-osx/ghc-9.6.6/build/aoc2024-exe/aoc2024-exe 3 | -------------------------------------------------------------------------------- /2024/Haskell/get: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -r "../.cookie" ]; then 4 | source "../.cookie" 5 | fi 6 | 7 | export TZ=CET 8 | thisyear="$(date +%Y)" 9 | thismonth="$(date +%m)" 10 | thisday="$(date +%d)" 11 | 12 | day=$(expr $thisday + 0) # Strip leading zero 13 | 14 | year=2024 15 | 16 | if [ "$thisyear" -ne "$year" ] || [ "$thismonth" -ne 12 ] || [ "$thisday" -gt 25 ]; then 17 | echo "Not a valid date: $thisday / $thismonth / $thisyear" 18 | exit 0 19 | fi 20 | 21 | # Include leading zero for days 1 - 9 22 | daystring=$(printf "%02d" $day) 23 | filename="../data/day$daystring.in" 24 | 25 | if [ -r "$filename" ]; then 26 | echo "Filename $filename already exists!" 27 | exit 0 28 | fi 29 | 30 | curl -sS -o "$filename" -b "$AOC_COOKIE" https://adventofcode.com/$year/day/$day/input && echo "Curled into $filename" 31 | 32 | head "$filename" 33 | -------------------------------------------------------------------------------- /2024/Haskell/hie.yaml: -------------------------------------------------------------------------------- 1 | cradle: 2 | cabal: 3 | - path: "src" 4 | component: "lib:aoc2024" 5 | 6 | - path: "app/Main.hs" 7 | component: "aoc2024:exe:aoc2024-exe" 8 | 9 | - path: "test" 10 | component: "aoc2024:test:aoc2024-test" 11 | -------------------------------------------------------------------------------- /2024/Haskell/run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ## ghcid -c "stack ghci --main-is aoc2024:exe:aoc2024-exe" --test="Day${1}.main" 4 | 5 | # export PATH=$(stack path --compiler-bin --silent):$PATH 6 | 7 | ghciwatch --command "stack repl" --test-ghci="Day${1}.main" 8 | -------------------------------------------------------------------------------- /2024/Haskell/src/Advent/Coord.hs: -------------------------------------------------------------------------------- 1 | module Advent.Coord where 2 | 3 | import Linear (V2(..), R2(_y), R3(_z), perp, R1(_x)) 4 | import Control.Lens (over) 5 | 6 | type Coord = V2 Int 7 | type Dir = V2 Int 8 | 9 | origin, up, down, left, right :: (Traversable t, Applicative t, Num a, Eq (t a), R2 t) => 10 | t a 11 | origin = pure 0 12 | up = over _y (+1) $ pure 0 13 | down = over _y (subtract 1) $ pure 0 14 | left = over _x (subtract 1) $ pure 0 15 | right = over _x (+ 1) $ pure 0 16 | 17 | -- Similar to above but north is V2 0 (-1) due to how 18 | -- parseAsciiMap parses top left as 0 0 19 | north, south, west, east :: (Traversable t, Applicative t, Num a, Eq (t a), R2 t) => 20 | t a 21 | north = over _y (subtract 1) $ pure 0 22 | south = over _y (+1) $ pure 0 23 | west = over _x (subtract 1) $ pure 0 24 | east = over _x (+ 1) $ pure 0 25 | 26 | above, below :: (Traversable t, Applicative t, Num a, Eq (t a), R3 t) => 27 | t a 28 | above = over _z (+1) $ pure 0 29 | below = over _z (subtract 1) $ pure 0 30 | 31 | turnAround, turnLeft, turnRight :: V2 Int -> V2 Int 32 | turnLeft = perp 33 | turnRight = perp . perp . perp 34 | turnAround = negate 35 | 36 | invert :: V2 a -> V2 a 37 | invert (V2 x y) = V2 y x 38 | -------------------------------------------------------------------------------- /2024/Haskell/src/Advent/Parsers.hs: -------------------------------------------------------------------------------- 1 | module Advent.Parsers where 2 | 3 | import Text.ParserCombinators.Parsec 4 | 5 | pNumber :: Parser Int 6 | pNumber = read <$> (try ((:) <$> char '-' <*> many1 digit) <|> many1 digit) 7 | 8 | pBetween :: String -> String -> Parser a -> Parser a 9 | pBetween start end = between (string start) (string end) 10 | 11 | pFind :: Parser a -> Parser a 12 | pFind = try . pSkipManyTill anyChar 13 | 14 | -- https://hackage.haskell.org/package/parser-combinators-1.3.0/docs/src/Control.Monad.Combinators.html#skipManyTill 15 | pSkipManyTill p end = go 16 | where 17 | go = do 18 | r <- optionMaybe $ try end 19 | case r of 20 | Nothing -> p >> go 21 | Just r -> pure r 22 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day01.hs: -------------------------------------------------------------------------------- 1 | module Day01 where 2 | 3 | import Lib (freqs, allNums, (.:)) 4 | import Data.List (transpose, sort) 5 | import qualified Data.Map as Map 6 | 7 | part1 :: [Int] -> [Int] -> Int 8 | part1 = sum .: zipWith (abs .: subtract) 9 | 10 | part2 :: [Int] -> [Int] -> Int 11 | part2 l (freqs -> r) = foldr ((+) . similar) 0 l 12 | where 13 | similar x = x * Map.findWithDefault 0 x r 14 | 15 | main :: IO () 16 | main = do 17 | [left, right] <- map sort . transpose . map allNums . lines <$> readFile "../data/day01.in" 18 | print $ part1 left right 19 | print $ part2 left right 20 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day02.hs: -------------------------------------------------------------------------------- 1 | module Day02 where 2 | 3 | import Lib (select, allNums, zipWithTail, count) 4 | 5 | safe :: [Int] -> Bool 6 | safe xs = (all (> 0) diffs || all (< 0) diffs) && all ((<= 3) . abs) diffs 7 | where 8 | diffs = zipWith subtract xs (tail xs) 9 | 10 | main :: IO () 11 | main = do 12 | input <- map allNums . lines <$> readFile "../data/day02.in" 13 | print $ count safe input 14 | print $ count (any (safe . snd) . select) input 15 | 16 | -- 486 17 | -- 540 18 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day03.hs: -------------------------------------------------------------------------------- 1 | module Day03 where 2 | 3 | import Advent.Parsers (pBetween, pNumber, pFind) 4 | import Text.ParserCombinators.Parsec 5 | (Parser, parse, sepBy, char, many, option, string, (<|>)) 6 | import Data.Functor (($>)) 7 | 8 | parseInput :: Parser a -> String -> a 9 | parseInput f = either (error . show) id . parse f "" 10 | 11 | mul :: Parser Int 12 | mul = pBetween "mul(" ")" ((*) <$> pNumber <* char ',' <*> pNumber) 13 | 14 | part1 :: String -> Int 15 | part1 = parseInput (sum <$> many (pFind mul)) 16 | 17 | part2 :: String -> Int 18 | part2 = parseInput enabled 19 | where 20 | enabled = option 0 . pFind $ 21 | string "don't" *> disabled 22 | <|> (+) <$> mul <*> enabled 23 | disabled = option 0 . pFind $ string "do()" *> enabled 24 | 25 | main :: IO () 26 | main = do 27 | input <- readFile "../data/day03.in" 28 | print $ part1 input 29 | print $ part2 input 30 | 31 | -- 175015740 32 | -- 112272912 33 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day05.hs: -------------------------------------------------------------------------------- 1 | module Day05 where 2 | 3 | import Lib (allNums, middle, tuple) 4 | import Data.List.Extra (partition, sortBy, splitOn, sumOn') 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | import Data.Set (Set) 8 | import qualified Data.Set as Set 9 | import Data.Bool (bool) 10 | 11 | -- The input probably provides the complete set of rules, so it is possible to 12 | -- sort by checking if a letter appears in the set of letters that the other 13 | -- letter has to be in front of. 14 | orderNums :: Map Int (Set Int) -> Int -> Int -> Ordering 15 | orderNums rules a b = bool LT GT (b `Set.member` Map.findWithDefault Set.empty a rules) 16 | 17 | main :: IO () 18 | main = do 19 | (rules, pages) <- parseInput <$> readFile "../data/day05.in" 20 | let comp = orderNums rules 21 | let (sorted, unsorted) = partition ((==) <*> sortBy comp) pages 22 | print $ sumOn' middle sorted 23 | print $ sumOn' (middle . sortBy comp) unsorted 24 | 25 | parseInput :: String -> (Map Int (Set Int), [[Int]]) 26 | parseInput input = (rules, pages) 27 | where 28 | [top, bot] = splitOn "\n\n" input 29 | rules = Map.unionsWith (<>) $ do 30 | [from, to] <- map allNums $ lines top 31 | pure $ Map.singleton to (Set.singleton from) 32 | pages = map allNums $ lines bot 33 | 34 | -- 4959 35 | -- 4655 36 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day07.hs: -------------------------------------------------------------------------------- 1 | module Day07 where 2 | 3 | import Lib (allNums) 4 | import Data.List (partition) 5 | import Data.Set (Set) 6 | import qualified Data.Set as Set 7 | 8 | combine :: [Int -> Int -> Int] -> [Int] -> Bool 9 | combine ops (num:x:xs) = any (== num) $ foldl go (Set.singleton x) xs 10 | where 11 | go acc val = Set.filter (<= num) 12 | $ foldMap (\op -> Set.map (\v -> v `op` val) acc) ops 13 | 14 | main :: IO () 15 | main = do 16 | input <- map allNums . lines <$> readFile "../data/day07.in" 17 | 18 | let (p1, rest) = partition (combine [(*),(+)]) input 19 | print . sum . map head $ p1 20 | 21 | let f a b = a * 10 ^ (floor (logBase 10 (fromIntegral b)) + 1) + b 22 | print . sum . map head . (p1 <>) $ filter (combine [(*),(+),f]) rest 23 | 24 | -- 2437272016585 25 | -- 162987117690649 26 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day08.hs: -------------------------------------------------------------------------------- 1 | module Day08 where 2 | 3 | import Lib (invertMap, select, within, findBounds, parseAsciiMap) 4 | import Advent.Coord (Coord) 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | import Data.Set (Set) 8 | import qualified Data.Set as Set 9 | 10 | main :: IO () 11 | main = do 12 | (bounds, ants) <- parseInput <$> readFile "../data/day08.in" 13 | 14 | let antinodes pick xs = Set.fromList $ do 15 | (a, as) <- select xs 16 | b <- as 17 | let diff = a - b 18 | pick . takeWhile (within bounds) $ iterate (+ diff) a 19 | 20 | print $ Set.size $ foldMap (antinodes (take 1 . drop 1)) ants 21 | print $ Set.size $ foldMap (antinodes id) ants 22 | 23 | parseInput :: String -> ((Int, Int, Int, Int), [[Coord]]) 24 | parseInput input = (bounds, Map.elems antennas') 25 | where 26 | antennas = invertMap $ parseAsciiMap (Just . pure) input 27 | antennas' = Map.delete '.' antennas 28 | bounds = findBounds $ antennas Map.! '.' 29 | 30 | -- 371 31 | -- 1229 32 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day10.hs: -------------------------------------------------------------------------------- 1 | module Day10 where 2 | 3 | import Lib (parseAsciiMap, ordinalNeighbours) 4 | import Advent.Coord (Coord) 5 | import Data.Map (Map) 6 | import qualified Data.Map as Map 7 | import qualified Data.Set as Set 8 | import Data.Semigroup 9 | 10 | solve :: Monoid m => Map Coord Int -> (Coord -> m) -> Coord -> m 11 | solve input f = go 0 12 | where 13 | go 9 pos = f pos 14 | go v pos = foldMap (go (v + 1)) next 15 | where next = [ p | p <- ordinalNeighbours pos, Map.lookup p input == Just (v + 1)] 16 | 17 | main :: IO () 18 | main = do 19 | input <- parseAsciiMap (Just . read . pure) <$> readFile "../data/day10.in" 20 | let starts = [ k | (k, 0) <- Map.assocs input ] 21 | print $ sum $ map (Set.size . solve input Set.singleton ) starts 22 | print $ sum $ map (getSum . solve input (const (Sum 1))) starts 23 | 24 | -- 811 25 | -- 1794 26 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day11.hs: -------------------------------------------------------------------------------- 1 | module Day11 where 2 | 3 | import Lib (iterateN, allNums) 4 | import Data.IntMap (IntMap) 5 | import qualified Data.IntMap as IM 6 | 7 | blinkStones :: IntMap Int -> IntMap Int 8 | blinkStones stones = IM.fromListWith (+) $ do 9 | (stone, count) <- IM.assocs stones 10 | (,count) <$> blink stone 11 | 12 | blink :: Int -> [Int] 13 | blink 0 = [1] 14 | blink n 15 | | odd digs = [n * 2024] 16 | | otherwise = [left, right] 17 | where 18 | digs = floor (logBase 10 (fromIntegral n)) + 1 19 | (left, right) = n `divMod` (10^(digs `div` 2)) 20 | 21 | main :: IO () 22 | main = do 23 | input <- IM.fromListWith (+) . map (,1) . allNums <$> readFile "../data/day11.in" 24 | print $ sum $ iterateN 25 blinkStones input 25 | print $ sum $ iterateN 75 blinkStones input 26 | 27 | -- 199946 28 | -- 237994815702032 29 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day12.hs: -------------------------------------------------------------------------------- 1 | module Day12 where 2 | 3 | import Lib (parseAsciiMap, ordinalNeighbours, count) 4 | import Advent.Coord (Coord, north, south, east, west) 5 | import Advent.Search (floodFill) 6 | import Data.Map (Map) 7 | import qualified Data.Map as Map 8 | import Data.Set (Set) 9 | import qualified Data.Set as Set 10 | 11 | gardens :: Map Coord Char -> [Set Coord] 12 | gardens mp = flip floodFill (Map.keysSet mp) $ \key -> 13 | filter ((== key `Map.lookup` mp) . (`Map.lookup` mp)) $ ordinalNeighbours key 14 | 15 | perimeter :: Set Coord -> Int 16 | perimeter mp = foldr f 0 mp 17 | where f k acc = acc + count (`Set.notMember` mp) (ordinalNeighbours k) 18 | 19 | sides :: Set Coord -> Int 20 | sides mp = sum $ map (edges . dirs) [north, south, east, west] 21 | where 22 | dirs dir = Set.filter (\k -> (k + dir) `Set.notMember` mp) mp 23 | edges vals = length $ floodFill (filter (`Set.member` vals) . ordinalNeighbours) vals 24 | 25 | main :: IO () 26 | main = do 27 | input <- parseAsciiMap Just <$> readFile "../data/day12.in" 28 | let solve f = sum . map (\mp -> Set.size mp * f mp) . gardens 29 | print $ solve perimeter input 30 | print $ solve sides input 31 | 32 | -- 1396562 33 | -- 844132 34 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day18.hs: -------------------------------------------------------------------------------- 1 | module Day18 where 2 | 3 | import Lib (binaryMinSearch, allNums, tuple, ordinalNeighbours) 4 | import Advent.Coord (Coord, origin) 5 | import Advent.Search (search) 6 | import Data.Maybe (isNothing, fromJust, listToMaybe) 7 | import Data.Set (Set) 8 | import qualified Data.Set as Set 9 | import Linear (V2(V2)) 10 | 11 | shortestPath :: [Coord] -> Int -> Maybe Int 12 | shortestPath input n = listToMaybe [ l | (l, V2 70 70) <- search go [origin] ] 13 | where 14 | blocks = Set.fromList $ take n input 15 | inside (V2 x y) = x <= 70 && x >= 0 && y <= 70 && y >= 0 16 | go pos = map (1,) . filter inside . filter (`Set.notMember` blocks) $ ordinalNeighbours pos 17 | 18 | main :: IO () 19 | main = do 20 | input <- map (uncurry V2 . tuple . allNums) . lines <$> readFile "../data/day18.in" 21 | print . fromJust $ shortestPath input 1024 22 | let Just firstFailure = binaryMinSearch (isNothing . shortestPath input) 1025 (length input) 23 | putStrLn . (\(V2 x y) -> show x <> "," <> show y) $ input !! (firstFailure - 1) 24 | 25 | -- 344 26 | -- 46,18 27 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day19.hs: -------------------------------------------------------------------------------- 1 | module Day19 where 2 | 3 | import Lib (count) 4 | import Data.List.Extra (splitOn, isPrefixOf, isInfixOf) 5 | import Data.MemoTrie (memo) 6 | 7 | countOptions :: [String] -> String -> Int 8 | countOptions towels design = go design 9 | where 10 | limited = filter (`isInfixOf` design) towels 11 | go = memo $ \case 12 | [] -> 1 13 | xs -> sum $ do 14 | t <- map length $ filter (`isPrefixOf` xs) limited 15 | pure $ go (drop t xs) 16 | 17 | main :: IO () 18 | main = do 19 | (towels, designs) <- parseInput <$> readFile "../data/day19.in" 20 | let result = map (countOptions towels) designs 21 | print $ count (> 0) result 22 | print $ sum result 23 | 24 | parseInput :: String -> ([String], [String]) 25 | parseInput input = (words $ filter (/= ',') top, lines bot) 26 | where [top, bot] = splitOn "\n\n" input 27 | 28 | -- 306 29 | -- 604622004681855 30 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day20.hs: -------------------------------------------------------------------------------- 1 | module Day20 where 2 | 3 | import Lib (parseAsciiMap, count, ordinalNeighbours, mannDist) 4 | import Advent.Coord (Coord) 5 | import Advent.Search (search) 6 | import Control.Monad (guard) 7 | import Data.List.Extra (tails) 8 | import qualified Data.Map as Map 9 | import Data.Set (Set) 10 | import qualified Data.Set as Set 11 | 12 | findCheat :: [(Int, Coord)] -> [Int] 13 | findCheat path = do 14 | (cost, pos) : rest <- tails path 15 | (c, p) <- rest 16 | let md = mannDist pos p 17 | guard $ md <= 20 && c - cost - md >= 100 18 | pure md 19 | 20 | main :: IO () 21 | main = do 22 | (start, mp) <- parseInput <$> readFile "../data/day20.in" 23 | let cheats = findCheat $ search (map (1,) . filter (`Set.member` mp) . ordinalNeighbours) [start] 24 | print $ count (== 2) cheats 25 | print $ length cheats 26 | 27 | parseInput :: String -> (Coord, Set Coord) 28 | parseInput input = (start, Map.keysSet mp) 29 | where 30 | mp = parseAsciiMap f input 31 | start = head [ p | (p, 'S') <- Map.assocs mp ] 32 | f = \case 33 | '#' -> Nothing 34 | any -> Just any 35 | 36 | -- 1507 37 | -- 1037936 38 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day22.hs: -------------------------------------------------------------------------------- 1 | module Day22 where 2 | 3 | import Lib (maximumVal', iterateN, allNums, slidingWindow) 4 | import Data.Map.Strict (Map) 5 | import qualified Data.Map.Strict as Map 6 | import Data.Bits (xor) 7 | 8 | generateSecret :: Int -> Int 9 | generateSecret = gen (* 2048) . gen (`div` 32) . gen (* 64) 10 | where gen f n = (f n `xor` n) `mod` 16777216 11 | 12 | changes :: Int -> Map [Int] Int 13 | changes input = foldr (\(k, v) acc -> Map.insert k v acc) Map.empty 14 | . (`zip` drop 4 xs) 15 | . slidingWindow 4 16 | $ zipWith subtract xs (tail xs) 17 | where 18 | xs = map (`mod` 10) . take 2000 $ iterate generateSecret input 19 | 20 | main :: IO () 21 | main = do 22 | input <- allNums <$> readFile "../data/day22.in" 23 | print $ sum (map (iterateN 2000 generateSecret) input) 24 | let p2 = snd . maximumVal' . foldr (Map.unionWith (+) . changes) Map.empty 25 | print $ p2 input 26 | 27 | -- 19150344884 28 | -- 2121 29 | -------------------------------------------------------------------------------- /2024/Haskell/src/Day25.hs: -------------------------------------------------------------------------------- 1 | module Day25 where 2 | 3 | import Lib (parseAsciiMap, count, (.:)) 4 | import Linear (V2(V2)) 5 | import Advent.Coord (Coord, origin) 6 | import Control.Monad (guard) 7 | import Data.List.Extra (splitOn, partition) 8 | import qualified Data.Map as Map 9 | 10 | heights :: ([Int] -> Int) -> [Coord] -> [Int] 11 | heights comp kl = map f [0..4] 12 | where f col = comp [ y | V2 x y <- kl, x == col ] 13 | 14 | solve :: [[Int]] -> [[Int]] -> Int 15 | solve = count (and . uncurry (zipWith (<))) .: liftA2 (,) 16 | 17 | main :: IO () 18 | main = do 19 | input <- parseInput <$> readFile "../data/day25.in" 20 | let (locks, keys) = input 21 | locks' = map (heights maximum) locks 22 | keys' = map (heights minimum) keys 23 | print $ solve locks' keys' 24 | 25 | parseInput :: String -> ([[Coord]], [[Coord]]) 26 | parseInput = partition (origin `elem`) . map (Map.keys . parseAsciiMap f) . splitOn "\n\n" 27 | where f c = guard (c == '#') *> Just c 28 | 29 | -- 3155 30 | -------------------------------------------------------------------------------- /2024/Haskell/src/gen: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in $(seq -f "%02g" 05 25); do 4 | echo "module Day$i where 5 | 6 | import Lib 7 | import Advent.Coord 8 | import Data.Maybe 9 | import Control.Lens 10 | import Control.Monad 11 | import Control.Monad.State 12 | import Data.List.Extra 13 | import Data.Map (Map) 14 | import qualified Data.Map as Map 15 | import Text.RawString.QQ 16 | import Text.ParserCombinators.Parsec hiding (count) 17 | 18 | part1 input = undefined 19 | 20 | part2 input = undefined 21 | 22 | main :: IO () 23 | main = do 24 | 25 | let run str input = do 26 | putStrLn str 27 | print input 28 | 29 | -- print $ part1 input 30 | -- print $ part2 input 31 | 32 | run \"\nTest:\n\n\" $ parseInput testInput 33 | 34 | -- input <- parseInput <$> readFile \"../data/day$i.in\" 35 | -- run \"\nActual:\n\n\" input 36 | 37 | parseInput = id 38 | 39 | -- parseInput = either (error . show) id . traverse (parse p \"\") . lines 40 | -- where 41 | -- p = undefined 42 | 43 | testInput = [r| 44 | |]" >Day$i.hs 45 | 46 | done 47 | -------------------------------------------------------------------------------- /2024/Haskell/stack.yaml.lock: -------------------------------------------------------------------------------- 1 | # This file was autogenerated by Stack. 2 | # You should not edit this file by hand. 3 | # For more information, please see the documentation at: 4 | # https://docs.haskellstack.org/en/stable/lock_files 5 | 6 | packages: 7 | - completed: 8 | hackage: free-algebras-0.1.1.0@sha256:0fc65b4c1e013c8defbcc093e7910c9f824997d4d88da28f6948c163b6c0a16d,2525 9 | pantry-tree: 10 | sha256: 63b9910795ab0a16e2dadf89eed56215a6fb6e9fea15eb4f303457ea9811602b 11 | size: 1140 12 | original: 13 | hackage: free-algebras-0.1.1.0@sha256:0fc65b4c1e013c8defbcc093e7910c9f824997d4d88da28f6948c163b6c0a16d,2525 14 | - completed: 15 | hackage: process-1.6.18.0@sha256:cd0a3e0376b5a8525983d3131a31e52f9ffefc278ce635eec45a9d3987b8be3e,3025 16 | pantry-tree: 17 | sha256: 3f9fef1f9a6ed1a6923578ada0bc8c16d016344cc67614473384524334463cc2 18 | size: 1675 19 | original: 20 | hackage: process-1.6.18.0@sha256:cd0a3e0376b5a8525983d3131a31e52f9ffefc278ce635eec45a9d3987b8be3e,3025 21 | snapshots: 22 | - completed: 23 | sha256: 08bd13ce621b41a8f5e51456b38d5b46d7783ce114a50ab604d6bbab0d002146 24 | size: 720271 25 | url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/22/43.yaml 26 | original: lts-22.43 27 | -------------------------------------------------------------------------------- /2024/Haskell/test/Spec.hs: -------------------------------------------------------------------------------- 1 | main :: IO () 2 | main = putStrLn "Test suite not yet implemented" 3 | -------------------------------------------------------------------------------- /2024/data/day11.in: -------------------------------------------------------------------------------- 1 | 872027 227 18 9760 0 4 67716 9245696 2 | -------------------------------------------------------------------------------- /2024/data/day17.in: -------------------------------------------------------------------------------- 1 | Register A: 48744869 2 | Register B: 0 3 | Register C: 0 4 | 5 | Program: 2,4,1,2,7,5,1,3,4,4,5,5,0,3,3,0 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Advent of Code 2 | 3 | [Advent of Code Homepage](https://adventofcode.com/) 4 | 5 | This is the main repo for all my solutions. 6 | This was created after solving many problems, files have been moved around, and there is no guarantee that anything will work out of the box. 7 | 8 | Stats: 9 | 10 | - [2024: 50/50](2024) 11 | - [2023: 50/50](2023) 12 | - [2022: 50/50](2022) 13 | - [2021: 50/50](2021) 14 | - [2020: 50/50](2020) 15 | - [2019: 50/50](2019) 16 | - [2018: 50/50](2018) 17 | - [2017: 50/50](2017) 18 | - [2016: 50/50](2016) 19 | - [2015: 50/50](2015) 20 | --------------------------------------------------------------------------------