aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAria <me@aria.rip>2023-01-02 21:58:56 +0000
committerAria <me@aria.rip>2023-01-02 21:58:56 +0000
commit5eb58ad076f2cd435b11b140820da224b60b73d5 (patch)
tree2a67939595fbf993ff04f69b9cd3f0aa20827d96
initial commit
-rw-r--r--2020/.gitignore62
-rw-r--r--2020/01a.hs13
-rw-r--r--2020/01b.hs13
-rw-r--r--2020/02a.hs31
-rw-r--r--2020/02b.hs31
-rw-r--r--2020/03a.hs48
-rw-r--r--2020/03b.hs48
-rw-r--r--2020/04a.hs30
-rw-r--r--2020/04b.hs58
-rw-r--r--2020/05a.hs57
-rw-r--r--2020/05b.hs69
-rw-r--r--2020/06a.hs14
-rw-r--r--2020/06b.hs17
-rw-r--r--2020/07a.hs36
-rw-r--r--2020/07b.hs38
-rw-r--r--2020/08a.hs34
-rw-r--r--2020/08b.hs76
-rw-r--r--2020/09a.hs24
-rw-r--r--2020/09b.hs34
-rw-r--r--2020/10a.hs29
-rw-r--r--2020/10b.hs34
-rw-r--r--2020/11a.hs62
-rw-r--r--2020/11b.hs62
-rw-r--r--2020/12a.hs62
-rw-r--r--2020/12b.hs67
-rw-r--r--2020/13a.hs45
-rw-r--r--2020/13b.hs51
-rw-r--r--2020/14a.hs89
-rw-r--r--2020/14b.hs88
-rw-r--r--2020/15a.hs49
-rw-r--r--2020/15b.hs44
-rw-r--r--2020/16a.hs69
-rw-r--r--2020/16b.hs97
-rw-r--r--2020/17a.hs64
-rw-r--r--2020/17b.hs61
-rw-r--r--2020/18a.hs86
-rw-r--r--2020/18b.hs97
-rw-r--r--2020/19a.hs158
-rw-r--r--2020/19b.hs95
-rw-r--r--2020/1a.hs28
-rw-r--r--2020/1b.hs28
-rw-r--r--2020/20a.hs92
-rw-r--r--2020/20b.hs306
-rw-r--r--2020/21a.hs60
-rw-r--r--2020/21b.hs74
-rw-r--r--2020/22a.hs54
-rw-r--r--2020/22b.hs71
-rw-r--r--2020/23a.hs54
-rw-r--r--2020/23b.hs82
-rw-r--r--2020/24a.hs67
-rw-r--r--2020/24b.hs100
-rw-r--r--2020/25a.hs43
-rw-r--r--2020/LICENSE7
-rw-r--r--2020/README.md3
-rw-r--r--2020/inputs/day1200
-rw-r--r--2020/inputs/day10107
-rw-r--r--2020/inputs/day10_short31
-rw-r--r--2020/inputs/day1197
-rw-r--r--2020/inputs/day11_short10
-rw-r--r--2020/inputs/day12768
-rw-r--r--2020/inputs/day12_short5
-rw-r--r--2020/inputs/day132
-rw-r--r--2020/inputs/day13_short2
-rw-r--r--2020/inputs/day14546
-rw-r--r--2020/inputs/day14_short4
-rw-r--r--2020/inputs/day156
-rw-r--r--2020/inputs/day16265
-rw-r--r--2020/inputs/day16_short12
-rw-r--r--2020/inputs/day178
-rw-r--r--2020/inputs/day17_short3
-rw-r--r--2020/inputs/day18377
-rw-r--r--2020/inputs/day19530
-rw-r--r--2020/inputs/day19_short47
-rw-r--r--2020/inputs/day19b530
-rw-r--r--2020/inputs/day21000
-rw-r--r--2020/inputs/day201727
-rw-r--r--2020/inputs/day20_short107
-rw-r--r--2020/inputs/day2142
-rw-r--r--2020/inputs/day21_short4
-rw-r--r--2020/inputs/day2253
-rw-r--r--2020/inputs/day22_short13
-rw-r--r--2020/inputs/day231
-rw-r--r--2020/inputs/day23_short1
-rw-r--r--2020/inputs/day24403
-rw-r--r--2020/inputs/day24_short20
-rw-r--r--2020/inputs/day252
-rw-r--r--2020/inputs/day25_short2
-rw-r--r--2020/inputs/day3323
-rw-r--r--2020/inputs/day41000
-rw-r--r--2020/inputs/day5932
-rw-r--r--2020/inputs/day62197
-rw-r--r--2020/inputs/day7594
-rw-r--r--2020/inputs/day8634
-rw-r--r--2020/inputs/day8_patch634
-rw-r--r--2020/inputs/day91000
-rw-r--r--2021/.envrc1
-rw-r--r--2021/.gitignore57
-rw-r--r--2021/day1/01a.rkt18
-rw-r--r--2021/day1/01b.rkt23
-rw-r--r--2021/day10/10a.hs50
-rw-r--r--2021/day10/10b.hs66
-rw-r--r--2021/day11/11a.py42
-rw-r--r--2021/day11/11b.py44
-rw-r--r--2021/day12/12a.py34
-rw-r--r--2021/day12/12b.py32
-rw-r--r--2021/day13/13a.hs34
-rw-r--r--2021/day13/13b.hs45
-rw-r--r--2021/day14/14.hs43
-rw-r--r--2021/day15/15a.py63
-rw-r--r--2021/day15/15b.py80
-rw-r--r--2021/day16/16.hs87
-rw-r--r--2021/day17/.gitignore1
-rw-r--r--2021/day17/Cargo.lock42
-rw-r--r--2021/day17/Cargo.toml9
-rw-r--r--2021/day17/src/main.rs90
-rw-r--r--2021/day18/18.py132
-rw-r--r--2021/day19/19.hs108
-rw-r--r--2021/day2/02a.rkt25
-rw-r--r--2021/day2/02b.rkt27
-rw-r--r--2021/day20/20.hs61
-rw-r--r--2021/day21/21.py52
-rw-r--r--2021/day21/21b.py55
-rw-r--r--2021/day22/22a.hs110
-rw-r--r--2021/day22/22b.hs94
-rw-r--r--2021/day23/Setup.hs2
-rw-r--r--2021/day23/app/Main.hs138
-rw-r--r--2021/day23/day23.cabal52
-rw-r--r--2021/day23/package.yaml40
-rw-r--r--2021/day23/src/Lib.hs6
-rw-r--r--2021/day23/stack.yaml68
-rw-r--r--2021/day23/stack.yaml.lock20
-rw-r--r--2021/day24/24_convert.py27
-rw-r--r--2021/day24/24a.mzn117
-rw-r--r--2021/day24/24b.mzn117
-rw-r--r--2021/day25/25a.hs87
-rw-r--r--2021/day3/03a.rkt30
-rw-r--r--2021/day3/03b.rkt35
-rw-r--r--2021/day4/04a-alt.rkt49
-rw-r--r--2021/day4/04b-alt.rkt49
-rw-r--r--2021/day4/04t.rkt9
-rw-r--r--2021/day4/parser.rkt8
-rw-r--r--2021/day4/reader.rkt21
-rw-r--r--2021/day5/05a.rkt36
-rw-r--r--2021/day5/05a_grammar.rkt6
-rw-r--r--2021/day5/05b.rkt39
-rw-r--r--2021/day6/06.clj30
-rw-r--r--2021/day7/07a.clj19
-rw-r--r--2021/day7/07b.clj22
-rw-r--r--2021/day8/08a.clj12
-rw-r--r--2021/day8/08b.clj69
-rw-r--r--2021/day9/09.cpp154
-rw-r--r--2021/shell.nix35
-rw-r--r--2022/.cargo/config.toml2
-rw-r--r--2022/.gitignore6
-rw-r--r--2022/.gitlab-ci.yml26
-rw-r--r--2022/Cargo.lock2078
-rw-r--r--2022/Cargo.toml71
-rw-r--r--2022/fake_inputs/day14148
-rw-r--r--2022/fake_inputs/day92000
-rw-r--r--2022/flake.lock147
-rw-r--r--2022/flake.nix72
-rw-r--r--2022/src/day01.rs21
-rw-r--r--2022/src/day02.rs105
-rw-r--r--2022/src/day03.rs62
-rw-r--r--2022/src/day04.rs35
-rw-r--r--2022/src/day05.rs145
-rw-r--r--2022/src/day06.rs47
-rw-r--r--2022/src/day07.rs110
-rw-r--r--2022/src/day08.rs110
-rw-r--r--2022/src/day09.html38
-rw-r--r--2022/src/day09.rs238
-rw-r--r--2022/src/day10.rs82
-rw-r--r--2022/src/day11.rs127
-rw-r--r--2022/src/day12.rs141
-rw-r--r--2022/src/day13.rs132
-rw-r--r--2022/src/day14.html38
-rw-r--r--2022/src/day14.rs230
-rw-r--r--2022/src/utils.rs59
178 files changed, 26542 insertions, 0 deletions
diff --git a/2020/.gitignore b/2020/.gitignore
new file mode 100644
index 0000000..0bc021e
--- /dev/null
+++ b/2020/.gitignore
@@ -0,0 +1,62 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/haskell,sublimetext
+# Edit at https://www.toptal.com/developers/gitignore?templates=haskell,sublimetext
+
+### Haskell ###
+dist
+dist-*
+cabal-dev
+*.o
+*.hi
+*.hie
+*.chi
+*.chs.h
+*.dyn_o
+*.dyn_hi
+.hpc
+.hsenv
+.cabal-sandbox/
+cabal.sandbox.config
+*.prof
+*.aux
+*.hp
+*.eventlog
+.stack-work/
+cabal.project.local
+cabal.project.local~
+.HTF/
+.ghc.environment.*
+
+### SublimeText ###
+# Cache files for Sublime Text
+*.tmlanguage.cache
+*.tmPreferences.cache
+*.stTheme.cache
+
+# Workspace files are user-specific
+*.sublime-workspace
+
+# Project files should be checked into the repository, unless a significant
+# proportion of contributors will probably not be using Sublime Text
+# *.sublime-project
+
+# SFTP configuration file
+sftp-config.json
+
+# Package control specific files
+Package Control.last-run
+Package Control.ca-list
+Package Control.ca-bundle
+Package Control.system-ca-bundle
+Package Control.cache/
+Package Control.ca-certs/
+Package Control.merged-ca-bundle
+Package Control.user-ca-bundle
+oscrypto-ca-bundle.crt
+bh_unicode_properties.cache
+
+# Sublime-github package stores a github token in this file
+# https://packagecontrol.io/packages/sublime-github
+GitHub.sublime-settings
+
+# End of https://www.toptal.com/developers/gitignore/api/haskell,sublimetext
diff --git a/2020/01a.hs b/2020/01a.hs
new file mode 100644
index 0000000..1c72ecc
--- /dev/null
+++ b/2020/01a.hs
@@ -0,0 +1,13 @@
+module Day1A where
+
+import System.Environment (getArgs)
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ c <- readFile $ head args;
+ let ns = map read $ lines c;
+
+ print $ head [a * b | a <- ns, b <- ns, a + b == 2020];
+
+ return (); \ No newline at end of file
diff --git a/2020/01b.hs b/2020/01b.hs
new file mode 100644
index 0000000..17d6e02
--- /dev/null
+++ b/2020/01b.hs
@@ -0,0 +1,13 @@
+module Day1B where
+
+import System.Environment (getArgs)
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ c <- readFile $ head args;
+ let ns = map read $ lines c;
+
+ print $ head [a * b * c| a <- ns, b <- ns, c <- ns, a + b + c == 2020];
+
+ return (); \ No newline at end of file
diff --git a/2020/02a.hs b/2020/02a.hs
new file mode 100644
index 0000000..3671403
--- /dev/null
+++ b/2020/02a.hs
@@ -0,0 +1,31 @@
+module Day2 where
+
+import Data.List.Split (splitOn)
+import Text.Read (readMaybe)
+import System.Environment (getArgs)
+
+valid :: (Int, Int) -> Char -> String -> Bool
+valid (lo, hi) c s = len >= lo && len <= hi
+ where len = length (filter (== c) s)
+
+parseHeader :: String -> (Int, Int, Char)
+parseHeader s = (lo, hi, c)
+ where [range, (c:_)] = splitOn " " s
+ [lo, hi] = map read $ splitOn "-" range
+
+lineValid :: String -> Bool
+lineValid s = valid (lo, hi) c pass
+ where [header, pass] = splitOn ": " s
+ (lo, hi, c) = parseHeader header
+
+-- Usage: runghc --ghc-arg="-package split" 2a.hs inputs/day2
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let nums = filter lineValid l
+
+ putStrLn $ show $ length nums;
+
+ return (); \ No newline at end of file
diff --git a/2020/02b.hs b/2020/02b.hs
new file mode 100644
index 0000000..5754fe0
--- /dev/null
+++ b/2020/02b.hs
@@ -0,0 +1,31 @@
+module Day2 where
+
+import Data.List.NonEmpty (xor, fromList)
+import Data.List.Split (splitOn)
+import Text.Read (readMaybe)
+import System.Environment (getArgs)
+
+valid :: (Int, Int) -> Char -> String -> Bool
+valid (lo, hi) c s = xor $ fromList [s!!lo == c, s!!hi == c]
+
+parseHeader :: String -> (Int, Int, Char)
+parseHeader s = (lo, hi, c)
+ where [range, (c:_)] = splitOn " " s
+ [lo, hi] = map (\x -> x - 1) $ map read $ splitOn "-" range
+
+lineValid :: String -> Bool
+lineValid s = valid (lo, hi) c pass
+ where [header, pass] = splitOn ": " s
+ (lo, hi, c) = parseHeader header
+
+-- Usage: runghc --ghc-arg="-package split" 2b.hs inputs/day2
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let nums = filter lineValid l
+
+ putStrLn $ show $ length nums;
+
+ return ();
diff --git a/2020/03a.hs b/2020/03a.hs
new file mode 100644
index 0000000..a2438b7
--- /dev/null
+++ b/2020/03a.hs
@@ -0,0 +1,48 @@
+module Day3 where
+
+import System.Environment (getArgs)
+
+data Square = Empty | Tree
+ deriving (Eq, Ord, Show)
+
+type Map = [[Square]]
+
+-- Converts lines to a map
+toMap :: [String] -> Map
+toMap = map toRow
+ where toRow = map toSquare
+ toSquare '.' = Empty
+ toSquare '#' = Tree
+ toSquare _ = error "Invalid map character"
+
+-- Get the size of a map
+-- Note this returns (height, width)
+getSize :: Map -> (Int, Int)
+getSize m = (length m, length (head m))
+
+-- Get the square at the given (y, x) coord
+-- This wraps the x coord, but not the y
+get :: Map -> Int -> Int -> Square
+get m y x = m!!y!!(x `mod` w)
+ where (_, w) = getSize m
+
+-- Get the squares encountered along a slop, starting at (y, x)
+-- and descending along (f, r)
+getSquaresAlongSlope :: Map -> Int -> Int -> Int -> Int -> [Square]
+getSquaresAlongSlope m y x f r | y >= h = []
+ | otherwise = get m y x : getSquaresAlongSlope m (y + f) (x + r) f r
+ where (h, _) = getSize m
+
+-- Count the number of trees along a given slope, starting at (0, 0)
+checkSlope :: Map -> Int -> Int -> Int
+checkSlope m f r = length $ filter (== Tree) $ getSquaresAlongSlope m 0 0 f r
+
+-- Usage: ./3a inputs/day3
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let m = toMap l;
+ print $ checkSlope m 1 3
+ return () \ No newline at end of file
diff --git a/2020/03b.hs b/2020/03b.hs
new file mode 100644
index 0000000..43e7ba2
--- /dev/null
+++ b/2020/03b.hs
@@ -0,0 +1,48 @@
+module Day3 where
+
+import System.Environment (getArgs)
+
+data Square = Empty | Tree
+ deriving (Eq, Ord, Show)
+
+type Map = [[Square]]
+
+-- Converts lines to a map
+toMap :: [String] -> Map
+toMap = map toRow
+ where toRow = map toSquare
+ toSquare '.' = Empty
+ toSquare '#' = Tree
+ toSquare _ = error "Invalid map character"
+
+-- Get the size of a map
+-- Note this returns (height, width)
+getSize :: Map -> (Int, Int)
+getSize m = (length m, length (head m))
+
+-- Get the square at the given (y, x) coord
+-- This wraps the x coord, but not the y
+get :: Map -> Int -> Int -> Square
+get m y x = m!!y!!(x `mod` w)
+ where (_, w) = getSize m
+
+-- Get the squares encountered along a slop, starting at (y, x)
+-- and descending along (f, r)
+getSquaresAlongSlope :: Map -> Int -> Int -> Int -> Int -> [Square]
+getSquaresAlongSlope m y x f r | y >= h = []
+ | otherwise = get m y x : getSquaresAlongSlope m (y + f) (x + r) f r
+ where (h, _) = getSize m
+
+-- Count the number of trees along a given slope, starting at (0, 0)
+checkSlope :: Map -> Int -> Int -> Int
+checkSlope m f r = length $ filter (== Tree) $ getSquaresAlongSlope m 0 0 f r
+
+-- Usage: ./3b inputs/day3
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let m = toMap l;
+ print $ product $ map (uncurry $ checkSlope m) [(1, 1), (1, 3), (1, 5), (1, 7), (2, 1)]
+ return () \ No newline at end of file
diff --git a/2020/04a.hs b/2020/04a.hs
new file mode 100644
index 0000000..09dd5c3
--- /dev/null
+++ b/2020/04a.hs
@@ -0,0 +1,30 @@
+module Day4a where
+
+import System.Environment (getArgs)
+import Data.List.Split (splitOn)
+
+-- Split a passport declaration into k:v declarations
+getDeclarations :: String -> [String]
+getDeclarations xs = concat [splitOn "\n" y | y <- splitOn " " xs]
+
+-- Split a passport declaration into tuples of (key, value)
+getTuples :: String -> [(String, String)]
+getTuples xs = [(head x, x!!1) | x <- map (splitOn ":") $ getDeclarations xs]
+
+-- Check a passport is valid
+passportValid :: String -> Bool
+passportValid xs = and [r `elem` map fst tups | r <- reqs]
+ where tups = getTuples xs
+ reqs = ["byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid"]
+
+-- Usage: runghc --ghc-arg="-package split" 4a.hs inputs/day4
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+
+ let ps = splitOn "\n\n" content;
+ let valid = filter passportValid ps;
+
+ print $ length valid;
+ return (); \ No newline at end of file
diff --git a/2020/04b.hs b/2020/04b.hs
new file mode 100644
index 0000000..0a15431
--- /dev/null
+++ b/2020/04b.hs
@@ -0,0 +1,58 @@
+module Day4a where
+
+import System.Environment (getArgs)
+import Data.List.Split (splitOn)
+
+-- Split a passport declaration into k:v declarations
+getDeclarations :: String -> [String]
+getDeclarations xs = concat [splitOn "\n" y | y <- splitOn " " xs]
+
+-- Split a passport declaration into tuples of (key, value)
+getTuples :: String -> [(String, String)]
+getTuples xs = [(head x, x!!1) | x <- map (splitOn ":") $ getDeclarations xs]
+
+-- Check a passport is valid
+passportValid :: String -> Bool
+passportValid xs = and [r `elem` map fst tups | (r, _) <- reqs] && -- Contains all required fields
+ and [f v | (k, v) <- tups, (t, f) <- reqs, t == k] -- Passes validation rules
+ where tups = getTuples xs
+ reqs = [("byr", numberValid 4 1920 2002),
+ ("iyr", numberValid 4 2010 2020),
+ ("eyr", numberValid 4 2020 2030),
+ ("hgt", heightValid),
+ ("hcl", hexClValid),
+ ("ecl", enumValid ["amb", "blu", "brn", "gry", "grn", "hzl", "oth"]),
+ ("pid", numberValid 9 0 999999999)]
+
+-- Validation functions
+
+-- digits, low, high, value
+numberValid :: Int -> Int -> Int -> String -> Bool
+(numberValid d l h) x = length x == d && val >= l && val <= h
+ where val = read x
+
+heightValid :: String -> Bool
+heightValid x | u == "cm" = v >= 150 && v <= 193
+ | u == "in" = v >= 59 && v <= 76
+ | otherwise = False
+ where u = drop (length x - 2) x
+ v = read $ take (length x - 2) x :: Int
+
+enumValid :: [String] -> String -> Bool
+(enumValid e) x = x `elem` e
+
+hexClValid :: String -> Bool
+hexClValid ('#':ds) = and [x `elem` "abcdef0123456789" | x <- ds] && length ds == 6
+hexClValid _ = False
+
+-- Usage: runghc --ghc-arg="-package split" 4b.hs inputs/day4
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+
+ let ps = splitOn "\n\n" content;
+ let valid = filter passportValid ps;
+
+ print $ length valid;
+ return (); \ No newline at end of file
diff --git a/2020/05a.hs b/2020/05a.hs
new file mode 100644
index 0000000..e22239c
--- /dev/null
+++ b/2020/05a.hs
@@ -0,0 +1,57 @@
+module Day5A where
+
+import System.Environment (getArgs)
+
+data Keymap k a = Leaf k a
+ | Node k (Keymap k a) (Keymap k a)
+ deriving (Eq, Show)
+
+type SeatingPlan = Keymap Int (Keymap Int Bool)
+
+data Step = Bigger | Smaller
+
+setFromSteps :: Ord k => [Step] -> a -> Keymap k a -> Keymap k a
+setFromSteps [] v (Leaf k _) = Leaf k v
+setFromSteps (Bigger:xs) v (Node k l r) = Node k l (setFromSteps xs v r)
+setFromSteps (Smaller:xs) v (Node k l r) = Node k (setFromSteps xs v l) r
+
+performSteps :: Ord k => [Step] -> Keymap k a -> Keymap k a
+performSteps _ k@(Leaf _ _) = k
+performSteps [] k = k
+performSteps (Bigger:xs) (Node _ _ r) = performSteps xs r
+performSteps (Smaller:xs) (Node _ l _) = performSteps xs l
+
+fromList :: Ord k => [(k,a)] -> Keymap k a
+fromList ((k, v):[]) = Leaf k v
+fromList xs = Node k (fromList (take pivot xs)) (fromList (drop pivot xs))
+ where pivot = length xs `div` 2
+ (k, _) = xs!!pivot
+
+constructPlan :: Int -> Int -> SeatingPlan
+constructPlan rows cols = fromList [(i, fromList $ zip [0..cols - 1] (replicate cols False)) | i <- [0..rows - 1]]
+
+toSteps :: String -> [Step]
+toSteps "" = []
+toSteps ('B':xs) = Bigger : toSteps xs
+toSteps ('R':xs) = Bigger : toSteps xs
+toSteps ('F':xs) = Smaller : toSteps xs
+toSteps ('L':xs) = Smaller : toSteps xs
+
+toSeatId :: Int -> Int -> Int
+toSeatId r c = (r * 8) + c
+
+passToSeatId :: SeatingPlan -> String -> Int
+passToSeatId k s = toSeatId r c
+ where steps = toSteps s
+ (Leaf r col) = performSteps (take 7 steps) k
+ (Leaf c _) = performSteps (drop 7 steps) col
+
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let p = constructPlan 128 8
+ let ids = map (passToSeatId p) l;
+ print $ maximum ids; \ No newline at end of file
diff --git a/2020/05b.hs b/2020/05b.hs
new file mode 100644
index 0000000..efe26bb
--- /dev/null
+++ b/2020/05b.hs
@@ -0,0 +1,69 @@
+module Day5B where
+
+import System.Environment (getArgs)
+
+data Keymap k a = Leaf k a
+ | Node k (Keymap k a) (Keymap k a)
+ deriving (Eq, Show)
+
+type SeatingPlan = Keymap Int (Keymap Int Bool)
+
+data Step = Bigger | Smaller
+
+setFromSteps :: Ord k => [Step] -> a -> Keymap k a -> Keymap k a
+setFromSteps [] v (Leaf k _) = Leaf k v
+setFromSteps (Bigger:xs) v (Node k l r) = Node k l (setFromSteps xs v r)
+setFromSteps (Smaller:xs) v (Node k l r) = Node k (setFromSteps xs v l) r
+
+performSteps :: Ord k => [Step] -> Keymap k a -> Keymap k a
+performSteps _ k@(Leaf _ _) = k
+performSteps [] k = k
+performSteps (Bigger:xs) (Node _ _ r) = performSteps xs r
+performSteps (Smaller:xs) (Node _ l _) = performSteps xs l
+
+fromList :: Ord k => [(k,a)] -> Keymap k a
+fromList ((k, v):[]) = Leaf k v
+fromList xs = Node k (fromList (take pivot xs)) (fromList (drop pivot xs))
+ where pivot = length xs `div` 2
+ (k, _) = xs!!pivot
+
+toList :: Ord k => Keymap k a -> [(k, a)]
+toList (Leaf k v) = [(k, v)]
+toList (Node _ l r) = toList l ++ toList r
+
+constructPlan :: Int -> Int -> SeatingPlan
+constructPlan rows cols = fromList [(i, fromList $ zip [0..cols - 1] (replicate cols False)) | i <- [0..rows - 1]]
+
+toSteps :: String -> [Step]
+toSteps "" = []
+toSteps ('B':xs) = Bigger : toSteps xs
+toSteps ('R':xs) = Bigger : toSteps xs
+toSteps ('F':xs) = Smaller : toSteps xs
+toSteps ('L':xs) = Smaller : toSteps xs
+
+toSeatId :: Int -> Int -> Int
+toSeatId r c = (r * 8) + c
+
+setPassOccupied :: String -> SeatingPlan -> SeatingPlan
+setPassOccupied s k = setFromSteps (take 7 steps) col' k
+ where steps = toSteps s
+ (Leaf _ col) = performSteps (take 7 steps) k
+ col' = setFromSteps (drop 7 steps) True col
+
+kmFilter :: Ord k => (a -> Bool) -> Keymap k a -> [(k, a)]
+kmFilter f (Leaf k v) | f v = [(k, v)]
+ | otherwise = []
+kmFilter f (Node _ l r) = kmFilter f l ++ kmFilter f r
+
+filterUnoccupied :: SeatingPlan -> [(Int, Int)]
+filterUnoccupied k = [(r,c) | (r, col) <- toList k, (c, occupied) <- toList col, not occupied]
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let p = constructPlan 128 8;
+ let full = foldr setPassOccupied p l;
+
+ print $ filterUnoccupied full;
diff --git a/2020/06a.hs b/2020/06a.hs
new file mode 100644
index 0000000..33647ed
--- /dev/null
+++ b/2020/06a.hs
@@ -0,0 +1,14 @@
+module Day6A where
+
+import Data.List (delete, nub)
+import Data.List.Split (splitOn)
+import System.Environment (getArgs)
+
+-- Usage: runghc --ghc-arg="-package split" 6a.hs inputs/day6
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+
+ print $ sum $ map (length . delete '\n' . nub) $ splitOn "\n\n" content;
+ return (); \ No newline at end of file
diff --git a/2020/06b.hs b/2020/06b.hs
new file mode 100644
index 0000000..2cf3f03
--- /dev/null
+++ b/2020/06b.hs
@@ -0,0 +1,17 @@
+module Day6B where
+
+import Data.List (nub)
+import Data.List.Split (splitOn)
+import System.Environment (getArgs)
+
+sharedElems :: [String] -> [Char]
+sharedElems xs = filter (\x -> all (x `elem`) xs) (nub $ concat xs)
+
+-- Usage: runghc --ghc-arg="-package split" 6b.hs inputs/day6
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+
+ print $ sum $ map (length . sharedElems . lines) $ splitOn "\n\n" content;
+ return (); \ No newline at end of file
diff --git a/2020/07a.hs b/2020/07a.hs
new file mode 100644
index 0000000..32c4aaf
--- /dev/null
+++ b/2020/07a.hs
@@ -0,0 +1,36 @@
+module Day7A where
+
+import System.Environment (getArgs)
+import Text.Regex.PCRE
+
+type Rule = (String, [(Int, String)])
+
+parseRule :: String -> Rule
+parseRule xs = (parent, children)
+ where parentMatch = xs =~ "^([a-z ]*) bag" :: [[String]]
+ parent = head parentMatch!!1
+ childrenMatch = xs =~ "([0-9]+) ([a-z ]*) bag" :: [[String]]
+ childrenNs = map (read . (!! 1)) childrenMatch
+ childrenNames = map (!! 2) childrenMatch
+ children = zip childrenNs childrenNames
+
+-- Keep applying f to a until the output stops changing
+untilUnchanged :: Eq a => (a -> a) -> a -> a
+untilUnchanged f a | n /= a = untilUnchanged f n
+ | otherwise = n
+ where n = f a
+
+-- Add the bags that can contain these bags to the list
+addParents :: [Rule] -> [String] -> [String]
+addParents rs xs = map fst $ filter (\(n, cs) -> n `elem` xs || any (`elem` map snd cs) xs) rs
+
+-- Usage: runghc --ghc-arg="-package regex-pcre-builtin" 7a.hs inputs/day7
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let rules = map parseRule $ lines content;
+ let topLevels = untilUnchanged (addParents rules) ["shiny gold"]
+ print topLevels;
+ print $ length topLevels - 1;
+ return (); \ No newline at end of file
diff --git a/2020/07b.hs b/2020/07b.hs
new file mode 100644
index 0000000..d703295
--- /dev/null
+++ b/2020/07b.hs
@@ -0,0 +1,38 @@
+module Day7A where
+
+import System.Environment (getArgs)
+import Text.Regex.PCRE
+
+type Rule = (String, [(Int, String)])
+
+parseRule :: String -> Rule
+parseRule xs = (parent, children)
+ where parentMatch = xs =~ "^([a-z ]*?) bag" :: [[String]]
+ parent = head parentMatch!!1
+ childrenMatch = xs =~ "([0-9]+) ([a-z ]*) bag" :: [[String]]
+ childrenNs = map (read . (!! 1)) childrenMatch
+ childrenNames = map (!! 2) childrenMatch
+ children = zip childrenNs childrenNames
+
+-- Keep applying f to a until the output stops changing
+untilUnchanged :: Eq a => (a -> a) -> a -> a
+untilUnchanged f a | n /= a = untilUnchanged f n
+ | otherwise = n
+ where n = f a
+
+ruleFor :: String -> [Rule] -> Rule
+-- ruleFor x rs | null r = (x, [])
+-- | otherwise = head r
+-- where r = filter ((== x) . fst) rs
+ruleFor x = head . filter ((== x) . fst)
+
+nBags :: [Rule] -> String -> Int
+nBags rs x = 1 + sum [n * nBags rs c | (n, c) <- snd $ ruleFor x rs]
+
+-- Usage: runghc --ghc-arg="-package regex-pcre-builtin" 7a.hs inputs/day7
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let rules = map parseRule $ lines content;
+ print $ nBags rules "shiny gold" - 1;
diff --git a/2020/08a.hs b/2020/08a.hs
new file mode 100644
index 0000000..846c3df
--- /dev/null
+++ b/2020/08a.hs
@@ -0,0 +1,34 @@
+module Day8A where
+
+import System.Environment (getArgs)
+
+data Instruction = Nop | Acc Int | Jmp Int
+ deriving (Eq, Show, Ord)
+
+readSigned :: String -> Int
+readSigned ('+':xs) = read xs
+readSigned xs = read xs
+
+parseInstruction :: String -> Instruction
+parseInstruction xs | ins == "nop" = Nop
+ | ins == "acc" = Acc num
+ | ins == "jmp" = Jmp num
+ where ins = take 3 xs
+ num = readSigned $ drop 4 xs
+
+execUntilLoop :: [Instruction] -> [Int] -> Int -> Int -> Int
+execUntilLoop is vs ip ax | ip `elem` vs = ax
+ | otherwise = case ins of Nop -> execUntilLoop is vs' (ip + 1) ax
+ Acc x -> execUntilLoop is vs' (ip + 1) (ax + x)
+ Jmp x -> execUntilLoop is vs' (ip + x) ax
+ where ins = is!!ip
+ vs' = ip : vs
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let is = map parseInstruction l;
+ print $ execUntilLoop is [] 0 0;
+ return (); \ No newline at end of file
diff --git a/2020/08b.hs b/2020/08b.hs
new file mode 100644
index 0000000..5740e60
--- /dev/null
+++ b/2020/08b.hs
@@ -0,0 +1,76 @@
+module Day8A where
+
+import System.Environment (getArgs)
+import Data.List (nub)
+
+data Instruction = Nop Int | Acc Int | Jmp Int | Dead
+ deriving (Eq, Show, Ord)
+
+readSigned :: String -> Int
+readSigned ('+':xs) = read xs
+readSigned xs = read xs
+
+parseInstruction :: String -> Instruction
+parseInstruction xs | ins == "nop" = Nop num
+ | ins == "acc" = Acc num
+ | ins == "jmp" = Jmp num
+ where ins = take 3 xs
+ num = readSigned $ drop 4 xs
+
+-- (ip, ax). Runs until infinite loop or end of program.
+getTrace :: [Instruction] -> [(Int, Int)] -> Int -> Int -> [(Int, Int)]
+getTrace is ts ip ax | ip `elem` (map fst ts) || ip >= length (is) = ts
+ | otherwise = case ins of Nop _ -> getTrace is (ts ++ [(ip, ax)]) (ip + 1) ax
+ Acc x -> getTrace is (ts ++ [(ip, ax + x)]) (ip + 1) (ax + x)
+ Jmp x -> getTrace is (ts ++ [(ip, ax)]) (ip + x) ax
+ where ins = is!!ip
+
+-- Get by how much this instruction changes ip
+delta :: Instruction -> Int
+delta (Nop _) = 1
+delta (Acc _) = 1
+delta (Jmp x) = x
+delta Dead = 9999999999
+
+-- Flip this instruction, then get by how much ip changes.
+deltaFlip :: Instruction -> Int
+deltaFlip (Nop x) = x
+deltaFlip (Acc _) = 1
+deltaFlip (Jmp x) = 1
+deltaFlip Dead = 999999999
+
+-- A reference to an instruction, either unchanged or flipped (Nop <-> Jmp)
+data InstructionRef = Idx Int | Flipped Int
+ deriving (Show, Eq, Ord)
+
+-- Get all the ways to reach t from instruction set is. If s is set, allow one 'flip' per chain.
+potentialTraces :: [Instruction] -> Int -> Bool -> [[InstructionRef]]
+potentialTraces _ 0 _ = [[]] -- We start here
+potentialTraces is t s | s = unswappedPaths ++
+ concat [map ([Flipped i] ++) $ potentialTraces (kill is i) i False | (i, x) <- isi, (i + deltaFlip x) == t]
+ | otherwise = unswappedPaths
+ where isi = zip [0..] is
+ kill xs i = take i xs ++ [Dead] ++ drop (i + 1) xs
+ unswappedPaths = concat [map ([Idx i] ++) $ potentialTraces (kill is i) i s | (i, x) <- isi, (i + delta x) == t]
+
+-- Parse instructions from a file
+insFromFile :: String -> IO [Instruction]
+insFromFile n = do
+ c <- readFile n
+ return $ map parseInstruction $ lines c;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ is <- insFromFile $ head args;
+
+ -- Print out the full trace
+ let trace = getTrace is [] 0 0;
+ putStrLn "<<>> = 0";
+ putStr $ unlines $ map (\(i,x) -> show i ++ ": " ++ show (is!!i) ++ " --> " ++ show x) trace;
+
+ if (fst $ last trace) /= (length is - 1) then
+ -- Print out all the ways to get to the end, potentially swapping (once)
+ print $ nub $ potentialTraces is (length is) True
+ else
+ return ();
diff --git a/2020/09a.hs b/2020/09a.hs
new file mode 100644
index 0000000..4ee18f2
--- /dev/null
+++ b/2020/09a.hs
@@ -0,0 +1,24 @@
+module Day9A where
+
+import System.Environment (getArgs)
+
+potentialSum :: [Int] -> Int -> [(Int, Int)]
+potentialSum xs t = filter ((== t) . uncurry (+)) [(x, y) | x <- xs, y <- xs, x /= y]
+
+mapSumPrev :: [Int] -> Int -> [[(Int, Int)]]
+mapSumPrev xs l = [potentialSum (take l $ drop (i - l) xs) v | (i, v) <- zip [25..] (drop l xs)]
+
+numsFromFile :: String -> IO [Int]
+numsFromFile p = do
+ c <- readFile p;
+ return $ map read $ lines c;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ xs <- numsFromFile $ head args;
+
+ let unob = head $ filter (null . fst) $ zip (mapSumPrev xs 25) [25..];
+ let unob_n = xs !! snd unob;
+ putStrLn $ "No way to sum up to " ++ show unob_n;
+ return ();
diff --git a/2020/09b.hs b/2020/09b.hs
new file mode 100644
index 0000000..a643b29
--- /dev/null
+++ b/2020/09b.hs
@@ -0,0 +1,34 @@
+module Day9B where
+
+import System.Environment (getArgs)
+
+potentialSum :: [Int] -> Int -> [(Int, Int)]
+potentialSum xs t = filter ((== t) . uncurry (+)) [(x, y) | x <- xs, y <- xs, x /= y]
+
+mapSumPrev :: [Int] -> Int -> [[(Int, Int)]]
+mapSumPrev xs l = [potentialSum (take l $ drop (i - l) xs) v | (i, v) <- zip [25..] (drop l xs)]
+
+rangesSummingTo :: [Int] -> Int -> [[Int]]
+rangesSummingTo [] _ = []
+rangesSummingTo xs t = filter ((== t) . sum) $ map (`take` xs) [1..length xs]
+ ++ rangesSummingTo (drop 1 xs) t
+
+numsFromFile :: String -> IO [Int]
+numsFromFile p = do
+ c <- readFile p;
+ return $ map read $ lines c;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ xs <- numsFromFile $ head args;
+
+ let unob = head $ filter (null . fst) $ zip (mapSumPrev xs 25) [25..];
+ let unob_n = xs !! snd unob;
+ putStrLn $ "No way to sum up to " ++ show unob_n;
+
+ let rs = head $ rangesSummingTo xs unob_n;
+ print rs;
+
+ putStrLn $ "Smallest + Largest = " ++ show (minimum rs + maximum rs);
+ return ();
diff --git a/2020/10a.hs b/2020/10a.hs
new file mode 100644
index 0000000..5df6941
--- /dev/null
+++ b/2020/10a.hs
@@ -0,0 +1,29 @@
+module Day10A where
+
+import System.Environment (getArgs)
+import Data.List (sort)
+
+-- Get the longest chain of adapters possible
+getJoltsChain :: [Int] -> [Int]
+getJoltsChain ss = xs ++ [last xs + 3]
+ where xs = sort ss
+
+-- Read a line-seperated file of numbers
+numsFromFile :: String -> IO [Int]
+numsFromFile p = do
+ c <- readFile p;
+ return $ map read $ lines c;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ xs <- numsFromFile $ head args;
+
+ let chain = 0 : getJoltsChain xs;
+
+ let diffs = zipWith (-) chain (drop 1 chain);
+ let diff3s = length $ filter (== -3) diffs;
+ let diff1s = length $ filter (== -1) diffs;
+
+ print $ diff1s * diff3s;
+ return ();
diff --git a/2020/10b.hs b/2020/10b.hs
new file mode 100644
index 0000000..e6851f6
--- /dev/null
+++ b/2020/10b.hs
@@ -0,0 +1,34 @@
+module Main where
+
+import System.Environment (getArgs)
+import Data.List (sort)
+import qualified Data.IntMap.Strict as M
+
+-- Delete elements from a list until element t is encountered
+deleteUntil :: Eq a => [a] -> a -> [a]
+deleteUntil [] _ = []
+deleteUntil (x:xs) t | x == t = xs
+ | otherwise = deleteUntil xs t
+
+-- Get the number of posisble valid permutations of a list of adapters
+possiblePerms :: [Int] -> M.IntMap Int
+possiblePerms ss = foldl addToMap (M.fromList [(0, 1)]) (sort ss ++ [end])
+ where getChildren x m = [k | k <- [x-3..x-1], k `M.member` m]
+ end = maximum ss + 3
+ addToMap m x = M.insert x (sum $ map (m M.!) (getChildren x m)) m
+
+
+-- Read a line-seperated file of numbers
+numsFromFile :: String -> IO [Int]
+numsFromFile p = do
+ c <- readFile p;
+ return $ map read $ lines c;
+
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ xs <- numsFromFile $ head args;
+
+ print $ possiblePerms xs;
+ return ();
diff --git a/2020/11a.hs b/2020/11a.hs
new file mode 100644
index 0000000..f6a4e9d
--- /dev/null
+++ b/2020/11a.hs
@@ -0,0 +1,62 @@
+module Day11A where
+
+import System.Environment (getArgs)
+
+-- Type declarations
+type AreaMap = [[Space]];
+data Space = Occupied | Empty | Floor
+ deriving (Show, Eq, Ord);
+
+
+-- Keep applying f to a until the output stops changing
+untilUnchanged :: Eq a => (a -> a) -> a -> a
+untilUnchanged f a | n /= a = untilUnchanged f n
+ | otherwise = n
+ where n = f a
+
+-- Get the space at x, y, or floor if it's out of bounds
+idxOrFloor :: AreaMap -> Int -> Int -> Space
+idxOrFloor ss x y | x >= length (head ss) || y >= length ss || x < 0 || y < 0 = Floor
+ | otherwise = ss!!y!!x
+
+-- Get spaces adjacent to (x, y), including diagonals
+adjSpaces :: AreaMap -> (Int, Int) -> [Space]
+adjSpaces a (x, y) = [idxOrFloor a x' y' | x' <- [x-1..x+1], y' <- [y-1..y+1], x' /= x || y' /= y]
+
+-- Mutate a space given its current state and its adjacent spaces
+mutateSpace :: Space -> [Space] -> Space
+mutateSpace Empty adj | Occupied `notElem` adj = Occupied
+ | otherwise = Empty
+mutateSpace Occupied adj | length (filter (== Occupied) adj) >= 4 = Empty
+ | otherwise = Occupied
+mutateSpace x _ = x
+
+-- Mutate all spaces on the map
+mutateAll :: AreaMap -> AreaMap
+mutateAll rs = [[mutateSpace s (adjSpaces rs (c, r)) | (c, s) <- zip [0..] ss] | (r, ss) <- zip [0..] rs]
+
+-- Read a map in from its string representation
+readMap :: String -> AreaMap
+readMap = map readLine . lines
+ where readLine [] = []
+ readLine ('.':xs) = Floor : readLine xs
+ readLine ('L':xs) = Empty : readLine xs
+ readLine ('#':xs) = Occupied : readLine xs
+ readLine _ = error "Invalid character passed to readMap"
+
+-- Read a map from the filename
+mapFromFile :: String -> IO AreaMap
+mapFromFile s = do
+ contents <- readFile s;
+ return $ readMap contents;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ m <- mapFromFile (head args);
+
+ let final = untilUnchanged mutateAll m;
+ let occ = sum $ map (length . filter (== Occupied)) final;
+
+ putStrLn $ "Occupied Seats: " ++ show occ;
+ return ();
diff --git a/2020/11b.hs b/2020/11b.hs
new file mode 100644
index 0000000..75f4bda
--- /dev/null
+++ b/2020/11b.hs
@@ -0,0 +1,62 @@
+module Day11B where
+
+import System.Environment (getArgs)
+
+type AreaMap = [[Space]];
+data Space = Occupied | Empty | Floor
+ deriving (Show, Eq, Ord);
+
+
+-- Keep applying f to a until the output stops changing
+untilUnchanged :: Eq a => (a -> a) -> a -> a
+untilUnchanged f a | n /= a = untilUnchanged f n
+ | otherwise = n
+ where n = f a
+
+-- Find if an occupied seat is visible from (x,y) looking along (dx, dy)
+occupiedAlongDir :: AreaMap -> (Int, Int) -> (Int, Int) -> Bool
+occupiedAlongDir ss (x, y) (dx, dy) | x >= length (head ss) || y >= length ss || x < 0 || y < 0 = False
+ | ss!!y!!x == Empty = False
+ | ss!!y!!x == Occupied = True
+ | otherwise = occupiedAlongDir ss (x + dx, y + dy) (dx, dy)
+
+-- Count the number of visible occupied seats from (x, y), looking along all directions incl diagonals.
+visibleOccupied :: AreaMap -> (Int, Int) -> Int
+visibleOccupied a (x, y) = length [(x', y') | x' <- [x-1..x+1], y' <- [y-1..y+1], x' /= x || y' /= y, occupiedAlongDir a (x', y') (x'-x, y'-y)]
+
+-- Mutate a space given its current state and its adjacent spaces
+mutateSpace :: Space -> Int -> Space
+mutateSpace Empty adj | adj == 0 = Occupied
+ | otherwise = Empty
+mutateSpace Occupied adj | adj >= 5 = Empty
+ | otherwise = Occupied
+mutateSpace x _ = x
+
+-- Mutate all spaces on the map
+mutateAll :: AreaMap -> AreaMap
+mutateAll rs = [[mutateSpace s (visibleOccupied rs (c, r)) | (c, s) <- zip [0..] ss] | (r, ss) <- zip [0..] rs]
+
+-- Read a map in from its string representation
+readMap :: String -> AreaMap
+readMap = map readLine . lines
+ where readLine [] = []
+ readLine ('.':xs) = Floor : readLine xs
+ readLine ('L':xs) = Empty : readLine xs
+ readLine ('#':xs) = Occupied : readLine xs
+
+-- Read a map from the filename
+mapFromFile :: String -> IO AreaMap
+mapFromFile s = do
+ contents <- readFile s;
+ return $ readMap contents;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ m <- mapFromFile (head args);
+
+ let final = untilUnchanged mutateAll m;
+ let occ = sum $ map (length . filter (== Occupied)) final;
+
+ putStrLn $ "Occupied Seats: " ++ show occ;
+ return ();
diff --git a/2020/12a.hs b/2020/12a.hs
new file mode 100644
index 0000000..a147884
--- /dev/null
+++ b/2020/12a.hs
@@ -0,0 +1,62 @@
+module Day12A where
+
+import System.Environment (getArgs)
+
+data Instruction = North Int | East Int |
+ South Int | West Int |
+ TLeft Int | TRight Int |
+ Forward Int
+ deriving (Eq, Show, Ord);
+
+-- ((x, y), direction)
+type State = ((Int, Int), Int);
+
+initialState :: State;
+initialState = ((0, 0), 90);
+
+directionToDisplacement :: Int -> (Int, Int)
+directionToDisplacement 0 = (0, 1)
+directionToDisplacement 90 = (1, 0)
+directionToDisplacement 180 = (0, -1)
+directionToDisplacement 270 = (-1, 0)
+directionToDisplacement _ = error "Invalid direction"
+
+readInstructions :: String -> [Instruction]
+readInstructions = map readInstruction . lines
+ where readInstruction ('N':xs) = North $ read xs
+ readInstruction ('S':xs) = South $ read xs
+ readInstruction ('E':xs) = East $ read xs
+ readInstruction ('W':xs) = West $ read xs
+ readInstruction ('L':xs) = TLeft $ read xs
+ readInstruction ('R':xs) = TRight $ read xs
+ readInstruction ('F':xs) = Forward $ read xs
+ readInstruction _ = error "Invalid instruction"
+
+doInstruction :: Instruction -> State -> State
+doInstruction (North r) ((x, y), d) = ((x, y + r), d)
+doInstruction (South r) ((x, y), d) = ((x, y - r), d)
+doInstruction (East r) ((x, y), d) = ((x + r, y), d)
+doInstruction (West r) ((x, y), d) = ((x - r, y), d)
+doInstruction (TLeft r) ((x, y), d) = ((x, y), (d - r) `mod` 360)
+doInstruction (TRight r) ((x, y), d) = ((x, y), (d + r) `mod` 360)
+doInstruction (Forward r) ((x, y), d) = ((x + (x' * r), y + (y' * r)), d)
+ where (x', y') = directionToDisplacement d
+
+instructionsFromFile :: String -> IO [Instruction]
+instructionsFromFile s = do
+ contents <- readFile s;
+ return $ readInstructions contents;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ is <- instructionsFromFile (head args);
+
+ let final = foldl (flip doInstruction) initialState is;
+ putStrLn $ "Final State: " ++ show final;
+
+ let ((x, y), _) = final;
+ let dist = abs x + abs y;
+ putStrLn $ "Distance: " ++ show dist;
+
+ return ();
diff --git a/2020/12b.hs b/2020/12b.hs
new file mode 100644
index 0000000..040287e
--- /dev/null
+++ b/2020/12b.hs
@@ -0,0 +1,67 @@
+module Day12B where
+
+import System.Environment (getArgs)
+
+data Instruction = North Int | East Int |
+ South Int | West Int |
+ TLeft Int | TRight Int |
+ Forward Int
+ deriving (Eq, Show, Ord);
+
+-- ((shipX, shipY), (wY, wX))
+type State = ((Int, Int), (Int, Int));
+
+initialState :: State;
+initialState = ((0, 0), (10, 1));
+
+rotateAround :: (Int, Int) -> Int -> (Int, Int)
+rotateAround (wx, wy) (-90) = (-wy, wx)
+rotateAround (wx, wy) 0 = (wx, wy)
+rotateAround (wx, wy) 90 = (wy, -wx)
+rotateAround (wx, wy) 180 = (-wx, -wy)
+rotateAround (wx, wy) (-180) = rotateAround (wx, wy) 180
+rotateAround (wx, wy) 270 = rotateAround (wx, wy) (-90)
+rotateAround (wx, wy) (-270) = rotateAround (wx, wy) 90
+rotateAround _ _ = error "Direction not defined"
+
+moveToward :: (Int, Int) -> (Int, Int) -> Int -> (Int, Int)
+moveToward (sx, sy) (wx, wy) r = (sx + (wx * r), sy + (wy * r))
+
+readInstructions :: String -> [Instruction]
+readInstructions = map readInstruction . lines
+ where readInstruction ('N':xs) = North $ read xs
+ readInstruction ('S':xs) = South $ read xs
+ readInstruction ('E':xs) = East $ read xs
+ readInstruction ('W':xs) = West $ read xs
+ readInstruction ('L':xs) = TLeft $ read xs
+ readInstruction ('R':xs) = TRight $ read xs
+ readInstruction ('F':xs) = Forward $ read xs
+ readInstruction _ = error "Invalid instruction"
+
+doInstruction :: Instruction -> State -> State
+doInstruction (North r) ((sx, sy), (wx, wy)) = ((sx, sy), (wx, wy + r))
+doInstruction (South r) ((sx, sy), (wx, wy)) = ((sx, sy), (wx, wy - r))
+doInstruction (East r) ((sx, sy), (wx, wy)) = ((sx, sy), (wx + r, wy))
+doInstruction (West r) ((sx, sy), (wx, wy)) = ((sx, sy), (wx - r, wy))
+doInstruction (TLeft r) ((sx, sy), (wx, wy)) = ((sx, sy), rotateAround (wx, wy) (-r))
+doInstruction (TRight r) ((sx, sy), (wx, wy)) = ((sx, sy), rotateAround (wx, wy) r)
+doInstruction (Forward r) ((sx, sy), (wx, wy)) = (moveToward (sx, sy) (wx, wy) r, (wx, wy))
+
+instructionsFromFile :: String -> IO [Instruction]
+instructionsFromFile s = do
+ contents <- readFile s;
+ return $ readInstructions contents;
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ is <- instructionsFromFile (head args);
+
+ let final = foldl (flip doInstruction) initialState is;
+ putStrLn $ "Final State: " ++ show final;
+
+ let ((x, y), _) = final;
+ let dist = abs x + abs y;
+ putStrLn $ "Distance: " ++ show dist;
+
+ return ();
diff --git a/2020/13a.hs b/2020/13a.hs
new file mode 100644
index 0000000..1346a68
--- /dev/null
+++ b/2020/13a.hs
@@ -0,0 +1,45 @@
+module Day13A where
+
+import System.Environment (getArgs)
+import Data.Maybe (catMaybes)
+import Data.List.Split (splitOn)
+import Text.Read (readMaybe)
+import Text.Printf
+
+-- Get the nearest bus in the list after the given time
+-- Returns (time, bus)
+getNearest :: Int -> [Int] -> (Int, Int)
+getNearest e xs | not $ null rs = (e, head rs)
+ | otherwise = getNearest (e + 1) xs
+ where rs = filter (\x -> e `mod` x == 0) xs
+
+-- Parse the input as a string
+-- Returns (current time, list of valid buses)
+parseInput :: String -> (Int, [Int])
+parseInput x = (read t, catMaybes ts)
+ where (t:r) = lines x
+ bs = splitOn "," (head r)
+ ts :: [Maybe Int]
+ ts = map readMaybe bs
+
+-- Parse a file given the path
+-- Returns (current time, list of valid buses)
+parseFromFile :: String -> IO (Int, [Int])
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- runghc --ghc-arg='-package split' 13a.hs inputs/day13
+main :: IO ()
+main = do
+ args <- getArgs;
+ (now, bs) <- parseFromFile (head args);
+
+ let (t, b) = getNearest now bs;
+ let w = t - now;
+
+ printf "You could get bus %d at %d\n" b t :: IO ();
+ printf "This is a %d minute wait\n" w :: IO ();
+ printf "Answer = %d\n" (b * w) :: IO ();
+
+ return ();
diff --git a/2020/13b.hs b/2020/13b.hs
new file mode 100644
index 0000000..4a66ec2
--- /dev/null
+++ b/2020/13b.hs
@@ -0,0 +1,51 @@
+module Day13B where
+
+import System.Environment (getArgs)
+import Data.List.Split (splitOn)
+import Text.Read (readMaybe)
+import Text.Printf
+
+-- Extended Euclidean Algorithm
+-- Returns (s, t) such that as + bt = gcd(a,b)
+extendedEu :: Int -> Int -> (Int, Int)
+extendedEu _ 0 = (1, 0)
+extendedEu a b = (t, s - q * t)
+ where (q, r) = quotRem a b
+ (s, t) = extendedEu b r
+
+-- Solve for x in (a, n) such that x = a mod n
+-- Assumes all ns are coprime
+crt :: [(Int, Int)] -> Int
+crt xs | r < 0 = -(r + n')
+ | otherwise = r
+ where n' = product $ map snd xs
+ r = sum [a * snd (extendedEu n (n' `div` n)) * (n' `div` n) |(a, n) <- xs]
+
+-- Calculate the nearest time with the given parameters
+solvePuzzle :: [Maybe Int] -> Int
+solvePuzzle bs = crt [(i `mod` x, x) | (i, Just x) <- zip [0..] bs]
+
+-- Parse the input as a string
+-- Returns (current time, list of buses / nothing if x)
+parseInput :: String -> (Int, [Maybe Int])
+parseInput x = (read t, ts)
+ where (t:r) = lines x
+ bs = splitOn "," (head r)
+ ts :: [Maybe Int]
+ ts = map readMaybe bs
+
+-- Parse a file given the path
+-- Returns (current time, list of buses / nothing if x)
+parseFromFile :: String -> IO (Int, [Maybe Int])
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- runghc --ghc-arg='-package split' 13a.hs inputs/day13
+main :: IO ()
+main = do
+ args <- getArgs;
+ (_, bs) <- parseFromFile (head args);
+
+ printf "Answer = %d\n" (solvePuzzle bs) :: IO ();
+ return ();
diff --git a/2020/14a.hs b/2020/14a.hs
new file mode 100644
index 0000000..3595c0e
--- /dev/null
+++ b/2020/14a.hs
@@ -0,0 +1,89 @@
+module Day14A where
+
+import System.Environment (getArgs)
+import Text.Regex.PCRE
+import Text.Printf
+import qualified Data.Map as Map
+
+-- Types
+type U36 = [Bool];
+data Instruction = SetAddr Int Int |
+ SetMask Mask
+ deriving (Eq, Show);
+
+data MaskBit = Zero | One | Preserve
+ deriving (Eq, Show);
+type Mask = [MaskBit];
+
+type State = (Mask, Map.Map Int Int)
+
+-- The initial state - An empty mask and all 0s.
+initialState :: State
+initialState = (toMask "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", Map.empty)
+
+-- Apply a mask to a U36
+applyMask :: Mask -> U36 -> U36
+applyMask = zipWith maskBit
+ where maskBit Zero _ = False
+ maskBit One _ = True
+ maskBit Preserve x = x
+
+-- Apply a mask to an int
+applyMaskInt :: Mask -> Int -> Int
+applyMaskInt m = fromU36 . applyMask m . toU36
+
+-- Conversion to/from u36
+toU36 :: Int -> U36
+toU36 = genBit 35
+ where genBit 0 x = [x `mod` 2 == 1]
+ genBit e x = (x >= (2 ^ e)) : genBit (e - 1) (x `mod` (2 ^ e))
+
+fromU36 :: U36 -> Int
+fromU36 [] = 0
+fromU36 (x:xs) | x = 2 ^ (length xs) + fromU36 xs
+ | otherwise = fromU36 xs
+
+-- Parse a string as a mask
+toMask :: String -> Mask
+toMask [] = []
+toMask ('X':xs) = Preserve : toMask xs
+toMask ('1':xs) = One : toMask xs
+toMask ('0':xs) = Zero : toMask xs
+
+-- Parse a string as an instruction
+parseInstruction :: String -> Instruction
+parseInstruction xs | not (null sm) = SetMask (toMask (sm!!0!!1))
+ | not (null sa) = SetAddr (read (sa!!0!!1)) (read (sa!!0!!2))
+ | otherwise = error "Invalid Instruction"
+ where sm = xs =~ "^mask = ([X01]{36})" :: [[String]]
+ sa = xs =~ "^mem\\[(\\d+)\\] = (\\d+)" :: [[String]]
+
+-- Parse a string, with one instruction per line
+parseInput :: String -> [Instruction]
+parseInput = map parseInstruction . lines
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO [Instruction]
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- Run the given instructions on the given state
+run :: State -> [Instruction] -> State
+run s [] = s
+run (_, a) (SetMask m:xs) = run (m, a) xs
+run (m, a) (SetAddr k v:xs) = run (m, Map.insert k (applyMaskInt m v) a) xs
+
+-- runghc --ghc-arg='-package regex-pcre-builtin' 14a.hs inputs/day14
+main :: IO ()
+main = do
+ args <- getArgs;
+ is <- parseFromFile (head args);
+
+ let (_, mem) = run initialState is;
+ let s = sum mem; -- Defaults to values :)
+
+ printf "Answer = %d\n" s :: IO ();
+
+ return ();
diff --git a/2020/14b.hs b/2020/14b.hs
new file mode 100644
index 0000000..8be43e1
--- /dev/null
+++ b/2020/14b.hs
@@ -0,0 +1,88 @@
+module Day14B where
+
+import System.Environment (getArgs)
+import Text.Regex.PCRE
+import Text.Printf
+import qualified Data.Map as Map
+
+-- Types
+type U36 = [Bool];
+data Instruction = SetAddr Int Int |
+ SetMask Mask
+ deriving (Eq, Show);
+
+data MaskBit = Floating | One | Preserve
+ deriving (Eq, Show);
+type Mask = [MaskBit];
+
+type State = (Mask, Map.Map Int Int)
+
+-- The initial state - An empty mask and all 0s.
+initialState :: State
+initialState = (toMask "000000000000000000000000000000000000", Map.empty)
+
+-- Apply a mask to a U36, returning all addresses this should mutate
+applyMask :: Mask -> U36 -> [U36]
+applyMask [] [] = [[]]
+applyMask (One:ms) (b:bs) = [True : s | s <- applyMask ms bs]
+applyMask (Preserve:ms) (b:bs) = [b : s | s <- applyMask ms bs]
+applyMask (Floating:ms) (b:bs) = [x : s | s <- applyMask ms bs, x <- [True, False]]
+
+-- Apply a mask to an int
+applyMaskInt :: Mask -> Int -> [Int]
+applyMaskInt m = map fromU36 . applyMask m . toU36
+
+-- Conversion to/from u36
+toU36 :: Int -> U36
+toU36 = genBit 35
+ where genBit 0 x = [x `mod` 2 == 1]
+ genBit e x = (x >= (2 ^ e)) : genBit (e - 1) (x `mod` (2 ^ e))
+
+fromU36 :: U36 -> Int
+fromU36 [] = 0
+fromU36 (x:xs) | x = 2 ^ (length xs) + fromU36 xs
+ | otherwise = fromU36 xs
+
+-- Parse a string as a mask
+toMask :: String -> Mask
+toMask [] = []
+toMask ('X':xs) = Floating : toMask xs
+toMask ('1':xs) = One : toMask xs
+toMask ('0':xs) = Preserve : toMask xs
+
+-- Parse a string as an instruction
+parseInstruction :: String -> Instruction
+parseInstruction xs | not (null sm) = SetMask (toMask (sm!!0!!1))
+ | not (null sa) = SetAddr (read (sa!!0!!1)) (read (sa!!0!!2))
+ | otherwise = error "Invalid Instruction"
+ where sm = xs =~ "^mask = ([X01]{36})" :: [[String]]
+ sa = xs =~ "^mem\\[(\\d+)\\] = (\\d+)" :: [[String]]
+
+-- Parse a string, with one instruction per line
+parseInput :: String -> [Instruction]
+parseInput = map parseInstruction . lines
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO [Instruction]
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- Run the given instructions on the given state
+run :: State -> [Instruction] -> State
+run s [] = s
+run (_, a) (SetMask m:xs) = run (m, a) xs
+run (m, a) (SetAddr k v:xs) = run (m, foldr (\k a -> Map.insert k v a) a (applyMaskInt m k)) xs
+
+-- runghc --ghc-arg='-package regex-pcre-builtin' 14a.hs inputs/day14
+main :: IO ()
+main = do
+ args <- getArgs;
+ is <- parseFromFile (head args);
+
+ let (_, mem) = run initialState is;
+ let s = sum mem; -- Defaults to values :)
+ printf "Answer = %d\n" s :: IO ();
+
+ return ();
diff --git a/2020/15a.hs b/2020/15a.hs
new file mode 100644
index 0000000..9e574ef
--- /dev/null
+++ b/2020/15a.hs
@@ -0,0 +1,49 @@
+module Day15A where
+
+import System.Environment (getArgs)
+import Text.Printf
+
+-- Parse a string, with one number per line
+parseInput :: String -> [Int]
+parseInput = map read . lines
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO [Int]
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- Index of an element in a list
+indexOf :: Eq a => [a] -> a -> Maybe Int
+indexOf [] t = Nothing
+indexOf (x:xs) t | x == t = Just 0
+ | otherwise = case indexOf xs t of
+ Nothing -> Nothing
+ Just x -> Just (x + 1)
+
+-- Index of an element in a list, starting from the right / end
+indexOfRight :: Eq a => [a] -> a -> Maybe Int
+indexOfRight xs t = case indexOf (reverse xs) t of
+ Nothing -> Nothing
+ Just x -> Just (length xs - x - 1)
+
+-- Run until the given turn
+runTillTurn :: [Int] -> Int -> [Int]
+runTillTurn ns l | length ns == l = ns
+ | otherwise = runTillTurn ns' l
+ where x = last ns
+ ns' = case indexOfRight (take (length ns - 1) ns) x of
+ Just x -> ns ++ [(length ns - 1) - x]
+ Nothing -> ns ++ [0]
+
+-- runghc 15a.hs inputs/day15
+main :: IO ()
+main = do
+ args <- getArgs;
+ ns <- parseFromFile (head args);
+ let xs = runTillTurn ns 30000000;
+
+ printf "Answer = %d\n" (last xs) :: IO ();
+
+ return ();
diff --git a/2020/15b.hs b/2020/15b.hs
new file mode 100644
index 0000000..1efe53e
--- /dev/null
+++ b/2020/15b.hs
@@ -0,0 +1,44 @@
+module Main where
+
+import System.Environment (getArgs)
+import Text.Printf
+import qualified Data.IntMap.Strict as Map
+
+-- This does the same thing as 15a, it's just done in a more memory-optimised way.
+
+-- Parse a string, with one number per line
+parseInput :: String -> [Int]
+parseInput = map read . lines
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO [Int]
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- Generate a map from the list of initial numbers
+mapFromInitial :: [Int] -> Map.IntMap Int
+mapFromInitial xs = foldr (\(i,x) m -> Map.insert x i m) Map.empty (zip [0..] xs)
+
+-- Run till the given turn, this time using a map to store last occurences.
+-- This means we don't get the full 'log', just the final turn.
+-- map, prev, current index, stopping len
+runTillTurn :: Map.IntMap Int -> Int -> Int -> Int -> Int
+runTillTurn occ prev i n | i >= n = prev
+ | otherwise = runTillTurn occ' curr (i + 1) n
+ where curr = case Map.lookup prev occ of
+ Nothing -> 0
+ Just x -> (i - 1) - x
+ occ' = Map.insert prev (i - 1) occ
+
+-- runghc 15b.hs inputs/day15
+main :: IO ()
+main = do
+ args <- getArgs;
+ ns <- parseFromFile (head args);
+ let x = runTillTurn (mapFromInitial ns) (last ns) (length ns) 30000000;
+
+ printf "Answer = %d\n" x :: IO ();
+
+ return ();
diff --git a/2020/16a.hs b/2020/16a.hs
new file mode 100644
index 0000000..0342e5d
--- /dev/null
+++ b/2020/16a.hs
@@ -0,0 +1,69 @@
+module Day16A where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+
+
+-- name, (lo, hi)
+type FieldDef = (String, [(Int, Int)])
+
+-- (fields, your ticket, nearby tickets)
+type Input = ([FieldDef], [Int], [[Int]])
+
+parseTicketLine :: String -> [Int]
+parseTicketLine = map read . splitOn ","
+
+parseRange :: String -> (Int, Int)
+parseRange x = (head ns, last ns)
+ where ns = map read $ splitOn "-" x
+
+parseFieldDef :: String -> FieldDef
+parseFieldDef x = (n, ranges)
+ where [n, rs] = splitOn ": " x
+ ranges = map parseRange $ splitOn " or " rs
+
+parseFields :: [String] -> [FieldDef]
+parseFields = inner . head . splitOn [""]
+ where inner = map parseFieldDef
+
+
+findYourTicket :: [String] -> [Int]
+findYourTicket ("your ticket:":xs) = parseTicketLine (head xs)
+findYourTicket (_:xs) = findYourTicket xs
+findYourTicket [] = error "Couldn't find your ticket"
+
+findOtherTickets :: [String] -> [[Int]]
+findOtherTickets ("nearby tickets:":xs) = map parseTicketLine xs
+findOtherTickets (_:xs) = findOtherTickets xs
+findOtherTickets [] = error "Couldn't find nearby tickets"
+
+
+-- Parse the input
+parseInput :: String -> Input
+parseInput xs = (parseFields ls, findYourTicket ls, findOtherTickets ls)
+ where ls = lines xs
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO Input
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+fieldValid :: FieldDef -> Int -> Bool
+fieldValid (_, rs) x = any (\(l,h) -> x >= l && x <= h) rs
+
+invalidValues :: Input -> [Int]
+invalidValues (cs, _, ts) = concat [filter (\x -> not (any (`fieldValid` x) cs)) t | t <- ts]
+
+-- runghc --ghc-arg='-package split' 16a.hs inputs/day16
+main :: IO ()
+main = do
+ args <- getArgs;
+ i <- parseFromFile (head args);
+ let vs = invalidValues i;
+
+ printf "Answer = %d\n" (sum vs) :: IO ();
+
+ return ();
diff --git a/2020/16b.hs b/2020/16b.hs
new file mode 100644
index 0000000..a3ba48a
--- /dev/null
+++ b/2020/16b.hs
@@ -0,0 +1,97 @@
+module Day16B where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+
+
+-- name, (lo, hi)
+type FieldDef = (String, [(Int, Int)])
+
+-- (fields, your ticket, nearby tickets)
+type Input = ([FieldDef], [Int], [[Int]])
+
+parseTicketLine :: String -> [Int]
+parseTicketLine = map read . splitOn ","
+
+parseRange :: String -> (Int, Int)
+parseRange x = (head ns, last ns)
+ where ns = map read $ splitOn "-" x
+
+parseFieldDef :: String -> FieldDef
+parseFieldDef x = (n, ranges)
+ where [n, rs] = splitOn ": " x
+ ranges = map parseRange $ splitOn " or " rs
+
+parseFields :: [String] -> [FieldDef]
+parseFields = inner . head . splitOn [""]
+ where inner = map parseFieldDef
+
+
+findYourTicket :: [String] -> [Int]
+findYourTicket ("your ticket:":xs) = parseTicketLine (head xs)
+findYourTicket (_:xs) = findYourTicket xs
+findYourTicket [] = error "Couldn't find your ticket"
+
+findOtherTickets :: [String] -> [[Int]]
+findOtherTickets ("nearby tickets:":xs) = map parseTicketLine xs
+findOtherTickets (_:xs) = findOtherTickets xs
+findOtherTickets [] = error "Couldn't find nearby tickets"
+
+
+-- Parse the input
+parseInput :: String -> Input
+parseInput xs = (parseFields ls, findYourTicket ls, findOtherTickets ls)
+ where ls = lines xs
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO Input
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+fieldValid :: FieldDef -> Int -> Bool
+fieldValid (_, rs) x = any (\(l,h) -> x >= l && x <= h) rs
+
+validTickets :: Input -> [[Int]]
+validTickets (cs, _, ts) = filter (all (\x -> any (`fieldValid` x) cs)) ts
+
+discardInvalid :: Input -> Input
+discardInvalid i@(cs, m, _) = (cs, m, validTickets i)
+
+findPositions :: FieldDef -> [[Int]] -> [Int]
+findPositions f ts = filter (\k -> all (fieldValid f . (!!k)) ts) [0..length (head ts) - 1]
+
+-- Takes a list of lists of possibilities, and selects one from each such that there are no duplicates
+selectOne :: [[Int]] -> [Int]
+selectOne xs | all ((== 1) . length) ps = map head ps
+ | ps == xs = selectOne $ ([head $ head undecided]:tail undecided) ++ singletons
+ | otherwise = selectOne ps -- Recurse until every list of possibilities is singleton
+ where singletons = filter ((== 1) . length) xs
+ undecided = filter ((> 1) . length) xs
+ reqs = map head singletons -- Numbers that are already taken
+ ps = map (\x -> if length x > 1 then deleteReqs x else x) xs -- Possibilities assuming this one is taken
+ deleteReqs (n:ns) | n `elem` reqs = ns
+ | otherwise = n : deleteReqs ns
+ deleteReqs [] = []
+
+
+startsWith :: Eq a => [a] -> [a] -> Bool
+startsWith a b = and $ zipWith (==) a b
+
+-- runghc --ghc-arg='-package split' 16b.hs inputs/day16
+main :: IO ()
+main = do
+ args <- getArgs;
+ i <- parseFromFile (head args);
+ let (cs, m, ts) = discardInvalid i;
+
+ let ps = zip (map fst cs) (selectOne $ map (`findPositions` (m:ts)) cs)
+ let deps = filter (startsWith "departure" . fst) ps;
+ let vals = map ((m!!) . snd) deps;
+ printf "Drawing from %d fields\n" (length deps) :: IO ();
+
+ printf "Answer = %d\n" (product vals) :: IO ();
+
+ return ();
diff --git a/2020/17a.hs b/2020/17a.hs
new file mode 100644
index 0000000..d888379
--- /dev/null
+++ b/2020/17a.hs
@@ -0,0 +1,64 @@
+module Day17A where
+
+import System.Environment (getArgs)
+import Text.Printf
+import qualified Data.Map.Strict as Map
+
+-- Types
+type Coord = (Int, Int, Int);
+type ActiveMap = Map.Map Coord Bool
+
+-- Add two coords
+addCoord :: Coord -> Coord -> Coord
+addCoord (x, y, z) (x', y', z') = (x + x', y + y', z + z')
+
+-- The range of cubes that need to be simulated.
+consideredRange :: ActiveMap -> (Coord, Coord)
+consideredRange m = (addCoord (Map.foldrWithKey (compCoord min) (0, 0, 0) m) (-1, -1, -1),
+ addCoord (Map.foldrWithKey (compCoord max) (0, 0, 0) m) (1, 1, 1))
+ where compCoord f (x', y', z') _ (x, y, z) = (f x' x, f y' y, f z' z)
+
+-- The neighbours of the given cube
+neighbours :: Coord -> [Coord]
+neighbours (x, y, z) = [(x', y', z') | x' <- [x-1..x+1],
+ y' <- [y-1..y+1],
+ z' <- [z-1..z+1],
+ x' /= x || y' /= y || z' /= z]
+
+-- Simulate the cube at the given coord
+simulateCube :: ActiveMap -> Coord -> Bool
+simulateCube m c | s && n `elem` [2..3] = True
+ | n == 3 = True
+ | otherwise = False
+ where s = Map.findWithDefault False c m
+ n = length $ filter (== True) $ map (\x -> Map.findWithDefault False x m) (neighbours c)
+
+-- Run one cycle of simulation
+runCycle :: ActiveMap -> ActiveMap
+runCycle m = foldr (\(k, v) m' -> Map.insert k v m') m changes -- Run all changes simultaneously
+ where ((lx, ly, lz), (hx, hy, hz)) = consideredRange m
+ changes = [((x, y, z), simulateCube m (x, y, z)) | x <- [lx..hx], y <- [ly..hy], z <- [lz..hz]]
+
+-- Parse the input
+parseInput :: String -> ActiveMap
+parseInput xs = foldr (\c m -> Map.insert c True m) Map.empty coords
+ where ls = zip (lines xs) [0..]
+ coords = concatMap (\(hs, y) -> [(x, y, 0) | ('#', x) <- zip hs [0..]]) ls
+
+-- Read and parse given filename
+parseFromFile :: String -> IO ActiveMap
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- runghc 17a.hs inputs/day17
+main :: IO ()
+main = do
+ args <- getArgs;
+ i <- parseFromFile (head args);
+
+ let final = foldr (\_ m -> runCycle m) i [1..6];
+
+ printf "Answer = %d\n" (Map.size $ Map.filter (== True) final) :: IO ();
+
+ return ();
diff --git a/2020/17b.hs b/2020/17b.hs
new file mode 100644
index 0000000..417fda0
--- /dev/null
+++ b/2020/17b.hs
@@ -0,0 +1,61 @@
+module Day17B where
+
+import System.Environment (getArgs)
+import Text.Printf
+import qualified Data.Map.Strict as Map
+
+-- Types
+type Coord = (Int, Int, Int, Int);
+type ActiveMap = Map.Map Coord Bool
+
+-- Add two coords
+addCoord :: Coord -> Coord -> Coord
+addCoord (x, y, z, w) (x', y', z', w') = (x + x', y + y', z + z', w + w')
+
+-- The range of cubes that need to be simulated.
+consideredRange :: ActiveMap -> (Coord, Coord)
+consideredRange m = (addCoord (Map.foldrWithKey (compCoord min) (0, 0, 0, 0) m) (-1, -1, -1, -1),
+ addCoord (Map.foldrWithKey (compCoord max) (0, 0, 0, 0) m) (1, 1, 1, 1))
+ where compCoord f (x', y', z', w') _ (x, y, z, w) = (f x' x, f y' y, f z' z, f w' w)
+
+-- The neighbours of the given cube
+neighbours :: Coord -> [Coord]
+neighbours (x, y, z, w) = [(x', y', z', w') | x' <- [x-1..x+1], y' <- [y-1..y+1], z' <- [z-1..z+1], w' <- [w-1..w+1], x' /= x || y' /= y || z' /= z || w' /= w]
+
+-- Simulate the cube at the given coord
+simulateCube :: ActiveMap -> Coord -> Bool
+simulateCube m c | s && n `elem` [2..3] = True
+ | n == 3 = True
+ | otherwise = False
+ where s = Map.findWithDefault False c m
+ n = length $ filter (== True) $ map (\x -> Map.findWithDefault False x m) (neighbours c)
+
+-- Run one cycle of simulation
+runCycle :: ActiveMap -> ActiveMap
+runCycle m = foldr (\(k, v) m' -> Map.insert k v m') m changes
+ where ((lx, ly, lz, lw), (hx, hy, hz, hw)) = consideredRange m
+ changes = [((x, y, z, w), simulateCube m (x, y, z, w)) | x <- [lx..hx], y <- [ly..hy], z <- [lz..hz], w <- [lw..hw]]
+
+-- Parse the input
+parseInput :: String -> ActiveMap
+parseInput xs = foldr (\c m -> Map.insert c True m) Map.empty coords
+ where ls = zip (lines xs) [0..]
+ coords = concatMap (\(hs, y) -> [(x, y, 0, 0) | ('#', x) <- zip hs [0..]]) ls
+
+-- Read and parse given filename
+parseFromFile :: String -> IO ActiveMap
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+-- runghc 17b.hs inputs/day17
+main :: IO ()
+main = do
+ args <- getArgs;
+ i <- parseFromFile (head args);
+
+ let final = foldr (\_ m -> runCycle m) i [1..6];
+
+ print (Map.size $ Map.filter (== True) final);
+
+ return ();
diff --git a/2020/18a.hs b/2020/18a.hs
new file mode 100644
index 0000000..7ed5a90
--- /dev/null
+++ b/2020/18a.hs
@@ -0,0 +1,86 @@
+module Day18A where
+
+import System.Environment (getArgs)
+import Text.Printf
+
+-- Types
+data Symbol = Num Int | Add | Mult | StartParen | EndParen
+ deriving (Eq, Show);
+
+data Expression = Expression :+: Expression | Expression :*: Expression | Paren Expression | Literal Int
+ deriving (Eq, Show);
+
+-- Read until there's some sort of operator, ie the entire number
+readUntilOp :: String -> (String, String) -- read, remaining
+readUntilOp [] = ("", "")
+readUntilOp xs@('+':_) = ("", xs)
+readUntilOp xs@('*':_) = ("", xs)
+readUntilOp xs@('(':_) = ("", xs)
+readUntilOp xs@(')':_) = ("", xs)
+readUntilOp (x:xs) = (x : r, re)
+ where (r, re) = readUntilOp xs
+
+-- Tokenise a string to a list of symbols
+toSymbols :: String -> [Symbol]
+toSymbols [] = []
+toSymbols(' ':xs) = toSymbols xs
+toSymbols ('+':xs) = Add : toSymbols xs
+toSymbols ('*':xs) = Mult : toSymbols xs
+toSymbols ('(':xs) = StartParen : toSymbols xs
+toSymbols (')':xs) = EndParen : toSymbols xs
+toSymbols xs = Num (read n) : toSymbols re
+ where (n, re) = readUntilOp xs
+
+-- Read till the next end paren at the same level
+-- This needs to not start with a start paren
+tillEndParen :: [Symbol] -> ([Symbol], [Symbol]) -- read, remaining
+tillEndParen (StartParen:xs) = ([StartParen] ++ i ++ [EndParen] ++ r, re)
+ where (i, is) = tillEndParen xs
+ (r, re) = tillEndParen is
+tillEndParen (EndParen:xs) = ([], xs)
+tillEndParen [] = ([], [])
+tillEndParen (x:xs) = (x:r, re)
+ where (r, re) = tillEndParen xs
+
+-- Reverse symbols, to get the right precedence level.
+revSyms :: [Symbol] -> [Symbol]
+revSyms = map swapParens . reverse
+ where swapParens StartParen = EndParen
+ swapParens EndParen = StartParen
+ swapParens x = x
+
+-- Parse a list of symbols to an expression tree
+toExp :: [Symbol] -> Expression
+toExp (StartParen:xs) = parenthesise r re
+ where (r, re) = tillEndParen xs
+ parenthesise r (Add:xs) = toExp r :+: toExp xs
+ parenthesise r (Mult:xs) = toExp r :*: toExp xs
+ parenthesise r [] = toExp r
+toExp (x:Add:y) = toExp [x] :+: toExp y
+toExp (x:Mult:y) = toExp [x] :*: toExp y
+toExp [Num x] = Literal x
+toExp [] = Literal 0
+
+-- Evaluate an expression
+evalExp :: Expression -> Int
+evalExp (Literal x) = x
+evalExp (x :+: y) = evalExp x + evalExp y
+evalExp (x :*: y) = evalExp x * evalExp y
+evalExp (Paren x) = evalExp x
+
+-- Parse the expressions in the given line seperated file.
+parseFromFile :: String -> IO [Expression]
+parseFromFile s = do
+ contents <- readFile s
+ return $ map (toExp . revSyms . toSymbols) (lines contents);
+
+-- runghc 18a.hs inputs/day18
+main :: IO ()
+main = do
+ args <- getArgs;
+ es <- parseFromFile (head args);
+
+ let ns = map evalExp es;
+ printf "Answer = %d\n" (sum ns) :: IO ();
+
+ return ();
diff --git a/2020/18b.hs b/2020/18b.hs
new file mode 100644
index 0000000..cb27c19
--- /dev/null
+++ b/2020/18b.hs
@@ -0,0 +1,97 @@
+module Day18A where
+
+import System.Environment (getArgs)
+import Text.Printf
+
+-- Types
+data Symbol = Num Int | Add | Mult | StartParen | EndParen
+ deriving (Eq, Show);
+
+data Expression = Expression :+: Expression | Expression :*: Expression | Paren Expression | Literal Int | Unparsed [Symbol]
+ deriving (Eq, Show);
+
+-- Read until there's some sort of operator, ie the entire number
+readUntilOp :: String -> (String, String) -- read, remaining
+readUntilOp [] = ("", "")
+readUntilOp xs@('+':_) = ("", xs)
+readUntilOp xs@('*':_) = ("", xs)
+readUntilOp xs@('(':_) = ("", xs)
+readUntilOp xs@(')':_) = ("", xs)
+readUntilOp (x:xs) = (x : r, re)
+ where (r, re) = readUntilOp xs
+
+-- Tokenise a string to a list of symbols
+toSymbols :: String -> [Symbol]
+toSymbols [] = []
+toSymbols(' ':xs) = toSymbols xs
+toSymbols ('+':xs) = Add : toSymbols xs
+toSymbols ('*':xs) = Mult : toSymbols xs
+toSymbols ('(':xs) = StartParen : toSymbols xs
+toSymbols (')':xs) = EndParen : toSymbols xs
+toSymbols xs = Num (read n) : toSymbols re
+ where (n, re) = readUntilOp xs
+
+-- Read till the next end paren at the same level
+-- This needs to not start with a start paren
+tillEndParen :: [Symbol] -> ([Symbol], [Symbol]) -- read, remaining
+tillEndParen (StartParen:xs) = ([StartParen] ++ i ++ [EndParen] ++ r, re)
+ where (i, is) = tillEndParen xs
+ (r, re) = tillEndParen is
+tillEndParen (EndParen:xs) = ([], xs)
+tillEndParen [] = ([], [])
+tillEndParen (x:xs) = (x:r, re)
+ where (r, re) = tillEndParen xs
+
+-- Split on the given symbol when it's found at the top level
+splitOnTop :: Symbol -> [Symbol] -> ([Symbol], [Symbol]) -- read, remaining
+splitOnTop t (StartParen:xs) = ([StartParen] ++ i ++ [EndParen] ++ r, re)
+ where (i, is) = tillEndParen xs
+ (r, re) = splitOnTop t is
+splitOnTop _ (EndParen:xs) = ([], xs)
+splitOnTop _ [] = ([], [])
+splitOnTop t (x:xs) | x == t = ([], xs)
+ | otherwise = (x:r, re)
+ where (r, re) = splitOnTop t xs
+
+-- Parse the given symbol list to an expression tree
+parse :: [Symbol] -> Expression
+parse [] = Unparsed []
+parse xs | not (null b) = parse a :*: parse b
+ | otherwise = parseLower xs
+ where (a, b) = splitOnTop Mult xs
+
+-- Parse the lower-precedence operators
+parseLower :: [Symbol] -> Expression
+parseLower (StartParen:xs) = parenthesise r re
+ where (r, re) = tillEndParen xs
+ parenthesise r (Add:xs) = parse r :+: parse xs
+ parenthesise r (Mult:xs) = parse r :*: parse xs
+ parenthesise r [] = parse r
+parseLower (x:Add:y) = parseLower [x] :+: parseLower y
+parseLower (x:Mult:y) = parseLower [x] :*: parseLower y
+parseLower [Num x] = Literal x
+parseLower [] = Literal 0
+
+-- Evaluate an expression
+evalExp :: Expression -> Int
+evalExp (Literal x) = x
+evalExp (x :+: y) = evalExp x + evalExp y
+evalExp (x :*: y) = evalExp x * evalExp y
+evalExp (Paren x) = evalExp x
+
+-- Parse the expressions in the given line seperated file.
+parseFromFile :: String -> IO [Expression]
+parseFromFile s = do
+ contents <- readFile s
+ return $ map (parse . toSymbols) (lines contents);
+
+-- runghc 18a.hs inputs/day18
+main :: IO ()
+main = do
+ args <- getArgs;
+ es <- parseFromFile (head args);
+
+ let ns = map evalExp es;
+ printf "Answer = %d\n" (sum ns) :: IO ();
+
+ return ();
diff --git a/2020/19a.hs b/2020/19a.hs
new file mode 100644
index 0000000..66c8838
--- /dev/null
+++ b/2020/19a.hs
@@ -0,0 +1,158 @@
+module Day19A where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+import Data.Char (isDigit)
+import qualified Data.Set as S
+import qualified Data.Map.Strict as M
+
+
+-- Rules parser
+
+-- Types
+data Rule = Literal Char | Reference Int | Concat Rule Rule | Union Rule Rule | End
+ deriving (Eq, Show);
+
+-- Convert a list of rules to the union of those rules
+toUnion :: [Rule] -> Rule
+toUnion [x] = x
+toUnion (x:ys) = Union x (toUnion ys)
+
+-- Parse the given line seperated list of rules
+-- Returns a map from id to rule
+parseRules :: String -> M.Map Int Rule
+parseRules = M.fromList . map parseRule . lines
+
+-- Parse the given rule, in format `0: 1 2 | 3 4`
+parseRule :: String -> (Int, Rule)
+parseRule s = (read idx, toUnion $ map parseNoUnion $ splitOn " | " def)
+ where [idx, def] = splitOn ": " s
+
+
+-- Parse the lower precedence parts (anything that isn't a union)
+parseNoUnion :: String -> Rule
+parseNoUnion "" = End;
+parseNoUnion (' ':xs) = parseNoUnion xs
+parseNoUnion ('"':xs) = Literal (head xs)
+parseNoUnion xs@(x:_) | not (null re)= Concat (Reference (read n)) (parseNoUnion (drop (length n + 1) xs))
+ | otherwise = Reference (read n)
+ where (n:re) = splitOn " " xs
+
+-- Parse the input into a list of rules and list of messages
+parseInput :: String -> (M.Map Int Rule, [String])
+parseInput s = (parseRules rs, lines ms)
+ where [rs, ms] = splitOn "\n\n" s
+
+-- Parse the file with the given name
+parseFile :: String -> IO (M.Map Int Rule, [String])
+parseFile f = do
+ contents <- readFile f
+ return $ parseInput contents;
+
+-- Finite State Machines
+
+-- Types
+-- starting states, accept states, transitions, epsilon transitions
+newtype FSM k = FSM (S.Set k, S.Set k, S.Set (k, Char, k), S.Set (k, k))
+ deriving (Show, Eq)
+
+-- Map a set of transitions
+mapTransitions :: Ord a => Ord b => (a -> b) -> S.Set (a, Char, a) -> S.Set (b, Char, b)
+mapTransitions f = S.map (\(s, c, t) -> (f s, c, f t))
+
+-- Map a set of epsilon transitions
+mapEpsilons :: Ord a => Ord b => (a -> b) -> S.Set (a, a) -> S.Set (b, b)
+mapEpsilons f = S.map (\(s, t) -> (f s, f t))
+
+-- Concatenate two FSMs
+concatFSMs :: Ord a => Ord b => FSM a -> FSM b -> FSM (Either a b)
+concatFSMs (FSM (ssa, fsa, tsa, esa)) (FSM (ssb, fsb, tsb, esb)) = FSM (S.map Left ssa, S.map Right fsb, ts', es')
+ where ts' = mapTransitions Left tsa `S.union` mapTransitions Right tsb
+ es' = mapEpsilons Left esa `S.union` mapEpsilons Right esb
+ `S.union` S.fromList [(Left s, Right d) | s <- S.toList fsa, d <- S.toList ssb]
+
+-- Take the union of two FSMs
+unionFSMs :: Ord a => Ord b => FSM a -> FSM b -> FSM (Either a b)
+unionFSMs (FSM (ssa, fsa, tsa, esa)) (FSM (ssb, fsb, tsb, esb)) = FSM (ss', fs', ts', es')
+ where ss' = S.map Left ssa `S.union` S.map Right ssb
+ fs' = S.map Left fsa `S.union` S.map Right fsb
+ ts' = mapTransitions Left tsa `S.union` mapTransitions Right tsb
+ es' = mapEpsilons Left esa `S.union` mapEpsilons Right esb
+
+-- Add a key to the given list. Used when generating lookup tables for new states
+addKey :: Eq a => Ord a => a -> [(a, Int)] -> [(a, Int)]
+addKey s [] = [(s, 1)]
+addKey s ks = ks ++ as
+ where as = case lookup s ks of
+ Just _ -> []
+ Nothing -> [(s, (snd . last) ks + 1)]
+
+-- Get all states in the given FSM
+allStates :: Ord a => FSM a -> S.Set a
+allStates (FSM (ss, fs, ts, es)) = ss `S.union` fs
+ `S.union` S.map fst3 ts `S.union` S.map lst3 ts
+ `S.union` S.map fst es `S.union` S.map snd es
+
+-- Convert a FSM of any type to an int based one.
+normalizeStates :: Eq a => Ord a => FSM a -> FSM Int
+normalizeStates fsm@(FSM (ss, fs, ts, es)) = FSM (ss', fs', ts', es')
+ where keymap = S.foldr addKey [] (allStates fsm)
+ ss' = S.map (unwrap . (`lookup` keymap)) ss
+ fs' = S.map (unwrap . (`lookup` keymap)) fs
+ ts' = mapTransitions (unwrap . (`lookup` keymap)) ts
+ es' = mapEpsilons (unwrap . (`lookup` keymap)) es
+
+-- Convert a rule to a FSM
+toFSM :: M.Map Int Rule -> Rule -> FSM Int
+toFSM m End = FSM (S.singleton 1, S.singleton 1, S.empty, S.empty)
+toFSM m (Literal x) = FSM (S.singleton 1, S.singleton 2, S.singleton (1, x, 2), S.empty)
+toFSM m (Reference n) = toFSM m r
+ where (Just r) = M.lookup n m
+toFSM m (Union a b) = normalizeStates $ unionFSMs (toFSM m a) (toFSM m b)
+toFSM m (Concat a b) = normalizeStates $ concatFSMs (toFSM m a) (toFSM m b)
+
+-- Get the new states after performing the given transition
+performTransition :: Ord a => S.Set (a, Char, a) -> S.Set a -> Char -> S.Set a
+performTransition ts ss t = S.fromList [d | (s, c, d) <- S.toList ts, c == t, s `S.member` ss]
+
+-- Get the new states including those that come from epsilon transitions
+performEpsilons :: Ord a => S.Set (a, a) -> S.Set a -> S.Set a
+performEpsilons es ss = S.fromList [d | (s, d) <- S.toList es, s `S.member` ss] `S.union` ss
+
+-- Run all given transitions from the given starting state.
+runFSM :: Ord a => FSM a -> String -> S.Set a -> S.Set a
+runFSM _ "" ss = ss
+runFSM fsm@(FSM (_, _, ts, es)) (x:xs) ss = runFSM fsm xs $ performEpsilons es $ performTransition ts ss x
+
+-- Determine if the given FSM will accept the given string
+acceptedBy :: Ord a => FSM a -> String -> Bool
+acceptedBy fsm@(FSM (ss, fs, _, _)) xs = any (`S.member` fs) $ runFSM fsm xs ss
+
+-- runghc --ghc-arg='-package split' 19a.hs inputs/day19
+main :: IO ()
+main = do
+ args <- getArgs;
+ (rs, ms) <- parseFile (head args);
+ let fsm = toFSM rs (unwrap (M.lookup 0 rs));
+
+ let ps = filter (acceptedBy fsm) ms;
+
+ printf "Answer = %d\n" (length ps) :: IO ();
+
+ return ();
+
+-- Helpers
+
+-- Unwrap a maybe value, throwing an error if wrong
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value"
+
+-- First of a 3tuple
+fst3 :: (a, b, c) -> a
+fst3 (a, _, _) = a
+
+-- Last of a 3 tuple
+lst3 :: (a, b, c) -> c
+lst3 (_, _, c) = c \ No newline at end of file
diff --git a/2020/19b.hs b/2020/19b.hs
new file mode 100644
index 0000000..d1fa763
--- /dev/null
+++ b/2020/19b.hs
@@ -0,0 +1,95 @@
+module Day19B where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+import Data.Char (isDigit)
+import qualified Data.Set as S
+import qualified Data.Map.Strict as M
+
+
+-- Rules parser
+
+-- Types
+data Rule = Literal Char | Reference Int | Concat Rule Rule | Union Rule Rule | End
+ deriving (Eq, Show);
+
+-- Convert a list of rules to the union of those rules
+toUnion :: [Rule] -> Rule
+toUnion [x] = x
+toUnion (x:ys) = Union x (toUnion ys)
+
+-- Parse the given line seperated list of rules
+-- Returns a map from id to rule
+parseRules :: String -> M.Map Int Rule
+parseRules = M.fromList . map parseRule . lines
+
+-- Parse the given rule, in format `0: 1 2 | 3 4`
+parseRule :: String -> (Int, Rule)
+parseRule s = (read idx, toUnion $ map parseNoUnion $ splitOn " | " def)
+ where [idx, def] = splitOn ": " s
+
+
+-- Parse the lower precedence parts (anything that isn't a union)
+parseNoUnion :: String -> Rule
+parseNoUnion "" = End;
+parseNoUnion (' ':xs) = parseNoUnion xs
+parseNoUnion ('"':xs) = Literal (head xs)
+parseNoUnion xs@(x:_) | not (null re)= Concat (Reference (read n)) (parseNoUnion (drop (length n + 1) xs))
+ | otherwise = Reference (read n)
+ where (n:re) = splitOn " " xs
+
+-- Parse the input into a list of rules and list of messages
+parseInput :: String -> (M.Map Int Rule, [String])
+parseInput s = (parseRules rs, lines ms)
+ where [rs, ms] = splitOn "\n\n" s
+
+-- Parse the file with the given name
+parseFile :: String -> IO (M.Map Int Rule, [String])
+parseFile f = do
+ contents <- readFile f
+ return $ parseInput contents;
+
+-- Parser
+
+-- Returns remaining if valid
+attemptConsume :: M.Map Int Rule -> Rule -> String -> [Maybe String]
+attemptConsume m End xs = [Just xs]
+attemptConsume m r [] = [Nothing]
+attemptConsume m (Literal t) (x:xs) | t == x = [Just xs]
+ | otherwise = [Nothing]
+attemptConsume m (Concat a b) xs = concat [attemptConsume m b re | Just re <- attemptConsume m a xs]
+attemptConsume m (Union a b) xs = attemptConsume m b xs ++ attemptConsume m a xs
+attemptConsume m (Reference n) xs = attemptConsume m (unwrap $ M.lookup n m) xs
+
+
+matchedBy :: M.Map Int Rule -> String -> Bool
+matchedBy m s = or [x == "" | Just x <- ps]
+ where ps = attemptConsume m (unwrap $ M.lookup 0 m) s
+
+-- runghc --ghc-arg='-package split' 19b.hs inputs/day19
+main :: IO ()
+main = do
+ args <- getArgs;
+ (rs, ms) <- parseFile (head args);
+
+ let ps = filter (matchedBy rs) ms;
+
+ print (length ps);
+
+ return ();
+
+-- Helpers
+
+-- Unwrap a maybe value, throwing an error if wrong
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value"
+
+-- First of a 3tuple
+fst3 :: (a, b, c) -> a
+fst3 (a, _, _) = a
+
+-- Last of a 3 tuple
+lst3 :: (a, b, c) -> c
+lst3 (_, _, c) = c \ No newline at end of file
diff --git a/2020/1a.hs b/2020/1a.hs
new file mode 100644
index 0000000..adac6bc
--- /dev/null
+++ b/2020/1a.hs
@@ -0,0 +1,28 @@
+module Day1 where
+
+import Text.Read (readMaybe)
+import System.Environment (getArgs)
+
+-- Cartesian product of a set with itself where ordering doesn't matter
+cp :: [a] -> [(a, a)]
+cp [] = []
+cp (x:xs) = [(x, y) | y <- xs] ++ cp xs
+
+getSomes :: [Maybe a] -> [a]
+getSomes xs = [x | Just x <- xs]
+
+sumEq :: Int -> [Int] -> [(Int, Int)]
+sumEq target = filter (\(x,y) -> x + y == target) . cp
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let nums = getSomes $ map readMaybe l :: [Int]
+
+ let (a,b) = head $ sumEq 2020 nums;
+ let r = a * b;
+
+ putStrLn $ show a ++ " + " ++ show b ++ " = 2020";
+ putStrLn $ show a ++ " * " ++ show b ++ " = " ++ show r; \ No newline at end of file
diff --git a/2020/1b.hs b/2020/1b.hs
new file mode 100644
index 0000000..6cebb47
--- /dev/null
+++ b/2020/1b.hs
@@ -0,0 +1,28 @@
+module Day1 where
+
+import Text.Read (readMaybe)
+import System.Environment (getArgs)
+
+-- All 3-tuples you can take from a list (where ordering doesn't matter)
+cp3 :: [a] -> [(a, a, a)]
+cp3 [] = []
+cp3 (x:xs) = [(x, y, z) | y <- xs, z <- xs] ++ cp3 xs
+
+getSomes :: [Maybe a] -> [a]
+getSomes xs = [x | Just x <- xs]
+
+sumEq :: Int -> [Int] -> [(Int, Int, Int)]
+sumEq target = filter (\(x,y,z) -> x + y + z == target) . cp3
+
+main :: IO ()
+main = do
+ args <- getArgs;
+ content <- readFile $ head args;
+ let l = lines content;
+ let nums = getSomes $ map readMaybe l :: [Int]
+
+ let (a,b,c) = head $ sumEq 2020 nums;
+ let r = a * b * c;
+
+ putStrLn $ show a ++ " + " ++ show b ++ " + " ++ show c ++ " = 2020";
+ putStrLn $ show a ++ " * " ++ show b ++ " * " ++ show c ++ " = " ++ show r; \ No newline at end of file
diff --git a/2020/20a.hs b/2020/20a.hs
new file mode 100644
index 0000000..cb91d54
--- /dev/null
+++ b/2020/20a.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE TupleSections #-}
+
+module Day20A where
+
+import System.Environment (getArgs)
+import Data.List.Split (splitOn)
+import Data.List.Extra (groupOn)
+import Data.List (transpose, sort, sortOn)
+import Data.Bool (bool)
+
+-- Types
+
+-- (y, x)
+type Tile = [[Bool]];
+type TileWithId = (Int, Tile);
+type Coord = (Int, Int);
+
+-- Flip Vertical, Rotations (0-3)
+data Orientation = Transform Bool Int;
+
+orients :: [Orientation]
+orients = [Transform f r | f <- [True, False], r <- [0..3]]
+
+-- Tile manipulation
+rotate :: Tile -> Tile
+rotate = transpose . reverse
+
+rotateN :: Int -> Tile -> Tile
+rotateN 0 t = t
+rotateN n t = rotateN (n - 1) (rotate t)
+
+reorient :: Orientation -> Tile -> Tile
+reorient (Transform False n) = rotateN n
+reorient (Transform True n) = rotateN n . reverse
+
+-- Edge manipulation
+
+-- A number uniquely representing this edge
+edgeIdentifier :: [Bool] -> Int
+edgeIdentifier = foldl (\n s -> n * 2 + bool 0 1 s) 0
+
+-- All edges that this tile can have
+-- Returns list of edge ids
+allEdges :: Tile -> [Int]
+allEdges t = map (edgeIdentifier . head . (`reorient` t)) orients
+
+getCornerIDs :: [TileWithId] -> [Int]
+getCornerIDs ts = map (fst . head) $ filter ((== 4) . length) tilesWithUniqEdges
+ where edges = concatMap (\(i, t) -> map (i,) $ allEdges t) ts
+ uniqEdges = map head $ filter ((== 1) . length) $ groupOn snd $ sortOn snd edges
+ tilesWithUniqEdges = groupOn fst $ sort uniqEdges
+
+-- runghc --ghc-arg='-package split' --ghc-arg='-package extra' 20a.hs inputs/day20
+main :: IO ()
+main = do
+ args <- getArgs;
+ ts <- parseFile (head args);
+
+ print $ product $ getCornerIDs ts;
+ return ();
+
+-- Utilities
+maybeNoDefault :: (a -> b) -> Maybe a -> Maybe b
+maybeNoDefault _ Nothing = Nothing
+maybeNoDefault f (Just x) = Just (f x)
+
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value"
+
+-- Get all possible combinations by picking one element from each of the sublists
+oneFromEach :: [[a]] -> [[a]]
+oneFromEach [] = [[]]
+oneFromEach (xs:xss) = concat $ [ map (x : ) (oneFromEach xss) | x <- xs]
+
+-- Parsing
+parseTileDef :: String -> (Int, Tile)
+parseTileDef s = (read n, map readLine ls)
+ where (f:ls) = lines s
+ n = drop 5 $ take (length f - 1) f
+ readLine [] = []
+ readLine ('.':xs) = False : readLine xs
+ readLine ('#':xs) = True : readLine xs
+ readLine _ = error "invalid input"
+
+parseInput :: String -> [(Int, Tile)]
+parseInput = map parseTileDef . splitOn "\n\n"
+
+parseFile :: String -> IO [(Int, Tile)]
+parseFile f = do
+ c <- readFile f
+ return $ parseInput c; \ No newline at end of file
diff --git a/2020/20b.hs b/2020/20b.hs
new file mode 100644
index 0000000..7bce210
--- /dev/null
+++ b/2020/20b.hs
@@ -0,0 +1,306 @@
+{-# LANGUAGE TupleSections #-}
+
+module Day20B where
+
+import Data.Maybe (isNothing, isJust)
+import Data.List (transpose, sortOn, nub)
+import Data.List.Split (splitOn)
+import System.Environment (getArgs)
+import qualified Data.Map.Strict as M
+import Text.Printf (printf)
+import Debug.Trace (trace)
+
+-- Types
+
+-- (y, x)
+type Tile = [[Bool]];
+type TileWithId = (Int, Tile);
+type Coord = (Int, Int);
+type Grid = M.Map Coord TileWithId;
+
+-- Flip Vertical, Rotations (0-3)
+data Orientation = Transform Bool Int;
+
+orients :: [Orientation]
+orients = [Transform f r | f <- [True, False], r <- [0..3]]
+
+-- top, left, right, bottom
+data Side = T | L | R | B
+ deriving (Show, Eq);
+
+sides :: [Side]
+sides = [T, L, R, B]
+
+complement :: Side -> Side
+complement T = B
+complement B = T
+complement L = R
+complement R = L
+
+-- Tile manipulation
+rotate :: Tile -> Tile
+rotate = transpose . reverse
+
+rotateN :: Int -> Tile -> Tile
+rotateN 0 t = t
+rotateN n t = rotateN (n - 1) (rotate t)
+
+reorient :: Orientation -> Tile -> Tile
+reorient (Transform False n) = rotateN n
+reorient (Transform True n) = rotateN n . reverse
+
+permutations :: Tile -> [Tile]
+permutations t = [reorient o t | o <- orients]
+
+--- Side / Edge manipulation
+-- Get the border on the given side of the tile
+border :: Side -> Tile -> [Bool]
+border T t = head t
+border B t = last t
+border L t = map head t
+border R t = map last t
+
+-- Get all borders of a given tile
+borders :: Tile -> [[Bool]]
+borders t = map (`border` t) sides
+
+-- Get the coord at the given side of that coord
+getSideCoord :: Coord -> Side -> Coord
+getSideCoord (x, y) T = (x, y - 1)
+getSideCoord (x, y) B = (x, y + 1)
+getSideCoord (x, y) L = (x - 1, y)
+getSideCoord (x, y) R = (x + 1, y)
+
+-- Return true if y is on the s of x
+checkBorder :: Tile -> Tile -> Side -> Bool
+checkBorder x y s = border (complement s) y == border s x
+
+-- y is on the s of x (if it exists)
+attemptCheckBorder :: Tile -> Maybe Tile -> Side -> Bool
+attemptCheckBorder _ Nothing _ = True
+attemptCheckBorder x (Just y) s = checkBorder x y s
+
+--- Grid manipulations
+
+-- Get the bounds of the grid
+-- Returns (low, high)
+squareBounds :: M.Map Coord a -> (Coord, Coord)
+squareBounds g = (M.foldrWithKey (compCoord min) (0, 0) g,
+ M.foldrWithKey (compCoord max) (0, 0) g)
+ where compCoord f (x', y') _ (x, y) = (f x' x, f y' y)
+
+-- Get the corners of the grid
+getCorners :: Grid -> [Coord]
+getCorners g = [(lx, ly), (lx, hy), (hx, ly), (hx, hy)]
+ where ((lx, ly), (hx, hy)) = squareBounds g
+
+-- Returns true if the grid is rectangular
+isRect :: Grid -> Bool
+isRect g = all (isJust . (g M.!?)) (getCorners g)
+
+-- Return true if given side is unfilled for coord of grid
+sideIsUnfilled :: Side -> Grid -> Coord -> Bool
+sideIsUnfilled s g c = isNothing $ M.lookup (getSideCoord c s) g
+
+--- Checking and solving
+fitsSpace :: Grid -> Coord -> Tile -> Bool
+fitsSpace g c t = and [attemptCheckBorder t (maybeNoDefault snd $ M.lookup (getSideCoord c s) g) s | s <- sides]
+
+-- Returns tiles that could be on the given side of the given coord
+possibleNeighbours :: [TileWithId] -> Grid -> Coord -> Side -> [TileWithId]
+possibleNeighbours ts g c s = filter (fitsSpace g c' . snd) ts
+ where c' = getSideCoord c s
+
+-- Check if the entire grid is valid
+isValid :: Grid -> Bool
+isValid m = M.foldrWithKey checkSquare True m
+ where checkSquare l (_, t) v = v && fitsSpace m l t
+
+-- Add to the given side of each coord, returning all possible ways to do so and the remaining tiles from each.
+fillSideOnce :: Side -> [TileWithId] -> Grid -> [([TileWithId], Grid)]
+fillSideOnce _ [] m = [([], m)]
+fillSideOnce s xs m | null mutations = [(xs, m)]
+ | otherwise = mutatedMaps
+ where mutations :: [(Coord, [TileWithId])] -- list of squares to mutate, and possibilities
+ mutations = filter (not . null . snd) $ map getNextFill $ M.toList m
+ getNextFill :: (Coord, TileWithId) -> (Coord, [TileWithId])
+ getNextFill (c, _) | sideIsUnfilled s m c = (getSideCoord c s, possibleNeighbours xs m c s)
+ | otherwise = (getSideCoord c s, [])
+ attempts :: [[(Coord, TileWithId)]] -- All the possible lists of mutations we can make
+ attempts = filter (allUnique . map (fst . snd)) $ map (zip $ map fst mutations) (oneFromEach $ map snd mutations)
+ mutatedMaps :: [([TileWithId], Grid)] -- new remaining tiles, new grid
+ mutatedMaps = map doAllMutations attempts
+ doAllMutations :: [(Coord, TileWithId)] -> ([TileWithId], Grid)
+ doAllMutations = foldr mutateMap (xs, m)
+ mutateMap :: (Coord, TileWithId) -> ([TileWithId], Grid) -> ([TileWithId], Grid)
+ mutateMap (newC, (newId, newTile)) (re, grid) = (filter ((/= newId) . fst) re, M.insert newC (newId, newTile) grid)
+
+fillRect :: [([TileWithId], Grid)] -> [([TileWithId], Grid)]
+fillRect xs | not (null fullSols) = fullSols
+ | otherwise = fillRect $ filter (not . (`elem` xs)) $ foldr (\s ps -> concatMap (uncurry $ fillSideOnce s) ps) xs sides
+ where fullSols = filter (null . fst) xs
+
+-- Pattern matching
+type Pattern = [Coord] -- List of coord offsets that must be set.
+
+data Square = Empty | Filled | Highlight
+ deriving (Eq, Show);
+type PlainGrid = M.Map Coord [[Square]]
+
+toSquare :: Bool -> Square
+toSquare True = Filled
+toSquare False = Empty
+
+monsterPattern :: Pattern
+monsterPattern = [
+ (0, 1),
+ (1, 2),
+ (4, 2),
+ (5, 1),
+ (6, 1),
+ (7, 2),
+ (10, 2),
+ (11, 1),
+ (12, 1),
+ (13, 2),
+ (16, 2),
+ (17, 1),
+ (18, 0),
+ (18, 1),
+ (19, 1)
+ ]
+
+patternAt :: Pattern -> Coord -> [Coord]
+patternAt p c = map (addCoord c) p
+
+-- Get the value at a specific coord
+getSpecificCoord :: PlainGrid -> Coord -> Maybe Square
+getSpecificCoord g (x, y) = getFromTile $ g M.!? (x `div` tileSize, y `div` tileSize)
+ where tileSize = length $ g M.! (0, 0)
+ getFromTile Nothing = Nothing
+ getFromTile (Just t) = Just $ t!!(y `mod` tileSize)!!(x `mod` tileSize)
+
+-- Set the value at a specific coord
+setSpecificCoord :: PlainGrid -> Coord -> Square -> PlainGrid
+setSpecificCoord g (x, y) b = M.insert (tx, ty) t' g
+ where tileSize = length $ g M.! (0, 0)
+ (tx, ty) = (x `div` tileSize, y `div` tileSize)
+ (sx, sy) = (x `mod` tileSize, y `mod` tileSize)
+ t = g M.! (tx, ty)
+ r = t!!sy
+ r' = take sx r ++ [b] ++ drop (sx + 1) r
+ t' = take sy t ++ [r'] ++ drop (sy + 1) t
+
+-- Returns true if the pattern is true at the given coord
+patternTrueAt :: PlainGrid -> Coord -> Pattern -> Bool
+patternTrueAt g b = all (areSet . addCoord b)
+ where areSet c = case getSpecificCoord g c of
+ Just Filled -> True
+ Just Highlight -> True
+ _ -> False
+
+-- Strip all borders from all tiles
+stripBorders :: Grid -> PlainGrid
+stripBorders = M.map strip
+ where strip (_, t) = map (map toSquare . init . tail) $ init $ tail t
+
+-- Find all occurences of a pattern
+findAllOccs :: PlainGrid -> Pattern -> [Coord]
+findAllOccs g p = trace (show (lx, hy, hx, hy)) $ filter (\c -> patternTrueAt g c p) $ [(x, y) | x <- [lx..hx], y <- [ly..hy]]
+ where ((ltx, lty), (htx, hty)) = squareBounds g
+ tileSize = length $ head $ g M.! (0, 0)
+ (lx, ly) = (ltx * tileSize, lty * tileSize)
+ (hx, hy) = ((htx + 1) * tileSize, (hty + 1) * tileSize)
+
+-- runghc --ghc-arg='-package split' --ghc-arg='-package extra' 20a.hs inputs/day20
+main :: IO ()
+main = do
+ args <- getArgs;
+ ((si, st):ts) <- parseFile (head args);
+
+ -- Expand the tiles to include all orientations
+ let ts' = concatMap (\(i, t) -> map (i,) $ permutations t) ts;
+ printf "%d possible tiles\n" (length ts');
+
+ -- Get our starting states
+ let starting = [(ts', M.singleton (0, 0) (si, t')) | t' <- permutations st];
+
+ -- Get the first solution that uses all tiles
+ let imgs = map snd $ filter (null . fst) $ fillRect starting;
+
+ printf "Found %d images\n" (length imgs);
+
+ -- Remove border tiles
+ let imgs' = map stripBorders imgs;
+
+ -- Find the monsters
+ let ((df, ms):_) = sortOn ((0 -) . length . snd) $ map (\img -> (img, findAllOccs img monsterPattern)) imgs';
+
+ printf "Found, at most, %d monsters\n" (length ms);
+
+ -- Delete all tiles part of a monster
+ let tiles = concatMap (patternAt monsterPattern) ms;
+ let img' = foldr (\c i -> setSpecificCoord i c Highlight) df tiles;
+
+ putStr $ prettyPrint img';
+
+ let answer = length $ filter (== Filled) $ concatMap (concat . snd) $ M.toList img';
+ printf "Tiles remaining = %d\n" answer;
+ return ();
+
+-- Utilities
+maybeNoDefault :: (a -> b) -> Maybe a -> Maybe b
+maybeNoDefault _ Nothing = Nothing
+maybeNoDefault f (Just x) = Just (f x)
+
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value"
+
+addCoord :: Coord -> Coord -> Coord
+addCoord (x, y) (x', y') = (x + x', y + y')
+
+-- Get all possible combinations by picking one element from each of the sublists
+oneFromEach :: [[a]] -> [[a]]
+oneFromEach [] = [[]]
+oneFromEach (xs:xss) = concat $ [ map (x : ) (oneFromEach xss) | x <- xs]
+
+allUnique :: Eq a => [a] -> Bool
+allUnique xs = length (nub xs) == length xs
+
+-- Pretty printing
+prettyPrintIds :: PlainGrid -> String
+prettyPrintIds grid = unlines [concatMap show (getRow y) | y <- [lyc..hyc]]
+ where ((_, lyc), (_, hyc)) = squareBounds grid
+ getRow y = map fst $ M.toAscList $ M.filterWithKey (\(_, y') _ -> y' == y) grid
+
+prettyPrint :: PlainGrid -> String
+prettyPrint grid = concat [unlines $ printTiles (getRow y) | y <- [lyc..hyc]]
+ where tileSize = length (grid M.! (0, 0))
+ ((_, lyc), (_, hyc)) = squareBounds grid
+ getRow y = map snd $ M.toAscList $ M.filterWithKey (\(_, y') _ -> y' == y) grid
+ printTiles ts = [concatMap (rowToStr . (!!y)) ts | y <- [0..tileSize - 1]]
+
+rowToStr :: [Square] -> String
+rowToStr [] = ""
+rowToStr (Filled:xs) = '#' : rowToStr xs
+rowToStr (Empty:xs) = '.' : rowToStr xs
+rowToStr (Highlight:xs) = 'O' : rowToStr xs
+
+-- Parsing
+parseTileDef :: String -> (Int, Tile)
+parseTileDef s = (read n, map readLine ls)
+ where (f:ls) = lines s
+ n = drop 5 $ take (length f - 1) f
+ readLine [] = []
+ readLine ('.':xs) = False : readLine xs
+ readLine ('#':xs) = True : readLine xs
+ readLine _ = error "invalid input"
+
+parseInput :: String -> [(Int, Tile)]
+parseInput = map parseTileDef . splitOn "\n\n"
+
+parseFile :: String -> IO [(Int, Tile)]
+parseFile f = do
+ c <- readFile f
+ return $ parseInput c; \ No newline at end of file
diff --git a/2020/21a.hs b/2020/21a.hs
new file mode 100644
index 0000000..d7006ac
--- /dev/null
+++ b/2020/21a.hs
@@ -0,0 +1,60 @@
+module Day21A where
+
+import System.Environment (getArgs)
+import Data.List (nub)
+import Data.List.Split (splitOn)
+
+-- Types
+type Food = ([String], [String])
+
+-- Parse a single line
+parseFood :: String -> Food
+parseFood x = (splitOn " " ings, splitOn ", " algsNParen)
+ where [ings, algs] = splitOn " (contains " x
+ algsNParen = take (length algs - 1) algs
+
+-- Parse a whole file
+parseFoods :: String -> [Food]
+parseFoods = map parseFood . lines
+
+parseFile :: String -> IO [Food]
+parseFile f = do
+ c <- readFile f
+ return (parseFoods c);
+
+-- Returns true if x is a sublist of y.
+sublist :: Eq a => [a] -> [a] -> Bool
+sublist xs l = foldr (\x a -> a && x `elem` l) True xs
+
+-- Get a list of foods with the given allergen
+withAls :: [Food] -> String -> [Food]
+withAls fs x = filter ((x `elem`) . snd) fs
+
+-- Get a list of foods with the given ing
+withIng :: [Food] -> String -> [Food]
+withIng fs x = filter ((x `elem`) . fst) fs
+
+-- Get all ingredients in all the given foods
+allIngs :: [Food] -> [String]
+allIngs fs = nub $ concatMap fst fs
+
+-- Get all allergens in all the given foods
+allAls :: [Food] -> [String]
+allAls fs = nub $ concatMap snd fs
+
+-- Get a list of foods that are in all foods with the given allergen
+getSynonymous :: [Food] -> String -> [String]
+getSynonymous fs x = filter ((xs `sublist`) . withIng fs) (allIngs fs)
+ where xs = withAls fs x
+
+
+-- Usage: runghc --ghc-arg="-package split" 21a.hs inputs/day21
+main :: IO ()
+main = do
+ args <- getArgs;
+ fs <- parseFile $ head args;
+ let syn = nub $ concatMap (getSynonymous fs) (allAls fs);
+ let notSyn = filter (not . (`elem` syn)) (allIngs fs);
+
+ print $ sum $ map (length . withIng fs) notSyn;
+ return (); \ No newline at end of file
diff --git a/2020/21b.hs b/2020/21b.hs
new file mode 100644
index 0000000..3620d3d
--- /dev/null
+++ b/2020/21b.hs
@@ -0,0 +1,74 @@
+module Day21B where
+
+import System.Environment (getArgs)
+import Data.List (nub, sort)
+import Data.List.Split (splitOn)
+
+-- Types
+type Food = ([String], [String])
+
+-- Parse a single line
+parseFood :: String -> Food
+parseFood x = (splitOn " " ings, splitOn ", " algsNParen)
+ where [ings, algs] = splitOn " (contains " x
+ algsNParen = take (length algs - 1) algs
+
+-- Parse a whole file
+parseFoods :: String -> [Food]
+parseFoods = map parseFood . lines
+
+parseFile :: String -> IO [Food]
+parseFile f = do
+ c <- readFile f
+ return (parseFoods c);
+
+-- Returns true if x is a sublist of y.
+sublist :: Eq a => [a] -> [a] -> Bool
+sublist xs l = foldr (\x a -> a && x `elem` l) True xs
+
+-- Get a list of foods with the given allergen
+withAls :: [Food] -> String -> [Food]
+withAls fs x = filter ((x `elem`) . snd) fs
+
+-- Get a list of foods with the given ing
+withIng :: [Food] -> String -> [Food]
+withIng fs x = filter ((x `elem`) . fst) fs
+
+-- Get all ingredients in all the given foods
+allIngs :: [Food] -> [String]
+allIngs fs = nub $ concatMap fst fs
+
+-- Get all allergens in all the given foods
+allAls :: [Food] -> [String]
+allAls fs = nub $ concatMap snd fs
+
+-- Get a list of foods that are in all foods with the given allergen
+getSynonymous :: [Food] -> String -> [String]
+getSynonymous fs x = filter ((xs `sublist`) . withIng fs) (allIngs fs)
+ where xs = withAls fs x
+
+-- Takes a list of lists of possibilities, and selects one from each such that there are no duplicates
+selectOne :: Eq a => [[a]] -> [a]
+selectOne xs | all ((== 1) . length) ps = map head ps
+ | ps == xs = selectOne $ ([head $ head undecided]:tail undecided) ++ singletons
+ | otherwise = selectOne ps -- Recurse until every list of possibilities is singleton
+ where singletons = filter ((== 1) . length) xs
+ undecided = filter ((> 1) . length) xs
+ reqs = map head singletons -- Numbers that are already taken
+ ps = map (\x -> if length x > 1 then deleteReqs x else x) xs -- Possibilities assuming this one is taken
+ deleteReqs (n:ns) | n `elem` reqs = ns
+ | otherwise = n : deleteReqs ns
+ deleteReqs [] = []
+
+-- Usage: runghc --ghc-arg="-package split" 21b.hs inputs/day21
+main :: IO ()
+main = do
+ args <- getArgs;
+ fs <- parseFile $ head args;
+ let as = sort $ allAls fs;
+ let ps = map (getSynonymous fs) as;
+ let als = zip as (selectOne ps)
+
+ print als;
+ putStrLn $ init $ concatMap ((++ ",") . snd) als;
+ return (); \ No newline at end of file
diff --git a/2020/22a.hs b/2020/22a.hs
new file mode 100644
index 0000000..95ae117
--- /dev/null
+++ b/2020/22a.hs
@@ -0,0 +1,54 @@
+module Day22A where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+
+-- Types
+-- Top = First
+type Deck = [Int];
+
+-- (P1, P2)
+type State = (Deck, Deck);
+
+-- Parsing
+
+parseDeck :: String -> Deck
+parseDeck = map read . tail . lines
+
+-- Parse the input
+parseInput :: String -> State
+parseInput xs = (p1, p2)
+ where [p1, p2] = map parseDeck $ splitOn "\n\n" xs
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO State
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+takeTurn :: State -> State
+takeTurn (c1:p1, c2:p2) | c1 > c2 = (p1 ++ [c1, c2], p2)
+ | otherwise = (p1, p2 ++ [c2, c1])
+takeTurn ([], _) = error "game is over!"
+takeTurn (_, []) = error "game is over!"
+
+getWinner :: State -> Deck
+getWinner (p1, []) = p1
+getWinner ([], p2) = p2
+getWinner s = getWinner $ takeTurn s
+
+getScore :: Deck -> Int
+getScore d = sum $ zipWith (*) (reverse [1..length d]) d
+
+-- runghc --ghc-arg='-package split' 22a.hs inputs/day22
+main :: IO ()
+main = do
+ args <- getArgs;
+ s <- parseFromFile (head args);
+
+ let winnerScore = getScore $ getWinner s;
+ printf "Answer = %d\n" winnerScore :: IO ();
+
+ return ();
diff --git a/2020/22b.hs b/2020/22b.hs
new file mode 100644
index 0000000..167e3ba
--- /dev/null
+++ b/2020/22b.hs
@@ -0,0 +1,71 @@
+module Day22B where
+
+import System.Environment (getArgs)
+import Text.Printf
+import Data.List.Split (splitOn)
+
+-- Types
+
+data Player = P1 | P2;
+
+-- Top = First
+type Deck = [Int];
+
+-- (P1, P2)
+type State = (Deck, Deck);
+
+-- Parsing
+
+parseDeck :: String -> Deck
+parseDeck = map read . tail . lines
+
+-- Parse the input
+parseInput :: String -> State
+parseInput xs = (p1, p2)
+ where [p1, p2] = map parseDeck $ splitOn "\n\n" xs
+
+-- Parse a file given the path
+-- Returns list of instructions
+parseFromFile :: String -> IO State
+parseFromFile s = do
+ contents <- readFile s;
+ return $ parseInput contents;
+
+takeTurn :: State -> [State] -> (State, [State])
+takeTurn s@(c1:p1, c2:p2) h | s `elem` h = ((p1 ++ p2 ++ [c1, c2], []), h)
+ | length p1 >= c1
+ && length p2 >= c2 = case getPlayerWinner ((take c1 p1, take c2 p2), []) of
+ P1 -> p1Win
+ P2 -> p2Win
+ | c1 > c2 = p1Win
+ | otherwise = p2Win
+ where p1Win = ((p1 ++ [c1, c2], p2), h')
+ p2Win = ((p1, p2 ++ [c2, c1]), h')
+ h' = s : h
+
+takeTurn ([], _) _ = error "game is over!"
+takeTurn (_, []) _ = error "game is over!"
+
+getPlayerWinner :: (State, [State]) -> Player
+getPlayerWinner ((_, []), _) = P1
+getPlayerWinner (([], _), _) = P2
+getPlayerWinner (s, h) = getPlayerWinner $ takeTurn s h
+
+getWinner :: (State, [State]) -> Deck
+getWinner ((p1, []), _) = p1
+getWinner (([], p2), _) = p2
+getWinner (s, h) = getWinner $ takeTurn s h
+
+getScore :: Deck -> Int
+getScore d = sum $ zipWith (*) (reverse [1..length d]) d
+
+-- runghc --ghc-arg='-package split' 22a.hs inputs/day22
+main :: IO ()
+main = do
+ args <- getArgs;
+ s <- parseFromFile (head args);
+
+ let winnerScore = getScore $ getWinner (s, []);
+ printf "Answer = %d\n" winnerScore :: IO ();
+
+ return ();
diff --git a/2020/23a.hs b/2020/23a.hs
new file mode 100644
index 0000000..ef515d4
--- /dev/null
+++ b/2020/23a.hs
@@ -0,0 +1,54 @@
+module Day23A where
+
+import System.Environment (getArgs)
+import Data.List (elemIndex)
+
+-- Types
+type State = [Int];
+
+-- Parsing input
+parseLine :: String -> [Int]
+parseLine = map (read . (: ""))
+
+parseFile :: String -> IO [Int]
+parseFile f = do
+ c <- readFile f
+ return (parseLine c);
+
+-- Get the index of the destination cup, given (n - 1)
+getDestIdx :: Int -> [Int] -> Int
+getDestIdx x is | x `elem` is = unwrap $ elemIndex x is
+ | x < minimum is = unwrap $ elemIndex (maximum is) is
+ | otherwise = getDestIdx (x - 1) is
+
+-- n, current state, assumes current cup is cup 0
+performMoves :: Int -> State -> State
+performMoves 0 s = s
+performMoves n (c:cs) = performMoves (n - 1) s''
+ where re = c : drop 3 cs
+ as = take 3 cs
+ dI = getDestIdx (c - 1) re
+ s' = take (dI + 1) re ++ as ++ drop (dI + 1) re
+ s'' = moveToFront s' (head $ tail re)
+
+-- Usage: runghc 23a.hs inputs/day23
+main :: IO ()
+main = do
+ args <- getArgs;
+ circ <- parseFile $ head args;
+
+ let final = performMoves 100 circ;
+ putStrLn $ tail $ concatMap show (moveToFront final 1);
+ return ();
+
+-- Utilities
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value"
+
+
+-- Move the given item to the front of the list, maintaining order.
+moveToFront :: Eq a => [a] -> a -> [a]
+moveToFront [] _ = []
+moveToFront (x:xs) t | t == x = x : xs
+ | otherwise = moveToFront (xs ++ [x]) t
diff --git a/2020/23b.hs b/2020/23b.hs
new file mode 100644
index 0000000..926ce5e
--- /dev/null
+++ b/2020/23b.hs
@@ -0,0 +1,82 @@
+module Main where
+
+import System.Environment (getArgs)
+import Text.Printf (printf)
+import qualified Data.IntMap as M;
+import Debug.Trace (trace)
+import Data.List (foldl')
+
+-- Types
+-- Stores the next cup for each cup value.
+type State = M.IntMap Int;
+
+-- Parsing input
+parseLine :: String -> [Int]
+parseLine = map (read . (: ""))
+
+parseFile :: String -> IO [Int]
+parseFile f = do
+ c <- readFile f
+ return (parseLine c);
+
+-- The maximum value cup to use
+maxCup :: Int
+maxCup = 1000000
+
+getNextCup :: State -> Int -> Int;
+getNextCup m n = M.findWithDefault (n + 1) n m
+
+-- Get the label of destination cup, given the current cup and the cups set aside
+getDestCup :: Int -> [Int] -> Int
+getDestCup x r | x <= 1 = last [i | i <- [maxCup - 4..maxCup], i `notElem` r]
+ | x - 1 `notElem` r = x - 1
+ | otherwise = getDestCup (x - 1) r
+
+-- Returns new state and whole chain of removed ones
+takeN :: State -> Int -> Int -> (State, [Int])
+takeN s i n = (M.insert i after s, finalIn)
+ where (_:finalIn) = foldr (\_ ks -> ks ++ [s `getNextCup` last ks]) [i] [1..n]
+ after = s `getNextCup` last finalIn
+
+
+-- Perform a single move on the given state with the given current cup
+-- Returns the new state and next current cup
+performMove :: State -> Int -> (State, Int)
+performMove m c = (m', (m' `getNextCup` c))
+ where (re, chain) = takeN m c 3
+ d = getDestCup c chain
+ m' = M.fromList [(d, head chain), (last chain, m `getNextCup` d)] `M.union` re
+
+-- Repeatedly performMove. This uses foldl' to prevent stack overflow
+performMoves :: State -> Int -> Int -> State
+performMoves s c n = fst $ foldl' (\(s', c') n -> performMove s' c') (s, c) [1..n]
+
+constructState :: [Int] -> State
+constructState xs = M.fromList [(last xs, maximum xs + 1), (maxCup, head xs)] `M.union` inner xs
+ where inner [] = M.empty
+ inner [x] = M.empty
+ inner (x:y:ns) = M.insert x y $ inner (y:ns)
+
+-- This is infinite, so use `take`
+getLinear :: State -> Int -> [Int]
+getLinear s c = n : getLinear s n
+ where n = s `getNextCup` c
+
+-- Usage: runghc 23b.hs inputs/day23
+main :: IO ()
+main = do
+ args <- getArgs;
+ ns <- parseFile $ head args;
+
+ let circ = constructState ns;
+
+ let final = performMoves circ (head ns) 10000000;
+ let [a,b] = take 2 $ getLinear final 1;
+
+ printf "%d * %d = %d\n" a b (a * b);
+ return ();
+
+-- Utilities
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value" \ No newline at end of file
diff --git a/2020/24a.hs b/2020/24a.hs
new file mode 100644
index 0000000..35a96de
--- /dev/null
+++ b/2020/24a.hs
@@ -0,0 +1,67 @@
+module Day24A where
+
+import System.Environment (getArgs)
+import Data.List (elemIndex)
+import qualified Data.Map.Strict as M;
+
+-- Types
+
+data Direction = E | SE | SW | W | NW | NE
+ deriving (Eq, Show);
+
+data Colour = White | Black
+ deriving (Eq, Show);
+
+type Coord = (Int, Int, Int);
+type Grid = M.Map Coord Colour;
+
+inverse :: Colour -> Colour
+inverse White = Black
+inverse Black = White
+
+-- Parsing
+parseDirections :: String -> [Direction]
+parseDirections "" = []
+parseDirections ('e':xs) = E : parseDirections xs
+parseDirections ('w':xs) = W : parseDirections xs
+parseDirections ('s':'e':xs) = SE : parseDirections xs
+parseDirections ('s':'w':xs) = SW : parseDirections xs
+parseDirections ('n':'e':xs) = NE : parseDirections xs
+parseDirections ('n':'w':xs) = NW : parseDirections xs
+parseDirections _ = error "Invalid directions"
+
+parseFile :: String -> IO [[Direction]]
+parseFile f = do
+ c <- readFile f;
+ return $ map parseDirections $ lines c;
+
+-- Grid manipulation
+
+flipTile :: Grid -> Coord -> Grid
+flipTile g c = M.insert c (inverse $ M.findWithDefault White c g) g
+
+baseCoord :: Coord
+baseCoord = (0, 0, 0)
+
+followDirections :: Coord -> [Direction] -> Coord
+followDirections c [] = c
+followDirections (x, y, z) (E:ds) = followDirections (x + 1, y - 1, z) ds
+followDirections (x, y, z) (W:ds) = followDirections (x - 1, y + 1, z) ds
+followDirections (x, y, z) (NE:ds) = followDirections (x + 1, y, z - 1) ds
+followDirections (x, y, z) (NW:ds) = followDirections (x, y + 1, z - 1) ds
+followDirections (x, y, z) (SE:ds) = followDirections (x, y - 1, z + 1) ds
+followDirections (x, y, z) (SW:ds) = followDirections (x - 1, y, z + 1) ds
+
+flipByDirections :: [Direction] -> Grid -> Grid
+flipByDirections ds g = flipTile g $ followDirections baseCoord ds
+
+-- Usage: runghc 24a.hs inputs/day24
+main :: IO ()
+main = do
+ args <- getArgs;
+ ds <- parseFile $ head args;
+
+ let final = foldr flipByDirections M.empty ds;
+ let blacks = M.size $ M.filter (== Black) final;
+ print blacks;
+ return (); \ No newline at end of file
diff --git a/2020/24b.hs b/2020/24b.hs
new file mode 100644
index 0000000..6e82148
--- /dev/null
+++ b/2020/24b.hs
@@ -0,0 +1,100 @@
+module Day24B where
+
+import System.Environment (getArgs)
+import Data.List (elemIndex)
+import Data.Maybe (isJust)
+import qualified Data.Map.Strict as M;
+import qualified Data.Set as S;
+
+-- Types
+data Direction = E | SE | SW | W | NW | NE
+ deriving (Eq, Show);
+
+dirs :: [Direction]
+dirs = [E, SE, SW, W, NW, NE]
+
+data Colour = White | Black
+ deriving (Eq, Show);
+
+type Coord = (Int, Int, Int);
+type Grid = M.Map Coord Colour;
+
+inverse :: Colour -> Colour
+inverse White = Black
+inverse Black = White
+
+type Blacks = S.Set Coord;
+
+-- Parsing
+parseDirections :: String -> [Direction]
+parseDirections "" = []
+parseDirections ('e':xs) = E : parseDirections xs
+parseDirections ('w':xs) = W : parseDirections xs
+parseDirections ('s':'e':xs) = SE : parseDirections xs
+parseDirections ('s':'w':xs) = SW : parseDirections xs
+parseDirections ('n':'e':xs) = NE : parseDirections xs
+parseDirections ('n':'w':xs) = NW : parseDirections xs
+parseDirections _ = error "Invalid directions"
+
+parseFile :: String -> IO [[Direction]]
+parseFile f = do
+ c <- readFile f;
+ return $ map parseDirections $ lines c;
+
+-- Grid manipulation
+flipTile :: Grid -> Coord -> Grid
+flipTile g c = M.insert c (inverse $ g `getTile` c) g
+
+baseCoord :: Coord
+baseCoord = (0, 0, 0)
+
+getTile :: Grid -> Coord -> Colour
+getTile g c = M.findWithDefault White c g
+
+followDirections :: Coord -> [Direction] -> Coord
+followDirections c [] = c
+followDirections (x, y, z) (E:ds) = followDirections (x + 1, y - 1, z) ds
+followDirections (x, y, z) (W:ds) = followDirections (x - 1, y + 1, z) ds
+followDirections (x, y, z) (NE:ds) = followDirections (x + 1, y, z - 1) ds
+followDirections (x, y, z) (NW:ds) = followDirections (x, y + 1, z - 1) ds
+followDirections (x, y, z) (SE:ds) = followDirections (x, y - 1, z + 1) ds
+followDirections (x, y, z) (SW:ds) = followDirections (x - 1, y, z + 1) ds
+
+flipByDirections :: [Direction] -> Grid -> Grid
+flipByDirections ds g = flipTile g $ followDirections baseCoord ds
+
+-- Part B
+
+-- Convert a grid to a set of black tiles
+toBlacksSet :: Grid -> Blacks
+toBlacksSet g = S.fromList $ map fst $ M.toList $ M.filter (== Black) g
+
+-- Get a map of coords to the number of black neighbours
+blackNeighbours :: Blacks -> M.Map Coord Int
+blackNeighbours bs = foldr addToNeighbours M.empty bs
+ where addToNeighbours c m = foldr addToCoord m [followDirections c [d] | d <- dirs]
+ addToCoord c m = M.insert c (1 + M.findWithDefault 0 c m) m
+
+-- Simulate one iteration given the rules in part B
+simulateOnce :: Blacks -> Blacks
+simulateOnce bs = maintainedBlacks `S.union` newBlacks
+ where bns = blackNeighbours bs
+ getBns c = M.findWithDefault 0 c bns
+ maintainedBlacks = S.filter (\c -> getBns c <= 2 && getBns c > 0) bs
+ newBlacks = S.fromList $ map fst $ M.toList $ M.filterWithKey (\c n -> n == 2 && c `S.notMember` bs) bns
+
+-- Usage: runghc 24b.hs inputs/day24
+main :: IO ()
+main = do
+ args <- getArgs;
+ ds <- parseFile $ head args;
+
+ let start = toBlacksSet $ foldr flipByDirections M.empty ds;
+ let final = foldr (\_ g -> simulateOnce g) start [1..100];
+ print (length final);
+ return ();
+
+-- Utilities
+unwrap :: Maybe a -> a
+unwrap (Just x) = x
+unwrap _ = error "unwrap on null value" \ No newline at end of file
diff --git a/2020/25a.hs b/2020/25a.hs
new file mode 100644
index 0000000..7b96ed4
--- /dev/null
+++ b/2020/25a.hs
@@ -0,0 +1,43 @@
+module Day25A where
+
+import System.Environment (getArgs)
+import Text.Printf (printf)
+import Data.Bits
+
+modExp :: Integer -> Integer -> Integer -> Integer
+modExp b 0 m = 1
+modExp b e m = t * modExp ((b * b) `mod` m) (shiftR e 1) m `mod` m
+ where t = if testBit e 0 then b `mod` m else 1
+
+-- subject, loop size
+encrypt :: Integer -> Integer -> Integer
+encrypt s n = modExp s n 20201227
+
+-- Brute force the loop size used for the given number with the given subject
+bruteLoopSize :: Integer -> Integer -> Integer
+bruteLoopSize k s = getNEqual 1 1
+ where getNEqual n x | new == k = n
+ | otherwise = getNEqual (n + 1) new
+ where new = (x * s) `mod` 20201227
+
+parseFile :: String -> IO (Integer, Integer)
+parseFile f = do
+ c <- readFile f;
+ let [a, b] = map read $ lines c;
+ return (a, b);
+
+-- runghc 25a.hs inputs/day25
+main :: IO ()
+main = do
+ args <- getArgs;
+ (a, b) <- parseFile $ head args;
+
+ let aLoop = bruteLoopSize a 7;
+ let bLoop = bruteLoopSize b 7;
+
+ printf "a loop size = %d\nb loop size = %d\n" aLoop bLoop;
+
+ let enc = encrypt a bLoop;
+ printf "key = %d\n" enc;
+
+ return ();
diff --git a/2020/LICENSE b/2020/LICENSE
new file mode 100644
index 0000000..2b1be0d
--- /dev/null
+++ b/2020/LICENSE
@@ -0,0 +1,7 @@
+Copyright 2020 Oscar Shrimpton
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file
diff --git a/2020/README.md b/2020/README.md
new file mode 100644
index 0000000..c0deabd
--- /dev/null
+++ b/2020/README.md
@@ -0,0 +1,3 @@
+# advent of code 2020
+
+My solutions for the [Advent of Code](https://adventofcode.com/) 2020. Most of these are in Haskell, since I was learning it in uni and I felt like practicing. \ No newline at end of file
diff --git a/2020/inputs/day1 b/2020/inputs/day1
new file mode 100644
index 0000000..7b7f47a
--- /dev/null
+++ b/2020/inputs/day1
@@ -0,0 +1,200 @@
+1713
+1281
+1185
+1501
+1462
+1752
+1363
+1799
+1071
+1446
+1685
+1706
+1726
+1567
+1867
+1376
+1445
+1971
+1429
+1749
+438
+1291
+1261
+1585
+1859
+1835
+1630
+1975
+1467
+1829
+1669
+1638
+1961
+1719
+1238
+1751
+1514
+1744
+1547
+1677
+1811
+1820
+1371
+740
+1925
+1803
+1753
+1208
+1772
+1642
+1140
+1838
+1444
+1321
+1556
+1635
+1687
+688
+1650
+1580
+1290
+1812
+1814
+1384
+1426
+1374
+1973
+1791
+1643
+1846
+1676
+1724
+1810
+1911
+1765
+945
+1357
+1919
+1994
+1697
+1632
+1449
+1539
+1725
+1963
+1879
+1731
+1904
+1392
+1823
+1420
+1504
+204
+1661
+1575
+1401
+1806
+1417
+1965
+1960
+1990
+1409
+1649
+1566
+1957
+514
+1464
+1352
+1841
+1601
+1473
+1309
+1421
+1190
+1582
+1825
+655
+1666
+1878
+1891
+1579
+1176
+1557
+1910
+1747
+1388
+1493
+1372
+1522
+1515
+1745
+1494
+1763
+1147
+1364
+1469
+1165
+1901
+1368
+1234
+1308
+1416
+1678
+1541
+1509
+1427
+1223
+1496
+1600
+1383
+1295
+1415
+1890
+1694
+1793
+1529
+1984
+1576
+1244
+1348
+1085
+1770
+1358
+1611
+1159
+1964
+1647
+818
+1246
+1458
+1936
+1370
+1659
+1923
+1619
+1604
+1354
+1118
+1657
+1945
+1898
+1948
+798
+769
+1689
+1821
+1979
+1460
+1832
+1596
+1679
+1818
+1815
+1977
+1634
+1828
+1386
+1284
+1569
+1970
diff --git a/2020/inputs/day10 b/2020/inputs/day10
new file mode 100644
index 0000000..1f6c5d6
--- /dev/null
+++ b/2020/inputs/day10
@@ -0,0 +1,107 @@
+59
+134
+159
+125
+95
+92
+169
+43
+154
+46
+110
+79
+117
+151
+141
+56
+87
+10
+65
+170
+89
+32
+40
+118
+36
+94
+124
+173
+164
+166
+113
+67
+76
+102
+107
+52
+144
+119
+2
+72
+86
+73
+66
+13
+15
+38
+47
+109
+103
+128
+165
+148
+116
+146
+18
+135
+68
+83
+133
+171
+145
+48
+31
+106
+161
+6
+21
+22
+77
+172
+28
+78
+96
+55
+132
+39
+100
+108
+33
+23
+54
+157
+80
+153
+9
+62
+26
+147
+1
+27
+131
+88
+138
+93
+14
+123
+122
+158
+152
+71
+49
+101
+37
+99
+160
+53
+3
diff --git a/2020/inputs/day10_short b/2020/inputs/day10_short
new file mode 100644
index 0000000..be5c492
--- /dev/null
+++ b/2020/inputs/day10_short
@@ -0,0 +1,31 @@
+28
+33
+18
+42
+31
+14
+46
+20
+48
+47
+24
+23
+49
+45
+19
+38
+39
+11
+1
+32
+25
+35
+8
+17
+7
+9
+4
+2
+34
+10
+3 \ No newline at end of file
diff --git a/2020/inputs/day11 b/2020/inputs/day11
new file mode 100644
index 0000000..da5f2b3
--- /dev/null
+++ b/2020/inputs/day11
@@ -0,0 +1,97 @@
+LLL.LLL.LLLLL.LLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL..LLLLLLL..LLLLLLL.LLLL.LLLLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.L.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLL.LLLL.LLLLLLLLL.LLLLL.LLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLL.LLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLL.LLLL
+...L..L.L......LL.L.......L...L..LLL....L.LL.L..L.L.LL..L..L............LLL.L..L.L.L..LL..
+LLLLLLLLLLLLLLL..LLLLL.L.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLL.L.LLLLLL.LLLLLLLL
+.LLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLL.LL.LLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLL.LLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLL.LLL
+......L.L.L...LLL.LL...........L.....L..L...LL......L..L.L.L.....LL.LL..L..LL.LL......LLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.L.LLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLL..LLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLL.L.LLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLL.LLLLLLL..LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+L....LL.LL.....LLL.......L.....L.L..L.LL.L...L.L..L.....L...L....LL.LLL...L..L.LL.L..L...L
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LL.LLLL.LL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL..LLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.L
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLL.L.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLL.LLLLL.LL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLL.LLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLL.LLL
+L....L......L..L..L.........L...LL..L..L.....L....L.LLL.L..L.LL..L..L..LL...L.......L.L...
+LLLLLLLLLLLLLLLL..LLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLL.LLLL.LL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLL..LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLL.LLLL.LLLLLLL.LLLLLLLLL.LLL.LLLLLLLL.LLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLL..LLLLLLLLLLLL.LLLLLLLLLLLLL.LLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL
+L...LL..L..L..L.LL..L......L..L..LL.....LL...L...LL..L.L........LL.LL..LL.L......L..L..L..
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL..LLLLLL.LLLLLL...LLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLL.LLL.LLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLL.L.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL..LLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+..............L.....L..L..L..L...L......L...LL...................LLLLL..L.LL...L.....L.L..
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLL.LL.LLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLL..LLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLL.LLLLLLLLLL.LLLL.LLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+L.....L..L...LL...L.L...L..L.....L..L...L....L...L...LL...L......LL..L..LL.L.L..L.L.L.L.L.
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL..LLLLLL.LLLLLLLL.L.LLLL.LLLLLLLL
+LLLLLLL.LLLLLL.L.LLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLL.LLLLL.LLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLL.LLLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLL..LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL..LLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL
+LLL..L.L.....L.....LL.L..LL.L.L......L..L.L...L.L....L.....LL..LL.L......L...L....L...L...
+L.LLLLLLLLLLL.LL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLL.LLLLLLL.LLL.LLLLLL.LLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLL.L.LLLLLLL.LLLLLL.LL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLL.LLLLLL.LLLLLLLLL.LLLL.LLLLLLLLL.LLLLLLL..LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLL
+.LL.....L.L.L...L.L.....L..L..LL....LLL.......L.L.......LL...LLL...L...L...LLL.L...LLLL..L
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLL..LLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLL.LLL.LLLLLLL.LLL.LLLLL.LLLLLLL.LLLLLLLL.LL.LLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLL.LLL.LLL.LLLLLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.L.LLLLLL.L.LLLLLLLLLLLLL
+LLLLLLL.LLLLLL.L.LLLLLLL.LLLL..LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLLLLL.L.LLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LL.LLLLLLLLLLLLLL.LLL.LLLL.LLLLL..LLLLLLLL
+.L..LLL..L..LL...L.L..L......L.L.L..L.....L.....L..L....LLL....L.......L.LLL..LL....L..L.L
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LL.LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLL.LL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLL.L.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LL...L.L.L..L.L..........L..L..LL.LL....L.L.L.L.LLL.......L.......L.L....L...L..LL........
+LLLLLLLLLLLL.LLL.LLLLLLLLLLLL.LLLLLLLLL.LLLL..LLLLLLLLLL....LLLLLLLLLLLLLL..LLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLL.LL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLL
+LLLLLL.LLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.L.LLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLL..LLLL.LLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLLL
+LLLLL.L.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLL.LLLL.LLLLLLL.LLLLLLLLLLL.L.LLLLLL.LLLLLLLL
+.LLL..L...L.L......LL.L..LL.LL.LLLLL...L...LLLL.L..L..LLL......L...LL.....L..LLLL.LL.LL..L
+LLLLLLL.LLLLLLLLLLL.LLL..LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLL.LL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLL.LLLLLLLLLLLLLLLLL.L.LLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLLLLLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLL.LLL
+L...L.......L..LLLL..L.LL...LL....L.....L.L..L...LLLLL.....LL.....L.L.LLL.L..L.LL.....L.L.
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL.LLL.LLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLL.LL.LLLLLLL.LLLLLLLLL.LLLLLLLLLLLLL..L.LLLLLLLLLLLLLLL
+L.LLLLL.LLLLLLLL.LLLLLLLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLL.L.LLLLLLLLLLLL.LLLLLLLLLLLLLLL.L.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLL.LLL.LLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLL.LLLLLLLL.LLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLLL.LLLLLL.LLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLLLLLLLL.LLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLL.L
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLL..LLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLL.LLLLLLLL..LLLLL.LLLLLLLL
+LLLLLLLLL.LLLLLLLLLLLLLLLLLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLL.LL.LLLLLLLL.LLLLLLLLLLLLLLL
+LLLLLLLLLLLLLLLL.LLLLLLL.LLLL.LLLLLLLLL.LLLLLLLLLLLLLLLLL.LLLLLLL.LLLLLLLLLLLLLLL.LLLLLLL.
+LLLLLLL.LLLLLLLL.LLLLLLL.LLLLLLLLLLLLLL.LLLLLLL.LLLLLL.LL.LLLLLLL.LLLLLLLL.LLLLLLLLLLLLLLL
diff --git a/2020/inputs/day11_short b/2020/inputs/day11_short
new file mode 100644
index 0000000..ff5431a
--- /dev/null
+++ b/2020/inputs/day11_short
@@ -0,0 +1,10 @@
+L.LL.LL.LL
+LLLLLLL.LL
+L.L.L..L..
+LLLL.LL.LL
+L.LL.LL.LL
+L.LLLLL.LL
+..L.L.....
+LLLLLLLLLL
+L.LLLLLL.L
+L.LLLLL.LL \ No newline at end of file
diff --git a/2020/inputs/day12 b/2020/inputs/day12
new file mode 100644
index 0000000..5f68e60
--- /dev/null
+++ b/2020/inputs/day12
@@ -0,0 +1,768 @@
+W5
+F91
+S3
+R90
+F98
+S3
+E1
+F51
+E3
+S5
+E4
+N2
+R180
+N3
+F25
+N1
+W4
+R90
+S1
+E1
+F18
+W2
+F13
+W5
+R180
+S5
+L90
+W1
+F23
+L270
+F7
+R180
+E2
+R90
+E4
+S3
+L90
+W2
+R90
+F47
+R90
+W5
+L270
+F8
+E2
+F72
+W3
+N4
+E1
+S2
+R90
+F8
+S1
+L270
+F59
+L90
+F100
+L90
+W1
+R90
+F73
+E5
+R180
+E2
+N4
+E3
+N3
+E1
+F42
+W3
+S3
+L180
+F8
+W5
+R180
+R180
+F88
+W3
+F49
+W3
+S1
+R270
+N1
+F63
+W1
+F87
+W3
+S4
+L90
+E2
+N5
+F12
+E3
+F32
+W3
+R180
+L90
+S2
+L180
+N4
+F41
+S2
+R180
+S3
+E3
+N1
+L270
+E3
+F33
+R90
+F94
+R270
+S5
+E3
+F75
+S3
+R180
+W2
+N4
+W4
+R90
+F61
+N3
+F33
+E5
+R180
+S3
+F39
+N5
+R90
+R180
+W3
+F67
+L90
+R90
+F83
+E3
+S2
+L270
+W2
+F13
+S5
+E5
+L90
+N2
+W5
+N4
+F68
+N1
+F95
+W1
+F56
+S1
+F55
+L90
+F85
+W5
+L90
+F25
+E3
+S3
+W3
+N3
+W5
+F27
+L90
+E5
+N2
+F62
+R180
+S3
+E4
+R90
+F31
+S2
+F24
+R180
+F20
+S2
+F26
+R90
+F55
+W1
+R90
+N3
+F53
+L180
+W4
+N3
+E3
+R90
+S2
+R90
+R90
+S5
+W1
+W3
+F100
+R90
+F27
+E2
+R90
+N5
+R90
+S1
+L90
+S3
+E5
+S5
+F23
+S5
+W2
+S5
+R180
+E5
+F79
+R90
+S5
+E3
+F68
+E3
+N1
+W4
+R90
+F46
+W3
+R90
+F31
+W2
+N4
+R90
+F33
+E4
+S2
+R180
+F69
+E2
+N5
+E4
+N1
+F30
+L90
+E2
+F40
+W4
+F27
+W2
+N3
+F30
+E3
+N1
+R90
+N2
+W3
+R90
+W2
+S5
+W3
+F77
+S3
+W2
+F86
+L90
+N3
+F45
+R180
+F58
+R90
+F75
+N2
+E1
+N1
+E4
+R90
+S4
+S2
+R180
+E4
+S4
+R180
+F16
+W1
+L180
+E5
+F10
+N5
+E3
+S1
+W1
+F36
+S4
+S3
+F28
+N3
+F21
+S5
+W4
+F78
+W4
+R180
+F93
+E5
+F47
+R90
+W2
+S1
+F52
+R270
+W5
+F24
+N5
+S3
+E2
+L270
+L90
+N4
+R90
+E1
+N1
+F73
+N4
+F67
+W4
+R90
+E5
+F8
+W3
+F5
+S5
+E4
+N5
+R180
+N2
+F46
+L90
+F69
+W5
+R90
+W3
+N3
+L180
+F78
+W1
+F47
+F9
+N4
+F76
+N4
+F2
+L90
+S1
+F61
+L90
+E1
+R90
+W2
+F75
+R90
+W1
+N3
+R90
+F22
+N2
+E5
+L180
+E2
+F20
+E4
+F29
+R90
+S5
+E1
+R90
+S3
+F51
+S1
+R90
+E2
+F15
+R90
+S2
+R180
+F18
+W3
+L90
+N4
+F20
+S1
+R90
+S2
+F30
+W4
+S2
+W2
+F52
+E4
+F76
+W5
+R90
+F2
+L180
+F82
+E1
+R180
+F94
+E4
+N1
+F78
+N1
+W2
+L90
+E1
+F14
+W1
+F50
+E5
+L90
+E4
+N5
+E3
+F51
+L90
+F91
+S2
+L90
+W4
+F46
+N1
+F52
+R90
+F91
+W5
+S4
+W3
+R90
+W3
+F94
+R90
+S3
+W3
+R90
+F88
+E5
+F15
+L90
+F46
+R90
+S5
+E5
+S3
+L180
+S1
+F29
+R270
+F13
+S4
+W2
+R90
+F40
+N3
+F85
+S3
+F18
+N3
+R180
+S5
+E1
+S5
+R90
+W1
+L90
+F94
+R270
+E5
+S1
+L270
+W5
+F78
+S5
+E1
+N3
+F98
+N1
+E2
+W3
+F80
+N4
+E1
+F78
+S1
+L270
+E4
+R90
+F15
+W4
+R90
+E5
+F53
+N1
+W4
+F19
+E1
+S2
+F21
+N2
+W2
+F2
+E4
+F27
+W5
+R180
+F85
+R180
+F40
+W3
+N1
+F52
+E2
+F77
+L180
+E1
+N3
+R90
+F55
+N2
+R90
+E5
+S3
+L90
+F88
+N3
+W5
+R90
+S3
+F85
+F52
+L90
+W3
+R270
+S5
+F34
+N2
+W1
+F65
+W2
+N4
+L180
+N1
+F73
+E2
+N5
+E3
+S4
+R90
+W4
+N5
+F24
+N3
+L90
+N4
+F99
+E2
+N2
+L180
+W3
+S4
+W5
+N2
+L180
+F66
+R90
+W1
+R180
+F100
+S2
+E4
+R90
+W4
+F51
+S1
+W2
+F26
+N3
+N1
+E2
+S2
+F11
+R90
+F25
+E4
+F78
+N2
+N2
+R180
+F68
+N3
+R180
+W4
+F21
+E2
+N2
+E5
+S5
+E3
+F23
+R90
+F30
+W5
+F3
+L90
+F82
+N4
+W5
+S3
+E2
+N4
+F4
+S2
+R90
+W3
+R90
+F14
+W4
+F14
+W4
+F92
+S1
+W4
+S5
+S3
+F77
+S1
+F45
+N1
+L180
+E5
+F86
+L90
+E4
+F12
+S1
+E3
+F46
+W1
+L90
+F20
+S4
+F89
+N2
+S2
+F18
+E4
+F37
+S4
+F48
+W4
+L180
+F93
+R90
+W5
+L90
+S1
+E4
+L90
+S4
+E4
+S5
+E4
+L90
+E5
+R180
+N4
+R90
+W2
+F44
+S1
+L180
+F15
+W2
+F84
+S5
+L90
+N5
+W4
+R180
+F11
+R90
+F47
+S4
+R180
+S4
+F48
+L90
+W4
+L90
+S2
+F22
+E3
+F85
+N4
+F53
+R90
+F65
+L90
+S3
+R90
+F80
+R90
+F40
+R90
+F9
+L180
+W5
+N5
+W1
+S4
+F87
+S5
+F43
+S3
+L90
+E5
+R180
+S4
+W2
+N3
+N3
+F98
+E2
+R90
+W5
+F4
+L90
+E4
+F48
+S5
+F81
+E3
+S3
+L90
+S2
+F62
+E1
+F17
+S3
+F95
+N3
+W5
+E2
+R90
+R180
+W5
+L90
+W3
+F31
+S3
+W3
+S4
+L90
+W5
+R90
+W4
+S3
+L90
+S2
+F11
+S4
+F93
diff --git a/2020/inputs/day12_short b/2020/inputs/day12_short
new file mode 100644
index 0000000..48c2a50
--- /dev/null
+++ b/2020/inputs/day12_short
@@ -0,0 +1,5 @@
+F10
+N3
+F7
+R90
+F11 \ No newline at end of file
diff --git a/2020/inputs/day13 b/2020/inputs/day13
new file mode 100644
index 0000000..3043e0a
--- /dev/null
+++ b/2020/inputs/day13
@@ -0,0 +1,2 @@
+1002576
+13,x,x,x,x,x,x,37,x,x,x,x,x,449,x,29,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,x,19,x,x,x,23,x,x,x,x,x,x,x,773,x,x,x,x,x,x,x,x,x,41,x,x,x,x,x,x,17
diff --git a/2020/inputs/day13_short b/2020/inputs/day13_short
new file mode 100644
index 0000000..e473080
--- /dev/null
+++ b/2020/inputs/day13_short
@@ -0,0 +1,2 @@
+939
+7,13,x,x,59,x,31,19 \ No newline at end of file
diff --git a/2020/inputs/day14 b/2020/inputs/day14
new file mode 100644
index 0000000..6cd863a
--- /dev/null
+++ b/2020/inputs/day14
@@ -0,0 +1,546 @@
+mask = 01100101XX0010111010X010X10001010111
+mem[59869] = 296403277
+mem[50029] = 14565
+mem[52488] = 627950233
+mem[48318] = 113982010
+mem[22257] = 82
+mem[27870] = 17795
+mem[55511] = 4594118
+mask = 00000X00000110111110X000XX00010XX001
+mem[61743] = 13086
+mem[3724] = 4029841
+mem[10560] = 236422779
+mem[28511] = 7957
+mem[32609] = 3123
+mem[3930] = 26884
+mask = 0110000XX1001011111X111010X010000100
+mem[42884] = 252696502
+mem[18565] = 820
+mem[28279] = 105604729
+mem[41611] = 1567094
+mem[36341] = 5551
+mem[35962] = 28056
+mask = X111X001010010X1111X0XX1X11X10001X00
+mem[52299] = 24969
+mem[41449] = 160272674
+mem[34903] = 14302599
+mem[35962] = 71766
+mask = X11001010XX010111010XX10100000X00101
+mem[44250] = 536
+mem[21842] = 494315083
+mem[51716] = 3417
+mem[37939] = 242985
+mask = 111100X1010XX011X1111100X000000010X0
+mem[35845] = 48792746
+mem[26794] = 1026647
+mem[47814] = 92296
+mem[63043] = 3100
+mem[26635] = 2181
+mem[40164] = 2436842
+mask = 0X1111X0X10110101011X100011X01010010
+mem[63001] = 36102371
+mem[47565] = 2512786
+mask = 010X000111X1X01X1110XX01111100101X10
+mem[18403] = 512
+mem[58372] = 65318068
+mem[53197] = 15875
+mem[58632] = 231362257
+mask = 0X1010X11110101X011000X0000000111001
+mem[4095] = 116134614
+mem[63365] = 186252884
+mem[19024] = 2449
+mem[30536] = 1021
+mem[49282] = 447504
+mem[16658] = 98394885
+mask = 0111000111001011X11011000X1111X0100X
+mem[64187] = 1431
+mem[11141] = 1904
+mem[39855] = 61495
+mask = 1111000XX100X01X111111111110XX011X11
+mem[44407] = 1449308
+mem[43902] = 2006
+mem[62547] = 3478
+mask = 0X1010010100X011101000X00010X0100111
+mem[3885] = 140726549
+mem[3307] = 938307640
+mem[22257] = 71231
+mem[41243] = 508095
+mem[25091] = 24579
+mask = X0000000XX011011111010X000XX0X000X01
+mem[22764] = 96570583
+mem[36352] = 56148675
+mask = 0X0X0011X110111010X001X10XX000101010
+mem[38443] = 1755
+mem[56360] = 25308
+mask = 11X0X00000X11X11111001XXXXX100001111
+mem[7833] = 785
+mem[4380] = 2874
+mask = 0X1000X11X0XX0X1101001011110001X0000
+mem[61544] = 144576256
+mem[2156] = 1658
+mem[26571] = 28977534
+mem[43902] = 1032904266
+mem[21524] = 463
+mask = 100X000010011011111XX01010001010X101
+mem[47123] = 5438
+mem[28936] = 39885
+mem[55045] = 946386
+mem[43630] = 143495580
+mem[10560] = 3231
+mask = 0110000X1X00101111XXX0000000010010X1
+mem[39551] = 524769
+mem[37150] = 397326
+mem[153] = 2696665
+mem[43255] = 44
+mem[14355] = 14827
+mem[51242] = 445851
+mask = X1X000X1110X10111X101100100X0X000XX0
+mem[40969] = 756383545
+mem[26794] = 100307329
+mem[48938] = 1863389
+mem[2345] = 2535119
+mem[53880] = 1759799
+mask = 11X0X0001X0110111X001X0011XX000XX000
+mem[8343] = 11387
+mem[48589] = 60
+mem[27590] = 5929131
+mem[3690] = 63744500
+mem[520] = 31249543
+mem[24387] = 473
+mem[21573] = 32235112
+mask = 11101001011X10111X10X111X00000000000
+mem[50565] = 563
+mem[26571] = 3496
+mem[3930] = 418
+mem[35770] = 7558838
+mem[12614] = 1619627
+mask = 011X010111001X11111001100000X00XX1X1
+mem[50701] = 111977200
+mem[19006] = 10909
+mem[16052] = 74134
+mem[43094] = 14253
+mem[50557] = 608639
+mem[59406] = 1422
+mask = 110X00001101101X11100XX011X000000011
+mem[52383] = 4751812
+mem[1669] = 833448227
+mem[35841] = 439768021
+mem[43630] = 7511
+mem[53126] = 343642
+mem[60802] = 1256603
+mask = 11100XXX11XX101111101100000X00X01010
+mem[49511] = 4982217
+mem[51824] = 270
+mem[51349] = 1890
+mem[59808] = 3773655
+mask = 111000XX110X10X11110011010110101101X
+mem[57730] = 57401
+mem[35630] = 973239
+mem[54672] = 138240715
+mem[8136] = 10996
+mem[55459] = 401980
+mem[17187] = 941
+mask = X111XX01X100101111X00X0001000000X011
+mem[41484] = 1242838
+mem[29717] = 1145160
+mem[27394] = 1108224
+mem[2816] = 272760856
+mask = 1XX00101000010111010X1111000X0010010
+mem[32201] = 304518
+mem[16394] = 79826575
+mem[39941] = 13157
+mem[35282] = 760997
+mem[63951] = 7011404
+mem[8985] = 123284486
+mask = 011X100111000011X110X0110000X1111010
+mem[34856] = 39388801
+mem[18190] = 3208452
+mask = 1X000X11XX1010111X10001111X00X101X00
+mem[32295] = 1729184
+mem[48809] = 3708309
+mem[17960] = 66227
+mem[39063] = 5571972
+mem[34523] = 1100265
+mem[17724] = 1074235
+mask = 1X000000100110X111101X1001010000010X
+mem[2309] = 1178
+mem[56623] = 5006
+mem[41091] = 951374
+mem[63942] = 21970475
+mem[8120] = 1167
+mem[50184] = 5634
+mask = 11X0001X111111X11010100XX0101X111000
+mem[63703] = 31429
+mem[19083] = 32307
+mem[48832] = 3825073
+mask = 11X000111111X11110X00000001000011X11
+mem[53491] = 953
+mem[39752] = 91899271
+mask = 111XX011X1011011111XX110X00X00000000
+mem[63089] = 3036
+mem[38445] = 356279
+mem[40137] = 10955
+mem[37568] = 477812
+mem[18443] = 85
+mask = 11X1100101X0101111X000X001X111101XX1
+mem[64998] = 758355504
+mem[10506] = 5946
+mem[58372] = 800
+mem[40606] = 1267021
+mem[42753] = 86680
+mem[38503] = 9164580
+mask = 1X110000XX100000X100010001110000X010
+mem[4805] = 898
+mem[50969] = 219378
+mem[3182] = 14757
+mask = 01101X0111X01011X0X000000111X0101001
+mem[26794] = 289
+mem[27899] = 67683
+mask = X1X0001111XX1X1X10X0X0111110000010X0
+mem[60968] = 128881
+mem[21049] = 153946
+mem[4625] = 6492
+mem[13554] = 14536684
+mask = 1110100X1X0110111X001011X1111X0X010X
+mem[49387] = 48190714
+mem[5514] = 58395
+mem[59861] = 2590
+mem[59717] = 706
+mask = 110000XX1101X01111100001111000X00000
+mem[52288] = 594838
+mem[47711] = 256545
+mem[37150] = 5576185
+mask = X1001000100X101110X0X1001X01X1X00X0X
+mem[12194] = 1010012
+mem[55682] = 745
+mem[19810] = 54828
+mask = X111100111001011X10X0110110X00000011
+mem[10747] = 10766086
+mem[40969] = 6443091
+mem[2563] = 7520
+mask = X110X001X10010111X1001X0001010X00X11
+mem[16385] = 16194
+mem[9178] = 1770
+mem[3885] = 584370
+mem[32909] = 551495
+mem[21842] = 534
+mem[59406] = 4042521
+mask = X110X0001100101X11100X00XXX0X00000X1
+mem[62127] = 1228052
+mem[34922] = 165241779
+mem[38187] = 7559
+mask = 00X101X111X0X1X1011010001X11111X0111
+mem[37035] = 51004
+mem[64187] = 9284
+mem[38834] = 163012800
+mask = 0X1X1001110010X111101X00101101001011
+mem[41856] = 13039831
+mem[63376] = 1043992
+mask = 00X000000X01X01111X01X011001101X11X0
+mem[14490] = 10619
+mem[63497] = 64
+mem[8985] = 2445
+mem[3372] = 2134806
+mem[43902] = 25402
+mem[63408] = 2150231
+mem[35251] = 252
+mask = 01100001010X101X11X0XX0X000010000010
+mem[11427] = 40388
+mem[5594] = 2064
+mem[14642] = 3216356
+mem[33886] = 16148
+mem[22872] = 317877
+mem[16905] = 22391
+mem[59260] = 14964908
+mask = 11X01000X10X1011110010000101X1XXX1X0
+mem[40205] = 162183
+mem[52774] = 21039251
+mem[47529] = 13977
+mask = 111X1X0101X0101111100X1011X10X0001XX
+mem[50214] = 131677558
+mem[37828] = 45776303
+mem[25486] = 270926
+mem[3307] = 100144082
+mask = 0X1X0101110011X1XX1010X010001X00X110
+mem[24709] = 4703889
+mem[20251] = 4768780
+mem[23739] = 292844
+mem[33886] = 59676
+mem[29424] = 157758852
+mem[48117] = 434386871
+mask = 111010010100X01X1X10101111XX10000X00
+mem[24094] = 50839
+mem[40525] = 62507
+mem[16058] = 11731
+mem[57853] = 286
+mem[13702] = 252
+mem[61517] = 92673
+mem[28899] = 10302
+mask = 0X101000011X10X111001X10101001011010
+mem[39054] = 164757015
+mem[46804] = 194909
+mem[17096] = 16017
+mem[50214] = 474
+mem[55787] = 471712
+mask = 010X0X0X110110111X1X10000X000XX011X0
+mem[50969] = 44594
+mem[62079] = 4008
+mem[26760] = 1302
+mem[40242] = 450994
+mask = 00100000000010X1010011X100X10X000111
+mem[13951] = 29184
+mem[44387] = 733
+mem[56481] = 1419987
+mem[21049] = 113460142
+mask = 111000X01101101X10001X01110X01000001
+mem[37955] = 23023
+mem[23639] = 7326
+mem[41939] = 125079
+mask = 010X101X00X110XXX011010100X10011100X
+mem[4000] = 325975899
+mem[65121] = 332644116
+mem[41463] = 345
+mem[16748] = 1087582
+mem[37842] = 894
+mask = X110100111X01011X11011XX00X0101X0001
+mem[19704] = 11095
+mem[8715] = 72847
+mem[41939] = 6370749
+mem[12294] = 6805400
+mem[21842] = 79
+mask = 01XX1X10XX011X1X101X01010001X1010011
+mem[50017] = 55985
+mem[49915] = 1470
+mem[38942] = 1053875
+mem[16748] = 874238254
+mem[59353] = 678489
+mem[57733] = 14739
+mask = 111111XX01X010X11110000001X11000111X
+mem[40606] = 199
+mem[17692] = 1696176
+mem[11913] = 4169294
+mask = 01101X0X01001011101XXX10001100001010
+mem[23120] = 237551058
+mem[28299] = 142
+mask = 1X10X0011110101X1X1X11001100110X1001
+mem[6118] = 115871
+mem[19568] = 514315
+mem[24764] = 365
+mask = 1110X0X11X0XX0X1111X11011X0000000000
+mem[47355] = 25865880
+mem[51774] = 163286264
+mem[37432] = 2954
+mem[31036] = 12067
+mask = 01110X01110010111XX001100001010X1101
+mem[28516] = 323191
+mem[43255] = 3274
+mem[58073] = 86929637
+mask = 01XX0001XX11001111X0X100X1010X101000
+mem[18330] = 378470
+mem[39651] = 1052033
+mem[7784] = 143118549
+mem[32641] = 10950293
+mem[4029] = 836004
+mask = 0110010X0100XX1X10101010101000X01110
+mem[64998] = 399249156
+mem[16391] = 2391
+mem[15113] = 25159
+mem[35039] = 1672488
+mem[44901] = 4947519
+mask = 001000X11101101X1X1000X0X00000111000
+mem[23194] = 192980783
+mem[2379] = 26471
+mem[52040] = 748413
+mask = XX101X11X1X01110X1100X0011X01110111X
+mem[35610] = 3487435
+mem[15827] = 1447
+mem[52266] = 8003180
+mem[6315] = 254747938
+mem[38582] = 21341903
+mem[23012] = 1942
+mem[52040] = 1040637609
+mask = 1110X011110XX0011111X001X000000111X0
+mem[19431] = 6438
+mem[55404] = 381
+mem[49702] = 21205234
+mem[28299] = 43345
+mem[32419] = 3944214
+mem[15970] = 1406843
+mask = 0110X001XX010X01XX1X1010111001000000
+mem[63608] = 2388415
+mem[19550] = 397
+mem[64770] = 354
+mask = 011XX011X1101X10X11001X0X0001X101001
+mem[27886] = 54971772
+mem[61000] = 547
+mem[9281] = 5472661
+mem[32039] = 20450
+mem[47529] = 214406
+mem[32922] = 2186075
+mask = X1X0000X0100101110X00100000010000101
+mem[54996] = 136156
+mem[1645] = 1422
+mem[645] = 51359613
+mask = 010X000110X100X1110000010011110010XX
+mem[58473] = 54000741
+mem[50214] = 118839
+mem[60719] = 4225
+mask = 11101000110010101X10X11011X00010X011
+mem[4967] = 2810
+mem[55561] = 270767273
+mem[50906] = 323094280
+mem[544] = 1779102
+mem[12700] = 122462
+mem[20654] = 71
+mask = 01100001X0X1000101X011101X100000X00X
+mem[40754] = 6033263
+mem[3724] = 640
+mem[6776] = 274
+mask = 00110X0111001111X010110000X010X00110
+mem[59461] = 40987
+mem[49367] = 418940480
+mem[12155] = 58648
+mem[50876] = 55597938
+mem[39338] = 125566
+mask = 01100001X110101111X001101X1100X0100X
+mem[16658] = 13293
+mem[19410] = 355061209
+mem[30127] = 9284451
+mem[35805] = 2422
+mask = 1X11X0010100X01X111X1101XX1101010011
+mem[10560] = 116
+mem[42153] = 4817997
+mem[40333] = 970832
+mem[19083] = 63018397
+mask = 011XX0X111XX101111100XX0101010011010
+mem[51898] = 95230576
+mem[49059] = 481728904
+mem[25416] = 1192004
+mem[6045] = 244681888
+mem[22225] = 208962448
+mask = X11X100XX1X0101111XX1110101X110110X0
+mem[10560] = 3688
+mem[50016] = 3038
+mem[25234] = 52018301
+mask = X11XX001X100101111100110X011110X1XXX
+mem[8343] = 111304110
+mem[9100] = 833307
+mem[43853] = 836994
+mem[9178] = 24458493
+mem[59596] = 257520799
+mask = 101X0X0000100X0X010000X1X0010X0XX111
+mem[13597] = 887
+mem[16422] = 232
+mem[52384] = 120276377
+mem[10834] = 6933
+mem[16058] = 992102418
+mem[24456] = 92155
+mask = X11000010100101111X01100001X10001XX1
+mem[37568] = 26930
+mem[16385] = 232190606
+mem[8340] = 113193119
+mem[35910] = 832
+mask = 11111001010010111110100XX1X11X100111
+mem[56429] = 6105943
+mem[33886] = 8020
+mem[51774] = 168714
+mask = 1111100101101X11110000000X0110001X0X
+mem[37828] = 28012
+mem[51551] = 320681847
+mem[34281] = 52088
+mask = 0110X001110XX01111100010X00X010X1010
+mem[36720] = 26721
+mem[39098] = 8365128
+mem[28279] = 994775
+mem[59762] = 1466626
+mem[17088] = 910296
+mem[33578] = 4789
+mem[31320] = 11279
+mask = X1010000X1011011101001XX000X010011X1
+mem[58476] = 20790
+mem[33584] = 339
+mem[21127] = 471449302
+mask = 0100X01X1101X011X010010XX0000X011000
+mem[39915] = 1754512
+mem[51774] = 183707725
+mem[43094] = 2797257
+mem[21120] = 8809
+mask = X010000X00XXX0X1X10010X11101X0100110
+mem[48113] = 54854990
+mem[43108] = 127392
+mem[57733] = 4840137
+mem[17088] = 7272071
+mem[65436] = 1211
+mask = X11010X01100101010100X11111000101X01
+mem[38787] = 139
+mem[9667] = 37073154
+mem[18731] = 370
+mem[4538] = 15900
+mem[13202] = 517905282
+mask = X11000011100001X1110X01001100X001010
+mem[12467] = 932
+mem[14070] = 12280
+mem[40105] = 184487874
+mem[33314] = 832859
+mask = 0X100000X1001011X11X1000X10001X0X000
+mem[17724] = 3496777
+mem[53907] = 23167
+mem[63544] = 1614248
+mem[50209] = 2618603
+mem[36348] = 384412976
+mem[44536] = 16223523
+mask = X110X1011X0011X11110X111X0X00001X000
+mem[4784] = 11971978
+mem[10982] = 398035940
+mem[7005] = 515
+mem[35241] = 1093398
+mem[63779] = 1906
+mask = 1100X00XX001101111X0X101X1010X001011
+mem[36341] = 2194817
+mem[40531] = 724
+mem[5658] = 468782968
+mem[62005] = 1168
+mem[3491] = 1329281
+mem[49511] = 672
+mem[49173] = 1048435
+mask = 1110XX0010X1101X11X01X1010011101010X
+mem[44290] = 660182
+mem[21184] = 291220
+mem[39098] = 2769543
+mem[30987] = 24159
+mask = 1010X00X00100X1111000X011XX10100X110
+mem[48117] = 29838
+mem[23924] = 4158
+mem[46502] = 501874
+mem[32481] = 713511
+mask = XX1000111XX1X01110X0X1001001X000100X
+mem[11848] = 60796
+mem[35576] = 125075628
+mem[7365] = 367051456
+mem[49453] = 2467302
+mem[63274] = 2446
+mask = X1100X01X10010111X10X10000X00000XXX1
+mem[59406] = 7522
+mem[26316] = 194122
+mem[33419] = 24756556
+mem[17066] = 827
+mask = 111100010100001011111X101011X000X0X0
+mem[28511] = 54553
+mem[9469] = 136199
+mem[6481] = 674106955
+mem[4029] = 62909806
+mask = 0010000000011X0X110X11X11XX100100011
+mem[19006] = 23636330
+mem[49695] = 113355
+mem[9478] = 25169678
+mem[26475] = 7337
+mem[1712] = 89775255
+mem[32101] = 917
+mask = 1X00X00X1101101111X010X011100000XXX0
+mem[24770] = 10592648
+mem[40969] = 757841
+mem[42211] = 7319070
+mem[42753] = 277734
+mem[30310] = 11988774
+mem[19470] = 89618256
+mem[2816] = 89780492
diff --git a/2020/inputs/day14_short b/2020/inputs/day14_short
new file mode 100644
index 0000000..2e961e3
--- /dev/null
+++ b/2020/inputs/day14_short
@@ -0,0 +1,4 @@
+mask = 000000000000000000000000000000X1001X
+mem[42] = 100
+mask = 00000000000000000000000000000000X0XX
+mem[26] = 1
diff --git a/2020/inputs/day15 b/2020/inputs/day15
new file mode 100644
index 0000000..4a1865f
--- /dev/null
+++ b/2020/inputs/day15
@@ -0,0 +1,6 @@
+2
+15
+0
+9
+1
+20 \ No newline at end of file
diff --git a/2020/inputs/day16 b/2020/inputs/day16
new file mode 100644
index 0000000..93329d1
--- /dev/null
+++ b/2020/inputs/day16
@@ -0,0 +1,265 @@
+departure location: 35-796 or 811-953
+departure station: 25-224 or 248-952
+departure platform: 47-867 or 885-959
+departure track: 44-121 or 127-949
+departure date: 49-154 or 180-960
+departure time: 35-532 or 546-971
+arrival location: 41-700 or 706-953
+arrival station: 25-562 or 568-968
+arrival platform: 31-672 or 680-969
+arrival track: 43-836 or 852-961
+class: 38-291 or 304-968
+duration: 31-746 or 755-956
+price: 46-711 or 719-971
+route: 35-584 or 608-955
+row: 39-618 or 640-950
+seat: 25-308 or 334-954
+train: 26-901 or 913-957
+type: 33-130 or 142-965
+wagon: 34-395 or 405-962
+zone: 46-358 or 377-969
+
+your ticket:
+97,103,89,191,73,79,83,101,151,71,149,53,181,59,61,67,113,109,107,127
+
+nearby tickets:
+895,527,676,768,695,821,473,414,835,426,741,650,886,709,938,355,113,358,106,888
+559,796,709,661,116,680,773,857,118,304,704,578,720,339,584,914,270,196,661,861
+390,557,348,432,734,441,74,761,272,266,531,704,52,78,200,478,455,664,663,339
+400,386,926,211,100,481,358,429,450,336,943,549,933,78,274,722,571,483,144,442
+579,509,478,975,218,855,93,759,92,406,339,648,144,128,478,948,489,482,547,926
+512,946,469,183,24,694,889,198,551,947,275,857,408,943,734,382,308,80,448,119
+305,830,449,54,518,193,663,825,95,946,484,672,248,701,257,395,827,783,218,189
+128,52,773,150,561,436,483,913,526,819,903,700,530,941,757,509,386,885,554,788
+779,947,111,357,206,252,661,481,124,450,773,554,779,827,116,466,259,434,901,898
+651,143,274,523,89,53,116,71,513,108,753,858,209,282,410,436,357,57,517,743
+87,691,793,306,426,127,152,836,192,497,276,418,66,771,147,910,824,917,767,510
+180,657,454,609,60,190,705,337,941,947,835,554,546,84,546,772,389,193,531,890
+128,387,865,735,462,548,652,89,902,728,490,490,278,931,81,265,449,523,948,112
+588,892,450,651,154,583,667,835,356,497,81,405,671,480,53,259,514,896,352,734
+928,686,618,946,933,205,485,392,445,119,69,248,265,398,522,725,438,781,821,555
+73,213,183,89,210,650,349,356,722,550,341,816,986,824,250,145,890,446,690,698
+488,462,456,569,746,471,460,995,916,777,526,116,520,71,762,569,455,472,890,647
+549,351,421,477,661,335,148,530,759,207,599,283,304,208,271,609,919,574,528,708
+610,833,569,613,672,664,924,99,94,389,819,664,727,739,249,768,836,911,252,825
+923,429,814,577,109,818,571,522,714,646,815,706,898,439,216,494,495,931,898,458
+96,852,211,822,181,71,697,709,542,745,273,813,493,499,474,196,469,79,276,792
+608,219,527,665,474,755,419,700,913,644,822,393,666,412,335,402,281,618,460,771
+267,438,112,433,853,103,676,766,187,831,490,569,927,826,771,334,773,377,342,209
+258,98,457,900,83,511,612,897,220,414,119,24,734,572,147,425,72,509,118,287
+81,386,854,74,363,118,738,448,53,772,526,112,198,948,926,915,186,526,408,501
+853,553,490,194,282,756,261,939,754,448,386,522,516,83,154,65,433,780,415,451
+153,702,580,200,948,198,146,379,121,109,759,114,153,659,794,735,852,568,347,84
+856,742,770,91,270,611,693,148,450,265,506,889,680,657,130,729,75,457,455,8
+188,553,865,61,184,208,643,405,996,212,856,574,943,470,745,532,185,811,613,735
+887,381,24,68,426,640,89,85,693,757,460,109,913,689,763,358,121,655,498,424
+772,771,418,58,922,152,272,378,689,254,290,568,453,24,73,768,254,457,503,896
+695,649,924,79,209,661,775,859,575,221,858,86,269,857,836,305,274,23,659,795
+61,553,740,52,522,270,388,124,736,660,457,897,262,665,833,104,442,530,270,479
+392,893,306,252,278,336,259,560,421,103,150,409,923,460,190,711,261,503,12,924
+863,768,397,857,384,260,70,916,96,470,390,466,472,666,442,50,457,819,532,69
+861,441,900,519,383,467,809,191,72,426,720,711,380,468,505,485,546,266,743,652
+189,82,440,738,685,640,507,194,699,694,449,449,404,437,553,113,947,433,925,64
+151,768,503,66,918,129,913,474,827,823,358,115,750,833,791,783,576,790,920,276
+432,813,10,925,689,694,558,462,813,194,515,739,476,210,490,182,726,609,480,421
+148,211,56,811,945,213,550,354,465,529,463,795,58,655,677,919,282,266,812,357
+462,455,76,737,383,471,663,617,811,84,97,796,263,546,930,442,871,409,827,467
+250,724,682,652,197,512,501,861,373,220,276,899,734,777,258,467,888,287,697,441
+89,918,763,793,208,823,694,467,212,264,755,889,104,643,530,766,702,767,462,154
+146,347,79,341,791,195,858,622,648,833,796,390,189,262,192,249,719,392,67,95
+367,144,697,887,430,506,343,739,220,283,455,469,507,471,684,85,547,489,856,832
+498,65,97,187,445,427,615,583,451,198,734,513,142,454,756,713,513,612,471,789
+501,483,212,690,715,739,735,410,900,561,584,336,855,727,651,70,526,613,776,527
+654,762,519,185,350,438,584,940,831,687,378,782,278,436,716,816,502,63,217,835
+825,265,471,920,584,286,118,109,616,271,772,511,192,726,633,103,407,416,419,418
+223,263,121,56,187,654,514,737,876,942,856,286,427,768,831,740,455,281,85,854
+486,642,271,617,576,672,459,151,763,890,665,697,708,96,180,678,98,579,854,354
+78,219,92,736,143,865,268,862,658,120,356,732,704,854,147,411,214,685,117,926
+491,777,270,230,62,552,477,427,618,337,213,508,790,571,345,512,410,69,72,552
+697,149,409,661,576,615,696,142,942,353,281,736,473,452,739,452,418,367,866,583
+354,738,737,108,637,112,211,825,356,926,520,766,345,355,700,948,279,212,764,90
+203,425,771,222,279,428,583,507,277,689,687,215,188,864,467,72,674,641,381,759
+479,763,261,511,655,62,568,781,656,223,530,75,692,987,104,935,266,733,467,262
+415,111,785,308,489,111,932,648,455,512,218,55,910,285,389,355,497,520,547,724
+650,76,531,598,767,216,406,947,438,212,920,256,611,572,660,395,865,789,251,856
+498,740,14,822,82,335,522,724,932,414,284,775,722,191,699,493,421,740,475,184
+151,337,451,581,663,419,279,400,646,272,64,744,181,684,512,727,393,142,739,469
+251,649,640,621,76,858,305,440,923,264,407,642,520,687,258,827,108,947,78,932
+832,546,893,919,218,96,196,478,418,769,722,864,576,382,597,787,392,949,655,691
+83,741,429,56,289,615,546,734,127,450,638,192,343,251,498,255,852,308,671,923
+447,818,826,743,145,695,285,485,414,432,864,358,95,481,104,931,10,734,561,931
+784,502,263,204,449,94,766,941,684,464,124,776,425,86,608,380,272,467,485,282
+261,449,457,646,349,721,199,466,731,783,198,192,61,455,901,366,512,449,725,70
+449,145,579,783,501,426,111,736,277,257,433,864,455,217,289,600,128,642,573,51
+21,788,352,920,184,794,783,938,785,405,614,885,580,102,515,129,57,502,93,938
+578,664,726,192,224,484,761,452,105,436,556,240,765,671,273,249,920,663,896,858
+217,436,644,118,743,764,671,273,746,922,891,721,390,856,897,561,910,826,788,117
+507,618,859,708,149,687,922,181,119,350,671,391,457,980,727,554,786,788,386,441
+617,478,483,217,640,929,183,935,274,771,245,258,664,385,834,286,79,434,448,145
+428,946,524,413,402,51,496,115,777,682,64,378,681,493,520,609,147,77,900,692
+261,642,350,949,640,561,626,63,394,254,829,525,886,584,51,409,380,812,515,550
+282,66,827,524,274,514,830,356,703,818,721,862,532,447,405,614,901,949,334,561
+101,546,574,365,439,390,922,96,581,72,896,782,80,513,439,280,78,149,520,291
+183,854,86,307,796,500,150,103,358,725,368,937,191,211,900,644,732,742,198,142
+616,558,63,650,349,127,349,554,484,80,103,261,678,407,832,212,265,187,767,693
+441,943,943,730,689,980,471,183,348,289,948,820,641,469,569,666,914,438,575,609
+860,482,775,386,283,487,216,717,930,513,53,255,335,756,502,392,378,199,720,790
+781,656,555,584,206,284,519,490,890,463,679,272,289,776,559,408,343,206,572,486
+665,795,189,287,569,889,387,363,939,207,523,501,819,856,259,516,146,210,816,855
+857,78,94,277,821,336,715,663,760,184,934,460,424,528,511,478,780,892,214,738
+568,457,280,108,243,892,831,917,127,928,351,99,282,103,889,645,767,416,380,349
+933,760,991,736,661,127,853,682,756,180,291,216,83,825,935,651,146,113,498,813
+84,408,381,551,50,274,696,471,15,514,612,616,197,780,916,198,763,102,523,503
+584,416,85,180,931,485,900,761,674,358,915,502,103,938,946,614,728,290,471,892
+695,51,391,102,251,560,391,334,23,578,80,731,729,482,811,61,919,769,87,272
+827,143,548,613,933,986,813,513,664,283,796,860,268,933,493,568,444,391,383,855
+780,504,571,489,910,927,254,71,889,430,405,59,472,886,482,486,826,887,700,781
+60,341,248,187,998,265,128,338,506,65,698,664,741,186,284,711,277,867,550,559
+406,304,376,249,742,790,181,345,62,668,498,645,684,822,180,478,812,74,432,506
+270,381,831,187,680,283,241,608,735,496,130,724,530,892,792,81,419,772,655,351
+482,106,781,656,336,736,64,737,192,357,264,663,185,709,988,383,191,443,217,97
+267,944,254,179,82,486,290,794,86,496,617,662,762,308,450,385,180,683,479,215
+926,406,626,860,422,897,710,735,693,82,520,561,180,268,252,651,922,250,554,251
+468,475,923,562,8,289,924,914,944,392,216,51,485,60,196,927,187,815,78,290
+61,855,766,451,864,361,271,105,153,927,338,939,475,788,60,939,104,212,546,900
+704,512,570,707,831,427,571,487,429,945,217,186,344,474,50,571,493,405,708,441
+388,867,405,398,740,196,147,451,470,546,460,128,98,77,405,776,285,510,824,153
+279,438,550,654,392,979,461,852,692,560,56,931,920,69,614,642,427,930,512,116
+116,78,490,214,275,494,488,550,397,435,206,144,461,898,947,901,688,557,482,51
+579,519,554,903,552,731,59,211,729,654,823,761,154,514,65,888,494,697,348,142
+68,129,412,83,870,932,154,643,730,786,659,352,835,681,524,433,658,436,261,347
+488,814,279,774,821,105,710,483,16,105,460,520,477,786,546,206,75,554,70,699
+652,515,670,211,289,611,348,896,926,199,691,282,718,349,291,104,209,201,823,692
+355,87,455,472,934,568,832,827,340,776,261,818,1,143,933,722,482,287,698,785
+449,557,357,270,94,463,647,885,853,701,61,59,761,923,578,611,424,729,920,81
+619,826,258,520,738,779,577,90,719,757,513,658,338,683,836,918,288,463,691,340
+646,128,424,440,87,709,788,391,305,308,381,188,746,78,794,386,636,813,500,270
+191,778,659,767,346,257,95,154,393,423,609,380,107,617,857,347,122,142,223,431
+516,71,889,922,407,522,870,736,777,147,394,118,818,689,358,344,470,207,526,761
+98,97,682,814,62,20,108,828,482,711,524,764,201,771,834,186,495,409,418,434
+287,305,54,611,337,489,771,537,816,683,517,465,304,220,515,770,467,572,148,666
+215,390,287,269,284,121,727,925,305,815,347,87,808,193,121,97,577,524,820,186
+266,213,87,854,580,489,764,57,275,250,538,338,547,307,269,121,143,106,115,183
+555,893,866,888,522,195,404,557,455,647,774,494,818,109,784,571,66,822,671,440
+658,555,105,338,505,661,573,740,127,508,56,667,642,449,658,111,120,398,255,60
+277,65,550,280,640,817,900,262,490,419,791,201,266,548,881,219,350,287,260,821
+494,478,573,415,928,70,821,231,394,121,383,562,666,440,664,77,474,348,380,820
+666,260,412,534,918,655,449,283,743,463,90,727,558,76,113,711,612,824,745,941
+898,815,783,816,94,289,69,222,480,201,108,640,580,522,205,117,468,715,127,781
+942,472,648,744,925,112,903,781,410,106,897,274,306,818,781,575,896,664,450,647
+407,390,945,269,818,584,616,96,642,185,813,127,900,830,708,475,221,888,366,650
+249,407,939,915,95,265,439,436,164,71,766,943,197,110,115,75,890,63,84,268
+277,82,617,513,128,334,114,549,621,284,653,709,818,104,836,478,892,181,113,205
+443,473,198,416,918,642,646,795,900,488,1,920,728,443,824,188,695,578,522,78
+80,443,451,573,181,518,592,735,688,110,919,143,387,64,142,411,193,252,643,919
+392,492,486,95,528,252,448,934,527,579,796,902,822,305,477,270,468,923,859,889
+643,356,190,830,863,153,76,91,932,457,691,880,344,775,108,512,512,286,61,769
+146,490,417,429,687,395,525,477,930,521,61,268,444,184,64,77,235,466,110,727
+461,582,343,666,825,188,84,941,886,107,382,129,487,660,261,173,192,72,53,913
+128,935,546,419,143,787,83,779,577,431,859,658,496,475,403,52,380,357,863,548
+472,900,916,942,777,776,433,659,422,357,53,826,204,182,19,686,575,796,509,532
+908,201,268,129,858,495,916,711,697,854,224,757,308,406,484,477,426,503,687,89
+794,628,392,180,822,508,555,787,57,202,568,387,507,937,185,916,575,514,103,91
+519,348,79,82,745,708,515,99,111,416,564,411,385,652,76,409,818,758,469,473
+489,121,342,573,488,439,504,435,519,919,62,265,764,690,927,622,788,348,823,556
+660,501,588,654,478,660,725,721,653,352,581,343,88,196,286,616,787,532,830,644
+766,525,582,471,947,198,501,89,104,900,745,685,362,455,249,211,389,812,506,113
+425,506,457,255,289,492,498,468,707,766,180,386,609,742,57,564,828,782,769,515
+275,363,148,699,351,525,812,767,67,932,87,551,308,866,112,188,304,440,431,392
+424,414,510,822,223,709,419,55,73,546,203,404,759,860,279,273,927,474,347,861
+505,439,783,384,765,719,58,415,353,778,418,674,147,433,794,93,945,823,411,70
+918,250,934,436,812,385,207,675,481,383,405,345,208,618,681,84,87,785,616,215
+264,94,350,861,116,502,155,946,578,938,391,187,96,666,491,927,653,260,220,429
+391,895,497,648,495,81,256,887,348,181,216,354,213,657,501,561,743,483,824,998
+938,854,791,777,740,100,767,862,648,432,942,104,562,93,670,216,650,6,220,526
+255,110,477,344,347,887,124,552,82,895,147,58,260,77,424,813,615,444,223,928
+925,691,345,895,708,388,860,249,563,119,503,928,865,97,498,492,202,426,661,117
+472,96,280,424,480,440,348,896,73,503,718,862,730,899,260,941,469,337,186,259
+708,646,6,220,482,700,202,918,889,337,831,130,656,890,921,766,530,210,66,381
+524,508,528,346,649,77,433,939,935,793,423,304,318,97,671,932,562,736,726,253
+145,215,651,721,675,819,206,696,723,111,216,512,385,285,928,726,709,495,437,666
+118,288,95,866,435,102,353,196,335,935,145,105,125,508,306,438,818,261,854,736
+656,529,742,807,189,416,856,290,414,933,88,572,348,473,925,104,831,186,281,665
+249,198,417,714,279,936,813,814,823,357,351,89,304,60,936,503,103,377,381,505
+787,933,280,527,492,704,405,252,468,785,305,457,431,193,378,521,896,283,422,741
+814,860,216,405,129,790,490,906,465,929,181,478,667,93,497,888,423,641,866,502
+834,521,429,529,388,792,477,216,440,683,739,251,831,360,770,650,51,337,727,205
+204,401,110,794,394,682,569,95,190,287,720,515,70,524,440,191,501,442,853,644
+186,259,509,476,664,687,865,420,186,220,480,651,229,933,153,765,497,546,471,580
+405,916,150,514,702,387,741,939,385,896,576,824,487,504,866,867,356,734,889,581
+734,358,829,735,548,142,437,388,331,773,455,182,152,336,459,489,483,79,581,470
+67,656,820,264,406,739,698,51,516,547,822,128,580,191,71,0,562,857,550,103
+513,490,822,982,934,763,555,194,145,789,99,917,380,253,504,388,344,420,75,180
+101,662,492,414,147,343,818,668,490,488,69,715,406,731,552,81,357,477,945,833
+495,931,719,384,274,145,366,98,501,356,654,437,507,898,248,406,387,556,757,381
+410,423,821,395,984,521,862,260,190,611,654,709,213,145,264,84,935,496,248,385
+494,94,549,59,784,488,435,685,191,769,181,143,213,441,918,7,90,446,514,734
+886,505,744,566,855,288,441,655,487,507,417,744,901,786,278,431,211,769,778,570
+85,812,930,667,610,117,735,881,706,414,65,857,289,287,758,109,556,891,103,84
+79,476,445,211,515,707,725,557,859,80,393,792,600,470,427,478,120,390,504,930
+552,896,73,618,449,447,692,818,662,887,338,820,690,185,406,553,586,643,335,75
+745,668,406,877,551,76,756,501,785,98,459,304,519,720,57,469,416,739,668,793
+276,834,581,258,764,557,184,760,186,859,857,175,939,924,578,759,866,349,681,287
+578,153,766,489,349,406,276,380,709,55,852,304,222,859,900,878,492,347,437,925
+579,665,790,901,416,929,75,914,940,205,814,354,196,681,909,432,652,265,651,194
+58,505,344,79,528,418,731,121,604,142,270,150,780,257,88,355,789,935,83,337
+455,419,391,189,187,497,687,531,130,129,400,856,206,276,260,273,727,696,571,769
+886,920,698,784,582,611,698,856,440,248,475,392,876,463,190,443,914,70,697,222
+91,205,353,920,477,475,153,672,948,573,485,270,665,480,63,222,784,473,457,993
+738,745,212,346,653,828,50,860,379,118,921,694,540,819,214,147,657,94,55,497
+793,17,194,925,150,350,755,554,508,252,527,289,55,253,694,509,769,102,59,118
+461,250,272,394,480,248,758,890,667,128,575,217,842,700,649,792,212,693,897,96
+926,928,558,452,588,515,289,459,221,481,913,60,465,61,143,580,415,744,442,685
+267,152,772,891,153,257,448,895,115,612,520,538,710,698,885,463,195,746,86,466
+776,89,497,277,344,684,573,414,194,455,667,626,127,523,271,283,340,446,471,784
+334,641,853,473,278,452,94,763,644,690,831,738,136,256,733,922,935,462,768,776
+249,142,256,97,75,562,458,828,865,680,444,361,644,464,930,423,789,84,688,419
+706,52,714,347,510,782,286,428,708,113,505,89,901,834,770,120,511,427,204,63
+86,62,501,468,64,885,105,641,214,825,453,560,388,764,79,123,690,413,380,487
+96,885,505,689,938,511,483,189,202,97,355,792,500,689,392,336,713,740,853,788
+531,89,925,122,261,479,923,864,816,106,568,453,692,518,556,929,709,78,928,790
+456,513,395,212,757,730,729,653,724,975,429,756,457,418,489,725,929,528,437,184
+947,854,154,255,95,70,724,682,226,94,423,187,641,616,252,105,885,558,658,695
+663,386,584,556,209,277,542,732,552,106,818,819,690,415,415,478,216,219,815,218
+272,743,99,339,74,647,72,488,577,353,89,426,91,745,823,135,782,757,773,57
+81,826,492,113,562,66,430,287,830,370,284,434,547,142,899,338,765,378,732,644
+644,350,490,929,901,816,942,69,493,257,118,695,858,713,79,222,500,343,116,608
+487,412,702,771,418,722,857,475,437,450,812,830,250,490,561,553,658,709,90,462
+550,60,90,145,429,203,991,509,94,283,500,608,468,892,460,617,916,277,857,474
+524,695,889,437,582,895,901,422,761,691,107,117,476,54,818,807,269,517,928,894
+507,715,776,831,120,385,338,415,377,95,579,445,696,785,91,696,274,568,307,415
+85,90,129,78,940,774,521,468,459,101,431,348,255,205,416,24,66,434,287,755
+897,937,896,507,895,657,932,858,819,890,471,430,994,681,410,420,925,498,280,940
+50,941,470,745,458,72,271,740,288,546,549,125,504,467,248,254,184,767,91,51
+575,461,649,149,54,762,925,613,741,584,408,922,738,305,377,703,433,410,755,81
+507,269,148,886,180,659,817,71,466,476,111,336,498,782,361,707,915,576,650,478
+764,475,57,763,925,88,515,555,803,641,351,414,271,548,121,657,719,467,860,473
+484,764,910,487,191,204,721,682,113,187,926,569,441,337,761,787,142,202,353,106
+714,437,468,562,811,198,443,420,118,610,743,923,666,643,513,743,934,354,433,357
+513,578,744,574,721,739,551,488,207,574,865,145,901,103,701,508,218,818,264,777
+684,572,186,679,944,776,78,105,947,212,937,424,857,412,929,787,532,186,260,812
+423,259,558,577,648,425,306,672,307,714,550,573,348,612,249,744,253,521,427,193
+270,273,474,746,531,836,269,443,471,433,100,732,625,510,654,557,894,420,688,248
+825,522,945,833,262,507,82,601,680,945,446,946,921,89,477,513,411,276,70,151
+472,664,80,343,277,669,268,224,59,791,347,342,128,934,645,741,375,379,687,185
+668,894,212,392,95,491,791,264,573,812,894,698,728,73,767,448,794,634,116,213
+885,52,940,305,788,558,447,705,744,526,557,571,549,777,690,886,393,392,377,518
+107,344,897,693,767,468,249,560,570,289,121,341,608,435,412,860,399,778,646,470
+429,351,515,87,726,888,523,650,418,464,803,200,666,56,813,829,670,816,192,657
+279,187,280,500,382,942,52,687,853,62,491,306,934,506,699,321,796,381,934,55
+69,772,786,783,722,222,759,358,265,853,710,445,567,920,770,645,936,224,80,733
+377,795,794,438,256,813,829,852,511,919,872,662,200,188,457,889,942,467,519,503
+437,96,211,829,931,335,347,811,409,700,736,20,119,525,395,338,930,474,734,486
+502,199,287,285,471,551,488,252,895,466,104,415,156,945,512,51,358,830,340,859
+129,340,461,772,670,686,812,386,438,744,662,590,532,811,577,143,641,888,308,934
+85,815,948,571,117,949,516,980,822,58,258,737,856,573,212,819,923,531,914,949
+945,531,934,344,917,692,343,281,291,288,164,811,697,899,897,187,928,266,285,852
+377,420,283,655,127,421,221,740,550,611,50,306,417,80,610,392,429,705,477,852
+116,211,852,422,484,933,215,215,760,202,349,789,440,685,615,536,149,616,729,568
+497,393,743,867,60,863,150,13,939,149,56,527,783,111,782,493,671,280,260,923
+742,284,811,708,148,710,925,265,734,413,384,731,992,689,467,784,103,886,259,73
+484,349,479,705,188,188,933,465,221,722,72,571,274,735,456,866,192,818,76,393
+942,998,248,914,272,380,380,924,461,61,291,392,154,709,420,574,813,493,786,511
+55,50,353,792,84,721,865,223,205,833,997,930,579,761,583,98,727,744,647,780
+766,82,280,201,943,695,516,898,68,143,682,205,387,780,433,230,744,200,690,936
+205,558,687,475,90,337,920,665,529,196,456,445,283,55,120,749,60,304,553,389
diff --git a/2020/inputs/day16_short b/2020/inputs/day16_short
new file mode 100644
index 0000000..ba62efb
--- /dev/null
+++ b/2020/inputs/day16_short
@@ -0,0 +1,12 @@
+class: 1-3 or 5-7
+row: 6-11 or 33-44
+seat: 13-40 or 45-50
+
+your ticket:
+7,1,14
+
+nearby tickets:
+7,3,47
+40,4,50
+55,2,20
+38,6,12 \ No newline at end of file
diff --git a/2020/inputs/day17 b/2020/inputs/day17
new file mode 100644
index 0000000..d8b3575
--- /dev/null
+++ b/2020/inputs/day17
@@ -0,0 +1,8 @@
+.#.#.#..
+..#....#
+#####..#
+#####..#
+#####..#
+###..#.#
+#..##.##
+#.#.####
diff --git a/2020/inputs/day17_short b/2020/inputs/day17_short
new file mode 100644
index 0000000..17630fd
--- /dev/null
+++ b/2020/inputs/day17_short
@@ -0,0 +1,3 @@
+.#.
+..#
+### \ No newline at end of file
diff --git a/2020/inputs/day18 b/2020/inputs/day18
new file mode 100644
index 0000000..4fd2cf6
--- /dev/null
+++ b/2020/inputs/day18
@@ -0,0 +1,377 @@
+9 + 4 + (3 + (6 * 5 + 9 * 2 * 4) * 9)
+((7 + 6) + 2 * 6 + 4 * 2 + 9) * 6 + 5
+7 * 3 * 9 * 6 + (4 + 2 + 4 * 9) + 7
+9 + (9 * 3 * 3 * (9 + 5 + 4) + 4)
+(8 * 5 + (7 + 5 + 3 + 6) * 9 + 7 * (9 * 8 + 7 * 2)) * 8
+3 + (6 * 2 * (9 + 2 + 5) * (9 * 2 * 6 + 8 * 5) * (2 + 2 + 3 + 7 * 9)) + 4 * 4 + (6 * 4 * (9 + 4) + 8 * 3 * (5 + 3)) * 5
+2 * 8 * (8 * 2 * 4) + (9 * 3 * 6) * 9
+2 + (8 * 4 * 9 * 3 + 8 * 2) + 4 * 9 * 6
+((6 * 4 + 9 + 5 * 7 + 3) * 4 + 8 * (3 + 6 + 9 * 9) + 9 * 6) + (7 * 7) + 6 * 2 * 2
+2 + 5 * 3
+2 + 6 * (8 + 6 * 5 + (3 * 9) + 3)
+3 + 2 * 4 + 9 * 4 + 9
+(7 + 5 + (4 + 7)) * (4 + 4 * 9) + 4 * 7 + 9 * 4
+8 + 5 * (3 + 3 + 8 + (4 + 3 * 4 + 3 * 4)) + (8 * 6 * 3) * 4 + 2
+(2 + 9 + 9 * (8 * 3 + 2 * 5 + 6 * 2)) * 4
+8 * 6
+9 * 4 * (5 + 4 + 2 + (4 * 7 + 9) * 4 * 6) * 5 * 2
+3 + (5 + (4 + 9 + 6) * 8 * 8 * (3 + 5 + 8 + 2)) * 7 + 5 * ((2 + 4 + 8 + 3) * 6 + 7 + 9)
+((8 + 3 * 5 + 7) + 9) * 2 + 2 * 8 * 4 * 5
+3 + 2 + 8 * (4 * (5 + 2 * 8 * 3 * 4) + (6 + 8 * 6) + 2 + 5 * 2)
+4 + ((2 + 4 * 9) * 4 + (6 + 6 + 3) * 3 + 8)
+3 * (5 + 6 + 6) + 3 + 4
+8 * 8 * (5 * 4 + 5 + 5 + 4) + 7 + 9
+5 * 3 + (7 * 7 + (3 + 8 * 3 * 4) * (3 + 4 + 8 * 5 + 4) + 9)
+7 + 6 * (3 * 6 * 9 * 8)
+3 + 8 * 6
+6 + ((2 + 6 * 2 + 2) + 8 + 2 + 3 + 6) + 9 * 6
+((8 * 5) + 8 * 5 + 6 + 9 + 9) + 9 * 9 * 6 * 6 + 3
+2 + 5 * 4 + (8 + 8 + (5 * 3 * 2 * 6) * 2 * 2 + 9) + 5 * 6
+(6 * (6 * 5) + 7) * 8 * 4
+9 * (9 * 7 * (8 * 3 * 5 + 5 * 8) * 7) + 9 + 2
+6 * (2 * 3 + (7 * 9) + 8 * 4 + 7) + ((5 + 6 + 7 + 7 * 8) + 2 + 7) * 6
+3 + 6 * 8 + (8 * 4 * (4 * 2 + 3 * 7 * 4 + 4) * 2) * 7
+7 * (7 + (8 + 5 + 2) * 9 + 6 + 2) * 5
+(4 + 6 * 8 + 6) + (4 * 6 + 9) * (5 + 9 * (9 + 7 + 2 + 7) + 6 * 4 * 6) * 6 * (2 * 8 * (2 + 6 * 9 + 5 + 9 + 5) + 8 * 6) + ((7 * 3 * 4 + 2 + 4) + (4 + 5 + 2 * 9 + 3))
+4 * 8 + ((7 + 6 * 8 + 3 + 8) + 9 * 4 + 4 + 2) * ((9 * 5) + (3 * 5 * 9 * 7) * 3 + (3 * 4 + 2 + 5 * 3 + 3)) * 2 + 4
+7 + 4 + 3 + ((4 * 5 + 9 * 2) + 6 * 2 * 4 * 2 * 3) * 4
+(4 + 2 * 3 + 7 + 9 + 6) + ((7 * 9 + 5) * 8) * (2 * (9 + 8 + 7) + 7 * 8 + (5 * 7 * 5 * 4 + 4 + 7)) + 7 * 9
+2 + (9 * 7 * 7 + (5 * 7) * (3 * 5 * 4 + 6 + 2 * 6) + 8)
+(9 * (5 + 5 + 5 + 2 * 5) * 6 * 6 + 4) + 2
+8 * 5 + 4 + 7 + (5 * 4 + 7 + (7 * 7 * 6 + 7 + 9 + 4) * (2 * 6)) + 4
+((5 + 8) * 6 + (6 + 3 * 3) * 2 * 2 + 9) * ((4 * 9 * 4 * 3) * (4 * 3 + 6 + 7)) + 8 + (8 * 2 * 8) + 9
+4 + 7 + (9 + (6 * 7 * 5) * 5 * 2)
+4 * 3 * (7 * 8 * 3 + 9 + (6 * 2 + 3 * 7 * 3 + 3) * 8) + ((5 + 4 + 6 + 6) + 9 * 3 * (3 * 7 * 2 * 3) + 4) + (3 * (6 * 5))
+3 * (8 + 7 * (7 + 4 + 3 * 6) * 7 * 9 * 7) + 5
+(9 + 8 + 6 + 5) + (4 * 8 * 9) + (2 * 8 * 8 + 6 * 5 + 5)
+(3 * 7 + 8) + (2 + 7 + (4 * 3 * 5 * 9 + 9) * 5 * 7) * 9 * 8 * (5 + 6 + 5 * 4)
+(9 + 9 * 2 * 7) + (3 + 3) + 2 + 4 * 5 + 5
+9 + ((3 + 7 * 8) * 5 * 9 + 6 * 5) * 4
+6 * 3 * (3 * 8 * 7 * 8 * 9 * 4) * 4 * (2 + 6 + 2 * 5 + (4 * 6 * 6 * 8 + 4))
+8 * (8 * 9 + (6 * 5) * 3 * 5 * 3)
+9 * 3 * 4 + 4 * (4 * 8 + 9 * 8 + 3) + ((9 * 6 + 2 + 8 * 5 * 3) + 2 * 5)
+(9 * 6 + 4 + 2 * 4 + 3) * 6 * 5 * 7 + (4 + (5 * 4 + 8) * 5 + 6 + 8 * (8 * 8 + 7)) + 3
+7 * (7 * (8 * 4 * 4 + 5 * 3 * 9) + 7 * (6 * 9 * 9 + 7 + 8) * 8) + 2
+8 * 5 + 7 * 3 * 5 * ((8 * 5 + 2 * 7 * 8 * 5) * (6 + 5 + 9 + 8 * 2))
+4 + ((4 * 9 * 3 + 2) + 5) * 6 + 4
+(2 * 5 * 9 + 4 * 4) + 6 + 3 + (5 * 3 + 8)
+(5 * 5 * (6 * 4 * 5) + 4) + 5 * 3 + 4 + 5 + 3
+2 + (7 + 9 * 5)
+8 + (7 + 7 + 7 + 2 + 8 * 3) * 4 * 4 * (6 + 2) * 5
+8 * 3 + 6 * 7 * 9 * 6
+7 * (7 + 4 * 9 * (3 + 7 * 8 * 5 + 7))
+4 * (4 * 5) * 8 * 3 * 3
+8 * 6 * (8 * (9 * 5 + 4 + 5) + (9 * 7 + 9 + 3 + 9 + 9) + (5 + 2 * 4 + 3) * (4 + 5)) + 4 + 8
+8 * ((3 * 5) * 9 + 8) + 9 * (7 * 7 * 4 * (6 + 4 + 2 + 8) + 3 * 3) + 8
+7 * 8 * (3 + (2 * 9 * 7 * 9 + 5 * 2) * 2 + 5)
+(9 + 8 * 3) * (5 + 9 * 3 * 5) * ((7 + 7 * 9 * 3 * 6) * 8) * 9 + (2 * 5)
+6 * 8 * 7 * 3 * 4
+3 * (3 * 4 * 8 + (6 * 5 + 3 + 5 + 2) * 2 + 4) + 3 + 9 + 2
+9 + (2 + 2 * 7 + 3 + 8) + 5 + (7 * 6 + 2 + 6 * 3 + 2) + 2
+5 + ((2 + 8 + 9 + 7 + 6) * (4 * 2))
+6 * (3 + 5 * 6 + 2 + 6)
+6 * 4 + 9 * (8 * 8)
+8 * 2 * 7 * (4 + 7 * 9 + (5 * 3 + 9 * 4 * 9)) * 7 * 5
+8 * 2 * 5 + 3
+4 * ((4 * 7 * 3 + 9) + 6) * 7 + 4 * 2
+6 * 3 + 3 * 6 + 2
+(8 * 9 * 4 + (4 * 3 * 5) + 4 + 6) + 5 * 6 + (5 + 8 * (6 + 9 * 8 + 2) + 2) + 9 + 7
+9 * 6 + 9 + 3 * 9 * (9 + 4 * 7)
+(8 * 2) + 4 * 6 * (6 * 4 * 3 * 6 * (5 + 2 + 8) * (3 * 8)) + 4 + 5
+2 * 6 * (9 * 6 + 7) + 8 * (7 + (7 * 6) + 7 * 3 * 3 + 5) + 2
+5 * (9 + 2) * 8 * 8 + 4 * 8
+3 + 8 * (9 + 7 * 3) + 3 + 9 * 8
+6 + 2 + (5 + 4 + 2 * 5 + 4 * (5 * 3 + 3 + 5 * 3 + 8)) * 2 + 2
+8 * ((9 + 3 * 3) + (8 * 5 + 2 + 7 + 8 + 8)) * 3
+4 + 6 + 6 * (4 + 6 * 8)
+(6 * 6 * 9) + (7 + 4) + 5
+4 * (2 * 6 * 3) * 5 * 6 + 9
+5 * 4 + ((4 * 7 * 7 * 9) + 3 * 9) * 9
+(4 + 5 * 4 + 9 + 2 * 8) + 4 * 3 * 8
+(7 + 6 + 8) + (3 * 4 + 2) + 2 * 6
+7 + 6 + 4 + 6 * ((6 + 5 * 8 + 9 * 4) + 8) * 5
+4 + (7 + 8 + 2 * (9 + 8 * 6 + 3 * 6 * 6) + (9 * 7 * 8 + 6 * 3) + (7 * 4))
+8 * 6 + 4 * (8 * 6 * 5 * (6 * 7 + 7) + 5) + 4 + 4
+(9 + 3 * (3 + 6 + 2)) + 9 + 2 * (9 * (3 * 3) + 6 + (6 * 9 * 2 * 8 + 6 + 3) + 8 * 9) + 5
+8 + (7 + 4 * (5 * 4 * 9 + 4 + 6 * 5) + (7 * 7 + 3) + 5) * 5 + 3
+2 + 3 * 4 + (4 * 8) * 3 + 8
+((2 * 5 * 9) + 8 * 5 + (2 * 4 + 5 + 3) + 8 * 6) * 4 * 9
+6 + (7 * 2 + 7 + 9 * 5 + 5) + 9 * 5
+8 + 8 + ((8 * 7 * 7 * 4 + 7 + 9) * 8 + 7 * 7 + 8) + 2
+(7 * (4 + 6 + 5 * 5 + 3) + (4 + 6 * 8 + 6 * 3 + 2) + 7 + (9 * 9) * 3) + 7 * 3 + 8 + 4 + (9 + 9)
+3 * 9 * 9
+(2 + 7 + (7 + 4 * 5 * 8 + 8)) * 5 * 5 * ((7 + 2) * 9 * 7 + 9 * (3 * 5))
+(9 * 6 * 9 + 4 + 2 * 4) * (3 + 6 * 6 + 7 * 3 * 6) * 8 * (6 + 5 * 4 * 4)
+(3 * 6) * (6 + 2) + (5 * 6 + 2 * 3 * 3) + 8 + 6
+8 * 7 + 2 + ((2 + 9 + 6 + 5) + 2 + 4 * 6 + (4 + 7 * 2 + 5 * 5 * 9)) + 6
+5 + 6 * 4 * 6 + 4 + (4 * 6 + 2 * 3)
+4 * 9 + (9 + (7 + 7 + 6) * (3 * 8 * 6 * 2 * 4) + 3 + 5 * 8) * 2
+2 + 6 + (5 + 5 + 3 * 2) + (9 + 7 * 6 + 8 + 3 * 9)
+2 + 2 + (7 + 3 + 2 + 4 * 5 * (4 * 2 + 7 * 7 + 3 * 2)) + 4
+8 + 4 * 6 * 2 + (9 * 7 * 2)
+6 + 8 + 5 + 4 + ((3 * 5) + 6 * 4 + 7) * 6
+((4 + 5 + 7) * 7 * (4 * 3 + 4 + 4) * 3 * 5) + (7 * 3 + 3 * 7 * 6) + (2 * 3 * 9) + (8 * 6 * 8 * 2 * 3 * 7) * 6
+2 + 8 * 7 * (7 * 8 + 8 + 9 * 3 * 5) * 3 + 2
+(2 * 4 + 7) * ((9 * 5 + 4 + 5 * 8) * 2 * 9 + 2) + 4 * (2 * 7 + 3 * 3 + 2 * 9)
+((5 * 5 * 9 + 9) + 9) * 5 + (2 + 2 * (3 * 7 + 3 + 8) * 4) * 9 + 8 * 3
+8 + 9 + 9 * (5 * 3 + 3) * ((7 + 4 * 7 + 2) * 2 * 4) + 2
+(7 * 5 * 2 * 3 * (8 + 9 * 2 + 5 + 4 + 9)) * 3 * 8 * 9 * (5 + (2 * 5 + 7 * 4 + 9 * 8))
+7 + (4 + 5 + 3 * 9 * 8) * 5 + 9 * 6
+8 + 8 * 4 + ((8 * 5) * 4 + (5 + 3)) * 3 + 8
+(8 * (5 + 4 * 5 + 6 * 6 + 7)) + (4 + (7 * 5) * 9 * 8 * 2 * (7 * 9 * 8)) + (3 + 4 + 4) * 3 * 2 + 7
+(3 * 9 * 5) * 7 * 8 * 3 * 5
+6 * (6 + 3) + 6 + 8
+4 * 7 * 3 + (9 * 2 + (2 + 8) * 9 * 5)
+(2 + 2 + 9 + 9 + 7 + (5 * 5 + 3 + 8 * 3 + 2)) * (9 * 6 * 5 * 3)
+3 * 4 + ((6 * 6 + 3 * 6 + 2 + 7) * 4 * (7 * 5 * 3 + 5) + (4 * 9 + 4 + 4 * 6 * 5)) + 9 + 2
+4 + 4 + 4 + (2 * 2 * 5 + 8) * 4 + 2
+(2 * 4 + 2) + 2 * 7
+(2 + 3 + 8 * 3 + 3 + 3) * 8 * 6 * (4 * (6 + 8 * 4 * 3 + 4 * 5) + 8)
+4 * 9 * 4 * ((4 + 5 + 9 + 7 + 9 + 4) + 7 + 5 * (7 + 6 + 3))
+(2 * 8 * 8 * 3 + (6 + 2 * 9 * 3) + 7) + 3 + ((4 * 3 + 3 * 4 + 8 * 4) + 9 * 4 * 3 * 5 + 4) * 7 * 9
+8 + (4 * (7 * 5 * 3 * 4 * 3) * 5)
+8 * 8 * 8 * ((6 + 4 * 6 * 7 + 6) * 5 * 5 * 7 * 6) * (5 * 4 * 7)
+7 + 4 * 7 * (6 * (5 + 9 * 4)) * (8 * 9 + 2) * 7
+2 * 2 * 6 * 5 * (7 * 6 + 4) * 7
+(4 * 2 + 9) + ((2 + 4 * 3 * 6 * 5) * (6 * 9 + 8 + 7 * 8 * 7) + 3 + 3 * (6 * 4 * 3 * 8 * 5)) * 6 * 6 + 5
+9 * ((8 + 5 * 6 * 2) + 3 * (7 * 2 + 3 * 7 * 2) * 4 + 3) * 8 + 5 + 9
+((9 * 6 * 5 * 4) + 3 + 7) * ((8 + 5) + 8 + 4 * 2 + 9 * 9) + 2 * 3 + 4 + 7
+6 + (5 * 9)
+7 + 8 + 4 * 5 * 6
+3 * 3 + 2 * (6 + 2 * 4 + 5) * ((7 * 6 + 6) + 3 + 6)
+6 + (9 + 2 * 3) + 5 + 8 * (4 * (5 + 6 + 7 + 6 + 7) * 2 * 9 * (8 + 9 + 3 + 4 * 7) * 8)
+5 * (4 * 7 + 2 * 3) * 9
+(4 * 4 * 5 + 9 * (8 * 8 + 7 * 8 * 7 + 3)) * (6 * 8) * 4 * 2 + 7 * (2 + (3 * 2 * 5 * 3))
+7 + (9 * 7 * 8) + 2
+(4 * 4 + 7 * 3 * 7) + (8 + (9 * 6 * 2 + 2 * 9) * (3 + 7 + 4 * 4) + 3 * 2)
+(2 * (3 + 3 + 4 * 3) + (3 + 4 + 6) + 6) * 5 * 5 + 8
+3 * ((6 + 6 * 9 + 5 + 4) * 7) + 8 + 7 + (6 * 7 + 7 + 9 * 8)
+2 * 6 + ((2 + 9 * 5) * 2 + (4 * 2 + 8) * 3 + 5 * 6)
+((4 + 2 + 9 + 5 + 7) * 3 + 9 + (3 + 6) + (6 * 3)) + 4 + 9 + (8 * 5 * (7 * 8 + 4 + 3) * 8 + 4) + 9
+4 * ((9 * 8 * 5 + 3 + 4) * 9 + (7 * 9 + 9) + 9) + 2
+(8 + 5 * 3 + 3 * 5 + 4) + (4 * (3 + 7 + 9 + 3) + (5 * 4 * 4 * 5 + 2 + 9) * 5)
+8 * 7 + 3 + 6 + 5 + 7
+2 * (4 * (6 * 2)) + (3 + 2 + (4 + 5 + 5)) + 2 + 6 + 5
+((3 + 4 * 8 * 2) * 8) + 5 * 8
+9 * 8 * 2 + (8 + 6 * (6 + 5 + 2 + 4 * 4) + (3 * 8))
+4 * ((7 + 5 * 3) * 3) + 7 + 2
+5 + (2 * 9 * (2 + 8 + 5) * (7 + 6 * 3 * 5 + 3 * 9) + 6) * 4 * ((2 + 9 + 5 * 8 + 3 + 8) * 4 + 2 + (4 + 4 + 2 * 4 + 3 + 2) * 5) + 7 + 2
+(4 * 3 * 6 + (6 * 9 + 3 + 2 * 3 + 8) * 9) * 2 * 7 * 4 * 3 + 3
+(7 * 5 * 4 + 9 + 7) * (2 * 8 + 6 + 3 + 6 * 8) * (2 * 5)
+(3 * 2 + 9 + (8 + 9)) + (2 + 3) + 4 * 4 * 8
+(5 * 2 * (7 + 8 * 7 + 4 * 9 * 3) + (9 + 6 + 6 * 8) + 7) * 4
+7 * 2 + 6 * 2 * (5 * (3 + 6 * 3 + 5) * 5 + (5 * 4) + 9)
+6 * 4 + 3 * ((4 * 3 + 4 * 3) * (4 * 2 * 3 * 7 + 9) + 6 * 8 * 9 + 3)
+9 + 2 * 8 + 7 * 6 + 2
+((3 + 4 * 9 + 3) + (5 + 8 + 2 + 6) * 2 * 8 + 2) * 3 * 3
+(6 + (8 * 6 + 5) * (6 * 9 + 4 * 2)) + 9 * 5 + 9
+(6 + (4 + 4 + 8 + 7) * (3 + 4 + 7 + 7 + 8) * 2 * (6 + 3 * 5 + 7)) + 2 * 6
+(5 * 4 * 2) * (5 * 4 * 9 + 4 * (9 + 6 + 3)) * 3 * 9
+9 * 7 + 8 + 4 + (6 + (6 + 3 + 9 + 9 + 4 * 6) * 8 * 4)
+(8 * 4) + 7 + 8 + 2 + (5 * 6)
+(5 * 3 * 2 + 2 * 5) * 7 + (8 * (8 + 6 + 5 + 7) * 6 + 5 * (2 * 8 * 4 * 5 + 8 * 7) + (2 + 7 * 3 + 6)) + 5 * 8
+7 + 9 * 6 + (9 + 4 * (2 + 8 * 8 + 7 * 9)) + (5 * 3 + (2 * 4 + 4) * 5 * (4 * 3 * 7)) + (7 + 6 * 9)
+2 + 8 * 4 + (5 + 8 * 9) * (8 + 3 * 8) * 3
+8 * 6 + (8 * 2 * 5 * 4 * 6) + 9 * 2 * 4
+7 + 7 + 3 * (2 + 2 + 4 * (9 * 2 + 6 + 5 * 4) * 8 + 2) * 3
+9 + (7 + 6) + (5 * 8 * 7) * (5 + 7 + 9)
+5 + (2 + (7 * 4) * 9 * (8 + 7 * 5) + 5 * (2 * 3 * 8)) * (7 + 9)
+5 * 7 + (8 + 2 * (5 + 3 * 6 * 9 + 9) * 5)
+(4 + (6 + 6 + 5 * 4)) + 4 + 3
+2 + 8 * (9 + (7 + 8 * 9 + 7 * 2 * 9) + 5 * 4 * 9 * 7)
+2 + ((5 * 5) * 8) + 2 * 9 * (8 + (6 * 4 + 9) * (7 * 7 * 6 * 7) * 5 * 6)
+(4 + 3 * 8) * (8 + 6 * 7 + (9 + 4 + 6 + 2 * 3))
+9 * ((4 + 3 * 4) + 6 * 6 + 9 + 2)
+(9 + 6 * 9) + 9 * 7 + 3 * 6 + (4 * 6)
+7 + 6 + (4 + 7 * 4 * 9 * 2)
+7 * (7 + (9 * 4 * 3)) * (2 * 2 * 4 + (2 * 8)) * 2
+(5 * 5 + 2 + 2 * (5 + 3 * 5 * 4)) * 3
+5 * 5 + ((5 + 7) + 3 * (9 + 2 * 6) + (5 + 4 * 3) + 6) * 7
+6 * 6 * 4 * (2 * 5) + ((9 * 7 + 4 * 7 * 2) + 6)
+5 + 9 + 5
+9 + (6 * 5 * 9 + (4 * 4 * 7 * 3 * 6 * 4) + (5 + 4 * 3 * 4 * 5 + 7))
+(4 * 5) + 6 + 3
+4 * (7 + 3 + (5 + 2 * 7)) * 7 + (3 + 3 * 9 * (8 * 8 * 3 + 3) + (4 * 7 * 3 + 6) * 5) + (8 + 3 * 7 + 4 * 5)
+4 + 4 + (3 + 7) + 2 + (9 + 7 + (5 + 5 + 4 * 7) + 8 * (5 * 7 + 7 + 3)) * 4
+(4 + 3 + 8 * 5 + 8) + 5 * (8 * 9 + 7) + (7 * 6 + (3 * 6 * 6 + 5 + 4) * 2 + (2 + 4) + (6 * 3 + 8)) + (2 * 7 * (2 * 6) + 3) + 9
+4 + 7 * 6 * 3 + (7 * 7 + 8 * 2 + 2) + 2
+7 + (8 * 8) * 6 + (7 + 9 * 5 + 3 + 5 + 3) * 4 + 4
+6 * ((3 * 3 + 4 + 6 + 2) * 3 * 4 + 4 + 2 + 5) * (5 * 2 * 3 * (9 * 7 + 5 * 8 + 4 + 8) + 4) + 9
+6 + (6 * 8 + 5) + 4 * ((8 + 8 * 6 + 3 + 8 * 4) * 6 + (6 + 7 * 5)) + 7 + 5
+(2 * 6 + 7 * 9 + 2) * 4 + 5 + 9
+6 + 3 * 4 + 4 + (8 * (6 * 7 + 5 + 3) * 2 * 8 * (2 + 6 + 7 + 7)) * 6
+4 + (3 + 5 + 4 + (4 * 2 * 8 + 2 * 9 * 4) + 7)
+2 + (2 * (9 + 2 + 6 * 4 * 9 + 7) * (3 + 7) + 8) + 7
+(6 * (7 + 9 + 6) + 7 + 9 * 4 + 8) + ((8 * 7 + 3 * 6) + 4 * 5) * 4 + 6 + 6 + 6
+4 + ((3 * 2 + 2) * 5 + (2 * 3 + 3) + 6)
+6 * (9 + 3 * 4 * 7) + 3 + 4 * 5
+6 + (7 * 4 + (4 * 5 + 2 * 4) * (9 + 4 * 3 * 2 * 9) + 7 * 7)
+(6 + 5 + (2 + 7 * 7 * 2 * 5) + (7 + 5 * 7 + 6) + (5 * 3)) * 7 + 3
+(5 + 2) + 3 * (6 + 4 + (5 + 7 * 2 * 6 + 7) * 3) * 6 * 6 * 2
+((8 + 5 * 6 + 5 + 3) * 3 * 6 * 4) + 8 + (5 * 8 * (7 * 9 * 9))
+8 * 8 * 5 + (5 + 8) * 4
+((6 * 5) * 3 * 3 + 2 * 8) + 7 + ((3 + 2) + 5 * 4 + (8 * 7 + 3) * 9 * (5 + 4))
+8 * 6 * 5 + 6
+6 * 9 * 3 * (7 + (8 + 2 + 7 + 3 + 3)) + 2
+(9 * 7) + 5 * (7 + 9 + (7 * 7 * 3 * 7 + 8) * 8 * 2 + 6) * (9 * (6 + 6 * 4) + 3 + 2 * 5) + 7
+8 * ((2 + 6 + 2 * 7 + 7 + 2) + 9 * 2 + (5 + 5 + 9)) + (3 * 5)
+8 + 2 + 5 + 8 + ((6 + 9 + 9 * 3) + 5 * 8 * 8)
+(2 * 4 * 6 * 5 + 6 * 3) + 7 + 5 * 8 * 3 + 8
+5 + 2 + 2 * 4 * 7 + (2 + 7)
+3 + ((8 + 3 * 5 + 8) * 6 + (6 + 7) + 8 + (9 * 3) + 7) * 3 * 3
+4 * 8 + 8 * (5 * (6 * 9 + 6) * 8 * 2 * (7 * 4 * 7 + 8 + 9 + 6) + 8) * 7 + 5
+4 + 2 + 4 + ((9 + 4 * 3 * 7 * 6) + 6 + 5 + 3 + 6)
+5 + (9 * (2 + 9 * 8 + 9)) + 4 * 2 * 4 * 7
+(6 * 8 * 5 * (3 + 5 + 7 + 6 * 7 * 9) + 3 * 5) * 3
+3 + 9 * 5 + (8 + 9 * 3) * 4 + (7 * 4 * 2 * (7 + 9) + 6 * (7 + 2))
+(4 + 3) * 5 * 4 * 9 + 3 + (7 + 3 * 8)
+9 + 5 + 9 * 5 * 8
+(7 * (9 + 9 * 6 * 4 + 4 + 2) + 8 * 7 + 2 * 3) + 4 * 5 + 4 + 4 * 5
+(3 + 8 * (3 + 8 * 9) * 3 * 7 * (8 + 7 * 9)) * 2 + (2 * (8 + 7) * 8 + (4 + 2) + 3 + 3)
+9 * (7 + 5 * 5 * 4 + 6) * 4 + 6 + (6 * 2) + 7
+2 * ((3 * 5 * 2 + 2 * 5) + 4 + 2 + 4 * 8 * (3 + 7)) * 3 * 3
+(7 + 9) + 6 + 7 + 9 + (9 + (8 * 4 + 5 * 3) + 7 * (8 + 3) * (7 * 3 + 7) + 7) + 7
+((5 + 6) * 6 + 8 + 6 + (7 + 3 * 5 * 7)) + 5 + (8 + 3 + 5) * 7 * 7 + 9
+(7 * 4) + 2 + (2 + (4 + 8 + 3 + 7 + 9 + 2) + 8) + 5
+((5 * 9 * 3) * 9 * 8 * (7 * 4 * 2 + 4 * 2)) * 3 * 4 + 2 * 8
+5 + ((8 * 8 + 8 * 4) * 5 + 6 + 5) + (9 * 6) + 2
+8 * 3 * 2 + 6 + (2 * 7 + 6 + 8 + 5)
+8 + 6 + 4 + 5 * 5 + (7 * (6 + 3 + 2 + 7) * 7 + 3 * 8)
+(6 * (9 * 3)) + 9 + 9
+7 + (9 + 6 * 6) * 6 + 3 * 4 * 5
+7 + 3 * (9 + 5 + 6 + 7) + 4 * 4 * 2
+7 * (7 + 3 * 4 + 5 * 7 * 7)
+2 + 3 + (2 + (2 * 2 * 9)) * 7 + 7
+5 + 8 * (9 * 5)
+(2 * 9 * 5) * 5
+3 + (2 + 4) + 7 * (7 + 5) + (7 + 2 + 8)
+7 + 7 + (3 + 6 + 3 * 7 * (4 + 8 + 7 * 5 * 3 * 7) * 6) * 9 + 4
+6 * 4 * 9 * 5 * 9 * (5 * 8 + 9 + 8 + 5)
+(7 + 6) * (9 + 3 + (7 * 6 * 5 * 8 * 2 * 5))
+9 + 5 * 7 * 5 * 5 + ((8 + 6 * 4 * 3 + 9 + 4) * 4 + 8 + 5 * 8 + 6)
+8 * (4 + (3 * 3 * 2 + 8 + 9 * 2) * (8 * 9 * 6)) * (3 * (7 * 4) + 7 * 6) * 6 + 2
+(5 + 3) * 8 + (6 + 5 * 5 + 2) + (6 * (5 * 6 + 8 + 5 * 7 * 7) * 3 * 5 * 2)
+((4 + 7 * 6 + 8 + 9 * 8) * (2 * 8 * 7 + 4 + 9) + (7 + 8 + 9) + 4 * 4) + 3 * 5 + 4 * 8 * 4
+4 + 4 * 5 * ((5 + 8 + 3 + 3 + 8) * 3 * 9 * (7 * 5 * 3 * 4 * 6 * 2) * 6 + 4) + 2
+6 + 3 * (5 + 9 + 8 * 2 + 4 + 5)
+6 * 7 + 7 * 2 + 7
+8 + ((8 + 9 * 7) * (8 + 2 + 7 + 7 + 6)) + 2 * 7 * (8 * 3 + 2 * 3)
+(7 * 8) * 3 * 3 * 9 + 7
+((6 + 2 + 6 + 8 * 6 * 7) * 9 + 9 * 8 + 5 + 2) + 2 + 8 + 2 * 7
+5 + 3 * 3 * (9 * 3 + (7 + 4) + 7 * (6 * 7 + 8)) * 7 + ((2 + 4 + 2 * 9) + 4 + 2 + 3)
+(5 * 9 + 9 * 3) + 2 * 2 + 2 + (6 * 6 + 9 + 2) + 4
+8 + 8 + 3 * (7 * 3 * 7 * 9)
+6 + (5 + 6) + 8
+4 + (3 + 5 + 8 * 9)
+(9 + 6 + 2) * 2 * (5 * 7 * 9) + (6 * 2 * (6 * 3 * 8 * 5) + 2 + 5 * 2) + 8 * (5 * 5 + (7 + 9 + 4) * 5)
+(2 * 9 + 5 + 6 * 5) * 2 + 6 * 3 + (6 * 4) * 9
+6 + 3 * (2 * 7) + 7
+6 + 4 + 5 * 7 + 4 * (8 * (6 + 9 * 8 + 9 + 7 * 8) * 7)
+3 + ((7 * 3 + 6) + (4 + 5 + 7 * 2 + 2 * 3) + 3 * 4 + 2 * 2)
+4 * (5 + 9 + 3 * 5 + 5) + 7 * (6 + (7 + 9 * 3) + (5 + 5 + 2) * 9) * 5 * (4 * 7 + 7 + 9)
+8 + (9 * 3 * 7 * 4) * (4 * 9 + 5 + 8)
+5 + 7 * 6 * 9 * 8 + ((8 + 3 * 3 + 2 * 2) + 7 * (8 * 6 * 9) * (9 + 8 * 3))
+(6 * 9 * 5) + (7 + (8 * 8) + 5 + 2 * 6 * 7) * (2 + 2 + (5 * 8) + 3)
+9 + ((7 * 7 * 5 * 8 * 9 * 8) * 7 + 6 + 6)
+2 * 9 * 3 * 9
+(3 + 2 + 2 * 2 * 6) * ((3 * 8 * 3 + 4 + 6 + 7) * 4 + 8 * 2 + 5 + 7) + 3 * (6 * 9 * 2 + 6 * 2 + 5) + (7 * (3 * 9 + 5) + 5 * (7 * 3 * 9 * 7) + 9)
+2 + (8 + 3 + 8 + 6 * 5) + (5 * 6 * 6) * 9 * 8
+8 * 7 * 4 * (2 * 4 * 2 * (8 * 5 * 2 + 7)) + 5 + 5
+8 * (3 + 5 * (4 + 7 * 5 + 8 * 6) + 6 * 8)
+(2 + 8 + 6 * 2 * (6 * 2 * 6 + 4 + 6 * 6)) * 6 + 6 + (6 * 4 + 2 + (9 * 5 * 3)) * ((8 * 2 * 7) * 4) * ((2 + 4 + 7) + 5 * 2 + 7 * 9)
+(9 * (9 + 5 * 2 * 8) * 8 + 3 + (3 + 7 + 7)) * ((5 * 5 * 7) * 2 + (5 + 4))
+9 + ((8 * 9 + 9 + 4) + 2 * (6 * 3 + 9) + (3 * 5) + 9 + 7)
+5 * ((6 * 6) + 8 + 8 * 6 + (9 + 9 + 5 + 2)) * ((2 + 8 + 5 * 2) * 4 * 6 + 4 + 4 + 5)
+4 + 5 + (5 * (2 * 4 * 5 * 4 * 4) + 4) + (8 + (6 + 2 * 8 * 7 + 6)) * (6 + 7 * 2 * 8 * (5 + 7 + 8) * 9) + 2
+(5 * (2 * 2 + 3 * 7) + 9 + (5 * 5 + 5 * 9) * 9) + 8 + 8 + (2 * 3)
+(7 + 5 * 2 * 2) * 5
+4 + (8 + 2 + 5 + 9) * 5 + 3 + 3 + 5
+(5 * 2) * 8
+9 * 7 * ((2 * 7 * 6 * 7) + 8) * 3 * (7 * 7)
+7 + 9 * 8 + (2 + (9 * 3 * 9) + 3 * 9 * 3 + 2) + (4 * 3) + 3
+7 * 9
+(3 * (3 * 4) + 5) * 9 + 6 + 9 * (7 * 2 * 2)
+4 + 5
+((8 * 2 + 4 * 5 + 7) * 8 * 5 * 8 + (9 * 6 * 2)) * (3 + (8 + 6 * 3 + 5 * 7 * 7)) + 9 + (2 * 7) * ((3 * 4 * 4 * 4) + 6 + 7)
+2 + 7 + (3 + 7 * 9) * 6
+2 + 9 + 3 * 4 + (7 + (8 * 7 + 5 * 3 + 7) * (5 + 8 * 7 + 8))
+(3 + (4 + 8 * 8 + 8 * 3) + 3 * 2 * 9) + 4 + 7 * 6 * ((8 * 8 + 2 + 3 * 9 * 4) * 8 * 7 * (7 * 9 * 2 * 5 + 3 * 8)) + (8 + 7 * 2 + 4 + 5)
+2 * ((8 + 8 * 4 + 2 + 6 + 4) + 4 + (7 + 6) + (7 * 6) * (6 * 6 + 4 + 4 + 5 + 9) + 8) + 9 * (6 + 9 * 9 * (3 + 7 * 2) + 7) + 7
+9 + ((5 * 8 * 2) + 6 * 6 * 6 * 5 * 8)
+8 + 3 * (7 + 5) + 4 * 3
+7 + (5 * 4 + (8 + 3 * 7 * 6) * 4 * (7 + 4 * 2 * 7 * 6) * 5) * 3 * 5 * 9 * 2
+(2 + 3) + ((3 + 4 + 4 * 5 + 5 * 9) + 8 + (2 + 9 * 4 * 9 + 3) * (3 * 2 * 6 * 3 + 9 * 6)) * (6 + 4) + 9 * 2
+8 + (9 * (8 * 5 * 2 * 3) + 5)
+2 * 2 + (8 * 9) * 9 * 8 + (7 + 8 + 5 + 9 * 5 + 2)
+5 + 7 + 8 + 5 * 6 + 3
+5 + 3 * (3 + 3 * 9 + 7) * 8
+(3 + 5 + 2 * 7) + (3 + 8 * 2 * (2 * 4 * 4 + 9)) + 8 * (8 + 3 + 7 * 2 + 8)
+9 + 3 * 2 + (8 + 9 * (8 * 6 * 9 + 8 * 3) * 6) * 8
+2 * ((7 + 5) * 4)
+(5 + (4 + 9 * 7)) + 5
+7 * 6 * 8 + (2 * 7 + 9) + 7 * 2
+7 + 9 * (6 * 7 * 3 * (6 * 6 * 7) * 8) + 4 + (5 + (5 * 4 * 6 + 7 + 3 * 4) * 4 * 8 * (6 * 8 * 4 * 6 + 5) * 8)
+(5 * 3 * 2) * 4 * 7 + 9 * (5 * 2 * 4 * 2 + (8 + 6))
+(7 + 8) * 9 * 6 + 8 + (4 + 7 * 2 + 8 * 9)
+9 + 8 * 6 + 5 * (2 * 8)
+(7 + 9 + (5 + 9) + (8 * 9 * 9 + 4 * 7 + 2) * 7) * 4 + 7 + 2 + 5 + 3
+3 * 5 + 8 + (9 * 3 * 2 + 8 + 8) + 2 + 3
+9 * ((3 * 9 + 9) + 8 + (3 + 6 + 4) * 9) + (8 + 5 + 8) + ((4 * 2 + 6 * 6 * 2) + 3 * 4) + 9 + ((7 + 9 + 2) * 4 * 2 + 8 + 9)
+8 + ((5 * 9 * 6 * 4 * 4 + 6) * 9 + 9 * (6 + 7) + (3 * 3 + 2) + (5 * 4 * 2)) + 5
+(2 * 7 + 6 + 5 * 9 + 3) * 2 * ((4 + 3 * 5) + (3 * 7) + 2 * (5 + 9 * 6 + 7) * 6) * (9 + 6 + (3 * 5) + 2 + 5) + (9 * 6 + 7 * (3 * 9)) * 2
+(4 * 2 * 7 + (6 * 2 + 5 + 3 + 6 * 6) * 2 + 8) + 4 * 9 * 2
+9 * 5
+8 + 8 + 9 + 6
+7 + 4 + (7 * 4 * (4 + 9 + 3)) * (3 + 6 * 3)
+(8 + (2 + 2 * 7 * 3 + 9 + 3) + 7 + 2 * 4) * 3 + 6 * 3
+(7 * 2 + 5 + 7) * 6 + 6 * 6
+5 * 6 * 9 + (8 + 3 * 6 * (3 + 8)) + 4 * 2
+(5 + 9 * 7 * 6 * 2 * 2) + 9
+(5 * 5) * 7 + 3 + 5 * 4 * 5
+7 * 4 + 5 * 9 * 9 * (9 + 6 + 6 + 6 + 2 * 6)
+(4 * 9 * (8 + 9 + 3 + 8 + 3) + (4 + 9 * 7 * 7 * 7 * 4)) + 6 + 4
+(7 * (9 * 4 + 2 + 8 * 5) * 6 * (9 + 6 * 6 * 4 + 3)) * 5 * (5 * 2 * 2 + (9 * 6 + 5 + 6) * 5 * 4) + (3 * (9 * 9) * 7 + 7 * 8 * 8) + 2
+2 * 4
+2 * 5 + 5 + 6 + (2 * 5 + 8 * 8 * 6 * 7)
+((5 + 3) * 6 * 5 + 9 + 9) * 8
+(9 + (6 * 5 * 2 + 7 + 4 * 9)) + 9 + 2 * 3 + 5 + (8 + 3 * 5 + 9 + 7 + 4)
+((9 * 9 * 5 + 7 * 9 + 8) + (6 * 4 * 9) * 6 * 2 * (6 + 9 + 2)) * (6 * 6 * 3)
+8 * 6 * (9 + (6 + 9 + 7 + 2) + 5 * 9 * 4) * (5 + 4) * 9 + 5
+9 * 3 + 8 + (9 + (2 + 5 * 6 * 9 * 4 * 9))
+4 + 5 * (6 + 4 + 8 + (8 + 9 * 2) + (7 + 9 + 5 * 2 * 5 * 9)) * 6 * 9
+9 + 2 + 8 * 4 * (7 + 6) + 8
+7 + (3 * 2 * (4 * 5 + 5 * 8) + 6 * 5) + (8 * (2 + 2 + 6 * 8 * 7) + 5 + 7 + (3 + 8) + 3) + 5 + 7
+9 + 6 + (8 * 8 * (2 + 5 + 2) * 2 + 3 * 6) + (2 + 6 + (7 * 3 * 3 + 3) + 9 * 2) * 9
+((4 * 2 * 9 + 7 + 4 + 2) + 2 * 9 * 4 + 9) * 9
+7 + 4 + (3 + (5 + 4)) * (4 + 8 * (9 + 3 + 6) * 4) * (5 * 4 * 7)
+7 + 4 + 2 + (5 * 5 + 2 * 5 + 8 * 9) + (9 * 4 * (8 + 2 + 7)) + ((2 * 8) + 8 + 3 + 6 + (7 + 6))
+8 + (4 * 6 * 6 + (5 + 8 + 6 + 5 + 7 * 3)) + (4 + 7 * 6 * 4 * 4 * (7 * 5 * 2 * 9 * 3 * 2)) + 9 + 6 + (9 * 9 * 3 + 3 + 8 * 6)
+5 + 6 * (6 + 8 * (3 * 3 + 4)) + 8 + 7 * 6
+4 + 5 + 9 + (4 + 8 * 7 + 2 + 5 * 7)
+(9 + 4 + 6 + 4) * 6 * 6
+(2 * 7 * 5 * (3 * 4) * 3) * 4 * 4 + (7 + 7 * 9 * 9 + 4)
+3 * (6 + 9 + 2 * (6 * 6 * 3 * 3 * 3 * 8) * 6) * 5 + 7
+3 * 7 + 7
+(7 + (4 + 2 + 5 + 2 + 6) * 4 * (2 * 9 * 4 * 7)) * (2 + (8 * 2) + 3 * (9 * 8) * 6 * 2)
+7 * ((5 + 6 * 8 * 2 * 8 * 6) + 2 + 6 * 5) + 3
+6 + 3 + (8 + 8 + (7 * 4 * 3 + 6) * (8 * 7 + 4 * 7 + 6) + 9 * 7)
+(8 + (2 * 9) + 8 * 6 * 6 + (5 + 6)) * 2 * 3 + 3 + (9 + 4 + 6 * 9 + 8 + 8) + 6
+(6 * 5 * 2 * 5) * 7 + (2 * 6 + (3 * 3)) + 4
+((7 * 3 + 8 * 9 + 7) * 4 * (2 + 3 + 5 + 5 + 5)) * 3
+(6 * 4 * 3) + 3 + 2 * 6
+3 + 7 + 8 * 4
+(6 * (7 + 6 * 6 * 2 + 7 + 3) + (3 * 3 * 8 * 4 * 7 * 6) * 3 + 9) * 9 * (2 + 2)
+(8 * 6 + 8 + 9) * (3 + 8)
+9 * ((8 * 4 * 8) * 3 * 2 * 3 * 4 + 6) + 8
+5 + 4 * 5 + (8 + 5 + 6 * 7 * 7)
+5 * ((5 * 2 + 7 + 6) * 9 * 7 * (7 + 6 + 3 + 5 * 5) + (5 + 8 + 7 + 4 + 9))
+8 * 6 * (9 + (9 * 8 + 2 * 3) + 2 * 6 * 3) + 7
+(7 * 6 * 2 + 6 + 4) + 9 * 4
+((4 * 8) * 8 * 7 + 2) * 8
+2 + 3 * ((8 + 2 * 3 * 9 + 8 + 8) + 9 + 4 + (5 * 2) + 9 * 3)
+(5 + 3 + 3) * ((5 + 4) + 5) + 8 * 8 * ((8 * 6 + 9 + 5) * 5 + 4 + 5 * 6) * 8
+(8 * (8 + 9 + 6) + 2 * 2) + 5 * 4 + 4 + 3
+(9 * 6 + 2 * 6) * (6 * 6 + 2) * (7 * (3 + 6 * 8 * 6 * 5) * 8)
+(2 + 8 + 8 + (6 * 3 * 2 * 3) + 4 * (8 * 5 * 8 * 4 + 6 + 2)) * 2 + 4 + 6 + 9
+9 * 9 * 9 + (6 + 9 * 3 + 6 * 5 * 5) * 3
+3 * 2 * (8 * (4 + 5 + 8 * 5 + 5)) * 5 * 9
diff --git a/2020/inputs/day19 b/2020/inputs/day19
new file mode 100644
index 0000000..f206eb8
--- /dev/null
+++ b/2020/inputs/day19
@@ -0,0 +1,530 @@
+70: 90 92 | 53 50
+99: 90 102 | 53 22
+24: 130 90
+125: 85 53 | 100 90
+61: 53 58 | 90 26
+88: 33 53 | 46 90
+32: 65 90 | 90 53
+48: 46 53
+116: 53 50 | 90 18
+40: 53 83 | 90 81
+54: 46 53 | 5 90
+36: 50 90 | 130 53
+58: 92 90 | 130 53
+2: 19 53 | 75 90
+95: 53 46 | 90 19
+124: 46 53 | 33 90
+79: 91 53 | 7 90
+46: 90 90 | 53 90
+87: 9 90 | 84 53
+122: 90 46 | 53 33
+15: 89 90 | 79 53
+41: 90 4 | 53 119
+7: 53 128 | 90 128
+93: 53 120 | 90 37
+121: 15 53 | 103 90
+91: 90 33 | 53 110
+5: 53 90 | 65 53
+26: 53 19 | 90 107
+44: 53 75 | 90 32
+23: 107 53 | 50 90
+33: 90 53 | 90 90
+75: 53 53 | 90 90
+18: 65 65
+59: 53 107 | 90 32
+104: 90 33 | 53 46
+20: 121 90 | 123 53
+100: 90 75 | 53 46
+131: 18 90 | 46 53
+9: 90 67 | 53 105
+37: 53 75 | 90 128
+3: 53 29 | 90 22
+120: 53 92 | 90 33
+35: 55 53 | 30 90
+115: 65 107
+106: 90 46 | 53 19
+89: 90 59 | 53 68
+83: 90 46 | 53 130
+25: 90 87 | 53 41
+11: 42 31
+84: 53 117 | 90 34
+8: 42
+53: "a"
+86: 53 6 | 90 12
+76: 53 78 | 90 97
+52: 126 90 | 115 53
+31: 53 35 | 90 20
+112: 110 90 | 32 53
+82: 101 90 | 127 53
+119: 53 27 | 90 93
+117: 90 81 | 53 23
+57: 82 53 | 43 90
+105: 90 126 | 53 21
+111: 53 32 | 90 110
+68: 53 18 | 90 46
+73: 71 90 | 24 53
+49: 77 90 | 48 53
+81: 90 50 | 53 75
+102: 32 53 | 128 90
+12: 92 53 | 19 90
+60: 62 90 | 108 53
+101: 53 104 | 90 62
+65: 53 | 90
+50: 53 90
+97: 53 56 | 90 64
+63: 99 90 | 39 53
+43: 90 125 | 53 60
+66: 130 90 | 33 53
+27: 53 2 | 90 14
+4: 3 90 | 74 53
+118: 53 76 | 90 57
+113: 86 53 | 13 90
+56: 90 28 | 53 54
+38: 36 90 | 69 53
+39: 10 53 | 23 90
+14: 90 50 | 53 18
+45: 53 72 | 90 40
+21: 130 90 | 107 53
+30: 90 113 | 53 1
+19: 53 53 | 90 53
+130: 53 53
+110: 53 65 | 90 90
+0: 8 11
+77: 53 110 | 90 92
+62: 53 33 | 90 19
+126: 50 90
+29: 75 53 | 5 90
+129: 98 53 | 47 90
+47: 53 94 | 90 95
+71: 107 53
+92: 53 53 | 90 65
+127: 22 53 | 109 90
+6: 92 53 | 32 90
+51: 26 90 | 66 53
+107: 90 53 | 53 90
+72: 90 124 | 53 104
+1: 53 96 | 90 52
+103: 53 73 | 90 61
+74: 2 90 | 131 53
+64: 90 7 | 53 122
+67: 53 70 | 90 104
+42: 53 25 | 90 118
+123: 63 90 | 80 53
+17: 46 53 | 130 90
+10: 19 90 | 33 53
+13: 53 112 | 90 17
+28: 90 128 | 53 110
+114: 53 5 | 90 50
+78: 49 90 | 51 53
+16: 111 53 | 14 90
+90: "b"
+85: 130 90 | 50 53
+80: 38 53 | 16 90
+69: 110 53 | 107 90
+98: 53 44 | 90 88
+94: 5 53 | 46 90
+108: 18 53 | 75 90
+55: 90 129 | 53 45
+128: 90 90
+34: 106 90 | 114 53
+109: 90 110 | 53 50
+96: 36 90 | 116 53
+22: 75 53 | 18 90
+
+aaaaaaaabbbbaabaabbbaaba
+aaaaaaaaabbaaabbbaabaaaaabbaaabaaabbbbbb
+babaabaaabaaabbbaaaabbba
+baaaabbbabbabbbbabaababa
+aaaaabaabbbabbbabaaabababaabaabbbaaaabba
+babababbbaababbabaaaaaab
+bbabbbabbabaaabaaaaaaaba
+bbaabbaaaababbabbbabbbbb
+babbbbbbbbbababaaaabbbab
+abbbbbbaaaabbaaaaabbaaababbbbbababbaaaab
+aabbaabaaabaabaababbbaaa
+baaabaabaaabaabbbbaaaaba
+aabababbaabaaaabbaaaabaaabbbbbaa
+bbbbbababbaabaaabaababbababbaabababbababbaabbabaaaabbbba
+bbbaabbbaababbaaaaaaaabb
+aaababbbbbaaababababaabb
+bbabaabbababbbaabbababaa
+baaabababbbbbaaababbabab
+aaaababaaabbaababbaaaabb
+ababbabaaabaaaabbbbaaaba
+bbaaababbbbababbabbaabba
+babbbbbbbbbababababbaaab
+babaabbbbababaababbaabaabbabaabb
+baaaaabaaaaaabaabbaaabaa
+aabbabaaabaaabababbbbaab
+bababaabaabbaabbababaaab
+babaababbbbbbabababbbaaa
+babaaabbaababaaaaaaabbbb
+bbbbbabbbbaabaaabbaabbaabaabbaabaababbaa
+bbababaaaaaaaababbbaabbabbbaabbabbabbaabaaaaaaaaabbbabbbbaabbaababaaaaabaabbaaaa
+abaaabababaaabaabbbaaaaa
+baabbbbbabbbabbbbbaababbaababaaabbbbaaaa
+abbbabbbabbbaabbbaaaabab
+babbabbbabbbbabbaaabbaaabbababbabbbbbbaababaabbb
+babaabaaabbaabaaaaabbbbbabaabaaaabbbbaaaaaaababbabbaabbbaaabaaaababaaaba
+aabbababbaaaaaaabbbbababbaabbbbaaababbbbaaaabbabbabbbbaaaabbababbbbbabba
+bbaaabbaabaabaaabbaaaabb
+bbaabaaaabbabbababbbbbabbaaaaaababbaabbb
+baaababaabbbabaabbaaaaabaaababab
+abababbabbaabaabbaaabbaa
+bbbbabbaababaaaabbbbaaaababbabbbabbbbbabbbaaabbabbbbbbbabbbaabababaabbbb
+bbabaaaaaaababbababbabaaaaaaabaabbbbbaaabababbaaaaaaaabbbbabaabaaaaaabbbbababaabaabbaababbaaabab
+babaaaabbaaabababbaaabbbbaaaaaaa
+babbbabbbaabbababbbaaabb
+abbbabaaabbabbbbbbabababaaaaabba
+baaaaaaaaababaaaabbbbbaabbaaaaba
+bbbabbbababbaababaabbabaaabbbabbabaaaababbbaaaab
+bbbaabaaabbaaaaabbabaaaa
+abababbabaababbaaabaabaaaaababbbbaaabbaabbbababbababaaba
+bbbaabbbbbbbbbaababbaabababbaabaabbbbaba
+babbaaaaaabaaabaabaabaabbbaaaababaaaaabaabbbaaaabbbabaabbabbbaabbbabaaab
+bbabbbbaababaabbababbbbaaaaabaabbaababbbabaabaaaaababaaabbabbbba
+abbabaaaaabbbbbabbaaabbb
+aababaaaaaaabaaabbababbb
+babbbbbbbbbababaaaabaaab
+bbbabaabababaaaabaaaabba
+aaababbbbabbaabbbabbbabbbbababaa
+abbbbaaaabaaaabaabaaaaba
+bbabaabbbaabbabbaaaababbbbbaabbaabaaaaaabbabbbbaababaaba
+abaaababaaaaaaabbbabbbbaabbababbbbbaababbbbbabbaabbbbbababbabbbb
+bababaababbaaaaaaabbabab
+baaabbaabbaabaaababbababbbabbbabbbbbbaab
+baaaaababaababbaaaababab
+abbaabaabbbabbaaaaabaaab
+abbbabbaabbaaaaabbbbaaaabaababbabaabbbaa
+bbaabbbbbaabbaaaabaabaaaababbaaa
+aaabaaaaabbabbabaaababaa
+aabaabbaaabbbbbaabbbbbbaabaabbba
+aababbaababbbabbabbbabab
+bbabbaaaaabbbbbaaabababa
+aaabbbbbabbbbbaababaabba
+aaaaaaaabbabaaabbbabbbaa
+bbbabaaaaaabaaaaaaababaa
+aabbbabbbabbabababbbabbbbbbbabba
+baababbababbaabaabbbbaba
+abbbaabbbabbbabbabbabbaa
+aabbaabbabbbbbbabaabbabbabbbbbbbaaabbbbbaaaabbba
+bababaabaabaaabaaaabbbaa
+bbbabaabbaaababababbbbba
+abbbaabbbbbaaaabbabbbbabababbabb
+baabaaaabbababbbabbaabbabaaaabab
+babaabbabbaabbbabbaabbababbbbabb
+aaaaabbbaaabbbbbabbabbbbbbbabaabbbabbbababaaaaaa
+babaaaabbababbaaababaababaaaabba
+bababaabbbbabababbabaaba
+aaabbbbbaabababbababbabb
+bbbaabbbbabbbbbbaabaabab
+baababbabbbbbabaabaabbbb
+abbbabaabbbbaabaababbbaa
+aababaaaaabaaabaaaaaaaba
+abbbbaaaababaaabbaaaaaaababbaaaababbbaabbaabbbbbaabbababbaaabbbb
+bbbbbbaabbbababaabaaaababbbbbaabaabbaaaabbbbaaababababaa
+bbbaabbaaaabaaababbabbaaaabbabbabaabbbaaaabaaaaa
+bbbabbbabbbbbaababaaabbbaaababbaabaabaaa
+abbbabbaabbaaaaaaabababa
+baabaabbabaaabbabbbaaabb
+aaabaabaabaaabaaababbbaa
+babbaabaabaaaabbabbbbaba
+bbbbaabbbaabbaabbbabbbbaabaaababaaaaabab
+baabaabbaaaaabaaaabbabaabbbbbabaaababbabbbbbababbabaabbbbbabaaba
+abaaabbaaabaabbaaaaabbba
+ababaaaabbaaaaaaabbbaabbabbbbabb
+babaabbababbbabbabaabaabbbbbaabbbabaaabbaaabbbba
+baabbbbbbbbabbbbbababbab
+ababbababaaaaabbbbbabbbbabaaaabbaaaaabaaabaababb
+aaabaabababaabababbababb
+aaabbbbaaaaabbbbbbabbabbbabaabaabbaaaaaabaaaaabbbbbabbbabaaaaabaababaaba
+bbaabbaaaaaababbbaababaa
+aaaaabbbbbaaaaabbaababaa
+aaabbbbbabbbbbababbbaabbaaabbabbabaaabbb
+baaaaabbbbbbbbbabbbbbabbbaabbbababbbbbaa
+abbabababbbbabbabbaabbaabaaaabaabbbbbaaabbbbbbaaabbabbbabbbaaabbbbaaabab
+bbabbbabbbbabaaaabbabbabbaaabbab
+aabbaaabaabbbabbbbbaaaba
+ababbabaabbbaabbaaaaabbbaabaabbbbbbbbbbbbaaabbbbbaabaaabbaaaabba
+bbabbbababababaabbaaabbb
+babbabbbbbbabbbabbabaabbabbaaabbababbababbabbbbbabababaa
+bbaaaaabaabaabaabbbabbbbaabbbbbbaaaaaaba
+aaaaababbaaaaababaaabaaaaaaaaaabababbabbabbaaaaa
+abaaabbbaaabaabaaabaaaabaaabbbaa
+baaaaababbabbbbaaaaaaaaabbbbabba
+bbaabbaabbbbbabaaabbbbbabaaabaaaaaabbaba
+bbaaabbabaaaaabbaabbaababaaaabaaababbbab
+aabbaaababbbbbbbaabbabba
+abbabbabbbaaabbababaaaaa
+abbaabaabbbbbbbbbbbabbbbbabaabaa
+aabbabaaababbabaabbbaaaa
+bbabaababbabbaaaaaabbbbbabbaabaabaaabbbbbabbaabbbaaaaababbaababbbbababab
+bbabbaabbbabbbbabaaabbaa
+aaaabbababbaaabbabbbabaabbbaaababababbab
+aaaababbaaabaabbbaabaaab
+aabbaabbaaabaaaabbaabbab
+babababbaabbbbabbbabbaabbaaaaababaabbabbabbabbbaabababaabbabbbaa
+baabbaabbababbbbabaaaaba
+aabaaabbababbbaaabbbabaabaaaabbbabaabbaaabbbaabaaaabaaaaabaaabbabbbabbbb
+aabbbbbbaabaaabaaabbbbabaaabaabaababbaababbaabab
+bbbabbbaaaaabaabbbbbbaaaaabbbbbabbabaaabbbbaabba
+aabbbaaaabaaaabbbbbabbab
+bbaaaaaaabbbbbbbababbbaa
+baaaabbbabbbbbbbbbaababa
+abbabaaaaabbbbbaaabbaaaa
+bbbbbbbbaabaabbbbaaaabba
+aabaaaaaaabbbaababbaabbbbababbabababaaab
+aaaabbabaabbabaaaaabbbab
+baaabbbbbbbabaabbbaabaabaaaaababbaabbbbababbbbababbbbababbbbbbab
+baabbbbbbababbbbabaaaaaa
+bbbbbbbbbaaaaababbabbbbbbbbaaabb
+abbaaabbaaaabbabbaabbabbbbaababbbbbbbabb
+abbabababbaabaaaabbbaaba
+abbabaaaaabbbbbbaaaabbbb
+bbaabaababababbabbabaaaa
+ababbbbbbabbabbababbaababbbabbabbbabbabaaaaaababaaaabaabbbaababa
+bbabbabbabbababaaaababaa
+baabbaaabaabaaaaabaaaaab
+bbbabbaabbaaababbaaaaaab
+bbbbaabaababbabababbaaaa
+babbbabbabbabbabbbaaabbaaabbaabababbbabb
+aaaababbbaaaaababbbbbbaaabaababb
+bbbbaaaabbbbaaaaaabaaababbaabaababababaa
+baabbbabaaababababbbabab
+aaaaaaabbbbbbabaababbabb
+aaaaaababbbaaaaabababbab
+baaabbbbaaaabababababbba
+ababbbabaaaabbabaaaaabababaabbba
+abbabbbbbabbaabaabaababb
+baaaaababbbaabababbaabab
+babbaaaaaabbbbaabbabbbabbbbbbababaabbabbababaaba
+bbbbbaaaaabababbaabaabbaabbbaabbabaabbba
+bbbbaabaaaabbbbbbabbaaab
+baaababaaababbaaaabbbbbbabaaaaaa
+aaabbaaaababaabbabbbbabbbbaaaaaaaaabbaaabaabbaabbbbabbabbabbaaabaaabaabb
+aabaabbabbbabbbaabaaaaab
+abaabaaaaabaabaaabaabbba
+aabbbbabaaababbbababbbaa
+bbabaaababbabbabaabbaabbbbbbabba
+aabbbaaaaabbbbbbbababaaabaabbbaa
+abbbbabbaabbabaabaababaaabbabaaabaabaabbaaaaabaabbaaabbabbaaaaab
+bbbabaaabbaabbbbaaaaaaba
+baaaaabbaaaaabaabbababbb
+bbbabbbbbabbbbbbbbbbabab
+abbbabaabbaaababbbbbabaa
+aaaaabaaaaababbbabaaaabbabaaaaba
+abbababbbbbaaabbaaaabbbabaaabbbaaaaabbaababaaaababaaaabb
+abaabbbbbbbabaabababbabbbbabaaabbabababbaaabbaabbaababab
+baabbababbbabbaaaaaaaaba
+aabbbabbaaaabaaaababaaab
+abbabaaaaabbbbabbabbbbaaabbbbbabbbaaaabbbbaababb
+abbbbbbaaaabaababbaabbaa
+bbbbaabaabaaababaaabbabbaabbbabbbbababbbaabbabbabaabaaba
+abbbabaaaababaaaababaaab
+bbabaaababbaabbababbabaabaababaa
+aaaabbbaaaaabbbbabbbbbbabbbabaabbbabbbaabbaabababababaaabbbaabbabbabaaaabbbbbbbbabaaabba
+abbaabaabbbabbbbabaaaaab
+abbaaaaababbbbbbbabbabbaabbababbaaaaaabbabbaaaabaabbbaba
+aababaaaaabaaabbbaabaaab
+bbbabababbbabbbbabbabaaababaaaaa
+abbbbaaababbaaabbaaaabbabaabaaab
+abaabaabbbbabaabaabababa
+aaaaaaaaabaaababbbabbabbaaaaaaabaaaabbababababaa
+abababbbabababbaaabbabbbbbaabbbbbbaaababbbabbbbaabbabbaa
+bbbbbabaaabbbbabaaabbabbabababbaaaaabbbb
+aabbbbaaaaababbbaabbabba
+baaaaababaaaaababbabbbbaaaaaabaaababbaaabaaaaaaa
+abaaaabbabbaaababbabbbbb
+bbaabaaabaaaaabbbabbaabaaaabaabbaaaaabba
+abbbbbbbbabbbbaabbabaaaaabbabbbabaaabaaa
+bbbaabaaabaaaababbbbbabbbbbbbabbbbaaaaba
+abbaaabbbaabaabbbbbbaaab
+aaabbaaabbabbaabbababbaa
+abbbabbbabababbababaaaaa
+bbabbbbabaaaaababbaababbbbbaabaabbabbaaaaaaaabbbaaabbaab
+abaaababbbaabaaababbabaa
+bbaabaabbaaabbbbbaaaaabbaabbbbbbabbabaaabbaabababababbbabaaaabab
+abbaaaaaaabbabaababbbbba
+bbbababababaaabbabaaaaaa
+babbbabbbbbabaabababbabb
+abbaaaaaabbabaaabbbbaabbbabababa
+abbabbbbbbabaabbbabbabba
+baabaaaaaaaabaabbbbababaaaabbaaabbbaaabbbabbbaba
+baaabaababbaaabbabbbbabb
+abaabaabbbbbaabbababbbaa
+bbbbaabaabbababbbbababaabaaabbabbbbbabbabbbabbab
+bbabaaababbabaaaaaabaabbaabaaabaaabbaababbaaabbbbbbbabba
+bbbabaaaabbabbabbbbabbab
+bababaaababbbbbbbaabbbaa
+abbbbbbbbbabbaaabbababbb
+aabbaaabaabbbaaabbbaaaba
+aabbabbbbabaabababbabbaa
+abbbabaababaaabbabaabaaaaabbbbababaaabaababbaaaa
+aaaaabaabaaababaabaaaaab
+bbbaabbbbbaabbaababaabbb
+abaaaabbabbabbbbbbbbaaab
+aabababbbaaabababbabbabbaaaaabab
+bbabbaaaaaaaaaabbaaababb
+baaaaabaaaabaaaabbbabbbbaabbbbaaabaabbabbabbbbbababaaaaa
+aaababbaaababaaaaaabaababbbabaaa
+babbaabbbaaabaababaabbba
+abbbabaaabbababaaababbbb
+abbbaabbbabbababaabbaaabbabbaaaa
+bbbaabababbaaabaaaababab
+aaaaaaaaabbabbabababaabbbbaaaabbbbababbaaaabbaaaabababaabaabababbbbaaabaaaabaabb
+bbbbbaaabababbabaabbbbaabaaaaabbabbbabbabaabbbbaaabaababbbaabbba
+aaabbabbaabbaaabbbaaabbaaabbbbbabaaaaabaaababaaabaabaaab
+bbaababbaabbbbbbaabbbaaaabaabbab
+bbbbababababaaaaabbbaabbaaababbbababbabaaabbbaaa
+bababaaaaabaaabbbbabbababbbbbaaa
+babababbaaaaaaababaababb
+bbaaaaaaaabababbabbaabab
+abbaaaaabbbbbbaaaababaab
+babaababaababbaabbbabbbbbabbabbb
+aabbbbbbaababaaaababaabb
+aaaababbabababbabbabbabbbbaaababbabbbaab
+bbabbaaaaabaaababaabbaabaaaaabab
+aaaaaaaabbbbbaaaabbaabab
+abaaaabbbabbbabbabaabaabbbaaaaabbbbaabbb
+babaaabbabababbabbaaaaba
+baaababaabbabaabbaababbb
+aababaaaabaaabbaabaababa
+bbbabaabbabbbabbbbaaabbb
+abaaabbabbaabbaabaaabbaa
+bbbababbbbbbbaaabababbbaabbbaabbbaabaaabbabbabbabbaabaaaababbbbbbbbbbababbbabbaa
+bbbbaaaaaabbbabbabbaabaababbababaabbabaaaaababbbbaababaa
+bababbbbbaabbaababababbbabbbaaab
+bbaababbabbbaabbbababbab
+baabaabbaabbaabbbaaaabab
+aaaaabbbbababaabaabaaaaa
+bbbabaababbabaaabbbbabab
+bbbabaabaaaaaaaabaabbbababbaaabaaaabbabbaaaaabbbabbaaabb
+aabbabaabbbbaabaaababaaaabbbabbbbbbaaaaababbbbab
+aaaaaaabbabaaabbababaabb
+abaaabaabbabbaaabbbbbaab
+aabaabbaabbabaaabbabbabbabbbbbbbaaaabbbb
+baabaaaabbbabaabaabbaabbaababbaaaabbaaaaaababaab
+baabbaaaaabbbbbbabbabbba
+aabbbbbbbbaababbaaabaabaabbbabaababbbabaabbababb
+bbabaabbbabbaababbababba
+bbbbaabbbbaabbaaabbbbaba
+aaababbabaabbabbabaaaaab
+aaabaabaaaaaabaaabababab
+ababbabaabbbbbabbabbaababababbba
+abbaaabbbbbabaabaabbbbbababaababaabaabaabbaabbbaabbbbaaa
+baabbaabbbaaabbaabaaaabbbbbbbbaaabaaababababbbba
+aaaababaaaaabbabaabbaaaababaabaabaabababababbbbaaabbaaaa
+aaabaabbbbbaabaaababaaba
+bababaabaabbbabbaaaabbababbabbaa
+baabaaaaaabbaababaaababb
+baaaabaaaaaaaaaabbabbbaa
+babbaabbabaaabaaabbaabaabababbbabaababababaaaaaaabaaaaabaaabbbba
+abbaaaaabaabbbbbabaaaaaabbbbbbba
+aaabbaaaabaaaabbbaababab
+baaabbbbaabbbabbaabbbaab
+babbaabbbabbabaaababbbababaababbbabbbbbbbbaabaaaabaaabbbbaabbbbbbaaabbbb
+bbabbabaaaaaaaabaaaaaabb
+ababbbbbababbabaaabbaababababbbbabbbbaaaaaaaaaaaabbbbbbabbbaabba
+aaababbaaabababbababaaba
+aaaaababbababbabbaaabbbbbbaaaabaaaabbabb
+baabbbbbabbbabbbaaabaaab
+babaaababaababbbababbbbabbababababbbbaab
+abaabaabbabababbbaababbbbabbbbab
+baababbababaaaaaaababaababbaabaaaabaaabaabbbbbbabbbbabaabbbababbaaaabbbabaaaaababbbababaabaaabab
+bbbbbbaaabbababaabbbbaab
+abbaaaaabbabbabaababbaaa
+baaabbbbaabaabbbbbbabbbbbaaaabab
+bbbbbbaaaabaabaabaaabbaa
+aabaabbabbbabbbaabaaabbb
+bbaababbaabbbbabbbababbb
+bababaaabbabbbabaaaaabbbaaabbaab
+babbabbbbbabaabbbbabbbbaaabbbaaabaabbbbaaabbaaaabbbbabbb
+babbababbbabbabaabbbbaab
+aaaabbabbbabbbbabbbbaabaabbabababaaabaabbbbbbbbabaaaabba
+bbbbaaabaaabaaaaabbaabababaaabbbabbabbbb
+bbbabababbbbbbaaabbbbbaa
+baababbabaabbabbaabaabbbaabbbbbabbabbbaa
+bbaabbbbbbabbababaaabbaa
+aaaaaababaabbbbbbaabbabbbababaaaaababababaaabbabaaaabbbbaaaabbabbabbbaab
+babbbabbbaaabbbbbbaaaaaaaaabaabbbaabbaaaaababaabababaaba
+abababbbaaaababbbbaaabaa
+ababbabaaaaababbabaaaaaa
+bababaaaabbaaabbbababbab
+bbaabbbaabbabbbbaabababa
+baabbbbbabbabbabbbbbaaab
+abbaaaaaaaaabaaabaaaabba
+aabbaabbbbbabbaababbababaaabaabb
+bbaababbbbbabbbaaaababbabbaababbabababbabbababaabbaaabaaabaabbaa
+abbbbbabaaabbabbababbaab
+aaaaabaaaabaaaababbbbaaa
+aabaaabbbabbabbbabababaa
+aabbbabbaaaaabbbaababaab
+abababbbbbaabbaaabbbaabbaaaaabaabaaaabaabbbaaababbaababaabaababaababbbbb
+babbaabaabababbbaaabbaab
+abbbaabbabbbbbbbbaaababababbbaabbababbab
+aaaababbabbaaaaabaabaabbbbabbbaaaaaaabba
+bababbbbbbbbaabbaaaabbba
+bbaabbbaaaaaabbbbabbbbaa
+aabbaabaabbbabaabababbbbbbbbabab
+babababbabbbabaabbbabaaaabababaa
+babaaababbaaaabbbaabbbba
+ababaaaaabbbbbbbbaabbabbbabbaabbaaaabababaababaa
+bbaaaaabbaaaabbbbabbaabaababaababaabbaabababbbbaabbabbaa
+baabbabbaaabaabbbbbbaabaaaaabaabaabaabab
+aaababbbbbaababbabbabbaa
+aabbaaabaabbaaabbaababab
+abbabaaaaababaaaaaaaaaaabaaabaaabbbbabaa
+aaabaabaabbbabaabaabbabbaababaaaabaababa
+abbabbabbababbbbbaaaaaab
+aabaaabbbbbaaaabbbabababbaaaabbbaaabbbab
+bababbaaababbabababbabaabababaababbabaaaaaabaaaabbaaaaaabaabaaab
+aababaaabaaaaabbabababaa
+aabbabaabbabbaaabbbaaaba
+aabbabbbabbabaababbaaaaaaabbbabbaaabbaabaaaabbbbaaaabbba
+abababbabbbbaaaababbbbab
+aaaabbbbbbbbaabbbaababbaaabbbbbaaababbabbbbaaaaaababaabbababbbaabaababba
+abaaabbababababbbabababa
+abaaabbaabababbbbaaaaaaabbbbabbb
+aabababbbbbabaaababbabbbababaabb
+abababbaabbbaabbaabbbbbabbbbbbbb
+aabaabbbbbaabbbabaaabbbbbbaaaaaabbbbbbbabababbaabaaaabaa
+babaaaabaaababbaaabababa
+bbaabbbaababbababbbaaaab
+bbbaaaababbbbbaabbbbbababbababbaabbaabababbabbbababbbbababbbabaaaabbabaaabaaaababbbbbaaaabaaabbb
+baabaabbbaabbabaaababbba
+bbbaabbbbbababbbbbbbaababbaabbaabbbbbaababbaabbabbbbaaabaabaabbabaabbbaa
+bbbbbbbababbbbbbaabaababaaaaabbbbbbabbbb
+aababbaabbbbaabbbbbaabbbaabaabaaaaaaabbbbabababa
+abbbabaaabaaabbabbaaaaba
+aaaaabbbaabbbbbbaaababbbbabaabbaababaabbbabaaaaabbaaabbb
+babbabbbbbabaaabaaaabbaa
+bbbbaabbaaaaabaabbabbaaabbabaaaa
+aaababbbaabaaabbbbbaabba
+aabbaabbababaaaaabbababbbababbaaabbbbaabbbbaaabbbaaabaab
+bbabbabaabbabaabababaaab
+bbaaababbbbbaabababbbbaa
+aaaababaabbaaabbabbbbbaa
+bbaabbbaabaabaabbbaaaaababbabaabbbabbabaaabbabbabbbbabaa
+babbababaabaaabababbababbbaaababbbabbbbbbabababa
+aababbaaaaabaabbbbaaabaaabbbbabb
+bbbaaabbabaabbbbaabbabbbbabbaabbbabaababbbbaaaaaaababaabaaaaaaabbababaaa
+abbaaabbbbabbaaaabaabbba
+aaaaabaaaaaabbabbbaabaaaabaaaaaa
+aaabbbbbbaabaabbabbbaaab
+abaabaabbabaabbabbababbb
+aabbbaaaabababbababbbabbbabbabababbbbaabbaaaaaaa
+baababaababbabbbbbbabbbbababbabaabaaaaba
+bbaabbaabbaaaaaaaaabbaba
+aaaaabbbbaabbababababbbbbaababbaaaabbaab
+abbaabbabaaabbbaaaaaaabbaababbbaaabbbbbbabaaaaabbaabaaaabaaaaaababaabaababbbbbbbbaabbabb
+baababbabbabbabaabbabaaababbbaaa
+baabbaabaababbabbbbbabbb
+aabbaaababbbabbbbaabbaabababbbbb
+aabbbabbaaabaabaabbbaaab
+abbbbbbbbabababbbbaaaaabaabaabbbbababbaa
+bbbbbaaabbabaaabaababbababbababababaabbbbabaaaaa
+abbabbabaabbbbbbaabbbbbbbabbabbbabbaaaaaabbbaabababbaaaa
+aaaababbaababbabaaaaabaaabbbbbbbbbbbbaba
+bbbbabbaabaaabbabbaaabbaaababbaabbabbabaababaababbaaabaa
+aaabbbbbbaabaabbbbaababa
+baabaaaaaaabbabbbabbbabbbabbaaabbaaaabab
diff --git a/2020/inputs/day19_short b/2020/inputs/day19_short
new file mode 100644
index 0000000..f5f6d4e
--- /dev/null
+++ b/2020/inputs/day19_short
@@ -0,0 +1,47 @@
+42: 9 14 | 10 1
+9: 14 27 | 1 26
+10: 23 14 | 28 1
+1: "a"
+11: 42 31 | 42 11 31
+5: 1 14 | 15 1
+19: 14 1 | 14 14
+12: 24 14 | 19 1
+16: 15 1 | 14 14
+31: 14 17 | 1 13
+6: 14 14 | 1 14
+2: 1 24 | 14 4
+0: 8 11
+13: 14 3 | 1 12
+15: 1 | 14
+17: 14 2 | 1 7
+23: 25 1 | 22 14
+28: 16 1
+4: 1 1
+20: 14 14 | 1 15
+3: 5 14 | 16 1
+27: 1 6 | 14 18
+14: "b"
+21: 14 1 | 1 14
+25: 1 1 | 1 14
+22: 14 14
+8: 42 | 42 8
+26: 14 22 | 1 20
+18: 15 15
+7: 14 5 | 1 21
+24: 14 1
+
+abbbbbabbbaaaababbaabbbbabababbbabbbbbbabaaaa
+bbabbbbaabaabba
+babbbbaabbbbbabbbbbbaabaaabaaa
+aaabbbbbbaaaabaababaabababbabaaabbababababaaa
+bbbbbbbaaaabbbbaaabbabaaa
+bbbababbbbaaaaaaaabbababaaababaabab
+ababaaaaaabaaab
+ababaaaaabbbaba
+baabbaaaabbaaaababbaababb
+abbbbabbbbaaaababbbbbbaaaababb
+aaaaabbaabaaaaababaa
+aaaabbaaaabbaaa
+aaaabbaabbaaaaaaabbbabbbaaabbaabaaa
+babaaabbbaaabaababbaabababaaab
+aabbbbbaabbbaaaaaabbbbbababaaaaabbaaabba
diff --git a/2020/inputs/day19b b/2020/inputs/day19b
new file mode 100644
index 0000000..98858e0
--- /dev/null
+++ b/2020/inputs/day19b
@@ -0,0 +1,530 @@
+70: 90 92 | 53 50
+99: 90 102 | 53 22
+24: 130 90
+125: 85 53 | 100 90
+61: 53 58 | 90 26
+88: 33 53 | 46 90
+32: 65 90 | 90 53
+48: 46 53
+116: 53 50 | 90 18
+40: 53 83 | 90 81
+54: 46 53 | 5 90
+36: 50 90 | 130 53
+58: 92 90 | 130 53
+2: 19 53 | 75 90
+95: 53 46 | 90 19
+124: 46 53 | 33 90
+79: 91 53 | 7 90
+46: 90 90 | 53 90
+87: 9 90 | 84 53
+122: 90 46 | 53 33
+15: 89 90 | 79 53
+41: 90 4 | 53 119
+7: 53 128 | 90 128
+93: 53 120 | 90 37
+121: 15 53 | 103 90
+91: 90 33 | 53 110
+5: 53 90 | 65 53
+26: 53 19 | 90 107
+44: 53 75 | 90 32
+23: 107 53 | 50 90
+33: 90 53 | 90 90
+75: 53 53 | 90 90
+18: 65 65
+59: 53 107 | 90 32
+104: 90 33 | 53 46
+20: 121 90 | 123 53
+100: 90 75 | 53 46
+131: 18 90 | 46 53
+9: 90 67 | 53 105
+37: 53 75 | 90 128
+3: 53 29 | 90 22
+120: 53 92 | 90 33
+35: 55 53 | 30 90
+115: 65 107
+106: 90 46 | 53 19
+89: 90 59 | 53 68
+83: 90 46 | 53 130
+25: 90 87 | 53 41
+11: 42 31 | 42 11 31
+84: 53 117 | 90 34
+8: 42 | 42 8
+53: "a"
+86: 53 6 | 90 12
+76: 53 78 | 90 97
+52: 126 90 | 115 53
+31: 53 35 | 90 20
+112: 110 90 | 32 53
+82: 101 90 | 127 53
+119: 53 27 | 90 93
+117: 90 81 | 53 23
+57: 82 53 | 43 90
+105: 90 126 | 53 21
+111: 53 32 | 90 110
+68: 53 18 | 90 46
+73: 71 90 | 24 53
+49: 77 90 | 48 53
+81: 90 50 | 53 75
+102: 32 53 | 128 90
+12: 92 53 | 19 90
+60: 62 90 | 108 53
+101: 53 104 | 90 62
+65: 53 | 90
+50: 53 90
+97: 53 56 | 90 64
+63: 99 90 | 39 53
+43: 90 125 | 53 60
+66: 130 90 | 33 53
+27: 53 2 | 90 14
+4: 3 90 | 74 53
+118: 53 76 | 90 57
+113: 86 53 | 13 90
+56: 90 28 | 53 54
+38: 36 90 | 69 53
+39: 10 53 | 23 90
+14: 90 50 | 53 18
+45: 53 72 | 90 40
+21: 130 90 | 107 53
+30: 90 113 | 53 1
+19: 53 53 | 90 53
+130: 53 53
+110: 53 65 | 90 90
+0: 8 11
+77: 53 110 | 90 92
+62: 53 33 | 90 19
+126: 50 90
+29: 75 53 | 5 90
+129: 98 53 | 47 90
+47: 53 94 | 90 95
+71: 107 53
+92: 53 53 | 90 65
+127: 22 53 | 109 90
+6: 92 53 | 32 90
+51: 26 90 | 66 53
+107: 90 53 | 53 90
+72: 90 124 | 53 104
+1: 53 96 | 90 52
+103: 53 73 | 90 61
+74: 2 90 | 131 53
+64: 90 7 | 53 122
+67: 53 70 | 90 104
+42: 53 25 | 90 118
+123: 63 90 | 80 53
+17: 46 53 | 130 90
+10: 19 90 | 33 53
+13: 53 112 | 90 17
+28: 90 128 | 53 110
+114: 53 5 | 90 50
+78: 49 90 | 51 53
+16: 111 53 | 14 90
+90: "b"
+85: 130 90 | 50 53
+80: 38 53 | 16 90
+69: 110 53 | 107 90
+98: 53 44 | 90 88
+94: 5 53 | 46 90
+108: 18 53 | 75 90
+55: 90 129 | 53 45
+128: 90 90
+34: 106 90 | 114 53
+109: 90 110 | 53 50
+96: 36 90 | 116 53
+22: 75 53 | 18 90
+
+aaaaaaaabbbbaabaabbbaaba
+aaaaaaaaabbaaabbbaabaaaaabbaaabaaabbbbbb
+babaabaaabaaabbbaaaabbba
+baaaabbbabbabbbbabaababa
+aaaaabaabbbabbbabaaabababaabaabbbaaaabba
+babababbbaababbabaaaaaab
+bbabbbabbabaaabaaaaaaaba
+bbaabbaaaababbabbbabbbbb
+babbbbbbbbbababaaaabbbab
+abbbbbbaaaabbaaaaabbaaababbbbbababbaaaab
+aabbaabaaabaabaababbbaaa
+baaabaabaaabaabbbbaaaaba
+aabababbaabaaaabbaaaabaaabbbbbaa
+bbbbbababbaabaaabaababbababbaabababbababbaabbabaaaabbbba
+bbbaabbbaababbaaaaaaaabb
+aaababbbbbaaababababaabb
+bbabaabbababbbaabbababaa
+baaabababbbbbaaababbabab
+aaaababaaabbaababbaaaabb
+ababbabaaabaaaabbbbaaaba
+bbaaababbbbababbabbaabba
+babbbbbbbbbababababbaaab
+babaabbbbababaababbaabaabbabaabb
+baaaaabaaaaaabaabbaaabaa
+aabbabaaabaaabababbbbaab
+bababaabaabbaabbababaaab
+babaababbbbbbabababbbaaa
+babaaabbaababaaaaaaabbbb
+bbbbbabbbbaabaaabbaabbaabaabbaabaababbaa
+bbababaaaaaaaababbbaabbabbbaabbabbabbaabaaaaaaaaabbbabbbbaabbaababaaaaabaabbaaaa
+abaaabababaaabaabbbaaaaa
+baabbbbbabbbabbbbbaababbaababaaabbbbaaaa
+abbbabbbabbbaabbbaaaabab
+babbabbbabbbbabbaaabbaaabbababbabbbbbbaababaabbb
+babaabaaabbaabaaaaabbbbbabaabaaaabbbbaaaaaaababbabbaabbbaaabaaaababaaaba
+aabbababbaaaaaaabbbbababbaabbbbaaababbbbaaaabbabbabbbbaaaabbababbbbbabba
+bbaaabbaabaabaaabbaaaabb
+bbaabaaaabbabbababbbbbabbaaaaaababbaabbb
+baaababaabbbabaabbaaaaabaaababab
+abababbabbaabaabbaaabbaa
+bbbbabbaababaaaabbbbaaaababbabbbabbbbbabbbaaabbabbbbbbbabbbaabababaabbbb
+bbabaaaaaaababbababbabaaaaaaabaabbbbbaaabababbaaaaaaaabbbbabaabaaaaaabbbbababaabaabbaababbaaabab
+babaaaabbaaabababbaaabbbbaaaaaaa
+babbbabbbaabbababbbaaabb
+abbbabaaabbabbbbbbabababaaaaabba
+baaaaaaaaababaaaabbbbbaabbaaaaba
+bbbabbbababbaababaabbabaaabbbabbabaaaababbbaaaab
+bbbaabaaabbaaaaabbabaaaa
+abababbabaababbaaabaabaaaaababbbbaaabbaabbbababbababaaba
+bbbaabbbbbbbbbaababbaabababbaabaabbbbaba
+babbaaaaaabaaabaabaabaabbbaaaababaaaaabaabbbaaaabbbabaabbabbbaabbbabaaab
+bbabbbbaababaabbababbbbaaaaabaabbaababbbabaabaaaaababaaabbabbbba
+abbabaaaaabbbbbabbaaabbb
+aababaaaaaaabaaabbababbb
+babbbbbbbbbababaaaabaaab
+bbbabaabababaaaabaaaabba
+aaababbbbabbaabbbabbbabbbbababaa
+abbbbaaaabaaaabaabaaaaba
+bbabaabbbaabbabbaaaababbbbbaabbaabaaaaaabbabbbbaababaaba
+abaaababaaaaaaabbbabbbbaabbababbbbbaababbbbbabbaabbbbbababbabbbb
+bababaababbaaaaaaabbabab
+baaabbaabbaabaaababbababbbabbbabbbbbbaab
+baaaaababaababbaaaababab
+abbaabaabbbabbaaaaabaaab
+abbbabbaabbaaaaabbbbaaaabaababbabaabbbaa
+bbaabbbbbaabbaaaabaabaaaababbaaa
+aaabaaaaabbabbabaaababaa
+aabaabbaaabbbbbaabbbbbbaabaabbba
+aababbaababbbabbabbbabab
+bbabbaaaaabbbbbaaabababa
+aaabbbbbabbbbbaababaabba
+aaaaaaaabbabaaabbbabbbaa
+bbbabaaaaaabaaaaaaababaa
+aabbbabbbabbabababbbabbbbbbbabba
+baababbababbaabaabbbbaba
+abbbaabbbabbbabbabbabbaa
+aabbaabbabbbbbbabaabbabbabbbbbbbaaabbbbbaaaabbba
+bababaabaabaaabaaaabbbaa
+bbbabaabbaaababababbbbba
+abbbaabbbbbaaaabbabbbbabababbabb
+baabaaaabbababbbabbaabbabaaaabab
+babaabbabbaabbbabbaabbababbbbabb
+aaaaabbbaaabbbbbabbabbbbbbbabaabbbabbbababaaaaaa
+babaaaabbababbaaababaababaaaabba
+bababaabbbbabababbabaaba
+aaabbbbbaabababbababbabb
+bbbaabbbbabbbbbbaabaabab
+baababbabbbbbabaabaabbbb
+abbbabaabbbbaabaababbbaa
+aababaaaaabaaabaaaaaaaba
+abbbbaaaababaaabbaaaaaaababbaaaababbbaabbaabbbbbaabbababbaaabbbb
+bbbbbbaabbbababaabaaaababbbbbaabaabbaaaabbbbaaababababaa
+bbbaabbaaaabaaababbabbaaaabbabbabaabbbaaaabaaaaa
+bbbabbbabbbbbaababaaabbbaaababbaabaabaaa
+abbbabbaabbaaaaaaabababa
+baabaabbabaaabbabbbaaabb
+aaabaabaabaaabaaababbbaa
+babbaabaabaaaabbabbbbaba
+bbbbaabbbaabbaabbbabbbbaabaaababaaaaabab
+baabaabbaaaaabaaaabbabaabbbbbabaaababbabbbbbababbabaabbbbbabaaba
+abaaabbaaabaabbaaaaabbba
+ababaaaabbaaaaaaabbbaabbabbbbabb
+babaabbababbbabbabaabaabbbbbaabbbabaaabbaaabbbba
+baabbbbbbbbabbbbbababbab
+ababbababaaaaabbbbbabbbbabaaaabbaaaaabaaabaababb
+aaabaabababaabababbababb
+aaabbbbaaaaabbbbbbabbabbbabaabaabbaaaaaabaaaaabbbbbabbbabaaaaabaababaaba
+bbaabbaaaaaababbbaababaa
+aaaaabbbbbaaaaabbaababaa
+aaabbbbbabbbbbababbbaabbaaabbabbabaaabbb
+baaaaabbbbbbbbbabbbbbabbbaabbbababbbbbaa
+abbabababbbbabbabbaabbaabaaaabaabbbbbaaabbbbbbaaabbabbbabbbaaabbbbaaabab
+bbabbbabbbbabaaaabbabbabbaaabbab
+aabbaaabaabbbabbbbbaaaba
+ababbabaabbbaabbaaaaabbbaabaabbbbbbbbbbbbaaabbbbbaabaaabbaaaabba
+bbabbbababababaabbaaabbb
+babbabbbbbbabbbabbabaabbabbaaabbababbababbabbbbbabababaa
+bbaaaaabaabaabaabbbabbbbaabbbbbbaaaaaaba
+aaaaababbaaaaababaaabaaaaaaaaaabababbabbabbaaaaa
+abaaabbbaaabaabaaabaaaabaaabbbaa
+baaaaababbabbbbaaaaaaaaabbbbabba
+bbaabbaabbbbbabaaabbbbbabaaabaaaaaabbaba
+bbaaabbabaaaaabbaabbaababaaaabaaababbbab
+aabbaaababbbbbbbaabbabba
+abbabbabbbaaabbababaaaaa
+abbaabaabbbbbbbbbbbabbbbbabaabaa
+aabbabaaababbabaabbbaaaa
+bbabaababbabbaaaaaabbbbbabbaabaabaaabbbbbabbaabbbaaaaababbaababbbbababab
+bbabbaabbbabbbbabaaabbaa
+aaaabbababbaaabbabbbabaabbbaaababababbab
+aaaababbaaabaabbbaabaaab
+aabbaabbaaabaaaabbaabbab
+babababbaabbbbabbbabbaabbaaaaababaabbabbabbabbbaabababaabbabbbaa
+baabbaabbababbbbabaaaaba
+aabaaabbababbbaaabbbabaabaaaabbbabaabbaaabbbaabaaaabaaaaabaaabbabbbabbbb
+aabbbbbbaabaaabaaabbbbabaaabaabaababbaababbaabab
+bbbabbbaaaaabaabbbbbbaaaaabbbbbabbabaaabbbbaabba
+aabbbaaaabaaaabbbbbabbab
+bbaaaaaaabbbbbbbababbbaa
+baaaabbbabbbbbbbbbaababa
+abbabaaaaabbbbbaaabbaaaa
+bbbbbbbbaabaabbbbaaaabba
+aabaaaaaaabbbaababbaabbbbababbabababaaab
+aaaabbabaabbabaaaaabbbab
+baaabbbbbbbabaabbbaabaabaaaaababbaabbbbababbbbababbbbababbbbbbab
+baabbbbbbababbbbabaaaaaa
+bbbbbbbbbaaaaababbabbbbbbbbaaabb
+abbaaabbaaaabbabbaabbabbbbaababbbbbbbabb
+abbabababbaabaaaabbbaaba
+abbabaaaaabbbbbbaaaabbbb
+bbaabaababababbabbabaaaa
+ababbbbbbabbabbababbaababbbabbabbbabbabaaaaaababaaaabaabbbaababa
+bbabbabbabbababaaaababaa
+baabbaaabaabaaaaabaaaaab
+bbbabbaabbaaababbaaaaaab
+bbbbaabaababbabababbaaaa
+babbbabbabbabbabbbaaabbaaabbaabababbbabb
+aaaababbbaaaaababbbbbbaaabaababb
+bbbbaaaabbbbaaaaaabaaababbaabaababababaa
+baabbbabaaababababbbabab
+aaaaaaabbbbbbabaababbabb
+aaaaaababbbaaaaabababbab
+baaabbbbaaaabababababbba
+ababbbabaaaabbabaaaaabababaabbba
+abbabbbbbabbaabaabaababb
+baaaaababbbaabababbaabab
+babbaaaaaabbbbaabbabbbabbbbbbababaabbabbababaaba
+bbbbbaaaaabababbaabaabbaabbbaabbabaabbba
+bbbbaabaaaabbbbbbabbaaab
+baaababaaababbaaaabbbbbbabaaaaaa
+aaabbaaaababaabbabbbbabbbbaaaaaaaaabbaaabaabbaabbbbabbabbabbaaabaaabaabb
+aabaabbabbbabbbaabaaaaab
+abaabaaaaabaabaaabaabbba
+aabbbbabaaababbbababbbaa
+bbabaaababbabbabaabbaabbbbbbabba
+aabbbaaaaabbbbbbbababaaabaabbbaa
+abbbbabbaabbabaabaababaaabbabaaabaabaabbaaaaabaabbaaabbabbaaaaab
+bbbabaaabbaabbbbaaaaaaba
+baaaaabbaaaaabaabbababbb
+bbbabbbbbabbbbbbbbbbabab
+abbbabaabbaaababbbbbabaa
+aaaaabaaaaababbbabaaaabbabaaaaba
+abbababbbbbaaabbaaaabbbabaaabbbaaaaabbaababaaaababaaaabb
+abaabbbbbbbabaabababbabbbbabaaabbabababbaaabbaabbaababab
+baabbababbbabbaaaaaaaaba
+aabbbabbaaaabaaaababaaab
+abbabaaaaabbbbabbabbbbaaabbbbbabbbaaaabbbbaababb
+abbbbbbaaaabaababbaabbaa
+bbbbaabaabaaababaaabbabbaabbbabbbbababbbaabbabbabaabaaba
+abbbabaaaababaaaababaaab
+bbabaaababbaabbababbabaabaababaa
+aaaabbbaaaaabbbbabbbbbbabbbabaabbbabbbaabbaabababababaaabbbaabbabbabaaaabbbbbbbbabaaabba
+abbaabaabbbabbbbabaaaaab
+abbaaaaababbbbbbbabbabbaabbababbaaaaaabbabbaaaabaabbbaba
+aababaaaaabaaabbbaabaaab
+bbbabababbbabbbbabbabaaababaaaaa
+abbbbaaababbaaabbaaaabbabaabaaab
+abaabaabbbbabaabaabababa
+aaaaaaaaabaaababbbabbabbaaaaaaabaaaabbababababaa
+abababbbabababbaaabbabbbbbaabbbbbbaaababbbabbbbaabbabbaa
+bbbbbabaaabbbbabaaabbabbabababbaaaaabbbb
+aabbbbaaaaababbbaabbabba
+baaaaababaaaaababbabbbbaaaaaabaaababbaaabaaaaaaa
+abaaaabbabbaaababbabbbbb
+bbaabaaabaaaaabbbabbaabaaaabaabbaaaaabba
+abbbbbbbbabbbbaabbabaaaaabbabbbabaaabaaa
+bbbaabaaabaaaababbbbbabbbbbbbabbbbaaaaba
+abbaaabbbaabaabbbbbbaaab
+aaabbaaabbabbaabbababbaa
+abbbabbbabababbababaaaaa
+bbabbbbabaaaaababbaababbbbbaabaabbabbaaaaaaaabbbaaabbaab
+abaaababbbaabaaababbabaa
+bbaabaabbaaabbbbbaaaaabbaabbbbbbabbabaaabbaabababababbbabaaaabab
+abbaaaaaaabbabaababbbbba
+bbbababababaaabbabaaaaaa
+babbbabbbbbabaabababbabb
+abbaaaaaabbabaaabbbbaabbbabababa
+abbabbbbbbabaabbbabbabba
+baabaaaaaaaabaabbbbababaaaabbaaabbbaaabbbabbbaba
+baaabaababbaaabbabbbbabb
+abaabaabbbbbaabbababbbaa
+bbbbaabaabbababbbbababaabaaabbabbbbbabbabbbabbab
+bbabaaababbabaaaaaabaabbaabaaabaaabbaababbaaabbbbbbbabba
+bbbabaaaabbabbabbbbabbab
+bababaaababbbbbbbaabbbaa
+abbbbbbbbbabbaaabbababbb
+aabbaaabaabbbaaabbbaaaba
+aabbabbbbabaabababbabbaa
+abbbabaababaaabbabaabaaaaabbbbababaaabaababbaaaa
+aaaaabaabaaababaabaaaaab
+bbbaabbbbbaabbaababaabbb
+abaaaabbabbabbbbbbbbaaab
+aabababbbaaabababbabbabbaaaaabab
+bbabbaaaaaaaaaabbaaababb
+baaaaabaaaabaaaabbbabbbbaabbbbaaabaabbabbabbbbbababaaaaa
+aaababbaaababaaaaaabaababbbabaaa
+babbaabbbaaabaababaabbba
+abbbabaaabbababaaababbbb
+abbbaabbbabbababaabbaaabbabbaaaa
+bbbaabababbaaabaaaababab
+aaaaaaaaabbabbabababaabbbbaaaabbbbababbaaaabbaaaabababaabaabababbbbaaabaaaabaabb
+bbbbbaaabababbabaabbbbaabaaaaabbabbbabbabaabbbbaaabaababbbaabbba
+aaabbabbaabbaaabbbaaabbaaabbbbbabaaaaabaaababaaabaabaaab
+bbaababbaabbbbbbaabbbaaaabaabbab
+bbbbababababaaaaabbbaabbaaababbbababbabaaabbbaaa
+bababaaaaabaaabbbbabbababbbbbaaa
+babababbaaaaaaababaababb
+bbaaaaaaaabababbabbaabab
+abbaaaaabbbbbbaaaababaab
+babaababaababbaabbbabbbbbabbabbb
+aabbbbbbaababaaaababaabb
+aaaababbabababbabbabbabbbbaaababbabbbaab
+bbabbaaaaabaaababaabbaabaaaaabab
+aaaaaaaabbbbbaaaabbaabab
+abaaaabbbabbbabbabaabaabbbaaaaabbbbaabbb
+babaaabbabababbabbaaaaba
+baaababaabbabaabbaababbb
+aababaaaabaaabbaabaababa
+bbbabaabbabbbabbbbaaabbb
+abaaabbabbaabbaabaaabbaa
+bbbababbbbbbbaaabababbbaabbbaabbbaabaaabbabbabbabbaabaaaababbbbbbbbbbababbbabbaa
+bbbbaaaaaabbbabbabbaabaababbababaabbabaaaaababbbbaababaa
+bababbbbbaabbaababababbbabbbaaab
+bbaababbabbbaabbbababbab
+baabaabbaabbaabbbaaaabab
+aaaaabbbbababaabaabaaaaa
+bbbabaababbabaaabbbbabab
+bbbabaabaaaaaaaabaabbbababbaaabaaaabbabbaaaaabbbabbaaabb
+aabbabaabbbbaabaaababaaaabbbabbbbbbaaaaababbbbab
+aaaaaaabbabaaabbababaabb
+abaaabaabbabbaaabbbbbaab
+aabaabbaabbabaaabbabbabbabbbbbbbaaaabbbb
+baabaaaabbbabaabaabbaabbaababbaaaabbaaaaaababaab
+baabbaaaaabbbbbbabbabbba
+aabbbbbbbbaababbaaabaabaabbbabaababbbabaabbababb
+bbabaabbbabbaababbababba
+bbbbaabbbbaabbaaabbbbaba
+aaababbabaabbabbabaaaaab
+aaabaabaaaaaabaaabababab
+ababbabaabbbbbabbabbaababababbba
+abbaaabbbbbabaabaabbbbbababaababaabaabaabbaabbbaabbbbaaa
+baabbaabbbaaabbaabaaaabbbbbbbbaaabaaababababbbba
+aaaababaaaaabbabaabbaaaababaabaabaabababababbbbaaabbaaaa
+aaabaabbbbbaabaaababaaba
+bababaabaabbbabbaaaabbababbabbaa
+baabaaaaaabbaababaaababb
+baaaabaaaaaaaaaabbabbbaa
+babbaabbabaaabaaabbaabaabababbbabaababababaaaaaaabaaaaabaaabbbba
+abbaaaaabaabbbbbabaaaaaabbbbbbba
+aaabbaaaabaaaabbbaababab
+baaabbbbaabbbabbaabbbaab
+babbaabbbabbabaaababbbababaababbbabbbbbbbbaabaaaabaaabbbbaabbbbbbaaabbbb
+bbabbabaaaaaaaabaaaaaabb
+ababbbbbababbabaaabbaababababbbbabbbbaaaaaaaaaaaabbbbbbabbbaabba
+aaababbaaabababbababaaba
+aaaaababbababbabbaaabbbbbbaaaabaaaabbabb
+baabbbbbabbbabbbaaabaaab
+babaaababaababbbababbbbabbababababbbbaab
+abaabaabbabababbbaababbbbabbbbab
+baababbababaaaaaaababaababbaabaaaabaaabaabbbbbbabbbbabaabbbababbaaaabbbabaaaaababbbababaabaaabab
+bbbbbbaaabbababaabbbbaab
+abbaaaaabbabbabaababbaaa
+baaabbbbaabaabbbbbbabbbbbaaaabab
+bbbbbbaaaabaabaabaaabbaa
+aabaabbabbbabbbaabaaabbb
+bbaababbaabbbbabbbababbb
+bababaaabbabbbabaaaaabbbaaabbaab
+babbabbbbbabaabbbbabbbbaaabbbaaabaabbbbaaabbaaaabbbbabbb
+babbababbbabbabaabbbbaab
+aaaabbabbbabbbbabbbbaabaabbabababaaabaabbbbbbbbabaaaabba
+bbbbaaabaaabaaaaabbaabababaaabbbabbabbbb
+bbbabababbbbbbaaabbbbbaa
+baababbabaabbabbaabaabbbaabbbbbabbabbbaa
+bbaabbbbbbabbababaaabbaa
+aaaaaababaabbbbbbaabbabbbababaaaaababababaaabbabaaaabbbbaaaabbabbabbbaab
+babbbabbbaaabbbbbbaaaaaaaaabaabbbaabbaaaaababaabababaaba
+abababbbaaaababbbbaaabaa
+ababbabaaaaababbabaaaaaa
+bababaaaabbaaabbbababbab
+bbaabbbaabbabbbbaabababa
+baabbbbbabbabbabbbbbaaab
+abbaaaaaaaaabaaabaaaabba
+aabbaabbbbbabbaababbababaaabaabb
+bbaababbbbbabbbaaaababbabbaababbabababbabbababaabbaaabaaabaabbaa
+abbbbbabaaabbabbababbaab
+aaaaabaaaabaaaababbbbaaa
+aabaaabbbabbabbbabababaa
+aabbbabbaaaaabbbaababaab
+abababbbbbaabbaaabbbaabbaaaaabaabaaaabaabbbaaababbaababaabaababaababbbbb
+babbaabaabababbbaaabbaab
+abbbaabbabbbbbbbbaaababababbbaabbababbab
+aaaababbabbaaaaabaabaabbbbabbbaaaaaaabba
+bababbbbbbbbaabbaaaabbba
+bbaabbbaaaaaabbbbabbbbaa
+aabbaabaabbbabaabababbbbbbbbabab
+babababbabbbabaabbbabaaaabababaa
+babaaababbaaaabbbaabbbba
+ababaaaaabbbbbbbbaabbabbbabbaabbaaaabababaababaa
+bbaaaaabbaaaabbbbabbaabaababaababaabbaabababbbbaabbabbaa
+baabbabbaaabaabbbbbbaabaaaaabaabaabaabab
+aaababbbbbaababbabbabbaa
+aabbaaabaabbaaabbaababab
+abbabaaaaababaaaaaaaaaaabaaabaaabbbbabaa
+aaabaabaabbbabaabaabbabbaababaaaabaababa
+abbabbabbababbbbbaaaaaab
+aabaaabbbbbaaaabbbabababbaaaabbbaaabbbab
+bababbaaababbabababbabaabababaababbabaaaaaabaaaabbaaaaaabaabaaab
+aababaaabaaaaabbabababaa
+aabbabaabbabbaaabbbaaaba
+aabbabbbabbabaababbaaaaaaabbbabbaaabbaabaaaabbbbaaaabbba
+abababbabbbbaaaababbbbab
+aaaabbbbbbbbaabbbaababbaaabbbbbaaababbabbbbaaaaaababaabbababbbaabaababba
+abaaabbababababbbabababa
+abaaabbaabababbbbaaaaaaabbbbabbb
+aabababbbbbabaaababbabbbababaabb
+abababbaabbbaabbaabbbbbabbbbbbbb
+aabaabbbbbaabbbabaaabbbbbbaaaaaabbbbbbbabababbaabaaaabaa
+babaaaabaaababbaaabababa
+bbaabbbaababbababbbaaaab
+bbbaaaababbbbbaabbbbbababbababbaabbaabababbabbbababbbbababbbabaaaabbabaaabaaaababbbbbaaaabaaabbb
+baabaabbbaabbabaaababbba
+bbbaabbbbbababbbbbbbaababbaabbaabbbbbaababbaabbabbbbaaabaabaabbabaabbbaa
+bbbbbbbababbbbbbaabaababaaaaabbbbbbabbbb
+aababbaabbbbaabbbbbaabbbaabaabaaaaaaabbbbabababa
+abbbabaaabaaabbabbaaaaba
+aaaaabbbaabbbbbbaaababbbbabaabbaababaabbbabaaaaabbaaabbb
+babbabbbbbabaaabaaaabbaa
+bbbbaabbaaaaabaabbabbaaabbabaaaa
+aaababbbaabaaabbbbbaabba
+aabbaabbababaaaaabbababbbababbaaabbbbaabbbbaaabbbaaabaab
+bbabbabaabbabaabababaaab
+bbaaababbbbbaabababbbbaa
+aaaababaabbaaabbabbbbbaa
+bbaabbbaabaabaabbbaaaaababbabaabbbabbabaaabbabbabbbbabaa
+babbababaabaaabababbababbbaaababbbabbbbbbabababa
+aababbaaaaabaabbbbaaabaaabbbbabb
+bbbaaabbabaabbbbaabbabbbbabbaabbbabaababbbbaaaaaaababaabaaaaaaabbababaaa
+abbaaabbbbabbaaaabaabbba
+aaaaabaaaaaabbabbbaabaaaabaaaaaa
+aaabbbbbbaabaabbabbbaaab
+abaabaabbabaabbabbababbb
+aabbbaaaabababbababbbabbbabbabababbbbaabbaaaaaaa
+baababaababbabbbbbbabbbbababbabaabaaaaba
+bbaabbaabbaaaaaaaaabbaba
+aaaaabbbbaabbababababbbbbaababbaaaabbaab
+abbaabbabaaabbbaaaaaaabbaababbbaaabbbbbbabaaaaabbaabaaaabaaaaaababaabaababbbbbbbbaabbabb
+baababbabbabbabaabbabaaababbbaaa
+baabbaabaababbabbbbbabbb
+aabbaaababbbabbbbaabbaabababbbbb
+aabbbabbaaabaabaabbbaaab
+abbbbbbbbabababbbbaaaaabaabaabbbbababbaa
+bbbbbaaabbabaaabaababbababbababababaabbbbabaaaaa
+abbabbabaabbbbbbaabbbbbbbabbabbbabbaaaaaabbbaabababbaaaa
+aaaababbaababbabaaaaabaaabbbbbbbbbbbbaba
+bbbbabbaabaaabbabbaaabbaaababbaabbabbabaababaababbaaabaa
+aaabbbbbbaabaabbbbaababa
+baabaaaaaaabbabbbabbbabbbabbaaabbaaaabab \ No newline at end of file
diff --git a/2020/inputs/day2 b/2020/inputs/day2
new file mode 100644
index 0000000..6158f52
--- /dev/null
+++ b/2020/inputs/day2
@@ -0,0 +1,1000 @@
+13-15 c: cqbhncccjsncqcc
+2-3 v: zvdvfd
+9-14 b: rbrbnbbbqdfrht
+11-12 k: kkkkkkkkkkxqk
+4-5 b: bqbbdm
+10-12 w: kwwkwwwrwzzwwwwzwswx
+1-11 g: grrmgmqgghw
+4-5 m: mbmhmvmwdvxmvpw
+1-13 n: ndnnnnnnnnnns
+11-18 l: lllllllllllllllllll
+4-5 c: cccscc
+2-4 k: bkfr
+9-13 k: lcmsvkknrxtkkksgvkjg
+1-2 b: bhwgb
+1-4 j: zjjcjj
+7-11 g: nnffggdmggr
+3-4 z: zzhzz
+4-10 g: mggkgvgggmggkggmqg
+4-5 n: dcmnl
+11-15 s: gzpdvsmnzsshswzs
+10-14 x: xmvpxjtlxxhxtpdhsnx
+5-15 v: zzhjdpgxlsvphzv
+4-8 k: dsfktqchpkk
+6-7 j: jzjgjqld
+12-16 r: rrrrrrrrrrrhrrrrhrr
+1-2 l: lllllll
+2-3 q: jqxwtggmgqmzpljdvkt
+8-11 p: xpmcppppwvzp
+7-8 c: vwcvkcct
+4-10 d: lsmdffzdsrk
+2-3 p: sxpg
+4-11 p: rzlgxshhpbp
+1-4 b: qbbbbbbbbbbb
+6-11 m: zwmzmmlbmxgphkks
+1-4 n: lnnnn
+15-16 h: hhbdmbhchhhkhhrw
+10-11 k: kkkqtwkkkkkkkkn
+2-13 m: mggmmxmrzmwglbmmm
+12-14 g: ggggrggggxgwhggggd
+7-11 l: llbqsqlkvll
+1-3 f: ffff
+4-9 h: qvnhvcmpmfdbqhkdsg
+3-8 d: ddsdddddd
+14-15 j: qjjjzjjjjjbxmjs
+3-5 j: jjjjtctjjjs
+12-13 q: qqqqqqqqqqqqgqqq
+1-8 p: xpppzdpp
+13-15 f: lnlnlkcwgnfqgmfhlwm
+12-17 g: gfgtgrvcxggggtggjg
+6-8 r: rrrrtwrqrrr
+9-12 r: ctldssjlrzhvpmqrtxd
+1-6 k: qkkkdkkkkkk
+17-18 x: bxrxxbxxzpbxnqxcsmn
+2-4 c: ccmr
+1-7 m: mmmmfrdmmmhl
+9-12 d: ddddddddxddhd
+13-14 f: ffffffffjffbbff
+4-6 c: ccchcc
+6-7 r: rrsrrrrcrrjbrrrr
+9-15 w: wzfbtqrwwgtmbxn
+6-7 q: qqqqqqrq
+1-7 l: lgpqzhlkb
+6-8 d: dhddkndp
+2-5 m: bjxmmmmm
+5-16 t: nbgjntfhpwtbrcftxt
+5-7 k: kkkkkhbkkkkk
+8-19 t: dsdstttfjhnttttvgttt
+3-4 t: ttltttt
+1-5 l: flfllllllllbhldll
+7-10 x: xxxxxxcxxxx
+2-7 t: ttttttctttt
+3-12 x: vlxfwpdncxzkmkxt
+1-5 b: mbbbbbdbbbtbwbhpbt
+3-16 q: fpqkkkqfkqdbrxlq
+5-6 p: lpcbtppjpt
+6-7 w: wcwwhwv
+9-13 v: vvvvvvvvvvvvvvv
+1-4 g: vgggtggghgggggggg
+2-9 p: mppsrrzwxdt
+4-5 f: ffffdfffffdf
+2-5 x: xkjss
+13-14 z: zzzzzzzzzzzzbhzz
+2-10 p: xmtkzpbrrj
+17-18 t: ttttttttttttttttttt
+2-8 j: cjjqbzpd
+4-12 z: zzzkzzhzzpzzdzz
+1-2 d: rdcdt
+2-3 j: wnltj
+7-9 r: rlrfbrdrqrbdr
+3-4 s: bcsss
+12-14 h: hhhhhhhhhhhbhhh
+3-5 h: rfhlc
+8-15 f: ffffffflffffffff
+3-15 s: ssxsssssssssssss
+2-4 h: hlbhshhmhhhg
+12-13 r: rrrrrrrrmrvrnrr
+3-5 p: ppppjp
+1-2 z: zqhdkgqqzfsxkjjzg
+6-8 k: kkkkkkzd
+1-12 h: qhhhhhhhhxhhhhh
+9-14 p: ppppppppqppppfp
+2-4 t: tsttt
+18-19 t: cttttllttttwxtttttt
+10-11 t: rkdbpntntttfw
+4-14 m: mdmmgtlmmwmbmmmk
+4-6 n: xxhnpmnfnn
+15-16 g: ggggggsggggggggng
+14-15 k: kpjxmkrksskpbwk
+15-18 f: fffffsffffffffnfffff
+18-19 p: gwpplnpndvpxgzjvhbpp
+8-12 l: ldclrkllbgpwllllcxms
+14-19 w: pxsjbtwwhdkptwcxwvr
+2-17 m: mtmmmmmmmmmmmmmmmm
+12-15 b: nbcsplrmvbjbqlc
+1-4 z: bzzszzzzz
+1-13 t: tttttttttttttttttt
+6-7 j: jjjjjmvjjjjjjjjjjj
+10-13 l: llclllllljllllll
+11-12 c: mzckxzsbbxcq
+2-14 k: kkckkkkbkkkkkrkkkkkk
+3-5 s: msssvqszssprssss
+7-10 f: fffffffffrf
+2-4 l: dlwrl
+3-7 v: slqgljmrqrwv
+4-6 d: pdddddnddddddd
+6-9 f: cnfffpfzfffffff
+4-17 v: vvvnvvvvvvvvvvvvvv
+7-9 q: qqqqqqqqkqqqqqnqq
+15-16 q: qqqqqqqqqqqqqqqqqq
+10-11 g: cgtrgggggggggg
+10-12 x: xxsxxsjxfxxlx
+3-12 j: jjljjjjjjjjjjjj
+8-9 c: ccbccczccthcc
+4-17 h: hhhfhhshhhhhhhhhhhh
+1-2 p: prppr
+4-12 q: qqqdqqqqqqqqqqq
+7-11 b: bbmbqbrtlwb
+4-7 l: lllhlllllz
+3-4 r: rrqc
+5-14 r: rrrrcrrrrrrqrrrrrrr
+10-11 d: pxdcxxjsddd
+9-11 s: sssssssspssssssss
+1-2 j: jfjljjjjjjjjjjjjjj
+3-4 v: vqnvvv
+2-3 c: wlcntvmsshxcgzc
+9-14 t: rbbljpttwwjtbj
+10-11 s: gnrdtfzttks
+1-4 x: xpxjxhdxx
+9-12 c: chccccccmpfccc
+14-16 j: jjjjjjjjjjjjjxjjj
+5-6 d: rpdndsbddwdd
+9-13 x: thpdhlcwxcxxvxbv
+4-6 g: nfsgqnvbntgwvlzlmmxg
+3-4 d: dttdcdtq
+2-4 n: wnntzbr
+2-10 j: jtpszbpjfjcgdjg
+6-7 b: bdspbvb
+10-14 z: vzznzzzwzlzzqzj
+7-8 c: cccccccc
+7-11 h: hklhdhssfbz
+7-8 h: hhhhhhqzhhhhhs
+3-5 b: bcgbwbbbbbdb
+5-6 q: qqlxqbgtqpkqt
+8-9 q: qqqqqhqkq
+2-4 q: qshp
+8-13 g: gggggggrgggbgghg
+1-5 k: ktcpgpk
+2-13 v: mvvwnvfkjrhvvdvvtsvk
+12-13 k: kxpkkkckjtkkj
+12-18 h: xhqngjkxqqzqhnhhhh
+11-12 k: kkkkkkkkkkkjk
+2-4 r: rdgrrr
+3-4 x: xwjx
+2-6 c: lcqzflc
+13-14 t: smlkctgbsqpftx
+4-5 b: fxtdbzbqbd
+4-7 s: wmsssznjzsdkgvdsxhd
+2-6 z: wpptkhk
+14-16 p: pppppzpppppbprppppp
+6-7 c: cccccbw
+1-6 h: mhhhhhh
+2-3 k: cwkgk
+3-4 l: llcl
+3-4 m: kmmx
+14-20 h: hhhhhhhhhhhrhhhhhhhh
+8-12 b: bcmbpbffwghcvjb
+10-15 f: fffdfqwmzfdfrfdbpf
+1-2 l: hlllljl
+1-3 g: vgbgg
+2-4 n: zgfn
+18-20 w: gmbwtzgzpmdwstsffqzw
+9-19 j: jjjjjjjjkjjjjjjjjjjj
+16-19 f: fffffffffffffrffffzf
+8-20 l: htdlzwsllllccwlflstf
+3-4 w: wwww
+2-4 b: sbbz
+4-6 n: nnrzbbnlcrnsbk
+7-8 c: wmzjtbvw
+5-7 l: cldlljlzzz
+5-6 h: hhzhbhhg
+4-5 f: scmrfftkc
+11-12 m: flfrbmdpdkpm
+6-7 v: xvvvcvkbnvvq
+4-11 h: qkjphjpfllhpqnbm
+2-5 b: bqbwbbwsb
+1-8 c: cqcscccbccrccq
+1-13 c: cccccccccccckccc
+7-8 h: hhhhhhhs
+1-3 l: llxl
+6-8 h: hhhhsnkv
+6-13 m: mmmmmmmmmmhmpmmm
+6-9 n: nrnmmnbnmn
+7-14 k: whkpphhkxlnnmkbhtnt
+4-10 n: nnnnnnnnnhkn
+3-4 c: mcnw
+8-13 b: bbbbbbbgbbbbbbbbb
+8-9 c: lcccdkjcjrqwck
+3-13 w: szmnhsmzwpdbkhtbf
+4-5 r: prrrz
+9-14 m: mmmmmmmmgmmmmmm
+7-8 q: kqpgrqqp
+16-17 p: fzxxpcpdhmvmrnvjp
+7-9 v: vvvvvvqzxs
+3-4 w: qwxw
+1-2 x: xqkx
+9-10 v: vccmlrlhvdtttfvcxwm
+11-14 h: mhvthqhvhhgmfhhhkhch
+3-4 n: nqzw
+2-5 j: jbjjjjjjjjjjjjjj
+11-15 g: bcxggqfmgzgfrdg
+3-5 v: gvwvvvrzf
+6-7 t: ttzdttr
+4-9 j: cgqjqdjvjbfjwdlvdgj
+5-6 s: hfflrzksshjqsbvsps
+1-4 p: pppn
+4-5 g: dprggmpfggbkpg
+2-3 k: kbhkkkk
+13-15 r: srrrtstrwwxzrrzr
+2-4 b: lbbnbzbb
+1-4 g: fvgz
+5-11 q: hxdhqrqqprpq
+2-4 z: zzgm
+1-13 w: wwwwhwwwwwwwwwwwww
+2-3 k: kkkkk
+4-8 g: nlgmhplgcv
+1-2 j: zncllmvgjnj
+11-13 f: fffffffffffflff
+2-8 p: bphqpxkr
+2-9 b: bbbbbbfbdbhjpbbbjbbb
+9-10 s: zpxnstzwsw
+7-16 c: ccccccccccccncsvccc
+6-8 r: rrwbrqgr
+6-12 v: vvvvvvvqvpvvvvzdd
+8-9 z: zzzzbzzmzzz
+15-16 t: tfttttntxttqtttc
+9-16 b: btbrbfplbbbmbbbbkbb
+7-8 q: qrqxrlqg
+8-12 q: qqqqqqqpqqqw
+5-8 v: jrrlpvvcvkjzjvvvv
+11-14 d: dddddddddddddq
+5-6 f: rfxmfzf
+3-4 t: tttqt
+10-14 c: bcccccccccrccfc
+3-7 n: snnqplvl
+5-6 z: kshzfzhlcsbqwqb
+6-11 s: sssssssssmsjsgssss
+3-7 v: qgcxvxvg
+12-17 v: vkvbsvxkvvnjvvrvvvx
+2-4 d: ddrrxbd
+8-10 x: tvxxtmgbsxpxbl
+7-9 r: rzrbgbrrrrrrmhm
+2-4 t: ttttt
+5-9 x: xxtwxxnssxlxx
+3-4 p: ppdp
+3-7 g: ggtgggtg
+1-2 k: kbbhjdkfvjqffcss
+1-2 l: lrlvlll
+10-12 x: xjkbqxkxzxxq
+7-9 d: dddhdkpdfdf
+5-8 m: mmmmmmmwm
+3-9 l: sfrjlzhcll
+7-18 m: mmmmmmcmmmmmmmmmmmm
+1-3 w: mwplxwwww
+7-8 t: tgtctbtrtdtttt
+3-6 p: lfpbbgfbpdhnqz
+5-6 d: ddddrd
+1-3 b: llbbbbb
+4-7 r: ktbrncrrnnsrr
+8-10 r: rrrrrrrfrrbrr
+1-8 l: wlklvlllnljlgtzll
+2-4 m: mmhmmxsm
+10-12 c: cmwkcnczsxmcrmjtc
+2-8 q: qmqqqqqzqq
+7-9 v: xvvvvwdnzzv
+3-7 j: lsjvmbrjjmpcwqnvvdgc
+3-9 l: bgmllldjrzhllsclc
+1-6 p: ptppfjpqpp
+7-8 r: mctrrstrrxrqtmrr
+7-8 d: qddddddxddddddddd
+4-11 r: rrrrrrrrrrbr
+4-8 s: lsfvtfss
+4-9 c: zcccccccj
+11-12 v: vvvvvvvvvvvm
+4-8 g: rggzlfgtm
+3-8 j: jjjjjjfhjsgj
+3-4 m: fmhmm
+15-16 l: ltllhlljtllllbtlllgl
+12-13 c: cccccvcccccqccccc
+6-7 q: qqnlqqhqqq
+1-8 z: znjqzxpz
+10-13 k: kxzmkbxnkbkktmkk
+8-15 k: bskzvggzsnlnxzz
+9-10 v: vbvvgvcwvs
+5-8 h: qhsnhhlhwpvzfb
+15-16 g: gdcgggggggtgcgtg
+8-9 z: fbgdnrzfb
+6-7 d: ddkdddh
+4-6 w: xzgfwwlbxft
+1-3 h: hkjhh
+1-3 p: pwprlp
+8-12 j: jdjjjjjdjjcjvjjjjjj
+11-14 m: bdsfwddfkgxsmrmm
+3-10 m: tmmcmfmmjmm
+3-4 b: dwhbzfjxl
+2-5 n: nnnnjcnnn
+16-17 v: vvvfnvvvltsxhrvvm
+1-7 v: qvvvvvwvvvdvv
+2-14 k: nxqblwwqmhqzkm
+3-4 t: ttts
+5-6 c: clnnfk
+12-13 s: sssssssssssts
+7-14 d: ddqdnwdkdmhddg
+3-4 t: tmsttm
+9-11 x: xxxtxxxxxxqxwntxj
+8-14 l: lllqklwlvlllmbslzlln
+9-12 n: sdsnnfncxnwnrn
+1-5 f: qfffff
+6-9 r: rzmphlrgrr
+1-4 m: grdm
+4-5 s: ssxsg
+1-4 n: xhnznnxnnn
+2-6 r: mcwldgbqlqsckgzlrd
+1-3 l: llmllll
+3-4 p: pjtgdnfjfcjtcnpgxpzq
+6-7 m: mmvmmmtn
+17-19 h: qgmhhhwwwhqhmhhthhch
+3-14 s: lhmnsfdrvnngrsfhxd
+1-6 p: pppppwp
+4-6 l: lzllltrl
+3-4 c: rpxccsc
+13-16 h: qsdznfqmsftqqthh
+2-4 k: wsvkm
+1-18 h: chhhhhhhlhhhhhhhhhhh
+17-18 d: xddddddddddddddddddd
+2-3 t: jtbrhpzjfpzhcmjql
+10-11 n: gjngnnncncnn
+7-13 r: rrrrrsrrrrrrlwrrr
+10-12 l: llldllslbldllwl
+17-19 m: mmmmmmmmmmmmmmmmfmm
+10-14 n: nnnnnnnnnbnnnnn
+17-18 x: xrxcxxxxxxxxxxxxxxwx
+3-4 b: lvxb
+5-6 r: rrrrrrr
+13-18 l: lllllllllllllllllpl
+8-12 m: mmmmmmmqmmmmmmmm
+7-8 l: llhqlllh
+3-8 p: nmrppdvpxcphxgmkpbsl
+9-10 v: hvsbttgsdvvj
+5-9 k: kgmvzzzckkgldk
+15-20 x: xqxxxjxxxxxxxxxxxxxl
+5-6 t: bbwpwtwbhwgqttzjv
+6-13 n: klzcfnnjqxrhjwpjfxnk
+5-8 d: pcnndzddddnsdqh
+5-14 k: kblbtvkwltfklk
+4-11 q: zxwdkqqkvqq
+10-12 s: tsssssssssssss
+3-5 r: rddsrrdksfqfrgr
+7-16 h: vdvhlsjxgvrbrxnhns
+3-4 z: zxtz
+4-8 x: xmnxdwmh
+11-12 r: gwsnfrnckrrxrx
+3-9 q: qqqqqqqqwqb
+9-14 f: bfnfffffvfpfffff
+6-9 p: pvpppkppcpp
+3-4 m: mmmz
+3-5 j: jjjjmjsjjrlkjjjjj
+4-6 p: jpbpjs
+6-9 r: bswdsrksdrzrgrfmjr
+8-10 l: lllllllxll
+3-7 v: vvhvvvvv
+4-11 n: mnjpbldngrrkbthhmdp
+2-4 r: frlrfblsrfzrhtpk
+16-17 h: nbghhnzshclxhhmkr
+2-5 z: zfzvzzzzzzzq
+1-5 l: lllzlfl
+9-10 d: dddddddddzd
+11-12 p: pspppppppbzp
+5-9 t: thzttpxrdhttdwqjsg
+7-10 w: tfdfwlwwzdvpnww
+4-6 z: fvcljzllwhbzscx
+14-15 m: mmmmmmmmmmmmmcd
+8-11 d: hgdmwgsdkdbghb
+13-15 v: vmvdvvqvvvkvqvvv
+13-14 f: fffffffclffffffmf
+2-5 s: ssscn
+11-13 w: wwwwwwwwwwwwww
+7-9 l: xnwrlkskll
+8-14 g: vggglvcrgscpgggt
+4-5 w: wwwww
+5-11 w: wwwwswwwwwwwwwww
+6-7 g: gggbvjg
+14-18 q: wqfqqqqqqnqsqrqqqq
+6-7 z: zzzztzqczzzzz
+6-12 n: wnnnnnnxftnkznpvvl
+10-16 j: jjjjjdjjjrhjjjjj
+1-10 l: lllllllllrll
+9-13 g: gdgggggggggkggn
+6-8 r: rrrrrrrs
+16-17 k: kkkkkxkkkkkkkkkck
+11-14 b: bbbjbxbfmqscqbdmgg
+3-8 d: sjdkmjppbdddhdxd
+6-7 g: xhkhwgqpbg
+11-12 x: xxxxnxxwgxxbdl
+6-8 c: cccscccwcccccccccc
+9-16 h: vhhhhhchwnghmkzhr
+5-9 v: vvvdnvvvvv
+4-16 n: nmqncgnbfhqnnpnbxwrl
+3-5 f: fljrf
+13-14 m: mmmmmmmmmmmmgfmmmmmm
+5-6 g: ggnggd
+2-6 w: wlvhvw
+13-18 h: hhhhhhhhhhhhhhhhhvh
+7-19 m: mmmmmmmmmmmmmmmmmmwm
+4-12 k: mcvtrtsdkvkkfjrmkn
+1-8 t: qvmrtttn
+6-7 f: fffffsf
+10-11 m: mmmmmmmmmjl
+15-17 v: mvrhvvvvnvrvzrvvfv
+10-14 m: mmtmmmnmmmmmmxm
+4-16 b: vcscdqcbcxswjfdbrqbx
+8-9 z: zzzzzzznzvz
+4-6 g: ggnggdpgggg
+2-4 d: hddxxnzzw
+9-10 g: gggggggggj
+4-7 k: kkkvkkkkkk
+1-3 r: rrrrj
+14-15 w: wwwwwwwwwwwwwwwww
+2-4 n: brfmln
+18-19 b: bxbbbbbghbbbbbbbbwb
+10-12 q: dqqqrqwcqgqqf
+2-5 g: sxfzgtrxkrmstdzfmw
+3-4 d: pcddq
+11-16 w: sbqwlwzwwwwwtwww
+2-12 c: wrccqxtccccchcccjcj
+16-17 b: bbbtbbbbbbbbbbbqb
+3-13 t: tttttttmgktdthtp
+1-3 t: ttcg
+13-14 z: zczzzzzzdwkzqz
+5-6 n: bnjhnjhnnq
+2-9 b: bjbgbzmlbbklbwt
+4-5 b: dtlbbwtjbkzzbghbghzk
+10-16 p: ppppppqpppwnpppppppp
+5-6 b: cbbwtbjkm
+15-16 p: ppppppppppppppqd
+4-8 m: lgmmhgktslzhbvw
+2-4 h: hhdlhhhhhhhhhhh
+14-18 k: ktmkkkkkwkklkjrkklfk
+5-7 x: sfxxsxx
+8-9 v: lkvxdpvjv
+7-8 r: rrrrrrsr
+4-6 b: btcbbv
+7-13 n: zhnhjhnmkzdbt
+7-9 j: jvjjjjjjjjjjjjxjj
+1-4 v: hdvfv
+2-5 f: rznpnxqwncmtkwfxcxqh
+16-17 x: zxgbhltrdhxkvvxsxf
+1-2 h: hkhhh
+3-4 h: zhxc
+4-9 z: vsmzhzwgjxfg
+11-13 x: xxxxxxxtzxxxc
+11-12 d: dddddddgddqj
+4-11 f: zkdhqnpgbff
+2-3 q: qqlqgqqqv
+4-9 b: bvnblwhbbkswmrhtf
+7-13 t: cztskdtqdtrkt
+4-5 f: fffcsf
+4-9 f: ctblqrflf
+1-2 l: lmllqhlnll
+3-6 v: vvqvvvvr
+7-9 b: bbrhbkjbb
+1-8 p: xpppppppp
+7-10 k: ckkpmktkqksgkkk
+1-7 m: lmmmmmmmmmmmmmm
+11-15 v: vvfvvmvvvvdvkvv
+10-11 b: kbbbbbbzbhbb
+11-12 l: jltgggtlcggllt
+10-13 q: kqnqqqqqqqqqq
+6-7 c: cjcccczc
+5-11 t: kdtstshrhfkcx
+3-12 v: vlvfzvwvxvvhvvsvvcvm
+9-10 t: xttttttttttt
+8-10 z: hctlkgjzvzh
+3-5 g: gtkwgk
+16-17 w: wwswwwwwwwwwwwwwwqww
+4-11 j: lbmwjzjxjpjhzjjpbj
+4-5 c: klbxc
+3-5 w: wlhvb
+4-8 x: xgxxxxxxxxxxxxdxnxx
+2-5 n: nnnkhn
+1-2 d: dxfd
+11-12 w: wjcqszwqwkcb
+6-11 v: sqpgzhnvndtmvvwl
+3-4 m: mmmqmmm
+1-3 d: mddb
+6-7 w: wwwwwnwwwwwwww
+12-14 z: zzzzzxzczzzrzzz
+5-10 f: mtcmmhfftft
+10-14 x: hhgvmxbwgxdcnz
+10-16 z: wzfzzmlmxxfhzqcbsnl
+3-4 p: ppvkppp
+8-11 h: hhhkhhhjhpbhhhh
+6-12 f: ffffdwffrsfffrffnfpk
+5-11 z: xqwzzzzbzpwk
+7-9 c: crccccccscccccc
+4-5 b: qpcnz
+2-13 m: lmnrrzfhmbwtmqbsg
+12-13 k: kkkkkkdkkkkkmk
+10-14 q: sdqfbqszdjhqfq
+8-13 h: hhhhhjhhhhhhbhh
+2-4 g: gfdb
+12-19 n: wtrhndnnnbwnnnnjnnn
+5-6 n: zdwnpn
+3-5 f: ffsffffff
+11-16 r: rrrvrrrrrrwrrrrrlrrr
+6-8 n: nnnnnfnnn
+10-13 b: brnlbblbkbbbjbbhx
+7-8 q: ftrfnqgqc
+11-12 c: ncccccccccgcccn
+3-4 z: tzzctzwzzvz
+3-5 t: tzrqg
+7-10 m: mmmmmmrmmqmmm
+1-2 c: cdccfcccc
+10-11 k: kkkkkkkkkwkk
+6-18 x: qndxdgmjvpppddwkbt
+8-17 c: pxhszsccndlbzkwgvx
+3-4 p: qlrvwdxpqtgwjrtqcc
+2-4 q: lkjq
+17-19 f: pffgflzxrxfdxffffnz
+3-11 x: kzsvmhcxnwj
+6-7 x: lxxxxxxcm
+1-8 n: nnnnnnnrn
+2-5 r: rtrrnr
+2-4 n: csvhrvhlp
+7-8 b: lbbpdbkb
+2-8 t: ztcrbvmst
+3-4 r: rwrr
+7-15 b: tbtrrbbpwsrvklqb
+9-13 d: dcfsgddmdsjgg
+2-7 d: mvdzscd
+6-8 d: jrjjdndq
+1-3 m: mhmvhtmmlbztvmsvmtmb
+10-12 c: ctwjbpkchccmbqw
+2-3 z: jvzwcrbgqbhvzbf
+2-7 g: qbwsdbg
+4-7 s: jsxpbmsmkhktfdq
+11-13 r: rrrrrrrrrrhrqr
+9-14 d: zddcdgddddxddntddm
+1-15 x: jgrxxxxfxkgbmsxzx
+2-17 p: kcppppkppppppppwm
+12-19 k: kkkkkkkkkkkmkkkkkkkk
+1-4 x: nzpxg
+5-12 p: xcbppqnppqgtrm
+11-14 h: dlhzhhhsbllcwhh
+13-14 q: qqqqqqqqqqqqqcq
+11-16 t: ttgnswrltltttjtj
+14-15 t: ttttvtttftttttjtc
+3-5 s: xssns
+9-11 q: mlqqtqnjqfl
+3-4 z: nzzhz
+2-5 k: skwbwkwgzj
+1-3 p: pppppcppppbpp
+5-10 r: rrrrlrrrrrr
+2-3 l: jlffrztcckl
+3-5 t: ttftttttr
+3-6 q: qtqtmnlqck
+1-4 v: vxfvmvxwvvjbxp
+1-5 z: tzzzzszvzzrmzmz
+10-11 l: lllllblllcx
+1-4 p: vppppp
+6-12 v: zvrwvvvrvhzb
+2-4 x: xxnv
+1-7 w: hwwwwwgwgwwbwqw
+3-7 w: wwwwwlfw
+5-6 l: kkpltd
+4-5 d: ddnrdk
+3-6 c: cncvkt
+8-9 j: vblczlfjjkj
+7-15 d: ddddxdgdddddddjddd
+4-7 z: vvmzdspzwptz
+5-7 t: cdrtfqt
+6-9 j: jjjjjdjjjjjjjj
+2-5 j: ljptkvvfl
+6-7 l: vhhnllgx
+5-6 g: gpcxwvgpvvgg
+5-12 q: plzqqnqzrhqgljj
+8-13 k: zkckdknkxkgkvmmkd
+4-10 s: jkvstssfcsrckjnzzbsl
+9-11 n: nlknnnnggnvnnnnn
+8-9 s: ssssrsgstk
+16-18 r: rrrrrrrrrrtrrrrbrrrr
+4-5 f: qxrzfcgfqfp
+2-10 p: pphtppppppplwpsp
+2-5 q: qqqqsq
+6-15 j: xjkxkjxxkjznjjj
+9-13 f: fvfvjlfmltfgf
+3-6 j: jnsrcj
+1-7 h: vhhhhhhh
+4-5 q: qrqqqf
+2-3 v: mvxb
+4-11 l: lllllllllldl
+7-17 k: mkcxhcmbcpjckkqznh
+7-9 v: vvpgvvvvs
+7-11 j: jjjjjjjjjjjs
+2-12 v: mlxjljvffxgv
+3-4 t: hhfn
+14-16 w: kwfwwqwcfcwwfmww
+5-6 j: jjjjjg
+11-12 n: nnnnnnrdnnmnn
+8-9 b: dsbbbfbbbb
+3-4 j: jjcjjj
+1-3 r: wrnr
+10-11 p: pppppppppqppp
+12-13 v: vvvvvvvvvwvvvv
+7-9 v: vvvqvvxvdvxv
+9-14 r: mmrrrrnrrxrrrwrrrrrr
+5-6 k: kkkkbkkr
+13-17 v: dbvgrchdpnzvxrdfv
+4-9 c: ccjbccqcpcclcc
+6-8 m: mbjmmxnb
+2-6 h: hhdhnvcc
+9-16 t: tttttttttttttttgt
+12-16 n: nnnnnnnnnnnnnnnwn
+3-14 z: zzdzzzzzzzzzzzz
+3-8 k: pmktwckzn
+9-13 q: gqqqqqqqrqqqqq
+3-6 l: lllllddll
+7-8 x: slxxzplxsxkcxlxxx
+2-5 v: vwvvd
+6-7 n: xxnnnmnnn
+2-4 z: zczz
+2-12 p: pppppppppppvp
+2-4 h: bqwhv
+5-7 t: btzttjg
+4-9 c: sxcskxxbcv
+1-6 c: cccccpc
+9-13 l: bcsllbvbjhrflt
+5-9 c: zprfctdnt
+1-5 z: zzzzz
+4-8 h: bpshnhxhrbk
+4-7 l: bqclvxf
+5-6 m: mmmmmgwcmgjj
+13-18 m: mmmnmmmmmmmmpmtmmgm
+1-5 w: cwwgwwwwwww
+14-16 h: hhhhhhhhhhhhhqhhh
+6-7 v: bvvjvvbvvv
+5-13 b: pbcbbqmbcsfblc
+17-18 j: jjjwjsrjjmkjjqjjjj
+4-6 t: ntttpt
+6-7 v: mvvnvvc
+11-12 v: vclgnzbvtvvjvs
+8-13 r: rlrzkjkrrxmdvzgt
+5-7 n: nnnnnnsnnnnn
+3-6 q: qpkjpq
+2-7 v: hvgnjfrkvx
+6-10 g: xgmrggggpbggfqgdpm
+9-10 s: ssssssswfszsdssszss
+5-6 p: pppjppwpp
+2-5 d: ddddddd
+9-13 p: ppjhpbppxpxxt
+10-15 t: cgtcnlltzdkbcjtvxs
+8-11 m: dkmmvtdmkbhmk
+3-4 z: rzzqzw
+4-8 z: zcxzswbzzqzxwkzz
+3-4 s: jsts
+2-7 b: bsbbbbbbbbbbb
+11-15 l: jjkslsltvfbqshl
+3-14 c: cqtxcgmcgvgfcccmg
+1-8 f: fbfwffhfbxffhlx
+4-11 r: drrmrrrzcfrj
+5-6 p: pwpvjp
+11-14 d: pnrddqwdlpdbddwg
+9-10 r: rrrwrrrznrrgqsr
+3-12 v: vsvvbvvkvvpdrvvv
+2-5 t: mtfqjrjlthk
+13-17 r: rrrrrrrrrrrrrrrrtr
+7-8 n: nnnnnnhnn
+3-4 r: wrpr
+1-14 p: ppppppppppppppppp
+8-9 m: vzkbzwnmwfqmmmmcmmnd
+11-14 p: pppnpvpwppvpppppppp
+17-19 h: lzhxlhhchxhbxhwvhsx
+10-11 n: nnnnznnnnlp
+3-12 f: kwflsfqflxpzbgxzdhzv
+8-10 x: xxvxxxxvxsxxlxxxx
+1-2 c: dclflczlj
+4-9 w: wwwtwwwwwww
+2-8 t: pfvtlbtxt
+4-9 f: pnfkffkfnh
+8-10 v: vjvvvvvvvvvvvv
+3-13 s: mfshscgmmrvzw
+6-10 g: gzggggpggkggzggggg
+13-14 n: fnnnnnnnnnwnrnnn
+4-14 k: lbvkwrkjkxjskg
+9-11 q: qqqqqqqqsqgq
+17-18 q: qqqqqqqqqqqqqqqqqd
+6-9 s: spsssgsrrssss
+8-14 m: qmmqjmmmmtpmnzgmm
+1-7 m: bmsrmmmmmmm
+14-17 k: kskdbkkkkdkkkktkqkkk
+4-5 c: ccccgfc
+2-5 k: kkkkzk
+2-11 q: qqwqlnqqqhtdvxqrc
+4-6 m: fdxkmmd
+7-10 j: mjgftcmjmjj
+17-18 m: mmmmmmmmmmmmmmmmnm
+2-4 v: svvv
+6-8 x: jxxhrxlp
+4-10 s: dsvdbsssmscs
+18-19 k: zwdgknqvqkgdhdhktkmr
+2-7 h: jdflgfh
+6-8 z: zmpzzzzzzzzgz
+3-6 m: mmrmmm
+4-8 w: wwtwktws
+4-10 k: dkjkqkkzvk
+3-7 b: bbbbbbfbbb
+4-12 z: zzzzzzzzzzzzz
+5-9 z: nmqdzzkzzzbj
+4-11 z: fzzgzzzzzztzz
+1-7 w: whwwwzrw
+5-6 t: tjtttv
+9-11 v: vzvhvxvvnvwvvv
+2-4 t: pkjtpp
+14-15 n: njpwjnsbnnnnngnnvnnn
+5-15 k: qtmvkkdjkslkqvk
+2-4 s: skszs
+2-3 g: zggjhgxzn
+16-17 p: ppppmppppppppppnppp
+4-10 z: zzzzzzzzzzz
+17-18 s: sssgsssskssssssssbs
+5-8 m: mmmmmmmbm
+1-5 l: llllmlql
+3-13 z: bmdwpgvzfdlgzgl
+1-4 p: pjplgjr
+1-9 v: vvvzvrvvk
+6-18 w: whwpwwflbcwwvwwwwst
+19-20 n: nnsnnjnnnnnnnnnnnnkx
+9-10 m: rlmxrnqrmkmmwmmmmm
+15-17 s: lvssssslssfsssksfb
+3-4 q: qqqpq
+7-13 h: hhhhhhhhhhhhdhhhhhhh
+2-6 h: dvkfhhmk
+4-6 s: nczssv
+10-12 p: pppppppppppdpprp
+16-18 s: sssssssssssssssgsg
+7-12 h: hhhhhhvhhhhhh
+4-12 f: ffftfffffffwff
+4-7 s: csqcpssbgvvmwdb
+6-10 p: ppppvppppdppd
+6-8 h: hxjhthhgzh
+3-10 f: fffffffffsf
+4-11 g: trggxlrnqrgh
+2-15 w: wjxwtvkwwpgwwww
+1-4 v: zjxv
+7-10 f: fffffflqff
+4-6 g: mgwgpbg
+1-10 z: vvzzzzzvzz
+6-7 f: ffffffnf
+11-15 w: wxzwwqdnnwwxjlwplcl
+10-11 s: hsslzjgsssvxsshnsc
+4-12 n: tlxdnpznjbknt
+7-8 k: mkhcvjxk
+10-12 j: jjjjjjjjjjnm
+2-7 c: fckckdpcksjckwcc
+3-8 s: sssdxssw
+12-14 t: ttttttttqttxttttpttt
+6-7 g: gggggggg
+5-10 f: fqffzffffffffgf
+6-7 t: ztqhpbt
+5-12 w: swwfwwwwwpwbwj
+2-4 w: qmww
+5-8 v: vvjnvvpv
+7-8 p: bcbtnppbxnnwpr
+4-12 z: zzkzdxntzlfbkkzzzw
+8-9 s: sssssssss
+15-18 h: jhvhhhcxwhhhhmhhhj
+6-10 w: bwwwwwwwwwwwww
+5-9 l: mtqlhlwlh
+5-7 l: ljllnllblpl
+15-17 h: hpgdkhsjwfnsjmhqxf
+3-4 g: gggxgggg
+1-2 q: qdqm
+6-10 n: hnnnqknnnnnlnnnnp
+13-17 q: djstfsmmqlshqqbqnf
+6-7 z: qzlzxzw
+7-12 g: qhghvbwdcvkgjl
+7-15 z: zzzzzznzzzzzzzzzzzzh
+3-6 w: zchpwvw
+3-4 c: wmbjp
+6-9 k: tckbvkkxkkqk
+11-13 p: pcppppppppppppbp
+5-7 r: rrrrsrxrr
+6-10 c: ccccczcccccccccc
+7-8 j: jjpjjplj
+5-7 m: mjmmmjrmfmmmmmmmm
+1-7 t: ttttttnttvpt
+6-12 t: tttfwtttttttttttttt
+7-17 x: hxwgrqqlxmrxrcwsx
+3-8 g: vjcgqrjhlq
+13-18 n: nnnfnnngnnnnjnnnhln
+13-15 f: ffffffffffffrbff
+13-15 x: xmswzjhtthggslslgx
+12-13 g: ggggggggggggggg
+3-9 f: cxfskjcbmhmmcpwn
+5-7 h: jxzbhbh
+2-3 m: mhmlmq
+1-3 m: rmmmgmzvcghdtgmsmnm
+14-15 s: wzssphxtsskpssr
+8-14 p: kppjppgfpprftj
+2-7 r: prnmlrrbm
+2-5 v: vvvvtvv
+1-5 n: nnnnzn
+2-5 t: xtlnfwhgvltx
+3-4 v: gvtv
+2-8 k: kvkstkfz
+2-6 j: jdjjjnjjjjzjjjj
+3-4 s: sshwsssss
+2-10 w: mnhkdtwdzwvsq
+6-8 b: bbbbkxbbtbbkbt
+14-19 h: hhhhhhhhhhhhhhhhhhhh
+6-10 d: ddddddddddddddd
+10-13 t: ttttttttthttjttt
+4-5 c: ctscw
+8-9 b: bbbvbbgmb
+10-12 s: sxssshsssswsscsx
+3-7 r: rdhrrkrkrrrrcrhrrr
+8-10 j: wjsslzjjntjjwjs
+1-4 q: gqqw
+4-6 t: tjlhvrt
+2-10 s: ssssssnssssssssx
+7-8 x: xxxxxxfw
+6-13 r: sxtcgrffrpdprnklbxbw
+1-3 p: ppbppppppp
+2-3 b: jbfr
+1-7 m: cmmmmqm
+4-5 t: tttzt
+7-9 s: zwbbbssvl
+10-13 w: wwwwwwwwwwwwdw
+13-14 n: nnnnnnnnnnnnnmkn
+5-11 q: jpbzqwqbwttgzn
+4-5 k: kkkwkkk
+10-17 w: sgtklkflsrfqxfwhjm
+6-12 w: wwjqwwlmphwkwwwwwjw
+2-13 p: ppppppppppppzp
+2-16 h: tslcwztxxtchgqlxsbx
+2-9 p: slptvtljpxdkf
+10-12 z: tnzzghzzgzfn
+3-18 f: ffxfffffffffffffff
+1-2 p: prdpdghkckdgpl
+6-8 x: fxxnbwrx
+7-9 z: zmzkzdpgjzzz
+7-14 p: pppppppppppppppb
+7-10 l: xltlzllllljzxlll
+18-20 n: nnnnnnnqnnnnnnnnnmnb
+15-18 p: pxmqxpmqwfntrpppmf
+1-15 v: kgmvwvrvmcvtrvvwv
+2-8 g: gxggggggg
+4-5 f: clfjfqmpffjfff
+3-5 r: rpjkf
+2-9 h: hhhhhshhrhh
+2-5 z: zxzzz
+5-11 k: kkkkkkkkkkkk
+8-9 n: nnddcfntnrgnnrnnc
+1-11 f: dfffffffffff
+2-4 x: dzphvg
+4-5 w: mnzlr
+2-6 f: jhrkfmg
+2-17 z: czzvvzzczznzhwzbzz
+2-5 r: xrjrg
+2-3 g: gggg
+7-9 s: ssssssbsssss
+17-19 k: kcwktkxkkbkqnwkkkkdz
+1-16 f: zmxdffmfgffxrffffqf
+7-8 q: qtmrkbqjq
+8-9 q: qqqqqqqqx
+10-18 n: nnnnnnnnnznnnnnnnnnn
+16-18 x: xwxxxxxxxxxxxxxxxrxx
+15-18 t: tttttftptttttttcttt
+10-11 h: hfxnlbsqxphtmstbhdn
+7-13 z: vdzdzmzxvfzzz
+2-5 n: nnpqgnnqnb
+12-16 v: pvjvvnbqzjnvvvvpjv
+4-5 d: ddddk
+4-8 l: lxvhlbclhgd
+3-12 v: vvkvvvvvvvvvvvvvvvvv
+17-18 j: jjjjjjjjjjjjjjjjdj
+6-7 b: ckbdbcsbb
+9-11 q: qrhxpcjjqbqt
+8-14 h: hhhhhhhhhhhhklhhhhn
+2-3 b: bzbjb
+2-15 w: nnmdgzhsvhpvswltvt
+1-5 l: lbclz
+15-17 d: wlddgdxsdcdfdcgdd
+18-20 q: dqsldgqqfqwsstqlmqtz
+1-6 q: qqqqqdq
+2-6 j: jpjjjjjj
+13-15 p: ztjlhtnsgphgxccpfsp
+6-13 m: ghvvmrglmmmcm
+3-6 b: nbbrmrfdlbs
+1-3 j: fwhjsr
+7-10 p: gcppcppzpppp
+4-12 r: rrrrrrrrrrrrrr
+16-20 d: djdddvdsddddlmddddpm
+14-19 x: xzxjxxxxxxxxxxxxxxj
+11-16 w: kwclzxjjwxlwkcnwkwv
+3-11 b: zhhxsgqxqbbg
+10-11 q: trbhqqzhdqw
+9-13 l: vcvlvqlwrlfvll
+7-9 x: xxxxxxxxgx
+5-6 n: nnnngnn
+2-5 p: pqpppppppqpxp
+4-17 z: zxrmzwwxwhqxxmqrv
+5-9 v: vvvvvvvvrvvvj
+6-7 x: qkhbxxkxs
+3-4 d: fcmd
+5-9 f: nsnlxstff
+6-9 x: hrtzmhrxxbmcc
+3-7 w: wwwwwwsww
+5-8 g: ngkdxggg
+8-13 r: rrrrphrrrrrrrrrrdrt
+2-6 f: rckzvzfrnp
+4-6 k: bfrpttcfbwmvhgn
+7-9 w: wwwwwwswww
+13-15 n: nnnnnnnnnnnnnnn
+4-8 j: jjjjjjjwjjj
+9-11 h: hhhhhhrhhhhhh
+4-7 h: thmhwrhss
+1-3 d: ddddddddddddd
+10-11 c: ckrcxwcdpqc
+2-4 g: kgghg
+3-12 s: ssssvwssssgqs
+2-7 s: sssssszs
+2-10 v: wvpbjqxvzsdpgmq
+12-15 n: nnnnnnbnqvrkfnn
+3-5 w: wlvdw
+11-14 t: pfrbxgcrwndttj
+6-7 w: qnnwwpfwwhw
+7-10 n: nnnvnnhnnx
+3-12 c: mmfcwvxqwpcclwlxfx
+2-3 p: lgpxpppp
+17-19 k: rfxvmnmfzrnktfpckpr
+2-9 k: kkkknkkkkkkk
+15-16 t: ttjmtttmttttttwt
+9-10 r: rrrrrrrrmrrrr
+3-4 p: jppppxf
+7-8 k: nkqbvkkt
+6-8 d: dddddrdddd
+6-7 q: czbqdgnc
+3-5 p: rxpppsx
+4-6 t: thvtwv
+2-13 d: dmdddddddddddd
+16-18 n: nnnnnnnnnnnnnnnnnnn
+11-12 s: ssfsdsmssswssh
+3-5 v: kxnvvvmvrvdvvssvvv
+5-8 x: nxxxxbxxxzx
+3-5 t: ctttftt
+5-7 s: hssvsgj
+5-8 r: rrrrrrrcrx
+1-13 v: vvvvvvvvvvvvpvvvvvv
+5-9 h: gxlrhsgswhchfxbwjd
+2-4 w: wgwb
+6-12 v: pmxnjtfsvvxvv
+1-4 n: vnntn
+2-3 w: wwww
+3-7 f: xmfbmnvnfkkmsd
+10-12 x: xxxxxxjgxxxxx
+2-3 l: cllvpbtmgzmrfmq
+2-4 l: llrlllnlxll
+5-10 h: hdhhhzhvtchhh
+8-10 q: lhqmdwcfhqngq
+1-5 t: twtfvcmktthtjltqvpwc
+6-8 s: sxsghtbs
+3-4 m: mmmmmmmmmmmmmmmm
+16-17 l: rjdpxhtblvllgvwhl
+5-13 s: brhsssnfcndsh
+7-13 v: swkfswvmkvjbnsgvwp
+1-3 k: wlfpzk
+2-4 t: tpttt
+2-9 t: cntttttcgtttt
+5-6 r: rrrrbh
+10-12 j: jjjjjjjjjzjjdj
diff --git a/2020/inputs/day20 b/2020/inputs/day20
new file mode 100644
index 0000000..513fac5
--- /dev/null
+++ b/2020/inputs/day20
@@ -0,0 +1,1727 @@
+Tile 1049:
+###.##....
+####....#.
+...#.#....
+....##...#
+#...#....#
+##...###..
+##..#.....
+####......
+##..##...#
+.....##..#
+
+Tile 1217:
+.#....#..#
+#.#....###
+##.#....#.
+##...###..
+###..#..#.
+.#...##...
+#.#..##...
+#...#.##..
+#..##....#
+.##.#..#..
+
+Tile 2357:
+.....#.#.#
+#....#...#
+.......#..
+..#.....##
+..........
+#.#.#...##
+#.#....###
+...#....#.
+#.##......
+#..#######
+
+Tile 1399:
+.##.######
+##.......#
+#.##...#..
+......#..#
+......#...
+.#........
+....#.#...
+....#.#...
+##...#.##.
+####.#####
+
+Tile 3733:
+#..#.#.#.#
+#...###..#
+#..#.####.
+...#......
+#.....#..#
+...#.#....
+##....#..#
+##...#....
+.#....#...
+#.#...#..#
+
+Tile 2503:
+#..#..####
+......#.##
+#...#...##
+..........
+.#.###.#.#
+.......#..
+.....#...#
+#.....##.#
+#.........
+#..#.##.#.
+
+Tile 1511:
+#.#.##.##.
+#####..#.#
+.#........
+###..#.#..
+#..#.##.##
+.#....#.##
+#....#....
+#....##...
+.........#
+#..##...##
+
+Tile 3583:
+##.##..#.#
+..#.####..
+#......###
+#.#..##.##
+#.......##
+#.#..#.#..
+.#.###..#.
+.#.....#..
+#......#.#
+#.##.....#
+
+Tile 1637:
+#.###..#.#
+#..#.....#
+.....#...#
+....#....#
+...#....#.
+....#....#
+.....#.#..
+#.##.....#
+#..#...#..
+##..#.####
+
+Tile 1453:
+.##.#..##.
+..........
+###.#..#.#
+#...###...
+..####...#
+#.#.......
+#...#....#
+#..#..##..
+#........#
+......###.
+
+Tile 1153:
+#...#..##.
+#........#
+..#.#...#.
+.#....###.
+#.#.##...#
+#....#..##
+##......##
+..#.......
+#.#......#
+#..##.##..
+
+Tile 3701:
+..###.#.#.
+...##....#
+#..##....#
+#.........
+##.###...#
+#..####.##
+....##....
+#.#.#....#
+..........
+.#####....
+
+Tile 2179:
+.#.#....##
+..#..##.##
+##..#..##.
+###.#.....
+..#..##...
+#...#...##
+......#..#
+##...#..#.
+..#.#.##..
+#.###....#
+
+Tile 1999:
+.#...#.###
+..........
+#......#..
+.#......#.
+.#.##.....
+###...#...
+.......##.
+#.........
+..##.....#
+#..##.##.#
+
+Tile 2333:
+.#.#....#.
+..#.......
+#..#...#..
+.......#..
+....#...#.
+...#.##.#.
+.#........
+#.#....#.#
+##........
+#..##.#...
+
+Tile 1733:
+.####..#.#
+.#..#.#..#
+#..##....#
+###..###.#
+.###.#.###
+#.#.##...#
+....#....#
+#....#.#..
+....#..#.#
+.....#....
+
+Tile 3217:
+#####.##.#
+#......#.#
+.........#
+#.#.....##
+##......#.
+#..#.#...#
+.##.......
+#..#.....#
+#.#.#..#..
+...#.#...#
+
+Tile 1471:
+...#.....#
+#...#...#.
+##.#....#.
+#.##....##
+#.#.##....
+..###...##
+#.#...##..
+.#..#...##
+#.##....##
+..#..#..##
+
+Tile 2089:
+###.##....
+..##...###
+........#.
+#........#
+...#.##.##
+......##..
+###...#...
+#........#
+..#.......
+.....#.##.
+
+Tile 2909:
+.....####.
+.#..#..###
+.##..#.##.
+........#.
+#....#....
+##.#.###..
+.##..#..##
+.......#..
+#.........
+#....#####
+
+Tile 3433:
+#.#..#....
+#........#
+#.#.#.#.#.
+.###.##...
+#....#.#.#
+.#....#.##
+.#....##..
+.#.......#
+#.....#...
+.###....#.
+
+Tile 3049:
+...#......
+#...##..##
+##.....#.#
+#.#....#.#
+...#....##
+......#..#
+#.......##
+....##...#
+.#.#.##...
+.######...
+
+Tile 2143:
+.######...
+.##.#..###
+##.##..#.#
+.#....#...
+.#.##...#.
+#...#....#
+##...#....
+##..##.#..
+#....##...
+##.#...#.#
+
+Tile 3299:
+#..##.##..
+..........
+#..#.#....
+.......##.
+..........
+..#...##..
+.#....#...
+#..##....#
+#...#....#
+.#.#.#####
+
+Tile 2803:
+..#....###
+..#.##.#..
+......###.
+.....#....
+#..##.#...
+.##...#..#
+#....#....
+...#......
+......#.##
+..###..#.#
+
+Tile 2311:
+#..##....#
+.....#....
+.#..##..##
+#..###....
+#..#..#.#.
+..........
+..#....#.#
+#..##.#.##
+.###.#.#..
+..##.##.#.
+
+Tile 1123:
+#.####...#
+......####
+..#..#...#
+..#.#..###
+###...#..#
+.#.#.....#
+.....#.##.
+#.#.#..#.#
+........##
+...##..###
+
+Tile 1777:
+..#######.
+##........
+...#..#.##
+........##
+##......##
+##....##.#
+#......#..
+.#...#..#.
+#..#.####.
+..###...#.
+
+Tile 1321:
+.###...##.
+#.......#.
+###....#..
+.#..##.#..
+#.#..##.##
+###.#..###
+#....#...#
+#.#.#.####
+.........#
+.##......#
+
+Tile 2287:
+.....#..#.
+.#..######
+..#.#.....
+#........#
+#..#.#..##
+.#....#.#.
+#.#.#....#
+....#.....
+..#.....##
+.#.#.#.#.#
+
+Tile 3727:
+.#.#.#..##
+##.#..#.#.
+##......##
+##....##.#
+.....#..##
+#...#....#
+.#....#...
+....#.###.
+..#......#
+.####.##.#
+
+Tile 1607:
+.......#.#
+#.....#...
+#.....#.#.
+.#..#.##.#
+#.#.#.....
+#.....#..#
+.....##..#
+.....###.#
+....#.....
+#..#..####
+
+Tile 1327:
+.##...#.#.
+###...#...
+##.......#
+.......###
+#.#......#
+#..#.....#
+.....#.#.#
+#........#
+#.#..#.#..
+#.#..##.##
+
+Tile 3889:
+.#.#.#..#.
+..##...#.#
+#...#...##
+#...#.#.##
+#.#.......
+###......#
+........##
+#..#....#.
+.....#...#
+####...#..
+
+Tile 1447:
+..###.##.#
+...#.#....
+.##......#
+.....##...
+......#...
+#..#.#.#.#
+#.#.#.##.#
+#..#...#.#
+###..##...
+#.##.#...#
+
+Tile 3767:
+.#....#...
+..........
+##........
+.#.......#
+.....#.#..
+.#.....#..
+#......#.#
+#.....#.##
+.....###.#
+...#.####.
+
+Tile 2957:
+##.#....##
+#.#.....#.
+.#....#...
+#....#.#.#
+......#...
+#.##..#...
+.........#
+..#.##..##
+###.......
+.#...#....
+
+Tile 3911:
+..#.##.##.
+#...#...#.
+.#.#.#####
+#.###..#.#
+#..#...#..
+###..#.#..
+...#.#....
+#.##...##.
+....#.....
+#...#.##.#
+
+Tile 2683:
+#.#####.#.
+#..#..##..
+......####
+#..##..#..
+#.##.#...#
+#........#
+###...#..#
+#..#......
+#.###....#
+.##.#.#.#.
+
+Tile 2267:
+#.#..#.#..
+...#.#..#.
+#..##..#..
+##.#...#.#
+..#......#
+##....#...
+#.........
+#..##.....
+...#..#...
+##..###.##
+
+Tile 1709:
+#..#...#..
+.#.##..#.#
+#...###..#
+##.##.#..#
+##.#......
+#..#..#..#
+..##...#..
+#....##..#
+#.....####
+#######...
+
+Tile 2347:
+##.##....#
+#........#
+....#.#...
+..#.##.###
+##....##.#
+...#.#.#..
+#..#......
+.#.......#
+....#.....
+.###.##.#.
+
+Tile 1051:
+###.#...##
+#.#.......
+#.......##
+..........
+###..###..
+..###..#..
+#..#...#..
+..#.......
+....##..#.
+.#.#.##.##
+
+Tile 2903:
+...##.....
+#..#.#....
+...#......
+#...#..#.#
+#..#......
+#...#...##
+##........
+#.#.......
+#.....##..
+...#####.#
+
+Tile 1619:
+#..###.#.#
+#.#......#
+#.......##
+......#..#
+.##......#
+#.....#..#
+#.##...#.#
+#..##....#
+.#....#.#.
+.####.###.
+
+Tile 3203:
+...#.##.#.
+#.###.....
+.#..#..#.#
+#.#..##...
+.....#.#.#
+..........
+.##..#...#
+.....##.#.
+.........#
+.#####.##.
+
+Tile 2269:
+.##.#...#.
+#....##.#.
+#.##.#.##.
+#.....#..#
+..........
+##......##
+.....##.#.
+#.........
+....#.....
+.....##.#.
+
+Tile 2027:
+#..#######
+#...##...#
+...#..#.##
+#...#.....
+#....#....
+##...#..##
+#...#.#..#
+###..###..
+#.#..#####
+#..#..#.#.
+
+Tile 1973:
+##.#.##..#
+.#.#.#...#
+#...#....#
+#......#..
+#.....##..
+...#....##
+.#.....#..
+#.##.....#
+........##
+.##.#.....
+
+Tile 3559:
+.######.##
+.......#..
+..##....##
+#.#.#.##.#
+#..#.#.#.#
+..#.#.#...
+.#.#..#..#
+#...#.#...
+.#.#..#..#
+##....####
+
+Tile 3319:
+#...#.....
+.#..##.#..
+##.#.....#
+..........
+..####....
+.##..#....
+...##.....
+#..#...#..
+###..#....
+#.#..#####
+
+Tile 3631:
+##....#..#
+.#..####.#
+##.#...#.#
+#....#..#.
+..........
+..##.....#
+#..#...#.#
+.......#.#
+#.##..#.#.
+.....####.
+
+Tile 2377:
+.....#...#
+#....#....
+..#.#.....
+.....#..#.
+........##
+###.....##
+#.........
+....#...##
+.........#
+.##.#.#.#.
+
+Tile 3331:
+#..#..#.#.
+##.......#
+....##....
+...###.#.#
+.###.##.#.
+###......#
+#.#.##....
+#.#...#...
+...#.....#
+..######.#
+
+Tile 2473:
+#.###....#
+#...#.#.#.
+#...##...#
+.#..#..##.
+........#.
+.#.#.#...#
+#.#.#..#.#
+.##.......
+.#.......#
+##.#..###.
+
+Tile 1039:
+##..#.##.#
+#......#..
+###....#.#
+..#..#....
+.##.......
+####.##..#
+##..#..#..
+.....#....
+##....#.#.
+#.....##.#
+
+Tile 2111:
+.#..#...#.
+#.##.#....
+.####..#.#
+#..#.#.#.#
+..#...#...
+..#.#.#...
+......#.#.
+#.....#..#
+..##..#..#
+####....##
+
+Tile 2039:
+#.####.###
+..#.#.##..
+..#..#....
+###.......
+#.#......#
+.........#
+.#.......#
+#.#...#.#.
+####.....#
+######.#..
+
+Tile 3391:
+.####.#.#.
+#.#...##.#
+.#.#.....#
+...##...#.
+.#..#..#..
+..#..##...
+.....#.#..
+#....#....
+.#..#..#..
+##.##..###
+
+Tile 1913:
+.#.#######
+#.#..#..##
+.##.#.....
+#.#......#
+....##....
+###..#....
+........##
+#.....##..
+.#..##...#
+##....#...
+
+Tile 2693:
+#..##.#..#
+.#....#.##
+.#...##..#
+...##.....
+###..#..##
+##..#....#
+...#.....#
+##........
+####...##.
+#...#.#.##
+
+Tile 1033:
+#####.#...
+#........#
+#.#...#.#.
+.###......
+..##....#.
+#...####.#
+....#..#.#
+.....##...
+.....#..##
+##..##.#..
+
+Tile 2273:
+#.##....##
+..........
+#..##...#.
+###.......
+..#.#.#.##
+##.......#
+##..##..#.
+..........
+.........#
+.##..##.##
+
+Tile 1787:
+.#.#.##.##
+###.#....#
+#...###.#.
+..#....#..
+.........#
+....#.#...
+.##.....#.
+.....###.#
+.###..#...
+.##.####..
+
+Tile 2689:
+.......###
+..#..#....
+#......#.#
+#.#.##...#
+#.#.#.#...
+.##.......
+..#..#.#..
+...##....#
+#......#.#
+.#.######.
+
+Tile 1933:
+######.#..
+..#.#...#.
+...#...#.#
+###.#....#
+..#.....#.
+#..####...
+##........
+..###....#
+....#.....
+#####.####
+
+Tile 1823:
+###.#..#.#
+..........
+.#.#...#..
+..#..##.#.
+.#..#..##.
+#.#.#....#
+.#..#....#
+........##
+###.#.#...
+#.......#.
+
+Tile 1439:
+.#.....#.#
+...#.#...#
+...#.#....
+...##..#..
+#...#..#..
+...#.#...#
+.#..#....#
+#...###..#
+#..#####..
+#.#.#...##
+
+Tile 1657:
+.####.##.#
+#....#....
+.#..#.....
+..##..#...
+##..#....#
+.#......#.
+#.###...#.
+.........#
+#.####....
+##....##.#
+
+Tile 3517:
+##.#.##.#.
+#..#....##
+##......##
+#...#..#..
+.##..##...
+........#.
+..#...##.#
+#.#..#....
+##....##.#
+####..#...
+
+Tile 3943:
+.#.#..##.#
+#........#
+#..#......
+#.......##
+##..#.....
+####...#.#
+.###....#.
+###.......
+.##.......
+..#...####
+
+Tile 2801:
+##.##.###.
+##.###.#..
+##.#......
+..###.....
+##.#..#...
+#......#..
+#.##.....#
+##.#.#...#
+....#....#
+..####..#.
+
+Tile 2411:
+#.#.#.#...
+.####.#.##
+....#..#.#
+........##
+....#..#..
+#...##..#.
+#.#......#
+#.....#...
+.#....#..#
+..#.....#.
+
+Tile 3907:
+#.....#..#
+.##..#....
+##..#.....
+.....#....
+.#..#.###.
+#......###
+......#...
+##.......#
+........##
+####.##.#.
+
+Tile 2819:
+..#.##.#.#
+..#..#...#
+...#...#.#
+..#...#...
+#....##.#.
+#.##.#....
+.........#
+#...#..###
+###.#.....
+......##..
+
+Tile 3307:
+.#.##..##.
+#..#...#.#
+#.#..#....
+#..#....#.
+....#...#.
+#.#..#...#
+...#.....#
+..#...##..
+#.#...#..#
+#.#.....##
+
+Tile 3313:
+#.##...##.
+.......###
+....#..#..
+#.###.##.#
+###.#.#..#
+....##....
+....#.##.#
+#..#.##..#
+..#.###.#.
+#.#.#.#.##
+
+Tile 3037:
+.###.#....
+#..#..##.#
+...####...
+#.##..#...
+#...#..#..
+...#.....#
+........#.
+###.##.#..
+#.####..#.
+###..#.##.
+
+Tile 2053:
+####.#....
+#.#..##..#
+.#...###.#
+#.####....
+#.........
+#.....#..#
+#.#.#.....
+..#.#...#.
+#..#.#...#
+..#..#.##.
+
+Tile 3769:
+....#..##.
+#..#......
+#...###..#
+#..##....#
+.#.......#
+#.........
+.#..#..##.
+#.#.#..#.#
+#.#.......
+#..##..#..
+
+Tile 1759:
+...##....#
+..........
+###......#
+##........
+.....#....
+#..##..#..
+......#.#.
+###..##..#
+.#....#..#
+......#.#.
+
+Tile 1229:
+#.##.#.#..
+#..#...###
+...#.....#
+.#....#..#
+#.##..##.#
+#..#...###
+..........
+.....###..
+..#..#..##
+##.#....##
+
+Tile 3821:
+.##.####.#
+......####
+......#.#.
+#....#.###
+.#.##..#.#
+..........
+...#.#...#
+..#...##..
+##.#.#..##
+####...###
+
+Tile 1319:
+#.##..#.##
+...#..##..
+..#.#.....
+.#..#....#
+#..#.#.#..
+#.....#..#
+#.#.#.....
+...###....
+##.##...#.
+.#.##.##..
+
+Tile 3167:
+#.#.....##
+.#...###.#
+.#...##.#.
+###..#...#
+....##..##
+.....#..##
+..#...#.##
+.......###
+.........#
+##.#.#.###
+
+Tile 3407:
+...##..#.#
+.#...##...
+.........#
+#..#..#.#.
+#.#....#.#
+...#.#...#
+.#.#......
+....#....#
+#..#....#.
+.####..##.
+
+Tile 1231:
+#...#..###
+#........#
+##.......#
+#.#..#....
+#.#.#.....
+.#..#.....
+#...#.....
+#..#...###
+..#.#....#
+#.##.###..
+
+Tile 3623:
+##.##.##..
+#..#.....#
+........#.
+#........#
+....#.....
+.......#..
+.....##..#
+###...###.
+..##..#..#
+.#..####.#
+
+Tile 3541:
+#.......#.
+##........
+.####...#.
+.#..#..#..
+#.....#..#
+..#...##..
+#..#...##.
+#....##..#
+....#...#.
+.#..#####.
+
+Tile 2939:
+..#.###..#
+......##..
+#...#.#...
+#.........
+#...#.#...
+#....#....
+##.....#..
+.......#..
+###..#####
+.#.###..##
+
+Tile 1847:
+.#####.##.
+....#.##.#
+...#......
+.#..#.....
+.....#.#.#
+##.##...##
+.......#.#
+.......###
+....#..#..
+...#.##...
+
+Tile 2887:
+####.##.#.
+#..##...##
+#..#..#...
+#........#
+##.#.#...#
+#.#..##...
+...##...#.
+#.#..#...#
+#.#.##....
+##.##.##.#
+
+Tile 3697:
+.##.....##
+#.........
+###.......
+..##.#....
+##...#.#..
+#...#....#
+#........#
+.#........
+.#.#......
+#...#...##
+
+Tile 2081:
+.###.#..#.
+..#.#....#
+......#.##
+#..#.#..##
+#...##....
+#....#...#
+.###......
+..#..#.#.#
+..#....###
+#...#...##
+
+Tile 2383:
+....##.##.
+.##......#
+.#.......#
+#.##.#...#
+#..#..#..#
+##.#.....#
+..#.#..#..
+#....#....
+.#.#.#.#..
+#..#.#.#..
+
+Tile 2557:
+##..#.###.
+..#.......
+.#....##..
+...#.#....
+...##.#...
+#.#.#....#
+........##
+#.....#..#
+##.....#..
+.###..#.##
+
+Tile 3637:
+#..#.###.#
+...#..###.
+#.......#.
+.......#.#
+...#.#....
+..........
+.........#
+.........#
+.###..###.
+###.#.#..#
+
+Tile 3989:
+...#.#.#.#
+..#..###..
+#...#..###
+#....##...
+#....#.#.#
+........##
+#.##....##
+#.....#.##
+#.##..#..#
+......#...
+
+Tile 2221:
+#...##.###
+.....#..#.
+.#..#....#
+.....#.##.
+..#.##...#
+........##
+#.....####
+.#.......#
+#.##...#..
+##.####...
+
+Tile 1523:
+..#..####.
+.#.#......
+#...#.##.#
+###..#..#.
+......##..
+.........#
+...#..##..
+#....#.#.#
+#......#..
+.#...#...#
+
+Tile 1583:
+.####.#.##
+#...#.#.##
+.....#....
+...#...#.#
+.###.....#
+..##.#...#
+#.##......
+#....##...
+#..#.....#
+.####..#..
+
+Tile 3919:
+..#..##...
+.#...#....
+#.####.#..
+..........
+#..#......
+#........#
+...##.#..#
+...#......
+#..##....#
+.#....#.#.
+
+Tile 2381:
+....######
+..##..##.#
+#...####..
+...#......
+###...#.##
+#...#.....
+#.##....##
+....#....#
+......#.#.
+...##.##.#
+
+Tile 3923:
+#####.#.#.
+.#.....#..
+....#.....
+#...#....#
+##........
+......#..#
+.....#...#
+#.#...#...
+.####....#
+####....#.
+
+Tile 2953:
+#.#.###..#
+....#.#...
+.#.#....##
+#...##...#
+#...##..#.
+###......#
+.#.##.#...
+.........#
+##.#.##.#.
+..#...#..#
+
+Tile 2441:
+....#.#.#.
+##..#.#...
+.....#.#.#
+#....#....
+#..#...###
+#....#....
+#......###
+..#..#.###
+.#.......#
+.#.#.##...
+
+Tile 3023:
+#.#.#####.
+..#.....##
+#..#.#...#
+.#....#..#
+..#.#...##
+##.....#..
+.#....#.##
+#.........
+####.#....
+#..##.#...
+
+Tile 2659:
+...##..#..
+##...##..#
+.#...#..##
+##....####
+....#.####
+##.#......
+..#.##...#
+.#.#..###.
+....#.##.#
+.##..###.#
+
+Tile 1069:
+.##.##..##
+#.........
+.#....#...
+##........
+..#......#
+.###...#.#
+##...##..#
+#..#.#....
+..#.....#.
+.#..###..#
+
+Tile 1181:
+##.##.##..
+#.....#..#
+..#...#..#
+.##.#.....
+#...#....#
+#.#......#
+...#...#.#
+#....##..#
+#..###.#..
+..#..#...#
+
+Tile 1663:
+....#..#..
+.###.#####
+#..#...#.#
+..........
+.........#
+.#.##....#
+.##.......
+.......#..
+##......##
+.#.##...#.
+
+Tile 3779:
+.##.##.#.#
+#...#....#
+#..##....#
+.#...#....
+##..#...#.
+.........#
+#...#...##
+#..#......
+###.....#.
+..##..#.#.
+
+Tile 1013:
+#.##.#.#.#
+.#..#.....
+.#.#.##...
+###......#
+.#.##..#.#
+.#..#..##.
+..........
+....#....#
+#......#.#
+#..###.###
+
+Tile 1747:
+.#.#..###.
+.......##.
+#..##..#..
+..#.#.#...
+##......##
+#......##.
+....##..##
+..#.#...##
+#...#..#..
+##.###.##.
+
+Tile 3931:
+..###..#..
+#..#......
+##....#...
+.##...#...
+#........#
+....#.#.#.
+.###.....#
+.#..#.....
+##.#......
+##.####..#
+
+Tile 2593:
+#.##..#..#
+.##.....##
+#.###...##
+#..#......
+##..##...#
+#.##......
+..#.#.#..#
+..#......#
+...#..#...
+.####.##..
+
+Tile 3677:
+#.#.#.#.##
+....#.....
+.#..##....
+.....##..#
+..#..#.#..
+..........
+###..##...
+##.#####.#
+#...#.....
+#.#..#####
+
+Tile 2633:
+.#..####.#
+.###...#..
+......#..#
+....###...
+#..#.##...
+.#..##.#.#
+##.....#.#
+#.......##
+#...#.#..#
+#.#..#.#..
+
+Tile 2129:
+..##.###..
+##..#...#.
+..#...#...
+#.....#...
+......#..#
+..#.##...#
+....#..###
+##....#...
+..........
+.#.#.##...
+
+Tile 2029:
+##.##.###.
+#..#......
+##......#.
+.#.###.##.
+...##...##
+#..#....##
+...###.#.#
+....#...##
+..#..#....
+...#.....#
+
+Tile 1873:
+.#...#...#
+#...##..##
+##.#.....#
+#.#..#..##
+....#.....
+..#..###..
+......#..#
+.........#
+#...#...#.
+##.##....#
+
+Tile 1567:
+##..##..#.
+....##..#.
+..#.....#.
+.#.#.....#
+#.#.##...#
+....##...#
+#....##..#
+....#.#..#
+.#...##..#
+##.#..##.#
+
+Tile 3571:
+####....#.
+.##.###.##
+.........#
+..#.....#.
+....##.#..
+.#.#.....#
+#.........
+#....#...#
+#........#
+#..#.##.#.
+
+Tile 2671:
+...#..##..
+..........
+#..#..##..
+##....#...
+#.......##
+###.#..#.#
+..##....##
+#...#.....
+.#...#...#
+......##..
+
+Tile 3229:
+...#.#..#.
+#.........
+...##.....
+...#.....#
+#.##......
+..#.#.#.##
+...####...
+.....##..#
+#.........
+.#.###....
+
+Tile 3083:
+##...#.#.#
+#.###....#
+#..#...#.#
+.#...#....
+#...#....#
+##...#.#.#
+..#......#
+#.#....#.#
+#..#.#.#..
+.#..#.....
+
+Tile 2239:
+######.#.#
+##.##.##.#
+.......##.
+#..#......
+##.....###
+........##
+..#....#..
+#...####..
+....####..
+..#.#####.
+
+Tile 3581:
+###.#..###
+#.#.#....#
+...#.#..##
+#..#...###
+.#.##.#...
+#..#..#...
+...#.#.#.#
+#...#..##.
+##....##..
+##...###..
+
+Tile 1061:
+.....###..
+###...#...
+#.#...###.
+........#.
+.#.....#.#
+##...##.##
+.........#
+#....##.#.
+.#.....#..
+.#...#.##.
+
+Tile 3967:
+..########
+##........
+.##.#...#.
+..##.##.##
+#.#....#.#
+.#.......#
+....#.....
+#.##......
+##..##.#..
+..#...#.##
+
+Tile 2749:
+.#######.#
+#..#..#...
+...#......
+....#....#
+....#.###.
+.#.#.#....
+.#..#.....
+...#....#.
+#.##.#..#.
+#####.###.
+
+Tile 1811:
+#.#.###.#.
+#.........
+.........#
+...#......
+........##
+..........
+.#####...#
+####.#....
+#.....#...
+#.#.#.#..#
+
+Tile 2477:
+####.#..##
+..#.##..##
+#....##...
+#.#...##..
+####....##
+#.......#.
+#####....#
+..#.......
+......#...
+.#.##.##.#
+
+Tile 1949:
+#.##..####
+#.##..#.#.
+###.......
+##.#.....#
+#..###..##
+##......#.
+.....#..##
+##...##..#
+.#........
+##.##.#..#
+
+Tile 2099:
+..##.#..##
+....#.#...
+#....#.#.#
+...#..#...
+##.....##.
+#..###.###
+.#.....#.#
+..#......#
+......#...
+.##..#.#..
+
+Tile 2767:
+.#.###.#..
+..#.#.#...
+...##.....
+..#.......
+......#..#
+.......#.#
+.....#....
+#.#.##..##
+..#..#....
+##...#.###
+
+Tile 3251:
+..##.#....
+.......#..
+.....#.#.#
+.#..##..##
+.#.##....#
+#.#....#..
+##..#....#
+.........#
+..#..#..##
+....####..
+
+Tile 3833:
+#..####.##
+...#......
+.#.....#.#
+##..##...#
+.....##..#
+#..#.#....
+...##...##
+..#.##...#
+........##
+##....#.#.
+
+Tile 3089:
+..#.......
+.....#....
+#####...#.
+##..#..#..
+.#.#.##.##
+..#.##..#.
+.......#..
+##..#....#
+...#..#...
+..#.###..#
+
+Tile 2861:
+#......#..
+...#.....#
+#.....#..#
+##.......#
+.#....#..#
+##..#.#...
+........#.
+#........#
+#.##...###
+#.#.###...
+
+Tile 1489:
+##.##.#.##
+.#.......#
+#..#.##..#
+#.#.......
+#.#....#..
+#.....##.#
+.##..####.
+.....#.#.#
+.......###
+#.#.#..#.#
+
+Tile 1801:
+#....#####
+#.#......#
+.........#
+#.#.....##
+#....#...#
+.##...#...
+##.###.#.#
+.#.#..##.#
+..#.#.#..#
+##..###.#.
+
+Tile 2677:
+#.#...#.##
+..........
+#...#.##.#
+#.#....#.#
+#.....#..#
+..#..#..##
+#.###..#.#
+##.#.....#
+........##
+##.####.#.
+
+Tile 3797:
+..#####.#.
+#.#..#..#.
+..#..#.##.
+..##.#.#..
+.##..#....
+.##.##..#.
+#......###
+........#.
+.#.##...#.
+..#..##### \ No newline at end of file
diff --git a/2020/inputs/day20_short b/2020/inputs/day20_short
new file mode 100644
index 0000000..b3aed46
--- /dev/null
+++ b/2020/inputs/day20_short
@@ -0,0 +1,107 @@
+Tile 2311:
+..##.#..#.
+##..#.....
+#...##..#.
+####.#...#
+##.##.###.
+##...#.###
+.#.#.#..##
+..#....#..
+###...#.#.
+..###..###
+
+Tile 1951:
+#.##...##.
+#.####...#
+.....#..##
+#...######
+.##.#....#
+.###.#####
+###.##.##.
+.###....#.
+..#.#..#.#
+#...##.#..
+
+Tile 1171:
+####...##.
+#..##.#..#
+##.#..#.#.
+.###.####.
+..###.####
+.##....##.
+.#...####.
+#.##.####.
+####..#...
+.....##...
+
+Tile 1427:
+###.##.#..
+.#..#.##..
+.#.##.#..#
+#.#.#.##.#
+....#...##
+...##..##.
+...#.#####
+.#.####.#.
+..#..###.#
+..##.#..#.
+
+Tile 1489:
+##.#.#....
+..##...#..
+.##..##...
+..#...#...
+#####...#.
+#..#.#.#.#
+...#.#.#..
+##.#...##.
+..##.##.##
+###.##.#..
+
+Tile 2473:
+#....####.
+#..#.##...
+#.##..#...
+######.#.#
+.#...#.#.#
+.#########
+.###.#..#.
+########.#
+##...##.#.
+..###.#.#.
+
+Tile 2971:
+..#.#....#
+#...###...
+#.#.###...
+##.##..#..
+.#####..##
+.#..####.#
+#..#.#..#.
+..####.###
+..#.#.###.
+...#.#.#.#
+
+Tile 2729:
+...#.#.#.#
+####.#....
+..#.#.....
+....#..#.#
+.##..##.#.
+.#.####...
+####.#.#..
+##.####...
+##..#.##..
+#.##...##.
+
+Tile 3079:
+#.#.#####.
+.#..######
+..#.......
+######....
+####.#..#.
+.#...#.##.
+#.#####.##
+..#.###...
+..#.......
+..#.###... \ No newline at end of file
diff --git a/2020/inputs/day21 b/2020/inputs/day21
new file mode 100644
index 0000000..5d2b7ea
--- /dev/null
+++ b/2020/inputs/day21
@@ -0,0 +1,42 @@
+rgt lmpxcr ssgkt klfp dfpqn scqc vzzxl hphcb pbmhl xrlmvz fvd cpj kxl gpplt jkrsn bhlbm dkxr vrzkz drpxzr bxhsq cvz nvhnsg jtzsqznl fjbjj slglnd qdbq gnrb zpbbvvm bqb mbdksj nlxh gtzp jrlvkz ctmzsr znjp zvmnv lhsgbq pdxhgx jrcczb vrpzss qdbj lsc jhrgz hqlm qlt kh grjf brhfcbt zjsh pkmbk rncjx nmszz fzpds qglps zjsz qfnq ftfx bbkth rkzqs vgp (contains nuts, shellfish)
+slmjchql qfnq lqdpl bgdq tjxp rkzqs zjsh znklc qdbj pbtns cpsbgsh qbtpnr nmszz vzzxl vrzkz vtrltkq znfrgvc dksfbk cvz qfvvf cvtj dmpl qnt hbbz zmhnj dfpqn rncjx scqc bccz hdnq zpbbvvm lnpbh pdxhgx nqstv fhpxz ftfx rgt ztrpkb lqtnn dqdn vlqtzzl msvgj dkxr fptpk bbkth jgkp hmshx xrlmvz trlmqn znjp vgp ztlbvp klfp slglnd rmthpj nfzczn hdkc nvhnsg cntfbt rmpnm bqfqcjb tkrr jgxbzks sks pchhkp qsrh kh mbdksj ctmzsr drpxzr xlqj bhlbm (contains soy, eggs, shellfish)
+zjdzx cpj bqfqcjb bqb ztlbvp hdkc hphcb zjsh pkgsf qllxhr grjf rgt vfnv gtzp sbsrk hdnq vzzxl httx vgp cntfbt ghfk hmshx rzjcs dbfk xfvtzq nvhnsg znfrgvc bbkth svrx rcv bgdq hqjgzmt rkzqs nmq lqdpl zcxxdp dxpdkp nqstv vrtfrj zhvsdc rsrgmkr nlxh lmpxcr rmpnm kxl qzbzd fzpds sltl cvtj zvmnv jgxbzks vrzkz cpsbgsh zdrlf cqbkj nmszz jrcczb qvhdl dlc sks lvjrbms vfhvp lhb knhvxm qlt dqdn ssgkt slmjchql nvbr cgrcmp pkmbk vllxj spzmvfl rvnfn ctmzsr cvz zqgzlr zmhnj fzgbq bhlbm (contains shellfish)
+pznl nmszz vtrltkq qpgj zqgzlr lnpbh gpplt rkzqs gmx bqb jgv hphcb dfpqn zcxxdp tkrr qbtpnr mbdksj hxfrh vfnv hmshx fmkbnr gnrb sltl kh drpxzr vzzxl fptpk ftfx ctmzsr jrnfp dksfbk qsrh rnxl czlpq dpkdp qzbzd dxpdkp fvpj tnjxcf zdrlf bxhsq bhlbm nlxh hqjgzmt qglps cf qllxhr cqbkj jmxpbtk nvdst slmjchql qnt dnzljk ckzdf vrzkz pbmhl ssgkt knhvxm gjvqffm xzhct xvmftv zmf qbnkj ltxqz mxk njcjm knqlqt bccz dbfk dlc vllxj rph frz zmhnj pkmbk (contains soy, sesame, fish)
+gbzcv znjp xvmftv pjgxpg bhlbm spzmvfl xfvtzq vrzkz bqb brhfcbt rmthpj hphcb vfnv knqlqt slmjchql vrtfrj fzgbq hxfrh rxzxs cgrcmp dg msvgj xcdb dksfbk zmhnj gjvqffm jsdcr rzjcs jgkp klfp flhzd dnzljk nmszz qbnkj bbkth hdkc vlqtzzl fptpk hmshx jrcczb lhsgbq tcp fvvjp cvz lhb rls rcv pspjgzx gtzp cntfbt ftfx qpgj vzzxl hbbz qfnq ztlbvp dxpdkp lmpxcr frnh qzbzd ctmzsr rkzqs svrx znklc zjsh knhvxm rnxl qbtpnr jmxpbtk zjsz vgp zpbbvvm pkgsf jrnfp rvnfn gpplt sks vtrltkq (contains sesame, fish)
+dmpl cpsbgsh msvgj qdbq tqtbd fptpk frnh zjdzx hbvqn rls bhlbm lhsgbq znklc rph bqfqcjb rmthpj dlc tkrr qfvvf xzhct dxpdkp qpgj rkzqs fvd ltxqz sltl zjsh ctmzsr kxl bbkth cvz znfrgvc jgkp zmhnj hphcb qvhdl vrzkz sbsrk jgxbzks qzbzd cgrcmp hqlm jmxpbtk mkpxx drpxzr kh rncjx qbnkj dbfk tjxp fvpj vpl nmszz jsdcr vzzxl dksfbk lqtnn pmhnmxr gnrb vkjggtx gmx cf (contains dairy, peanuts, sesame)
+qfvvf cntfbt cvz fvpj hxfrh vrzkz lsc zmf cgrcmp httx qvhdl xvmftv dksfbk zvmnv snxz lvjrbms zcxxdp gjvqffm pdxhgx czlpq spzmvfl knqlqt ctmzsr zhvsdc vzzxl rkzqs zjsh msvgj zmhnj nlxh dxpdkp hphcb dnzljk bqb lqdpl nvdst rcv tqtbd xfvtzq mkpxx (contains soy, eggs, peanuts)
+slmjchql zjsh qfnq lqdpl zmf vgp rkzqs cgrcmp snxz drpxzr zqgzlr cpsbgsh zvmnv vzzxl mxk knhvxm lsc dpkdp ltxqz xvmftv dnzljk ctmzsr spzmvfl pmhnmxr kh mbdksj gpplt znjp lvjrbms pkgsf hdkc vrzkz vfhvp znklc dg rcv jgxbzks fhpxz hbvqn qvhdl nqstv qglps dfpqn znfrgvc rncjx bqb gtzp xlqj zjsz pspjgzx zmhnj tjxp lmpxcr (contains nuts, sesame)
+zqgzlr hhth scqc jtfnm qdbq cf zcxxdp rxzxs rlxhc zdrlf qfnq slglnd dbfk fzgbq cpj rncjx zjsz pmhnmxr kxl qllxhr bqfqcjb dlc flhzd klfp dpkdp vrzkz zjdzx fptpk vzzxl rkzqs zhvsdc mbdksj snxz jsdcr xlqj qbnkj pznl tqtbd dqdn slmjchql xvmftv fjbjj vkjggtx qlt rnxl gpplt qpgj nvbr nlxh nqhk vfhvp hphcb zjsh qglps rph lhsgbq zvmnv rzjcs pchhkp frz dfpqn kh qbtpnr zmhnj drpxzr bccz cgrcmp msvgj cqbkj hdnq vttzh lsc dmpl pkgsf rmpnm pbtns xfvtzq (contains shellfish, dairy)
+hphcb hxfrh fptpk tsnhq ctmzsr qnt xvmftv nvbr zmf sks czlpq dlc cpsbgsh jtfnm znklc bhlbm bgdq qbtpnr nvhnsg slglnd jkrsn ghfk ztrpkb njcjm znjp jrnfp gpplt cpj tcp pdxhgx kxl mbdksj rnxl nvdst bxhsq zjdzx vzzxl rsrgmkr rvnfn rcv zmhnj xrlmvz dbfk tjxp ghtjbp rph zjsh rkzqs spzmvfl vlqtzzl (contains shellfish, soy)
+hphcb sbsrk qvhdl hbvqn cpsbgsh nvhnsg mkpxx ssgkt znklc cf jgv vzzxl dnzljk ttr pbtns cgrcmp rnxl cvz znjp fptpk kh zdrlf zmhnj zjsh svrx snxz slglnd lsc pdxhgx rmpnm cqbkj pznl frnh bxhsq bqfqcjb ghfk dxpdkp qbnkj hkzzg hbbz rkzqs grjf dbfk jkrsn zcxxdp ctmzsr nvbr hhth mbdksj lhb vrtfrj brhfcbt flhzd zjdzx hdkc nlxh jrlvkz dfpqn (contains nuts, peanuts, shellfish)
+hqjgzmt njcjm rlxhc brhfcbt fvvjp zjsh ghtjbp dnzljk qsrh zmhnj brhns pznl vzzxl jrnfp lnpbh rzjcs svrx pkmbk nfzczn pbtns nvhnsg pmhnmxr hdnq gjvqffm pjgxpg bxhsq vllxj lhb dksfbk tcp ssgkt vrzkz nvbr qzbzd dmpl pbmhl lmpxcr hdkc dpkdp rkzqs zdrlf sbsrk knqlqt pspjgzx qbnkj rph cqbkj drpxzr mbdksj ctmzsr dfpqn bccz kh vlqtzzl hbbz vfhvp (contains sesame, nuts)
+pchhkp jkrsn hbvqn vzzxl qsrh ctmzsr rzjcs cgrcmp xzhct zvmnv cntfbt dlc zqgzlr znfrgvc hqjgzmt dqdn pkmbk nmq zmhnj qdbj vrzkz qbnkj fzpds vlqtzzl qvhft bhlbm bccz rvnfn zjsh mbdksj lnpbh pbtns svrx rkzqs zhvsdc qbtpnr ltxqz dksfbk (contains dairy, shellfish)
+hkzzg vtrltkq nmszz hhth pjgxpg jgxbzks rcv cgrcmp tsnhq zmhnj dqdn fhpxz ltxqz pdxhgx ssgkt jrnfp gtzp tnjxcf qdbq hphcb dnzljk ghfk znklc nvdst tcp brhfcbt xzhct vzzxl nvhnsg ttr bbkth hdnq nmq rph jtzsqznl czlpq gnrb ctmzsr ftfx pkgsf msvgj zjsh sltl lsc qnt pbmhl cqbkj gztf vrzkz jrcczb zdrlf qfnq jtfnm qbnkj frnh jrlvkz hbbz klfp njcjm rvnfn pmhnmxr qglps sbsrk mbdksj nllks (contains nuts)
+spzmvfl fvvjp cvtj qsrh pspjgzx vzzxl svrx rkzqs vfnv xcdb jgv hdkc zmhnj ghtjbp fptpk frz lsc dmpl bhlbm qpgj sbsrk dnzljk vttzh hkzzg tsnhq ctmzsr dpkdp jgkp bxhsq lnpbh ztrpkb zjsh mxk jtzsqznl zpbbvvm vrtfrj rcv rph bgdq lhb bccz rls jhrgz nvdst hhth qnt vpl kh mbdksj zmf rncjx knqlqt flhzd jmxpbtk jrnfp lqtnn tnjxcf cpj fmkbnr tcp dfpqn hdnq vrzkz (contains shellfish, dairy)
+nqhk jrlvkz pjgxpg nvbr qvhdl rmthpj nqstv xcdb gpplt rgt vgp tjxp rlxhc rnxl tqtbd hqlm dkxr dbfk knqlqt msvgj scqc klfp httx hdnq hkzzg fmkbnr vllxj nmszz zjsh mkpxx ctmzsr dxpdkp fzpds xfvtzq nvhnsg kh qfvvf fzgbq dpkdp slmjchql knhvxm rcv mbdksj rzjcs vzzxl ghtjbp qzbzd jsdcr cpj pkmbk pdxhgx fptpk nlxh flhzd vrzkz qpgj spzmvfl jrnfp zmf ttr fvvjp qglps lhsgbq rkzqs snxz qfnq fvpj bbkth gztf lqtnn jgxbzks tkrr pbtns gjvqffm jgv nmq drpxzr czlpq kxl svrx hphcb (contains nuts)
+rph jkrsn dmpl tcp vrpzss jgkp cntfbt mkpxx spzmvfl dnzljk fvd cpj zmhnj cqbkj ltxqz tsnhq ctmzsr flhzd vtrltkq rkzqs pspjgzx hdnq vzzxl hbbz trlmqn cvtj fjbjj vrzkz gnrb hqjgzmt mbdksj lqdpl xrlmvz lnpbh jrlvkz qpgj kxl nvhnsg sbsrk svrx klfp vllxj slmjchql rncjx hkzzg bqfqcjb xvmftv qdbj dqdn nqhk tnjxcf vlqtzzl zcxxdp hxfrh vkjggtx pznl nmq qfvvf qdbq zjsh scqc (contains sesame, dairy, soy)
+rkzqs pchhkp jkrsn hqjgzmt qzbzd hbvqn zpbbvvm rph hphcb gmx njcjm nvbr qllxhr pbmhl ttr gpplt gbzcv vfhvp bccz hbbz nlxh mxk ltxqz vrzkz zjsz httx pmhnmxr fzgbq nvdst lqtnn vzzxl rvnfn pkmbk xzhct zqgzlr ctmzsr pznl bgdq znjp vllxj fvpj fvvjp mkpxx tkrr fhpxz tsnhq zjsh vttzh rmpnm gztf qbtpnr klfp cgrcmp fmkbnr jgv qglps mbdksj knhvxm sks kxl ckzdf cf (contains fish, sesame, nuts)
+fjbjj nqstv bqb dg vfnv gmx vzzxl qglps gpplt zjdzx zvmnv ctmzsr bqfqcjb xcdb tjxp gjvqffm hhth jrcczb bgdq cqbkj spzmvfl sltl qfnq vtrltkq dmpl qlt hphcb hdnq flhzd zmhnj vpl msvgj vrzkz dkxr jsdcr hbbz bbkth tsnhq svrx jrnfp lhsgbq slglnd gtzp cvtj ckzdf ztlbvp pspjgzx pbtns lmpxcr jmxpbtk mkpxx bxhsq ghfk rmpnm qllxhr dqdn fvpj ftfx vkjggtx qvhdl klfp qnt hdkc jtfnm zpbbvvm lqtnn nllks dfpqn vlqtzzl hbvqn jgkp hqlm grjf lsc pkgsf kxl qbtpnr qzbzd rkzqs nmszz zjsh (contains eggs, soy, dairy)
+knqlqt kh dlc vkjggtx jtfnm dnzljk svrx zmhnj dfpqn gpplt qvhft qsrh qzbzd hqlm kxl lqtnn qglps lvjrbms dmpl spzmvfl slmjchql knhvxm jmxpbtk ztlbvp vfhvp qnt rmthpj mbdksj xfvtzq lqdpl fjbjj vzzxl slglnd fhpxz snxz zhvsdc pbmhl nlxh ssgkt lhsgbq ckzdf tcp znfrgvc rkzqs lhb ctmzsr jrnfp frnh tjxp zjsh cgrcmp ftfx mxk rls vpl hphcb xcdb fptpk rvnfn fzgbq hkzzg vlqtzzl jkrsn ghfk vfnv (contains soy, fish)
+vfhvp rmpnm tsnhq sks cntfbt qdbj rzjcs vllxj pjgxpg gpplt mxk brhfcbt qsrh zqgzlr qdbq lhb fjbjj dlc ztlbvp rcv dg dxpdkp tqtbd zjsz pdxhgx zjsh znklc xvmftv rkzqs zcxxdp gmx cqbkj dqdn zmf vrtfrj ckzdf hdkc qpgj jsdcr bccz slglnd brhns bhlbm vrzkz jkrsn zvmnv nmq hbvqn rvnfn qvhft pbtns jrnfp knhvxm dfpqn spzmvfl rgt httx hphcb mbdksj bbkth jrlvkz zmhnj hxfrh rls fhpxz rlxhc jgv vlqtzzl fmkbnr tnjxcf tjxp jhrgz qbnkj svrx jmxpbtk tkrr nfzczn ctmzsr knqlqt qlt kh cvtj (contains dairy, fish)
+mbdksj dg hphcb jsdcr qvhdl bgdq pdxhgx vllxj jgxbzks ctmzsr hdkc hbvqn fhpxz znfrgvc cf svrx scqc rvnfn xlqj sks qvhft jrcczb zmf nqstv vzzxl jmxpbtk lvjrbms rcv tkrr vrtfrj nvbr bccz vlqtzzl qglps rkzqs zmhnj qzbzd pznl cpj cntfbt czlpq zjsz lqtnn zqgzlr slglnd jgkp vrzkz dpkdp sltl ztlbvp jrlvkz (contains shellfish, soy, peanuts)
+rncjx dg vfnv vzzxl pkgsf mbdksj jrcczb ltxqz zmhnj vtrltkq dfpqn gjvqffm dksfbk qbnkj slglnd nvdst hdnq ckzdf qlt hphcb mxk scqc sltl qfvvf jgxbzks cgrcmp bhlbm ttr njcjm cvz nvbr qglps vpl tcp trlmqn dnzljk pmhnmxr rlxhc zhvsdc lsc nvhnsg fhpxz gnrb brhns cf ctmzsr fzgbq fzpds fvd gztf drpxzr ssgkt pbtns rkzqs rmthpj fjbjj rmpnm bccz brhfcbt jmxpbtk zpbbvvm fvvjp zjsh rzjcs (contains eggs, shellfish)
+zmhnj hxfrh scqc tqtbd dqdn zjsh rcv sbsrk ctmzsr slglnd sltl zdrlf pspjgzx qbnkj gztf vrtfrj trlmqn rncjx bhlbm pchhkp qglps tsnhq fvvjp ztlbvp fptpk nvbr lmpxcr pkgsf xvmftv rvnfn qnt spzmvfl jrlvkz dpkdp flhzd ssgkt snxz rph rkzqs fjbjj gpplt vzzxl hphcb gbzcv nfzczn vrzkz jtzsqznl kxl (contains soy)
+zjsh scqc vlqtzzl fzgbq xlqj dxpdkp jgv tjxp qdbj jhrgz kh znjp mbdksj jgkp xfvtzq rzjcs hdkc dksfbk jmxpbtk ftfx lvjrbms nmq svrx ztlbvp xvmftv cvtj zhvsdc cpj cvz hmshx zmhnj rkzqs zjsz jtfnm slmjchql zmf vzzxl cf jkrsn lqdpl ctmzsr fmkbnr hdnq mxk dg hphcb gtzp qdbq vrtfrj vfhvp nllks znfrgvc vrpzss ghtjbp bqb fhpxz jtzsqznl (contains sesame, peanuts)
+pdxhgx rmthpj jrlvkz lqtnn pmhnmxr jmxpbtk vgp zjsh rncjx fvpj vrzkz rkzqs fptpk pbtns qzbzd bhlbm znfrgvc qbtpnr gtzp dbfk jsdcr pkmbk spzmvfl lhsgbq tqtbd gnrb vzzxl gpplt knqlqt frnh dksfbk qvhft lhb bqfqcjb hkzzg qfvvf scqc klfp cf mbdksj slmjchql dpkdp kh tsnhq ctmzsr rlxhc ssgkt hdnq rph rxzxs jgkp hbbz cqbkj xvmftv cpsbgsh pznl dnzljk zmhnj nvhnsg ztrpkb msvgj brhfcbt pchhkp rcv gmx rvnfn tcp zpbbvvm dlc cvz rzjcs (contains dairy, shellfish)
+qbnkj zcxxdp qglps dnzljk dkxr jgkp frnh knhvxm ctmzsr bgdq zhvsdc vrzkz dqdn tqtbd vzzxl xzhct slglnd rkzqs znfrgvc qfvvf snxz fvd cpsbgsh trlmqn gbzcv tsnhq qbtpnr rzjcs pmhnmxr nmq nvhnsg mbdksj knqlqt vgp njcjm brhns zjsh pkgsf zmhnj (contains sesame, nuts)
+spzmvfl zjsh fmkbnr qbtpnr pdxhgx fzpds qpgj vrzkz mkpxx jkrsn pchhkp tkrr zvmnv pspjgzx zmhnj hphcb rvnfn cf pmhnmxr nvdst frz qdbq fptpk fhpxz fzgbq nmszz qvhft gtzp vzzxl vlqtzzl dqdn pbmhl vkjggtx hqlm nmq trlmqn vtrltkq dpkdp lqdpl rkzqs ctmzsr qzbzd dksfbk fvvjp lvjrbms dkxr (contains soy, sesame, dairy)
+ctmzsr ssgkt msvgj xcdb tqtbd ghtjbp scqc nlxh nqhk vzzxl jrcczb tjxp vrtfrj ckzdf fvpj vfhvp jtzsqznl qpgj zqgzlr jmxpbtk ghfk sks gtzp zmhnj mkpxx vfnv jsdcr frnh zjsh rkzqs vrzkz httx rls qsrh xvmftv knqlqt jhrgz brhns frz qbtpnr njcjm fvd hbvqn rmthpj bxhsq lnpbh cpsbgsh bqb tsnhq rvnfn hqjgzmt slglnd lqdpl hphcb jgv cgrcmp slmjchql xrlmvz jgxbzks cvz qfvvf pbmhl cntfbt pznl rzjcs zvmnv cpj dksfbk gpplt znklc kh qfnq rmpnm tnjxcf dqdn ftfx qvhft ztlbvp jrnfp dfpqn hbbz pbtns bccz ttr (contains dairy)
+qbnkj bqb zmf lsc xfvtzq xrlmvz jgxbzks cvtj fvvjp gbzcv zqgzlr zmhnj vtrltkq jkrsn cvz kh lqdpl qzbzd rsrgmkr zjsz gpplt qlt cf fvd bbkth pkmbk pbmhl zhvsdc dmpl xcdb rmpnm rnxl lhb sks ssgkt vrzkz brhfcbt xzhct vzzxl pjgxpg ftfx fhpxz njcjm scqc hqjgzmt rkzqs lnpbh zjsh fzpds ctmzsr brhns trlmqn vlqtzzl lmpxcr jrcczb vllxj hphcb hxfrh rls qdbq znklc tsnhq dxpdkp cpj bhlbm zjdzx czlpq (contains eggs)
+hhth vkjggtx nmq zmhnj dmpl spzmvfl qfnq vzzxl pkgsf fjbjj rvnfn pkmbk frnh knhvxm vrzkz ctmzsr xcdb mbdksj nvdst cf fvd flhzd kxl cvz qbnkj hkzzg jtzsqznl rnxl sbsrk klfp cqbkj jsdcr rkzqs jhrgz nmszz slglnd nqstv qdbj zjsh tkrr zmf (contains nuts)
+nvbr ghtjbp nvdst fvd mkpxx xlqj dkxr znfrgvc mbdksj vfnv rph zpbbvvm gpplt ctmzsr rsrgmkr cvz ztlbvp rkzqs bbkth nfzczn hphcb httx zjsh zmhnj zhvsdc qsrh jsdcr gztf jrnfp trlmqn bccz pchhkp lhb qbnkj fjbjj dpkdp dxpdkp cgrcmp vlqtzzl zjsz rlxhc jgkp pkgsf jrlvkz nqhk tsnhq czlpq ckzdf vrzkz (contains nuts)
+tjxp xvmftv znklc ghfk svrx pbtns rgt fzgbq cgrcmp qvhdl lvjrbms rmpnm zmf cvz vzzxl bhlbm qllxhr pznl dfpqn ltxqz mbdksj bbkth jsdcr dkxr hdnq kxl nfzczn vpl jhrgz snxz trlmqn vrpzss njcjm gpplt zjsh dqdn ftfx zmhnj brhfcbt dmpl ztlbvp ctmzsr xcdb frnh nmszz jrcczb cpsbgsh vkjggtx knhvxm xfvtzq bxhsq xrlmvz rph jrnfp fhpxz cqbkj pdxhgx bqfqcjb lnpbh nmq frz gjvqffm klfp lqdpl rkzqs httx qdbj vrzkz pchhkp fzpds sks ttr gmx tqtbd (contains sesame, soy)
+lnpbh czlpq cpsbgsh zjsh rsrgmkr jmxpbtk vtrltkq cqbkj bxhsq vrzkz rnxl znfrgvc hqjgzmt pkgsf rlxhc dmpl lqdpl qbtpnr ghtjbp drpxzr scqc ztlbvp dxpdkp znklc kxl hphcb ctmzsr cgrcmp xlqj tkrr mkpxx rkzqs qvhdl qdbq gjvqffm cf gztf qglps gbzcv zpbbvvm frnh vfnv qbnkj vfhvp sks zvmnv mbdksj jrlvkz qlt rvnfn vkjggtx zmhnj (contains nuts, sesame)
+pkgsf rkzqs ckzdf fvvjp lhsgbq tsnhq tkrr qvhft qnt jtfnm vrzkz mkpxx lqtnn nllks qdbj pmhnmxr qdbq httx nmq pjgxpg bqfqcjb lmpxcr vlqtzzl rzjcs rncjx rvnfn cgrcmp ctmzsr rmpnm dmpl gnrb dfpqn jhrgz zjdzx nlxh zvmnv fvpj zjsh drpxzr mxk hbvqn vrtfrj jrnfp ghtjbp trlmqn dlc bccz hbbz nqstv vttzh pkmbk fzgbq bgdq ssgkt vrpzss vzzxl mbdksj hhth zmhnj dxpdkp rmthpj lqdpl (contains soy)
+ltxqz vttzh frnh hdkc rmthpj hxfrh bgdq jtfnm qbtpnr rlxhc tnjxcf lvjrbms ttr scqc dxpdkp rncjx hphcb vkjggtx qfvvf qzbzd jrnfp xlqj jrlvkz lsc rvnfn knqlqt zjdzx hqlm gbzcv qbnkj mbdksj qnt qpgj dkxr gjvqffm vllxj hmshx znfrgvc nvhnsg tqtbd hkzzg zpbbvvm cpsbgsh zdrlf sltl pkmbk rzjcs fzgbq trlmqn vzzxl czlpq rkzqs fptpk jgxbzks nqhk slmjchql vrtfrj ftfx ghfk fhpxz ctmzsr fmkbnr rls rcv snxz qlt zqgzlr zmhnj bqb nlxh vrpzss pchhkp vrzkz (contains soy)
+jrcczb xfvtzq nmszz sbsrk dpkdp pdxhgx cgrcmp qbnkj mbdksj rkzqs scqc rxzxs xzhct mkpxx ttr qglps vzzxl xlqj jsdcr pbtns qzbzd fvvjp vllxj zjsz frnh gnrb vpl zdrlf gztf vrpzss vrzkz dmpl hphcb gbzcv rgt kxl ctmzsr nlxh zjsh lvjrbms sltl brhfcbt lsc pmhnmxr fhpxz qsrh vkjggtx zcxxdp drpxzr jgxbzks (contains peanuts)
+tcp vlqtzzl zjsh rkzqs drpxzr cqbkj ftfx gbzcv xvmftv fptpk rncjx rnxl jtfnm nqstv znfrgvc jsdcr zmhnj jrnfp qfnq hphcb vzzxl bbkth flhzd jgxbzks ssgkt xcdb fvpj rlxhc ztrpkb qsrh qbtpnr bqfqcjb xzhct pznl hdnq qlt tjxp lvjrbms fhpxz cpj dpkdp mbdksj qpgj vrzkz xrlmvz rvnfn snxz hdkc ltxqz zjsz hxfrh pmhnmxr (contains nuts, fish, peanuts)
+vrtfrj ctmzsr zpbbvvm nvdst qvhdl rlxhc pbtns tcp lsc vrzkz dqdn hmshx fptpk rph rgt vllxj dbfk dkxr ttr nmszz qvhft znjp fhpxz jgv ftfx zjdzx zjsh znfrgvc qdbj vkjggtx znklc lhsgbq jsdcr frz pspjgzx pkmbk vpl pkgsf vfnv dnzljk hqlm klfp zmhnj njcjm pdxhgx dlc cntfbt ghtjbp qpgj rkzqs vtrltkq jrcczb fzgbq fjbjj vzzxl cgrcmp lvjrbms vlqtzzl hphcb svrx dmpl dxpdkp pjgxpg bbkth ztlbvp rncjx cqbkj (contains shellfish, eggs, soy)
+spzmvfl bccz xzhct qdbj qllxhr jgv rkzqs slglnd qlt tjxp rncjx rnxl fvpj fjbjj zhvsdc qnt nvbr mbdksj tkrr hphcb rcv znklc qdbq fzgbq nlxh rph rlxhc msvgj lhsgbq dfpqn cqbkj vrzkz znfrgvc tqtbd cntfbt zmhnj vrpzss xrlmvz flhzd zjsh httx znjp nmszz pbmhl pspjgzx ctmzsr kxl ftfx qzbzd zpbbvvm scqc jtfnm njcjm fvvjp (contains soy, shellfish, fish)
+brhns bbkth jtfnm znklc xzhct jrnfp tcp fptpk cqbkj mkpxx vpl ssgkt jgkp rmthpj hxfrh fvvjp zjsh pkgsf fzpds zmhnj tqtbd ltxqz rkzqs pmhnmxr rnxl gztf qvhft rxzxs qsrh ctmzsr fvd sks qbnkj xrlmvz rzjcs zmf hbvqn qbtpnr mbdksj nlxh nvdst ghtjbp slmjchql hphcb lhb zvmnv xcdb vllxj hmshx znjp vrpzss dbfk pchhkp klfp lqtnn bxhsq slglnd vlqtzzl cvz zdrlf vrzkz cpsbgsh nvhnsg pkmbk fzgbq dfpqn dlc fmkbnr cvtj (contains dairy)
+jtzsqznl bhlbm lsc lhb zpbbvvm ftfx znjp hphcb nqstv zjsh dksfbk pchhkp fzgbq pmhnmxr vrpzss knhvxm mbdksj pbmhl rkzqs httx bqfqcjb qvhft lqdpl jrlvkz zmhnj sks qbnkj nvdst czlpq pznl tnjxcf tkrr vrzkz hkzzg cf zdrlf nfzczn jrnfp gmx spzmvfl vzzxl rnxl znfrgvc dqdn jgxbzks jtfnm xcdb (contains nuts)
diff --git a/2020/inputs/day21_short b/2020/inputs/day21_short
new file mode 100644
index 0000000..6940ed2
--- /dev/null
+++ b/2020/inputs/day21_short
@@ -0,0 +1,4 @@
+mxmxvkd kfcds sqjhc nhms (contains dairy, fish)
+trh fvjkl sbzzf mxmxvkd (contains dairy)
+sqjhc fvjkl (contains soy)
+sqjhc mxmxvkd sbzzf (contains fish) \ No newline at end of file
diff --git a/2020/inputs/day22 b/2020/inputs/day22
new file mode 100644
index 0000000..126d35a
--- /dev/null
+++ b/2020/inputs/day22
@@ -0,0 +1,53 @@
+Player 1:
+42
+29
+12
+40
+47
+26
+11
+39
+41
+13
+8
+50
+44
+33
+5
+27
+10
+25
+17
+1
+28
+22
+6
+32
+35
+
+Player 2:
+19
+34
+38
+21
+43
+14
+23
+46
+16
+3
+36
+31
+37
+45
+30
+15
+49
+48
+24
+9
+2
+18
+4
+7
+20 \ No newline at end of file
diff --git a/2020/inputs/day22_short b/2020/inputs/day22_short
new file mode 100644
index 0000000..24d78bf
--- /dev/null
+++ b/2020/inputs/day22_short
@@ -0,0 +1,13 @@
+Player 1:
+9
+2
+6
+3
+1
+
+Player 2:
+5
+8
+4
+7
+10 \ No newline at end of file
diff --git a/2020/inputs/day23 b/2020/inputs/day23
new file mode 100644
index 0000000..9bab251
--- /dev/null
+++ b/2020/inputs/day23
@@ -0,0 +1 @@
+598162734 \ No newline at end of file
diff --git a/2020/inputs/day23_short b/2020/inputs/day23_short
new file mode 100644
index 0000000..7a64a0a
--- /dev/null
+++ b/2020/inputs/day23_short
@@ -0,0 +1 @@
+389125467 \ No newline at end of file
diff --git a/2020/inputs/day24 b/2020/inputs/day24
new file mode 100644
index 0000000..17d4e9e
--- /dev/null
+++ b/2020/inputs/day24
@@ -0,0 +1,403 @@
+nenwswenweswweenesweeenenwee
+nwnwnwnwswenenenwneswneenwnenenwnenwsw
+weweeeeneneseswesesweeesenwnw
+wnwwwwwnwwnewsewnwenwwnww
+enwnwsenwnenwnwseenwswnweseswenwswnwsw
+nwseseswsenwseswseseswsenweseeeenwnwsese
+senwwwwnweeswewwwewwnenenwswse
+swnwneswnweneneneswneneeneswne
+ewsenwweneeeenwnwneneswnewwswesene
+sesenwsweseseswnenenwnweenwseenewee
+seswwwswwnwnwsewneenenenwnwneneseww
+nenenenenenenenenwsenewne
+swwnwswswswwswswswswswswswe
+nenwswnesesesesesesesesesesenwsenwsesesew
+wswwneswswswweeswswwwswnwswswseswnew
+wwwwwnwwewenwwwwswnwwew
+neenwnwnwnenenenenwenenwnwwwnwswswse
+swwneswswswswnwseswswswswswsw
+seseseenesewnwseseeswwseseeseneesesw
+nesenwswseswnwwseswwwseswwnenewswwwse
+wwwwwwswewww
+seenewewenwneswneneneneneneswnenee
+sesewnwsenwnwesesweneswseseseswnwsee
+nenwnenenwnwnwswnenwnwsenenwnenwwnwnwne
+seseswneeneeseeewwnwseesenwsenwsee
+seseeeeseseweesesesewnesesesenwsene
+swwswswseswwwswnewe
+swwswswswwseneswswseswswwnewswwwsw
+neeswneneneenenenene
+neeswseseswswnwwseswnwwswswseseseseseswne
+ewneneneenewewnenewseneenwneeesw
+enwnenwneeeeseeeeswenweeneseese
+nwwnwnwnwnwnwnenenenenenenenenwsenwsene
+nwseenwnwnwnenwnwwsenwnwne
+seseswsenwswseswswswseeseswse
+seswneswswswswswswswswwwswsw
+enesenenwesesweeweeswseseeseseew
+wwswnwweneswneenwsesesenwnwsenwwnw
+swnwwnwswwewsenewenwnewseswnwwww
+wswewnwwswwnwswswswswswwswsweswesww
+swesenwnweeneseseseswswwnwsewwenwswne
+wwwswwsewwwwswwwwwnw
+neeenwwwswnewnenwnwsenwsewwwww
+seneswswsewswneswswseswswseseseseewnwsese
+nenenenewneneneneneneneneeseneweese
+wswsweeswswwswswswswwswswwswwnwsw
+wwwseswnewswswswwwwwwsw
+wnwnwnwwnwnwnwnenwenenweneswsewenwnwnw
+wwweswewnewwnwswsewwwwwnwnenw
+nwnwsweneeeseeseeeseesesesenwseswese
+nwwswswswwswwswewwwwsenwswsenwsww
+senwnenwnwnwnwnwnwnwnwnwnwnwsw
+neswnwseswswswswswswswswswsweswwswe
+eeeeeeeseenwnweeseesweeeenw
+swseseseswswwnwneswewwnwnwseeswnwswwne
+neesenwseesesewwnwseeseseenwnesw
+neswswswwwswswsesweswswsw
+eeneeewsenweseeeweeeneswee
+nwnenweneewnwnwnwwnwwwswnwsenwnwnwnw
+newneeneseneneswnenwnenenesenewnwsw
+seseneeewsweneneeeneseneeeswwwene
+swswswswseswswwsesesesweswswswneneswsww
+eeeeswneneeewseewneeseeee
+neeeneneneeeneneewneewwwnesenene
+eneswnwnenwneeswwswneeeenenwenese
+seenwseseseeneeseseeseseseweseswsese
+seswnwswswenewnewnwswsw
+wwwwwwwwwwwneswswwwnewswse
+seeseswseseseswwsesese
+nenenewenenewesenesewesenwewnewne
+nwneseneeneseneswneneneewneewnee
+nenenwneneewewneeseneeneeneeese
+eswnwswwswsewweswwnwneswwwswww
+neseswnweeeeseeeswee
+wwwwnwswwwswswswnwsese
+wseseswswwswswswnweswswsesweseesw
+nwneneneeewewwneneneeeeeswese
+eesesesewnwseenweeeeesenweseswse
+neneneneenenwneswneneneneeeneee
+wswswsweeseswswswswwnwnwwsw
+wseewesenwnwneswnenweewneneswwnw
+nwneeswswseswwseseneswesenenwsenesww
+nwsewwwwswswwsenw
+swswswewswnwswwswswnwewswwseswww
+swswwwsewwnenesewwswswswwwwww
+nenwnwnwwnwnwnwnwnwnwenwswnwnwnwnwsenwnw
+neneneneneneneneneneneneneneswe
+nwwwswenwwneenwnwwswewnwwnwsww
+eseswseswwnwneswneswsesewswnenesesw
+wwwwwnwnwwwe
+senwenenewwnewswneewnesewsenenenesene
+sewewneewnwneenenenenweneese
+swswswewwwewneswswwswswswswwww
+swwnwneneenenenenwnwnenewnwseswnwsenenw
+swnenwneenenwnwnwnwsenwnwnwnwnwnwnwnwnw
+neswsesewswseeeneseswnwwswswsw
+ewwwwswwwswwneswwwewnwnewwsene
+nwnwnenwnwnwsewnweneswwswnwnwsenewnee
+ewneseeeeeeewenweseeeeeee
+nwseswwswseewwnwwwnwwnwwwseswene
+swswwswweswswewswswswsw
+nwnwneswnwneenwnwnwneswnenwnwnwnenenwne
+eswweeeeswseenewenwsenwesesese
+seswnwneswnenenwnwnwesenesenwswnenenwnene
+nenwnenenwwnenwnwnenwnwsenwnwswse
+newwwweswswswwswseenewwseseswnwsw
+nwwnwsesenwnwnesenwnwswnwewnwnenenwnwnw
+nwneneneneneneneeswnwnenenwne
+wnwnwsenwnesenenenenenwnenwne
+nenenwnenewnesenenewseneneeneneseenenesw
+wneneswnwnenwnwswneeseenwseswnesesenww
+swseswseseswseswneswseswsewseswsese
+weeesweeesenwseeee
+nenwswswnenwweswseseseewseneneseswe
+neweewneswneenweeneesweewnenene
+nesesweenenewneenenenewesenesenew
+swswswswseseswseswswswswswnw
+neneswwwwwwwwwwsewsenewwswww
+nenenenwnenenenewsenenesenenewnenwnwne
+neeneeswneeseeseenenwnwwseswewee
+swswswswnwseseswneseswseseswswswwnenesw
+neeswnenwneeeeweswswsweneneenwe
+wsenweswseenwsewsesenwsenesesesesesenesw
+seseswseseseswneswswse
+swnewswwwsesewswnewwwswwswswswww
+senewneneneseneenenenwewenwwnwswsw
+weseneneseseseeeweeseswsweenesese
+swnewwswnwseswswswseswswwwswswswswne
+neneeenenweneneswenenesenwewneenesw
+seseseseneseswseseswswsewsenwseseesesese
+nenenwnwnwnenwnenenesenenwwneneneene
+nwnwnwsenenenwneswwnwnwnesenwnenenenew
+neeeeeweneseeweweeneeneenee
+wneneeneneenewneneeeeseeneneseeswe
+eswwwnwwnwwnwwwwwwwenwswneswe
+eseswwsweseeeneenewe
+sesesweseseswsesesenwseseseseweseswne
+sewseseseseseseseeseseseneseesenesw
+swwneewswwwnwwswswwenwewnwnwnww
+eneneeeenwsenwnwesesweeeeswee
+wwwwwwswwswwnew
+swswwwswwnwewwnwneswwnwseneneww
+swnewnwnewnwwsweseeseswwswnenenwsee
+swewswswwswswswswseswswswswesweswswnw
+neswswseswswswswswswswneswswwnweswswe
+seeseseneseswswwsewseseenwsesenwseswsw
+esewneswnewwesewneswneneneneeenwe
+nesewnenesweneeeneneenenenenwnenenese
+nwnenwnwwnwnenwnenwnwneeeneswnwnwenww
+eeeeeeswwwwnesenenwenwsenewsw
+nwswweswsweswsenwneswewswwswnesenwsw
+sesenwseseseseesesesesesesesesesesw
+nenesenenwnenwnwwnenwneneswnewesenene
+swnwwswswwwnenwwseswwwwnewewsee
+esesewswswsenwswswswnenewsw
+nwnwnwwnwnwnwnwnwse
+eeneenenewsenenewwnenenenenenesenwe
+sweseswswseneseswswswnwswnwswswseswswse
+eeseneeneneneeenenweeeeswnwee
+swswwewswwwnenwseswwswswswswswswsww
+neswswswnwwswnwseswweswswwswsww
+nwswnenwnewnweseneneeswswneswnwnwnesene
+ewnenwswwwnwnwnwnwnwwswwwwwwne
+wswseseseeseswnwwenenwneswsenesenwse
+nwnenenwseneswswsee
+nenenenenenwnewswnwnenwswnwnwenenwnwe
+neweweweswesenweesesenw
+eenwneeeeenwwneeseseseseswwsese
+seeseneswseeseeeee
+nwneswswnwwweswnenewwnwneseseswwwse
+newwwswwnwwnwnww
+neneeneseswnwenenesweneeneneweeew
+wswswnwneswenesenwnwnewnwsenenwnenesenenw
+wneneeneseswnweseseneewswenwnenwsese
+nwsweswswswwsweswswsenwwenweswneenw
+seneswswswswswseswswswswswswneswswswnwswse
+wswswneneneswswswswwsewswwnew
+enwsenwsenwswswewnewewnwweseww
+wswswseswsewwswwwwwswwwwnwnew
+swneswswswewswswswwwseswswswswswwswnw
+seeneweseeseeeswseeneseneswnwweswse
+eeeseweswseweeeeeswsenwneewe
+swnweneneeneeeneeenenewneneeene
+eeeeneseeeseneeswsenenweewnwnw
+swswswnewwseswseswswswseseneswewnwswe
+nwswswneeseswneswnwnwswsesw
+wwnwwswwwsewwswwwww
+sweeneeeneenwesweseeeneenweee
+nwwswsenwnwswnwnwnwswseeseseneenenwse
+nwwnenwnwnwswwwwwnwnwww
+wwwswnwnesenesewwseneesenwneseewsw
+nwnweenwnwnwswnwwnenwwsweswnweswene
+nenwnwnwnwneenenewwneswnenese
+nenenwnewnwsenwnewsweenene
+nwneenwneswsweswneseeswswsenenenenwnw
+swswseswseseneseseseseseswswswsenenweswse
+senwswwsenwswsenwswswswswswswswswswww
+nwnwenwneswnwnwnwnwnenwnwnwnwnwnwnw
+nwnwwenewnwnwswswwe
+swsweseswseswnwnesesesenesewseswseswne
+swseneswswneswwswnenwwswseseswneswswseswsw
+swswseswswswswwwseswswneswswwnewswsw
+seswseswseneswseeswsenwswseswsesewswswse
+nenenenenewnenwnenenesenenesenenenenene
+wnwnwsenenwwnwnwnwwnwwnwswnwwwee
+nesesesesesesesenwsewseesesesewnesesese
+seesesesesenenwsesesesweesesesesese
+nwseeesweneswnenweswwwwnwnwnwnwswene
+wswwswnenwnenesweswneswswseswswswsesenenw
+eesweeeeeeeenw
+wnwwwnwsewwnwnwwnwwsenwnenwwewnw
+nwswnwsewswnwnewswwneenwnenwsewnenwnw
+nenweenwneneneneswswneswsenwnenenenenenwse
+nwnenenenenwnenesenewnesenenenenenenwne
+seeeeeeseswnweeee
+swswwwnwwwwewswwwwwswwewnw
+wswwwswswnwwneseswseswwnewwswwnwse
+sesesenewseeeseseswe
+wswwsewwwwneswswwwwwnewswsew
+eneeenweneneswnwneneeeneeeeese
+neenenwneeeneeeneneneneneeswnenesw
+nwswenwseeseesenenwneswseeesewesw
+sewwneswswwsewnwswnwswsewnenewwsww
+wseswwsenwnwnewsesenwwsenwneeswwnee
+nwswseeeseeesesew
+nwwsewnwnenwnwenwswswnwsewwesewe
+ewneeeeeeweeeeeesweeenwe
+neswswswwswswnwswnwseswswswwswseeseswsw
+seseneeseeseneseeeewseseswseseenwse
+nwnwnwnwsenwwnwnenwwnenwnwwnwnwswnww
+nwseweseseswnwweneseswseneswswswswswnw
+swwswwwswswnwwweswswwwewswww
+nwnwnwswsenenenwwwseswnwnwnwesenwnwwnww
+eeeseeeeseswenwnwee
+enewneneeneseeeneeneeeeseeeew
+nwwnwnwswseswwnwnewnesewwneswnwesenw
+neeseswwwnwswwneeseswnewenwswswswsw
+seseswseswnwnwenwsesenwneewwneseee
+seseswswswesesenwseswnwswsene
+nenwewneswneeeneneneseeeneneneee
+sesesesesenwseseswseswsesesewnwsenesesw
+nwnwswneswnwseenwnwswneswnwesesenwnwe
+nwnwenewsweswnwsesenenewwnwnweswnw
+nenwneneswseenenewsenwnwswnwwnwnwnenenew
+sewseseseseswseswnesesesesesesese
+neweeneeneneeeesenenwswswneneneneee
+eneneeswwseneneswnenweeweswnenwswnw
+senwswnenwnwnenenenwnewnwnenwsenwwnwnene
+neswneswsenwswsewseenweseeeewsesese
+seseseswseesewnweseeesenwseseswseenwse
+sewwsesewwwwwwwnewwwnwwnwnw
+nweneswnenwenwnenenenwnwnenwneswwnwnw
+neneeneneneswenwneswnwnenwnwnwnwwswnene
+nwwnwnwnwnenwnwnwnwnwswnwnwnwsenw
+swwnwewwwsewswsww
+eeseeseeeeseseseseswnwwseesesese
+enwsenwseswwnwnwnenwnwwnwnwnwsenwnenew
+ewneeneseneeseneneenwneneeneenenesw
+seseseswnwsenenwseese
+wswswwwwwneseww
+neewneeswsenwnwnwnenenwnenwswnwnenwnw
+neneseseswneswnwnwesenwnweenwnwnwswsenww
+wwwnwnwwseenwsewwwwewwnenwnwsw
+nwnenwnwwwwnwnwenwnwwnwswwnwenw
+swseswwneesesesewseseseesesesenwswsese
+swswseeseseseseswswswswswwswswseneswnwsw
+senenesweewnweesewweneneseneeene
+wwwwnewwwwwsewwsewswwwwnew
+ewsesesesesesesenwswsese
+swswwswswneeswnwswwseswswsee
+sewnwwnewnwnewwwwwnenwsesewwnwww
+nenwneneneneneneneneseneeneneneswnw
+nwneseseeeswweee
+swwnwswwewswwseeswenwswswswswswsw
+swswneseswswswswnwswswswseeswswswswnwne
+wnwnewneenenesesenesweswneeswenene
+nwseseseseseswnwwseeseseeseseseesese
+eswnwswwnwwewwwnwnwsewenenwwse
+ewwswwwnenwewewwesewewww
+swseneseswswswswwswswswnwswswswsweswswnw
+swwwswnwwweewnwsew
+eeeeseseewnweewsweeeeeee
+nwnwnwnwnenwsenwnenwewnenwewnwsewnwnwnw
+nwsewnwnwnwneswnenwnenwnenwnwnenwswesw
+swnwnwwwewwnwwewwwewwswnwnw
+eneeeesweewnenwnenesewewnee
+nwnwnwswwnwnwnwwwsenwwwne
+eeeseeeseeweseeseseweeesenwse
+eswsewswswswswswswswwswswnwswsw
+seseeeseeeeeeesenwsw
+esweeswsesewseeneseseseneeswnwsenesew
+swswswswnweneseeseswseswwswswswswswsw
+wwwwswwswwneswswwwsww
+swswwsweswnwswswswsw
+nenenwsewsenewnenewnenwnwswneseneseswe
+seseswseseswswswswswswneswwswsenenwsesw
+swsewsenesesenwseseseseenwseesenesesw
+enwwwswwnwesweswsenesewwswswwnw
+nwswnwnwnwnwnenwnwnwnwnwnwnwnesenweneswnww
+swswswewwswseseswswwnwnwnwswneeswnww
+wswneenwewnweneswneneneesw
+seeeseswwseeneseweeswnenweswsenew
+nwnwnewnewnwwwwwsewwnwwswnwwese
+eeswnenwswswswswwswswswsw
+nwnenwneneneneneswneenenenwnwnwnenwnwsw
+seseseeeeseeseseseeswswnenwwe
+swwnewnwsewnwwnenenwwnwwsesewwnwnew
+nwnwsewnwneenwnwnwnwnenwnwneswsenenwnw
+wwwwwswwewwwwewnewwweww
+wnwsenwwsewnwwwnwnwnesenewnwswnew
+swsenesesenesesesesesesesewswesesesese
+seseneswswwseseseseseswneswseswseseesese
+enesenenwseneseseswweseeseneswwwsese
+sesesesenesewseseesesesewwswneseseesw
+eeeseeeeweesenenweeseseswese
+swnwnwswnweswenesenwsenwseewneneswsesw
+sewswseenesesesenwnwsenenwseesesewnesw
+swswswswswsweswnewswswsesenenwswswnwsw
+enesweeeneseeseswwseeeenweese
+esenwwnwswseneneseswneseesenesewse
+swswsesewswnesewsewneseneseswswnesese
+eseweeswseeeeseesenenee
+newneswswwwswswwwwwwswnewwwwsesw
+nenenewswnwswnesenwnwnenenenwnwnwnenwne
+wseswnewsewswwnwswnewwwwwswwww
+wwwswwwnwwwwenwwnwwnww
+weeeeeesweenweswwneeeeeeee
+wneswswswnwswswsewswwsewsw
+seenwewseseseseseeseeesesesenweesw
+neswnenenwwnwenwnwnwnwwenenene
+wnewwseeswwnewneswnenwswwwwsww
+swswnwneswnweswseswswswswwwwsweswwsw
+wswsenwwswswwswwweneswswwswswswnew
+nwnwwwenwesenwseswnwnw
+seneneeeneenewe
+nwwnweenenwwnwnwsenwswnwnweswnenwswnwne
+nwnwnwnwsenwnwnwnenenwnwsenwnenwnwenwnww
+seswnwseswswseeneswwseseswseswswswseswsw
+swswneswwswswnewswwwnweswswnesesenw
+seswswseseswswsesenesw
+seseneswseseseseseesenesesesewsenenwsw
+neneneenenwswnwnwneneswnewnwnewnenwee
+seseswsewswnwseseswsesweseseeseswnesesw
+wwnenenwswsenwnwneneeswseeswew
+swwswnwnwseseseswnwseenenwseswnweswenw
+nwswwswswswswswswsweswnewsweseswswnesw
+sewwswwwnwwenwwnesenewnwswwswsene
+swseswsesesesenwseweseswseseswswsenwseese
+seseeseseesesenweeesweweesee
+wewswnwnwswenwnwswewseneneswsewwne
+esesenwseseenwswnewswenwseseseswnwswnw
+neswswseseseseseswseswswwnenwseseseswese
+seeeesesesesenwsenesewseesenwsesww
+swswseswsweswwswswswseswseswswnwswsw
+neeneeeneseeenwsweeeseeenwwne
+swwesesesenesenenewsesenewseesewsese
+nenwnwnwwwnwswnwnwsenwwwwnewwnwnw
+eweneeenweewsweeeeeeseneese
+newneswneneneeeseswneneswneneneswnwsw
+nweeeeeeeeweweeeeeesese
+sewnwwwwwewenwnwnwwwwwwwww
+nenewneenenenenwwnenwnenenenenenwe
+eswswnesesewneseseswnwwswne
+eeseesweeewseseeeneeese
+wneswsewwseesesenwneeseseswneswnwsesw
+swwswseswsesesweseswseswsw
+swswswwswswswsenwswswswswwswseswnenwswsw
+seneswweeneswnwneeneeeseweeew
+swswsweswnewnenesenwseseswswseseswsww
+nwnesewsweswwwsenewwnewwwwww
+ewneseseeeenewnenenweeneeswnene
+wwwwwwnwwwewseewnenwwwnwwsw
+wwwseswwsewswneswwneswwwwwwnw
+nenwnesenwnenwneenwnwnwnwnwnenwnwnwwsesw
+swneenwwswenwenweseeweeese
+nwwnwenwnweseswneewnwenwswnwwnwswnw
+nwwnwsenenwnwseneswnwneswnwnwnenwnenenenw
+nenenwnwsenenenenenenenwnenwnwnw
+nenwwseeneneswwsesenesenwnenenwsenenee
+nwwswswenwwnwsenwweneenwnenwnwwwww
+wnwswnewwwwwswnwnwwwnewwnwwswne
+nwsenwnwswnwnwswnenwnenenwnenwnwnwnwnenw
+ewnenenewneneneneenenenenwnenene
+nwsesesenwnwseeseseseseeseseesweesesw
+seeswnenesewnenwnenenwnenwneneneswenene
+seeeswenwseswneeese
+swenwenwswswseneswsenw
+wnwnwwnwnwsewnwnwnwnenwnwnwnwsewnenw
+nwwsenwnwsenenwnwnwnwnwnwnwwnwnenenwnenw
+sesesesenenwseeseseswseseseseswe
+swwwneseswswnewswwwswswswwnewswswww
+wwnwwnwnewnwnwswwnwwnwnw
+wsenwswesenwneswswseswswswewsweswswnw
+eeseneeeeesweeewwneeseeneesw
+ewnenwnwnwswnwnwwsewwwnwnwewsenwnww
+nwesewsesesweeseesenenesesewseseesese
+seesweewneseseseenwseswneswenwsesenwse
+weeneswnesweswenwwnwnewswsenwene
+nwnwnwwwnwwwsenwneweswswwenwnwsene
+nwnwnwnwwnwnwwnwnwwwswwwnwsewnwe
+swneneeswseenwseneswnweenewnweenenw
+eweeneswenweneenwsweeeene
+nwnwnenwewseseneseneswwnenwnenwnwnwsenew
diff --git a/2020/inputs/day24_short b/2020/inputs/day24_short
new file mode 100644
index 0000000..55460d5
--- /dev/null
+++ b/2020/inputs/day24_short
@@ -0,0 +1,20 @@
+sesenwnenenewseeswwswswwnenewsewsw
+neeenesenwnwwswnenewnwwsewnenwseswesw
+seswneswswsenwwnwse
+nwnwneseeswswnenewneswwnewseswneseene
+swweswneswnenwsewnwneneseenw
+eesenwseswswnenwswnwnwsewwnwsene
+sewnenenenesenwsewnenwwwse
+wenwwweseeeweswwwnwwe
+wsweesenenewnwwnwsenewsenwwsesesenwne
+neeswseenwwswnwswswnw
+nenwswwsewswnenenewsenwsenwnesesenew
+enewnwewneswsewnwswenweswnenwsenwsw
+sweneswneswneneenwnewenewwneswswnese
+swwesenesewenwneswnwwneseswwne
+enesenwswwswneneswsenwnewswseenwsese
+wnwnesenesenenwwnenwsewesewsesesew
+nenewswnwewswnenesenwnesewesw
+eneswnwswnwsenenwnwnwwseeswneewsenese
+neswnwewnwnwseenwseesewsenwsweewe
+wseweeenwnesenwwwswnew \ No newline at end of file
diff --git a/2020/inputs/day25 b/2020/inputs/day25
new file mode 100644
index 0000000..cef9673
--- /dev/null
+++ b/2020/inputs/day25
@@ -0,0 +1,2 @@
+19241437
+17346587
diff --git a/2020/inputs/day25_short b/2020/inputs/day25_short
new file mode 100644
index 0000000..9cbfc23
--- /dev/null
+++ b/2020/inputs/day25_short
@@ -0,0 +1,2 @@
+5764801
+17807724
diff --git a/2020/inputs/day3 b/2020/inputs/day3
new file mode 100644
index 0000000..7a7786b
--- /dev/null
+++ b/2020/inputs/day3
@@ -0,0 +1,323 @@
+.........#....#.###.........##.
+..###.#......#......#.......##.
+##....#.#.......#.....#........
+#........#..........#.#...#...#
+#....###...##.....#........#...
+###..............##..#.....#...
+.................##.#..........
+.........##......#..###.....#.#
+..#..#...#.#.#...#.#.#.##...#..
+..............#.#.#..#..#..#...
+.#.#.#....#.........#.........#
+..#.#....##..#...#.....#..##..#
+............#.....#.........##.
+...#.#..#..........#.##.....#..
+#......#...##.......###........
+.....#....#.#..............#...
+.....#.......#..##.###.....#.#.
+.#.....#....##.#......##......#
+..##...##.........#..#.#..#....
+............#.......#.....#....
+.......................#...####
+.#.#.......#..#....#....##..#.#
+..#.##.#.#...............#.....
+#..##..#...#.....##..#...##.#..
+##...#....#####.....##...#...##
+.#..##..#..#.#..##.#.#........#
+....#..#........##......#.#....
+..#......#...##.#..##.......#..
+.#.#....#.#..#.....#..#...#....
+.....#.#.................#.....
+##.#........#.....#...........#
+#............#.....#..#.#...##.
+..#.#..#......#.......#......##
+....#.#....#...#....#..........
+.........#...#.##..#...#...#...
+....#...#...#..................
+..##...#.#....#...#......#.....
+#....#.......##..#...#..#......
+.#....##..#.#....#...##...#....
+#.................#...#.#...#..
+.#.....#..........#.......#....
+.#..........#.##....#.##......#
+#.#.....##.##..#.......#..#....
+.....#...#............#..##....
+...#.#.##.#..........#.#....#..
+.......#...#............#.....#
+..........#...##..#....###....#
+............#....#......###....
+...................####..#.##..
+...#.#.##.........#..#.#.......
+...........#.........#..###....
+.........#.........#...#...###.
+.#.#.##....#.#...........#.#...
+..###.....#...#.#.......##..#..
+.....#.#........#.#....#....##.
+......#...#........#.........#.
+...............#.........#.#...
+..#...#...#...#.###..###....#..
+#..#.......#..###.##.......#...
+#.#.........##..#.....###..#..#
+...#....#....#.#..#............
+..###..##....................#.
+..#.......#..........#.##......
+..##........#...###..##.#......
+......#.#...#.....#..##..#.....
+#........#......#..............
+........#........#.......#....#
+.....#.......#......#........##
+#.#......#.#...##.#.......#....
+#...................##...#.....
+..#.#...#..#...#..#.....#..#...
+.......##..................##..
+.............#..##.#......##..#
+###...........##.#....###..#...
+.#..........##...#..#......#...
+..#.###.#....#........#........
+....#....###.....#.......#.....
+.....##....#..##...#..#........
+.##...#..#....#..#.........#...
+#.........##....#..##..##......
+.#.#.............#.....##......
+..#.#............#.......##.#..
+..#.##..#.........#......#.#.#.
+.#...#...#..#....#...#....#.#.#
+....#...#..#.##..##.......##...
+.#.....#.....#............#....
+..........#....#..#..#......#..
+.............#....#..#.........
+....#.#.#.......#....#.#.......
+..##....#.#....#...#........###
+#...#..........#..........###..
+...#..#...#...#..##......#...#.
+.....................#...#..#.#
+#..#............#.........#.##.
+..#...#...........#.......#....
+.....##..........#...##.....##.
+.#.....#.#........##...........
+..#....#..#.#..##...#.........#
+.........#.###.##....#..###....
+.........#...##...##.#.#....##.
+...#..##.#...........#....#....
+..........#.#...........##.....
+...........#..........#...##...
+.........#..........#...#.#...#
+......#..#.................#...
+.....#...........#..#...#..###.
+.....#..#....#.#.##...##....##.
+...##.###.#.#..#.#....##.#.#...
+###.....#.....#........#...#...
+.#....#........#.#....#..#...##
+##.....#.....#......#.#..#...##
+.##....#...............#.......
+#.#.....#.#....#.........#.....
+..#...............#.......##...
+#...#.###..#....#.#.#..#.#.....
+##.###....##...#....#.....#....
+.......#................##.....
+....#....##..#....#..#......#..
+...#.........#...#........##.##
+.#..............#..............
+..##.......#.###..##.#.........
+..#...#...#...#...#...#.....##.
+.....#..##...#.....##..#.#.....
+..#.............#...#.........#
+#.........................#..##
+.............#..###........#...
+......#..#....#.##.......#..#..
+...#..#..#...#....#..#...##...#
+.##............#.......###.#...
+.#........#..#.................
+#.#.#.....##....##...#.....#.#.
+...##.......#.#......#...#.#...
+#.##....#.........#.....##...#.
+#...#..#....#.......#.##...##..
+.................##.#..##.#.#.#
+..#.............#.......#.#.##.
+#....##..................#...##
+..........#.......#..##........
+......#.#..#......#.#.........#
+#.#........#####......#.#.#....
+#..#........#.#..#.....#.......
+...#.............#.............
+.....#.......#......#..#.##..#.
+..#.........#..........#.##...#
+#.....#.#####......#.......###.
+.......#.....#...#.....#.#..#..
+#...#.#........#.#..#..#...#..#
+...#....#....##.....#..........
+.#.......##.......##...........
+...#.##.#.#..#....#...##....##.
+.#...#...#.........#...........
+.#.#.##..#.......#.#...#..#....
+.#....##.#.#...#......#......#.
+##..#..#..#..#.......#......#..
+.........#.#...........#....#.#
+........#....#.#...#.#..#......
+#.......#.#.................##.
+.....#..#..#....#.#........#.##
+.#..###..#....#..#........#.#..
+#...........#...#........#.....
+........#..#.#.#.#.......#....#
+....#..#..........#.#..#.....#.
+..####..........#..............
+....###.#..#........##..#......
+.#..#......##..........#...#...
+.#.....#....#......##.##...#.##
+..##.#.#......#.......##.......
+....##.......#..............#..
+........#.....##..............#
+.#...#....##.....#....#.......#
+....#.......###.......#.#.#....
+##.....##........#.....##......
+..........#.....#...##.#..#.#..
+..........#.#......#..........#
+..........#...#..#...#...#.....
+.#.......#..##.................
+.#........##..............#..#.
+.##...................#...#....
+.##....#.##.##........#........
+...##.....####.....#..#.......#
+...##.#...##...#.##............
+##.......#.....###..#..#...##..
+#.####...#...#...##..#..#....#.
+...#........##........#........
+#....#.#....##..#..#.##...#....
+...##....##....#.......#..###..
+..........#..#..........#..#.#.
+#..#....#.......#.......#....#.
+......#......#.....##..##.#..#.
+##.#.....#....#.......#...#...#
+..##..#.#...#...#.....###..##..
+....#..#.......#............##.
+#..##.#.#.....#####....#....#..
+.#........#...#.#..##.#.####.#.
+#...#...#.............#.#......
+.........#.....##..........#...
+.##....#....#........#......#.#
+#..###...#....#..........#.....
+.#...##.........#..#..#.#...#..
+#.#.#.......................#..
+#.....#..#.#............###....
+#...#.....#.....###..#..#.#.##.
+............#.........#.#.##...
+...#.......###......##......#..
+.#....#.#....##......##.#...#..
+.........#.......#....#...##..#
+................#.#.....#....#.
+.##......#....#..#..###..#...#.
+....##....#..#....#.##..#......
+.......#.#.....#..#............
+..........#....#....#..#..#....
+..#....#.....#.......#.........
+......#.........#.##..#....##.#
+..#..#.#.......##..#...##......
+...##..#.#.#...............##..
+..#.#.#......#....#.....#.##...
+..#.....#.#...........#....##..
+###.....##.....................
+.......#..#.................#..
+.#.#..#..#.........#......#...#
+##.......#.##.......#..........
+#..#.....#.....#.....#.......#.
+#..#.....#.....#..........#.#..
+.#....##....#.....#.......#.##.
+.....#.#......##..##.#.........
+#....##......#..#....#..##..#..
+#.##..#..#..............#...#..
+.#......#......#..#...........#
+..#.......#........#....#..#...
+.....##.#.......##....#.#....#.
+........#....................#.
+........#..#..........#........
+......#.#.....#.#.....#......#.
+#......##......###.##......#...
+...........###..#...#.......#..
+..#...###...#.....#....#...#..#
+.....##......#.#......##..#.#..
+#.#......##...#.....##...#...#.
+.#.#........#.......#.........#
+....#....#...##..........#.#...
+.#..##.#...#.#.....##......##..
+.#.....#..##....#....#....#..#.
+..#.......#.#.#..........#..#..
+#.#..#....#.##....#.......#....
+........##.........#..#.#......
+.......#.....#.##..##......#.#.
+.........................#.#.#.
+..#..............##.........#..
+.......###.#.#.......#.........
+#........#.....#.......#..#...#
+##....#..#....#...........#....
+..#..#.#.#.....#.#..#....#.....
+.#..##....#.##..#..............
+...#....##..#..#.##....#.#.....
+...##....#......##..#........#.
+....#......#....#....#........#
+...#..#...#.#...........#..#..#
+....#.#.#.........#...#...#....
+..........#....#......##....#.#
+..##..#...##.#...###.#.##......
+#........#.##......##.#........
+..#...#.##...#..........#.#...#
+...........#...........#.......
+......###....#..###..##........
+...#........#..#.#.............
+....#.#.....#.#............#..#
+##.#.....#........#....##.....#
+.......#.#...#..##.......#.#.#.
+#......##..#..#...#.....#..#.#.
+.#......###.....#..#.....#...#.
+....#.#.............#.##.......
+......#....#.....#.......#..#..
+#..#.#.#..#......#...#..#.#....
+#..............#.#....#...#....
+..#......#...##.#......#..#..#.
+.......##..#.##..#.#...#.....##
+.....#...........#....#.......#
+.#.........#..#..........##....
+#..##..#.#......##.......#..#..
+...#....#...........##.#.#.#..#
+#..#..#..#...........#....#.#.#
+.....##......#......#.#...#....
+.....#..##....###.....#....##..
+........#...##......#.....#..#.
+..#.#..#.#....#...#.......#....
+#.....#...#.....#.#.......#....
+......#...#.......#..##....#...
+#............#.....#....#......
+..##...#.....#..#......#...#...
+...#..#...#..#.......#........#
+...##.#.#........#........#....
+#.#..#......##.#..#..#......#..
+#.......#..#...................
+#.....#....#......#...........#
+.##.#...#.#...#..............##
+...###........#........#..##.#.
+..##....#.#.#.##..#.#......#...
+..#.#........#..............#..
+.......#.................##....
+..................#............
+....#.....#.#..............#.##
+......#.....#..#......#...#....
+..#....##......#...####....#.#.
+..........#...##...........##.#
+...#.#..#....#......#..#....#..
+#.........###...#.....#..#....#
+.#.#......##.#.....#...........
+...............#.#....##..#..#.
+..........#.#.#.#...#....##...#
+...#....##.................##..
+#..##..#...##.##.#......#.#.###
+#..#...#..#.....#...#.#..##...#
+..#................#...##....#.
+...#.....#.##.......##....#.#..
+....#.....#..#....##...........
+...............#..........#....
+....#...#........##...#........
+...#....#...#.###..............
+#.#....#.......#..#.##.##......
+.#.....#..#..#......#....#.#...
+...#..........................#
+............#.#..#.##......#...
+.....#..........#.#........#.#.
diff --git a/2020/inputs/day4 b/2020/inputs/day4
new file mode 100644
index 0000000..8cdfd0a
--- /dev/null
+++ b/2020/inputs/day4
@@ -0,0 +1,1000 @@
+hcl:#6b5442 ecl:brn iyr:2019
+pid:637485594 hgt:171cm
+eyr:2021 byr:1986
+
+eyr:2025 iyr:1938 byr:2014 hcl:#341e13
+hgt:66cm
+pid:70195175
+
+hcl:#efcc98
+iyr:2011 ecl:hzl
+eyr:2020 hgt:174cm pid:589700330
+
+hcl:#bba027 eyr:2027 cid:54
+ecl:brn pid:153cm
+iyr:2028 hgt:173cm
+byr:2004
+
+hcl:b45cec
+iyr:2011 ecl:oth hgt:185cm eyr:2029 pid:178cm
+
+hgt:185cm iyr:2016 eyr:2029 hcl:#888785 pid:026540921
+
+eyr:2025
+hcl:6962f7 byr:2015 ecl:oth iyr:1974
+hgt:191cm
+pid:2616015
+
+pid:268398556 iyr:2019 ecl:grn
+eyr:2027 byr:1951 hcl:#18171d hgt:67cm
+
+eyr:2029 hgt:153cm ecl:brn pid:183179186 byr:2013 hcl:#623a2f
+iyr:1957
+
+cid:121 iyr:1922 hcl:752fbc pid:79577560 byr:2025
+hgt:61cm eyr:1971
+
+iyr:2016
+eyr:2024 hcl:#18171d hgt:184cm
+ecl:hzl byr:1992 pid:751161201
+
+eyr:2021 ecl:blu byr:1938 iyr:2016 hcl:#b6652a pid:313406514 hgt:191cm
+
+hcl:#623a2f eyr:2021
+ecl:brn
+pid:145249653 hgt:167cm iyr:2019 byr:1991
+
+iyr:2022 pid:175cm
+byr:2021 eyr:2027 ecl:#f615b1
+hgt:172in hcl:#ceb3a1
+
+hgt:173in
+ecl:#0cba5e pid:1885981567 iyr:1968
+byr:1952
+eyr:1942
+
+ecl:oth eyr:2023 hgt:65cm pid:521737908 byr:1971 hcl:z iyr:2017
+
+byr:1936
+hcl:#cfa07d
+ecl:brn iyr:2011 pid:589047874
+eyr:2025
+
+hcl:#fffffd
+pid:912552538
+cid:159 hgt:160cm iyr:2012
+eyr:2023 ecl:hzl
+byr:1946
+
+iyr:2015
+ecl:amb hgt:72in
+cid:59 pid:782818257 hcl:#18171d eyr:2026
+byr:1952
+
+hgt:173cm iyr:2018 cid:96 ecl:amb byr:1986 pid:783160698 eyr:2026
+hcl:#602927
+
+hcl:#a97842 cid:199 pid:912273414 eyr:2030
+hgt:171cm ecl:hzl iyr:2011 byr:1960
+
+ecl:amb hgt:156cm
+iyr:2013
+hcl:#ceb3a1
+cid:116 pid:567057004 byr:1942
+eyr:2029
+
+ecl:#cddc40
+pid:045090966 cid:254
+hgt:75in hcl:#733820 eyr:2026 byr:1956
+iyr:2015
+
+pid:156cm
+eyr:2040
+hgt:176cm ecl:#02e67d hcl:b7c0e6
+iyr:1959 cid:129 byr:2022
+
+hgt:160cm byr:1933
+ecl:blu eyr:2029 iyr:2012 hcl:#888785 pid:028571975
+
+iyr:2017
+hcl:#390f37 hgt:171cm ecl:brn byr:1931 pid:015365720 eyr:2030
+
+iyr:2014 pid:697057757
+eyr:2026 hgt:188cm
+ecl:gry byr:1926
+
+pid:484310015 hcl:#fffffd hgt:150cm iyr:2018
+cid:53 ecl:gry eyr:2021 byr:1957
+
+hgt:156cm
+eyr:2026 byr:1963
+pid:063272603 ecl:brn iyr:2011
+hcl:#888785
+
+byr:1955 pid:310518398 hgt:191cm iyr:2018
+ecl:oth eyr:2023 cid:132 hcl:#888785
+
+byr:1938 hcl:#623a2f eyr:2023
+iyr:2010
+hgt:165cm
+pid:170304863
+cid:290 ecl:amb
+
+eyr:2026
+pid:021468065 hgt:164cm
+byr:1996 iyr:2016 hcl:#18171d
+ecl:brn
+
+byr:2027 ecl:oth pid:8258823391 hgt:153in hcl:#733820 eyr:1948
+
+byr:2026 ecl:#cd275a iyr:2012 eyr:2036 pid:5917499975
+
+byr:2004
+cid:151
+hcl:99ecb1
+eyr:2033 pid:871137711 iyr:1997
+hgt:184cm ecl:oth
+
+byr:2011
+hcl:z ecl:#eee1d2 hgt:59cm eyr:1925 iyr:2030 pid:#02ee78
+
+pid:742658992
+hcl:#888785
+byr:1995
+eyr:2024 hgt:162cm iyr:2013 cid:169 ecl:gry
+
+hgt:152cm byr:1946
+eyr:2027 iyr:2018
+pid:352799678
+hcl:#238da0
+ecl:amb
+cid:71
+
+hcl:#623a2f pid:723616064 eyr:2021
+hgt:172cm
+byr:1926 iyr:2013
+ecl:grn
+
+iyr:2019 hgt:94 byr:2028 eyr:1986
+pid:#ee7f00
+
+ecl:amb
+eyr:2027 pid:188153423 byr:1957 hcl:#d67ae1
+iyr:2011 hgt:183cm
+
+byr:1950 ecl:#e2495d iyr:2010 hgt:166cm eyr:2034 pid:151457075
+
+eyr:1981
+byr:2016 iyr:2029 pid:153cm ecl:#55c2a4 hcl:z
+hgt:76cm
+
+hgt:184cm ecl:amb eyr:2021
+hcl:#623a2f
+pid:414607669 iyr:1960 byr:2002
+
+eyr:2027 iyr:2020 hgt:179cm byr:1991
+pid:969568248
+ecl:blu
+
+hgt:175cm pid:536803427 hcl:#a97842 iyr:2012
+ecl:grn byr:1950 eyr:2027
+
+eyr:2028 hgt:60in hcl:#733820 iyr:2018 ecl:oth pid:871909483
+byr:1930
+
+hgt:155cm iyr:2020 byr:1960 eyr:2021
+pid:515710074 ecl:amb hcl:#341e13
+
+byr:1922 hcl:z iyr:1977 ecl:brn
+eyr:2023 hgt:119 pid:865700639
+
+ecl:gry hcl:959fcd pid:#633ac1
+byr:2011 hgt:68in
+eyr:2020
+
+iyr:1972 hcl:z cid:149 byr:2020
+hgt:166in pid:4548657 eyr:1960
+ecl:#cc987c
+
+eyr:2023 hcl:#b6652a iyr:2015
+hgt:187in pid:547953710 byr:1979 ecl:grn
+
+iyr:2018
+pid:508691429 ecl:oth eyr:2025 hgt:187cm cid:270
+hcl:#888785 byr:1977
+
+hgt:168cm eyr:2032 byr:2020
+ecl:gry iyr:1982
+hcl:z pid:648015564
+
+hcl:#fffffd pid:911858643 iyr:2016 ecl:gry eyr:2030 byr:1992 hgt:156cm
+
+pid:241562994 eyr:2026 ecl:grn hgt:164cm
+hcl:#c0946f byr:1945 iyr:2015 cid:296
+
+byr:1976 pid:269322775 ecl:hzl
+hgt:162cm hcl:#b6652a
+eyr:2022 cid:335 iyr:2012
+
+eyr:2028
+hgt:106
+pid:268626219 hcl:#a97842
+iyr:2011
+ecl:grn byr:1967
+
+iyr:2016 hcl:#888785 hgt:193cm ecl:oth
+pid:034099334 eyr:2027
+byr:1945
+cid:181
+
+pid:248319556 byr:1987 iyr:2010 cid:122 ecl:utc
+hcl:z hgt:190cm eyr:2030
+
+iyr:2019 hcl:#ceb3a1
+ecl:hzl
+cid:281 hgt:73in byr:1992
+eyr:2023
+
+hcl:#fffffd
+ecl:blu cid:340 hgt:176cm byr:1980 pid:809878309 iyr:2018
+
+hgt:167cm hcl:#866857 byr:1973 cid:143 eyr:2030 iyr:2012
+ecl:hzl pid:168618514
+
+hcl:c97d76 iyr:2016 pid:8439355994 byr:2013 eyr:2036 hgt:71cm
+cid:116 ecl:#055b62
+
+hcl:#341e13 pid:961548527 eyr:2027 hgt:192cm byr:1940 iyr:2011 ecl:oth
+
+byr:1935 hgt:189cm ecl:brn iyr:2012
+eyr:2028 hcl:#602927
+
+byr:2024
+eyr:1939 iyr:2020 hgt:140 pid:889951037
+hcl:#b6652a ecl:blu
+
+ecl:amb byr:1942
+iyr:2012 pid:161703003 hgt:181cm
+eyr:2027 hcl:#602927
+
+hcl:#18171d
+iyr:2015 byr:1935
+cid:204
+ecl:gry
+hgt:180cm eyr:2025 pid:988699528
+
+eyr:2025 byr:1985
+cid:192
+hcl:#866857 hgt:150cm pid:315179208 iyr:2010 ecl:blu
+
+hcl:#341e13 iyr:2013 eyr:2021 cid:62
+byr:1928
+hgt:168cm pid:862861470 ecl:hzl
+
+pid:099158408
+ecl:grn
+eyr:2026 iyr:2018 hcl:#b6652a cid:81
+hgt:185cm byr:1964
+
+byr:1990 hgt:155cm
+ecl:brn
+eyr:2023
+hcl:#ceb3a1 iyr:2012
+
+ecl:brn
+eyr:2026 cid:242 pid:658930205
+hgt:176cm byr:1990 iyr:2016 hcl:#d55f68
+
+hcl:#602927 pid:924899781
+eyr:2024 byr:1964
+iyr:2019
+cid:163
+hgt:181cm ecl:gry
+
+eyr:2026 ecl:blu pid:8812414708 iyr:2017 hcl:#a97842 hgt:190cm
+byr:1970
+
+hgt:152cm
+pid:403682313 iyr:2019
+hcl:#ceb3a1 ecl:oth
+eyr:2021 byr:1957
+
+pid:23799214
+byr:2030 hgt:66cm
+iyr:2022
+hcl:z ecl:#c806fe eyr:2035
+
+eyr:2022 hgt:177cm byr:1967 cid:194
+pid:060293594
+ecl:brn
+iyr:2016
+hcl:#cfa07d
+
+hgt:184cm hcl:#6b5442 eyr:2029
+ecl:oth iyr:2013 pid:26983291 byr:1965
+cid:147
+
+pid:255519852 byr:1975 hgt:192cm
+ecl:lzr
+iyr:2015 eyr:2030
+hcl:#623a2f
+
+iyr:2010
+ecl:blu
+hcl:#881267 hgt:162cm pid:121130250 byr:1935 cid:57 eyr:2025
+
+hgt:189cm
+hcl:#a97842
+iyr:2014 eyr:2024
+ecl:brn
+pid:972960330
+
+hcl:#623a2f eyr:2026 hgt:193cm cid:87 byr:1982 iyr:2020 pid:158154062 ecl:amb
+
+eyr:2025 hgt:191cm
+ecl:amb
+hcl:#341e13
+pid:137048981 iyr:2016 byr:1950
+
+byr:1930 eyr:2029 ecl:hzl hgt:75in
+pid:464272185 cid:341
+iyr:2012 hcl:#c0946f
+
+ecl:brn
+pid:952709301 byr:1926 hcl:#c0946f
+eyr:2028
+hgt:170cm
+
+pid:578940518 byr:2025 hgt:190in
+iyr:2030 cid:52 ecl:amb eyr:2027
+
+ecl:amb hgt:185cm cid:237 iyr:2016 pid:490377510 byr:1950 hcl:#18171d
+eyr:2025
+
+iyr:2014 hgt:156in pid:65952131
+ecl:blu byr:1938 hcl:#7d3b0c
+eyr:2023
+
+ecl:gry iyr:2016 pid:818347623 hcl:#888785 eyr:2030 hgt:174cm
+
+ecl:hzl
+hcl:#866857
+eyr:2027
+pid:213124752 hgt:179cm
+byr:1989
+
+pid:024846371 byr:1990 iyr:2018
+eyr:2026 hgt:161cm ecl:oth
+
+hcl:z hgt:129 iyr:2016
+eyr:2034
+pid:#b85e75 byr:2026 ecl:oth
+
+hgt:192cm hcl:#602927 ecl:blu iyr:2011
+pid:863613568 byr:1996 eyr:2027
+
+hgt:160cm cid:229 byr:1952
+iyr:2019
+ecl:#0ae2d6 eyr:2027 pid:719697407 hcl:z
+
+pid:040987502 cid:155 iyr:2012 hgt:173cm
+byr:2002
+hcl:#fffffd eyr:2023 ecl:hzl
+
+ecl:oth byr:1993 iyr:2019 pid:319157251 hcl:#733820 hgt:70in eyr:2027
+
+hcl:#9d85d4
+hgt:192cm pid:570514935
+cid:238 eyr:2022 ecl:gry byr:1989
+iyr:2016
+
+hgt:162cm
+cid:201 iyr:2015 eyr:2023 pid:553794028 byr:1922 ecl:amb hcl:#623a2f
+
+cid:56
+eyr:2024 ecl:amb hgt:179cm hcl:#efcc98
+pid:665225721
+iyr:2012 byr:1963
+
+byr:2026
+hcl:#888785
+iyr:1972 eyr:1980 cid:323 pid:153cm
+hgt:170cm ecl:blu
+
+pid:704204892 ecl:gry
+eyr:2023
+byr:1920 hgt:168cm iyr:2010 hcl:#3311ec
+
+pid:#7f3caf eyr:2023
+hcl:z hgt:146 byr:1990 ecl:amb
+iyr:2014 cid:270
+
+hgt:171cm ecl:blu pid:383695713
+cid:200 iyr:2010
+hcl:#602927 byr:1950 eyr:2024
+
+hgt:178cm byr:1935 hcl:#2da7db
+pid:597509269
+eyr:2020 iyr:2014
+ecl:blu
+
+eyr:2034
+ecl:#d4719a
+hcl:z hgt:67cm iyr:2023 pid:#268d93 byr:2006
+
+eyr:1939 pid:9942171839
+hgt:104
+iyr:1945
+byr:2011 ecl:#f9bafb hcl:#ceb3a1
+
+byr:1937
+iyr:2010 pid:979528684
+eyr:2028 hcl:#ceb3a1 ecl:gry hgt:164cm
+
+iyr:2019 eyr:2022 pid:044485658 hcl:#18171d byr:1996 hgt:169cm
+ecl:gry
+
+pid:031482456
+eyr:2024
+iyr:2015
+hgt:157cm hcl:#7d3b0c byr:1921
+ecl:oth
+
+pid:399398768
+ecl:lzr
+hcl:z
+eyr:1983 hgt:68cm
+byr:2024 iyr:2027 cid:127
+
+hgt:186cm eyr:2026 pid:140032921 ecl:amb cid:278
+byr:1937 iyr:2015
+
+hgt:172cm
+ecl:amb pid:718725983 hcl:#6b5442 eyr:2024
+iyr:2013 byr:1974
+
+ecl:amb iyr:2014 cid:216 hcl:#cfa07d
+eyr:2022 pid:442275714 hgt:68in byr:1999
+
+hgt:152cm cid:193
+iyr:2015 pid:806672342 hcl:#b6652a byr:1927 ecl:oth
+
+hcl:#7d3b0c byr:1925 iyr:2015 hgt:174cm pid:888044223 cid:168 ecl:oth eyr:2029
+
+ecl:gry byr:2009 hgt:156cm
+hcl:#888785 pid:263500722 iyr:2015 eyr:2021
+
+cid:103
+hcl:#ba8b89 ecl:hzl hgt:169cm
+byr:1929 pid:626102979 iyr:2016 eyr:2028
+
+iyr:2016 hgt:188cm cid:133
+byr:1926 ecl:hzl eyr:2023 hcl:#602927 pid:678092780
+
+ecl:utc byr:2025 pid:#584dc1 eyr:2037
+hgt:151cm iyr:1950 hcl:#cfa07d
+
+ecl:oth hgt:140 eyr:1977 hcl:#6b5442 iyr:1955
+byr:1999
+pid:868434068
+
+eyr:2029 hcl:#18171d cid:158 iyr:2016 hgt:166cm ecl:hzl
+pid:100226690 byr:1942
+
+ecl:#806ce8
+cid:153 iyr:2024 byr:1985 hcl:da8a68
+pid:#d9e5b0 eyr:2017
+
+eyr:2020 hgt:164cm cid:222 ecl:hzl byr:1945 hcl:#cfa07d
+iyr:2011
+
+iyr:2018 hgt:165cm
+pid:868536448 eyr:2026 byr:1930
+ecl:hzl hcl:#623a2f cid:128
+
+ecl:grn iyr:2012
+cid:326 byr:1950 hcl:#efcc98 eyr:2029 hgt:177cm pid:685629972
+
+byr:2004 hgt:168cm
+ecl:dne iyr:2020 hcl:z
+
+byr:1964 pid:132604237 ecl:oth hcl:#602927 hgt:188cm
+cid:78
+iyr:2012 eyr:2025
+
+byr:1945
+iyr:2023 ecl:#1a590c hgt:70in
+pid:186cm eyr:2031 hcl:z
+
+cid:178
+ecl:amb eyr:2024 hgt:162cm
+hcl:#18171d iyr:2016
+byr:1945 pid:737813370
+
+hcl:#18171d
+byr:1949
+pid:064917719
+hgt:176cm ecl:amb
+eyr:2034
+iyr:1998
+
+hgt:72in
+pid:711343766 hcl:#623a2f
+iyr:2010 byr:1977 ecl:amb cid:177 eyr:2023
+
+byr:1933 hgt:66 pid:22149379 eyr:2040
+ecl:#92d7a7 hcl:#cfa07d
+
+iyr:2020 byr:1946 eyr:2020 ecl:hzl pid:153cm
+hgt:159cm cid:261 hcl:#888785
+
+iyr:2013 byr:1931
+ecl:#2ced2e hcl:3c49c1 eyr:1950
+hgt:182cm cid:133 pid:#19fc55
+
+hcl:#a9abe6
+iyr:2016
+eyr:2029 ecl:hzl cid:343 pid:691253232 byr:1952 hgt:187cm
+
+hcl:z
+eyr:1964
+ecl:#5995e6
+byr:2021 hgt:72in pid:2103603035 iyr:1951
+
+iyr:2024 hgt:151in byr:1988 ecl:blu
+eyr:1961 cid:117
+hcl:z pid:5371118784
+
+hgt:71cm iyr:2021
+eyr:2033 ecl:amb
+hcl:z cid:202
+pid:207141921 byr:1987
+
+ecl:gry byr:1927 eyr:2024
+hgt:60in iyr:2014
+pid:847799723 cid:285
+hcl:#733820
+
+eyr:2022 hcl:#18171d
+pid:847063261
+byr:1926 ecl:grn
+iyr:2011
+
+pid:647225630 iyr:2016 hcl:#a97842 ecl:oth eyr:2025
+cid:144 hgt:182cm byr:1983
+
+hgt:150 byr:1924
+eyr:2024 hcl:1600da
+ecl:brn
+cid:168 pid:656253964
+
+hgt:153in pid:644514788 byr:1956 hcl:#866857
+iyr:2029
+ecl:utc
+
+cid:57 pid:755541617 byr:1961
+iyr:2019
+ecl:grn
+hgt:169cm hcl:#efcc98 eyr:2029
+
+iyr:2005
+eyr:2040 hcl:8080a4 byr:2013 pid:145803668
+
+iyr:2029
+hcl:z ecl:brn
+byr:1948
+hgt:76cm pid:186cm eyr:2031
+
+hcl:#888785 ecl:grn byr:1983 cid:268 pid:402246959 iyr:2018
+eyr:2020
+
+hgt:175cm eyr:2026 pid:594997236
+byr:1991 hcl:#ceb3a1 iyr:2015 ecl:blu
+
+byr:1989
+eyr:2027
+iyr:2020 hgt:192cm ecl:blu hcl:#cfa07d cid:61 pid:657979353
+
+pid:#a043a3 iyr:2016 byr:1947
+eyr:2031 hgt:191cm ecl:xry
+
+eyr:2023 ecl:blu byr:1948 cid:128 hgt:74in
+pid:966094274
+iyr:2015
+
+iyr:2020 ecl:zzz
+eyr:1999 hcl:3cf716 byr:2017 cid:343 pid:60198759
+hgt:70cm
+
+hgt:182 pid:80897411 byr:2014 eyr:2033 iyr:1941 ecl:#9c54e8 cid:107
+hcl:z
+
+iyr:2015 hcl:#866857 byr:1990 cid:167 pid:588340506 eyr:2030 hgt:168cm ecl:oth
+
+hcl:676aad hgt:151 cid:192 eyr:1930 ecl:oth byr:2012
+pid:513365039
+iyr:1943
+
+cid:119
+ecl:#921980 hgt:70cm
+eyr:2024 hcl:4909ee pid:#13fe6c iyr:2022 byr:2014
+
+eyr:2036 hcl:02fdbc hgt:155cm
+iyr:1946
+pid:508011940 ecl:utc byr:2025
+
+pid:#f74bbe eyr:2028 hcl:#c0946f hgt:171cm ecl:#9077c0
+byr:1951 iyr:2010
+
+iyr:2017 hgt:125 hcl:#cfa07d pid:731062033 ecl:brn eyr:2028 cid:255 byr:2020
+
+ecl:xry eyr:2033 byr:1978
+iyr:2012 hgt:70cm hcl:z
+pid:272848084
+
+ecl:blu hgt:174cm
+eyr:2030 byr:1999 hcl:#ceb3a1 iyr:2015
+pid:322583115 cid:301
+
+eyr:2007 byr:2007
+ecl:dne cid:322 pid:182cm iyr:2013 hgt:156in
+hcl:680e8c
+
+hgt:189cm hcl:#18171d
+byr:1996 ecl:amb
+eyr:2022 iyr:2020 pid:470853813
+
+pid:785152983 iyr:2014 eyr:2028 hcl:#d50ced ecl:hzl byr:1998
+
+ecl:hzl byr:1945 hcl:#7d3b0c cid:164 hgt:187cm pid:414181589 iyr:2018
+
+byr:1936
+hgt:183cm ecl:gry pid:376279728 hcl:#7d3b0c
+eyr:2023 iyr:2012
+
+byr:2000 hgt:157cm
+ecl:hzl
+iyr:2020
+pid:203994583
+eyr:2023 hcl:#866857
+
+eyr:1992 byr:2009
+iyr:2029
+hcl:dc80b3 hgt:70cm ecl:grn pid:#65c31d
+
+hcl:#7d3b0c
+byr:1945
+hgt:177cm
+iyr:2013 eyr:2028 pid:038116668 cid:74 ecl:blu
+
+pid:700997508 eyr:1970 ecl:zzz hcl:#888785 iyr:2013 byr:1986 cid:219 hgt:76cm
+
+eyr:2025 hgt:161cm
+iyr:2015 cid:188
+hcl:#fffffd
+pid:840085402 ecl:gry byr:1988
+
+pid:96550914 hcl:#481a3b byr:1997 ecl:#a57167
+cid:274 hgt:174cm
+
+hcl:#b6652a
+ecl:brn eyr:2029
+hgt:157cm iyr:2011 pid:910022061
+byr:1947 cid:273
+
+pid:010289131 eyr:2026
+byr:1930
+hcl:#b6652a ecl:grn
+cid:220 hgt:187cm iyr:2013
+
+hcl:#6b5442 ecl:grt hgt:120
+pid:454504291 eyr:1933 byr:2025 iyr:1930
+
+iyr:2016
+hgt:180cm ecl:amb eyr:2028 cid:237
+pid:334803890 byr:1953 hcl:#18171d
+
+eyr:2020 byr:2002 hcl:#c54f21
+iyr:2019 ecl:blu hgt:180cm cid:138
+
+byr:1933
+iyr:2020
+ecl:brn hgt:185cm
+hcl:#c0946f
+eyr:2020 pid:050791974
+
+byr:1933 ecl:brn hgt:186cm
+pid:643899463 eyr:2030 iyr:2019
+hcl:#866857
+
+iyr:2018 byr:1935 ecl:oth
+eyr:2029
+pid:732801213 hcl:#6b5442 hgt:169cm
+
+eyr:2020
+hcl:z byr:1996
+ecl:#4102ee
+pid:890541531 hgt:193cm iyr:2014
+
+pid:618379341 ecl:gry hcl:#18171d byr:1991 eyr:2025 hgt:154cm iyr:2019
+
+iyr:2013
+pid:912066964 ecl:grn eyr:2040 hgt:192cm byr:1974
+hcl:#18171d
+
+eyr:2025 cid:167 hgt:192cm
+pid:678328147 ecl:gry
+hcl:#18171d iyr:2017
+
+iyr:2011 byr:2021 hgt:189cm ecl:gmt hcl:z eyr:2035 pid:278839955
+
+eyr:2030 hcl:#efcc98
+ecl:blu iyr:2011
+pid:536958012 hgt:192cm byr:2002
+
+pid:#1306f2 byr:1976
+hcl:#790688 hgt:158cm ecl:grn eyr:2024 iyr:2019
+
+eyr:2030 hcl:#866857
+cid:50 ecl:oth pid:421235317
+iyr:2014 hgt:60in
+
+iyr:2020 byr:1971 cid:124
+pid:319896110 ecl:oth hcl:#fffffd
+
+cid:143
+eyr:2021 hgt:190cm pid:366021385 hcl:#18171d ecl:amb byr:1934
+iyr:2016
+
+hgt:169cm hcl:#602927 pid:177cm
+eyr:2022 byr:2020 ecl:#dd96f4 iyr:2014
+
+eyr:2020 hgt:173cm pid:591592395 ecl:oth byr:1966
+hcl:#c0946f iyr:2020
+
+pid:282088832 ecl:gmt
+hgt:167in byr:2016 hcl:z
+iyr:2018
+
+iyr:2016
+hgt:62in hcl:#c0946f
+pid:306204399 eyr:2020 ecl:brn
+byr:1999
+
+eyr:1947 byr:1984 pid:595671246 hcl:3d50e7 ecl:xry iyr:1947
+
+hgt:187cm
+eyr:2024 pid:477011496
+byr:1971
+hcl:#733820
+iyr:2010
+ecl:brn cid:165
+
+byr:2023
+pid:173cm
+hgt:193in eyr:2019 cid:102 ecl:grt hcl:#c0946f
+
+pid:195062251
+iyr:2027
+cid:138 byr:2021 ecl:brn eyr:2025 hgt:60in
+
+hgt:71cm hcl:z
+ecl:utc
+eyr:2021 iyr:1925 pid:5469028726 byr:2017
+
+hcl:#b6652a hgt:168cm
+byr:1960 ecl:grn
+pid:653140418
+iyr:2014 eyr:2023
+
+pid:#afa892 cid:190 hcl:z
+hgt:189cm
+eyr:2020 ecl:gry
+byr:2003
+iyr:1956
+
+hcl:e4cddf cid:185 pid:189cm hgt:175cm
+byr:2016 iyr:2010 ecl:#fa945d eyr:1947
+
+cid:176
+hcl:7752f8 eyr:2039 byr:2019 ecl:hzl iyr:2029 hgt:185cm pid:636534364
+
+cid:170 ecl:gmt hcl:ef5177 byr:2021
+eyr:1993
+hgt:71cm pid:2136295 iyr:2013
+
+byr:2028 pid:156cm hcl:d74b86 cid:238
+hgt:89
+iyr:1957 eyr:1937
+
+eyr:2030 byr:1932 hcl:#c0946f cid:349
+hgt:177cm
+ecl:grn iyr:2016
+
+hcl:z byr:2003
+ecl:#9b98b2 hgt:81 pid:13338103 eyr:2040
+
+iyr:2018 pid:801432704 hgt:73in byr:1964 cid:298 hcl:#fffffd ecl:amb eyr:2030
+
+cid:272
+iyr:2019 pid:369160624 byr:1929 hgt:184cm eyr:2025 hcl:#ceb3a1 ecl:blu
+
+hcl:#7d3b0c pid:525287934
+byr:1998 eyr:2027
+iyr:2017 hgt:168cm ecl:gry
+
+byr:1975 eyr:2027
+ecl:brn cid:125 hcl:4e319d
+hgt:172cm pid:308046532 iyr:2017
+
+hcl:b889c0 pid:6699675552 byr:2019 iyr:1968
+ecl:gmt
+eyr:2003
+hgt:180in
+
+byr:2025
+ecl:zzz hgt:162in hcl:z iyr:2002 pid:#87dca4 eyr:1951
+
+eyr:2022
+pid:549517742 ecl:hzl
+iyr:2026
+byr:2029 hgt:153cm hcl:2993de
+
+eyr:2024
+pid:755674604 iyr:2018 hcl:#c0946f
+ecl:gry byr:1966
+hgt:188cm
+
+pid:665375893 iyr:2017
+byr:1997
+eyr:2029 hgt:173cm ecl:gry
+
+hcl:#6b5442 hgt:74cm ecl:#0dc7f6
+pid:451038742 eyr:1982 byr:1939
+iyr:1932
+
+hcl:#18171d
+byr:1980 ecl:gry
+iyr:2019 hgt:167cm
+pid:326267989 eyr:2028
+
+cid:226 hgt:177cm ecl:hzl hcl:#a97842 eyr:2025
+iyr:2013
+byr:1949 pid:292166795
+
+ecl:oth pid:962521763
+iyr:2013 cid:71 eyr:2022 hgt:193cm hcl:#18171d byr:1969
+
+ecl:grn iyr:2028 eyr:2024
+hgt:189cm hcl:z byr:1940 pid:032392876
+
+iyr:2012 hgt:191cm cid:339 ecl:oth eyr:2028 pid:392810631 hcl:#b6652a byr:1959
+
+iyr:2011 byr:1975
+eyr:2027
+hcl:#18171d
+hgt:176cm
+ecl:gry pid:290432747
+
+cid:180 ecl:brn pid:210871734 eyr:2027
+byr:1946 hcl:z hgt:185cm iyr:2011
+
+byr:1924 ecl:grt
+eyr:2028 hgt:187cm pid:#608f4f
+
+eyr:2022 ecl:#a05063 byr:1926 hcl:#7d3b0c pid:3292990618 hgt:183in iyr:2021
+
+ecl:#a8b66c
+iyr:1942 eyr:1960 hgt:60cm byr:2027 pid:#3b6f3f hcl:9fae56
+
+hgt:183cm
+ecl:oth hcl:#c0946f pid:816986054 eyr:2020 iyr:2014 byr:1935
+
+hgt:174 byr:2008
+iyr:2029 hcl:9259e7 pid:85036214 ecl:gmt
+
+cid:85
+pid:032040868
+byr:2001 eyr:2027 hcl:#c0946f ecl:grn iyr:2020
+hgt:173cm
+
+hcl:#6b5442
+cid:308
+ecl:grt iyr:1939 byr:2009
+pid:9365125584 eyr:2031 hgt:67cm
+
+hgt:154cm
+byr:1936
+eyr:2030 hcl:491c70 pid:391887956 iyr:2029 ecl:blu
+
+hcl:#866857
+hgt:161cm cid:76 pid:921202500 eyr:2021 ecl:brn byr:1968
+
+iyr:2024 ecl:dne hcl:z pid:8054447805 hgt:154 eyr:2035 byr:2024
+
+hcl:#0a524b pid:667928918
+eyr:2025
+cid:245 ecl:brn byr:1973 hgt:179cm
+
+ecl:gry hgt:68in pid:322837855 eyr:2023
+cid:323 byr:1944
+iyr:2012
+
+byr:1940
+hgt:178cm ecl:hzl hcl:#c0946f iyr:2030
+eyr:2020 pid:788531859
+
+cid:253 iyr:2012 hgt:163cm
+pid:554364568 eyr:2025 byr:1976 ecl:grn hcl:#888785
+
+hcl:#efcc98 iyr:2015 ecl:gry eyr:2029 pid:273847553 cid:274
+hgt:68in byr:1933
+
+hgt:165cm
+pid:209462386 eyr:2024
+byr:1969 hcl:#733820 ecl:grn
+iyr:2020
+
+byr:1975 hgt:187cm eyr:2027 iyr:2018 hcl:#c0946f ecl:hzl pid:141969110
+
+hcl:z pid:534439483 iyr:2022 ecl:grt eyr:2036 hgt:164in cid:324
+byr:2025
+
+hcl:#74ca66
+iyr:2011
+pid:253012158
+hgt:188cm
+cid:246 ecl:oth eyr:2023
+
+byr:2020 pid:56939101 hcl:9f5f65
+eyr:1949
+iyr:2021 hgt:155in
+
+iyr:2020 hgt:174cm cid:304
+byr:1944
+eyr:2028 hcl:#733820
+
+hcl:#866857 ecl:gry eyr:2030 iyr:2014 hgt:63in byr:1997
+pid:371522079
+
+ecl:amb
+byr:1955 iyr:2013
+hcl:#888785 cid:265 eyr:2026 hgt:190cm pid:311393763
+
+eyr:2026 iyr:2019
+pid:721355771 byr:1947
+hcl:#733820
+hgt:71in ecl:gry
+
+cid:94 eyr:2024 byr:1938 pid:336868233 ecl:hzl
+iyr:2012
+hgt:177cm hcl:#7d3b0c
+
+ecl:brn iyr:2010
+eyr:2027
+pid:379769214
+cid:111 byr:1960 hcl:#cfa07d hgt:169cm
+
+hgt:179cm
+hcl:3f59a6 eyr:2036 byr:2025 ecl:oth pid:217404607
+iyr:2018
+
+ecl:amb pid:820370865 hgt:170cm iyr:2012 byr:1967 hcl:#efcc98 cid:309 eyr:2025
+
+byr:1940
+pid:008495978 ecl:gry hgt:159cm hcl:#602927 eyr:2024
+
+hgt:186cm
+byr:1971 pid:556900517 cid:334 hcl:#efcc98 ecl:brn
+iyr:2014
+
+iyr:2020 byr:1928
+cid:200 hgt:193cm
+ecl:grn hcl:#7d3b0c
+
+cid:233
+hcl:a3046e pid:626863952 ecl:lzr iyr:2029 eyr:2024 byr:2000 hgt:193cm
+
+cid:244
+hcl:#866857 ecl:amb byr:1931
+eyr:1928 pid:557376401 hgt:182cm iyr:2013
diff --git a/2020/inputs/day5 b/2020/inputs/day5
new file mode 100644
index 0000000..cfb1d3b
--- /dev/null
+++ b/2020/inputs/day5
@@ -0,0 +1,932 @@
+FFBBFFFLRL
+FFBBFBBRRL
+FBBBFFBLRL
+BBFBFFBLRR
+BFBBBFFLLL
+BFBBBBBLLR
+FBFBFBFLLR
+BFBFBBFLLR
+FBBFBFBLLL
+BBBFBFBRLL
+BFBBBFBLRL
+FBBFFFBLLR
+BFFBFBFLRL
+FBBBBFBRLR
+FFBBBBBRRL
+FBBFBFFLRL
+FBBBBBBLLR
+FBBFBBBRRL
+FBBFFBFRLL
+FBFBBBBRRR
+BFFBFBFRRL
+BFBFBBBLLR
+FFFFBFBLRL
+FBFFBFFLRL
+FFBFBBBRRR
+FFBFFFFLRR
+FBBBFFFLLR
+FFFFFBFLLL
+BFFFFFFLRL
+FBBBBBFRLR
+BBBFFBBRRR
+FFFFBBBRLL
+FBFFBBBRLR
+BFBBBFFRRL
+BBFBBFBLRL
+BFBFBFFRRR
+BBFBFFFLLL
+FBFBFBFRRR
+BFBFBFFRRL
+BBFBBFBRRL
+FFBBFBFLRL
+FBFFFFFRLR
+FBBFFFBLLL
+FBBBBFFRLL
+FFBBBBBLLL
+BFFBBFFRLR
+FFFBBFBRRR
+FBBBFFFRLL
+FFFBFBFLRL
+BFFBBFFLRL
+BFBBBBBLRL
+BFFFFFBRRR
+FFFBBFBLRL
+FBBBFBFRLL
+FBBFBFBLRR
+BBFBBFFLRR
+FBFFBBFLLL
+FFFFFBBRLL
+FFBBFFBRLR
+BBFFFFFLLL
+BFFFFBFLRR
+FBFBBFFRRL
+BFBFFBBLLR
+FBBBFBBRLR
+BBBFBFFRLL
+BBFFBBFRLR
+FFBFFBBRLR
+FFBBBFBRLR
+BBBFFFBLRR
+BBFBFBFLRR
+BFBBBBBRLR
+BFFFFFBLLR
+FBFFBFFRLL
+BBBFFBBRLR
+FFBBBFBRRR
+BFBBBFBRLR
+FBFFFBBLRL
+FFFBFFFRLL
+BBFFBFFLLL
+BFFBBFFRRR
+FFBFBFBRRL
+FFBBBFBRRL
+FBBFFBBRLR
+FBFFBBFRLR
+BFBFFBBRRR
+BBFBFBBRLR
+FFBFFFFRRL
+BBFFBFFLLR
+FBBFBFBRRR
+BFBFBBBRRL
+FBFBFFBRRL
+FFFBBFFRLL
+BFBFFFFRRR
+FBBFFBFLLR
+FFBFBFFRLL
+FBFFBFBLLL
+FBFBFFFLRL
+BBFFFFFRRR
+FBFFBBFLRR
+FBFFFBFLRL
+FBBBFBBRRL
+BFFBFFFRLR
+FFBBBBFLLR
+BFFFFBFLRL
+BFFBFFBRRR
+FFBFBFBLRL
+BBFFFBBRLL
+FFBFBBFRRR
+FFFBFBFRRL
+FBFFBFBRRR
+FBBBBFBRRL
+FBFFFFFLLR
+FFBFFFFLLR
+FBBBBFFRLR
+BBBFFBBLRR
+BBBFFBFLRR
+FBBFBBBLRR
+FBBFBBFRRL
+FFFBFFBLLL
+FBFFFFBLLL
+BBFFFFBLLL
+FBFFFBFLRR
+FFBFBFFLRR
+BBFBFFFRLL
+FFFBBBFRLR
+FFBFFBBRLL
+BBBFBFFRRL
+BFFBBBBLRR
+BFFFFFFLLL
+BBBFFFBLLL
+FBBBBBFRLL
+FBBFBBBLLR
+BBFBFFFRRR
+BBFFFBBLLL
+FBBFFBFLRL
+BBFBFFFLRR
+BFBFFBFRLL
+BFFFBFBLLR
+BBBFBFBLLL
+BBBFFBFRLR
+FBFFBFBRLR
+BFBBFFFLLL
+BBFFFFBLRR
+BBFFFBBRRL
+BBBFBFFLLL
+BFBFFBFLLL
+FBBBBFFLLR
+FFBFFFFRLR
+FFBBBFBRLL
+BFFFFFFRRL
+BFBFFBBLRL
+BBFBBBFRLL
+BFFFBFFLLR
+BBFBFFBRLL
+BFBBFFFRLL
+BBFBBFBRLR
+FFFBBFBRLR
+BFFFBBFLRL
+FFBFFBFRLL
+FFFBFFBLRL
+BFBBBFFRLR
+BBBFFBBLRL
+BFFBBBBRRL
+FFBBFFFRLL
+BFBFFBFLRL
+BFFBBBBRRR
+BBFBFBFRRL
+BBBFFBFRRL
+BFFFBFBLRL
+FFFBFBFRLR
+FBFFBBBLRR
+FFFFBBBLLL
+BBBFBBFLLR
+BFFBFBFRRR
+BFBFFFBRRR
+BBFBBBBLLR
+FFBBBBBLRL
+FFBFFBFLRR
+FFBBBFBLRR
+BBFBBFBRRR
+FFFFFFBRRR
+BFBFBFBRRL
+BBFFBBBLRR
+BBFBFFFRLR
+FBBFBFBLLR
+BFBBFFBRLL
+FFFFBFBLLR
+BFBFFBBRLR
+FBFFFBFRRR
+BFFBFFFRLL
+FBBBFFFRRR
+FFFBBBFLLL
+FBBBBBBRRL
+FBBFFBBLLR
+BBBFBFFLRR
+BFBBFBFLRR
+FFFBBBBRRR
+BFFFBBFRLR
+FBFFBBFLLR
+FBFFFFFRRL
+BBBFBBFLLL
+BBBFFFFRLR
+FFFFBBBRRR
+FBBBFBBLLL
+BFFBFFBLLL
+FBFBBFBRLR
+FFBFFBBLLR
+FFFFBFFLRR
+FBBFFBFLLL
+FBFBBFBRRR
+BBBFBFBLLR
+BBFFBFBLLL
+FFBFFBFRLR
+FBBBFBBLRR
+BBFBBFBLLL
+FFBFFBFRRR
+FBBBBFFLRL
+BFBBFBFLLR
+FBFBBBFRLR
+BFBBFFBLLR
+FFFBBBFLLR
+FFFBBBFRRL
+BFFFBFBRLR
+BBBFBBFLRR
+BBFBBFFLLR
+BBFBBBBRLR
+FBBFFFFLRR
+FBFBBFFRLL
+FFBFFFFRRR
+FFFBBFFRRL
+FFFBBFBRRL
+FFFBFBFLLR
+FFBBBBFRRR
+BFFFFBBRRL
+BFFFFBFRRR
+BFBBBFBLRR
+FFBBFFFRRL
+FBBBBBBRRR
+BBFBFFBLLR
+FBFFFFBRLL
+BFBBFBFLLL
+FBFFFBBRLL
+FBBBFFBLLR
+BBFBBBFRLR
+FBFBBFBLRR
+FFFFFBFLLR
+FBFBBBFLRL
+FFBFFFBRRR
+FFFBBFFLRL
+BBBFFFFLLR
+BFBFFFFRRL
+FBFBFBBLLR
+FBBBFBFRRL
+BBFBBBBRRL
+BFBBFBFLRL
+BFFBBFFLLR
+BFBFFBBRLL
+FBFFBFFRLR
+FBFBFBFLRR
+BFBFBBFRRR
+FBBBBFBLRL
+FFBBBFFRRR
+FFBBFFBRLL
+FFBBBBBRLL
+FBFFFBFRRL
+FFFBBBFLRL
+BBBFBFFRRR
+FFFBFFFRRR
+FBFFBFFLLL
+FFBBFFBRRL
+BFFBFFBRRL
+FFBBBFFRLR
+BBBFFFFRRR
+BBFBFBBRRR
+FBFBBBBLRR
+BFBFBFBLLL
+FFBBFFBLLR
+BFFFBBBRLR
+BFBBFBBRLR
+BFFFFBBLLR
+FBFBFBBRLR
+BFFBBBFLLR
+FBFFBFBLRL
+BFBFBBBRLL
+BFBBBFFLRL
+FFFBFFFLRR
+BFFBBFBRLL
+FFBBBBFRLL
+BBFFFBBLLR
+FBFBFBFRLR
+BBBFFFBRLR
+BFFFFFBRLR
+BBBFFFFLLL
+FFFBBFBRLL
+BFFFFFBRRL
+FBFFBBBRRL
+FBFBFBBLLL
+FBFBBFBRRL
+FBBFBBBRRR
+BFBFFBBRRL
+FBBBBFBLLL
+FBBBBBBRLR
+BBFFFBFRRL
+FFFFBFBLLL
+FFFFBBFLRR
+FFFFBFFLRL
+BFFFBBFRLL
+BBFFFFBRRR
+BFBFFFFRLL
+BFFFFBFLLR
+BBBFFBBRRL
+BBFBBFBLLR
+BFFFFBFRLR
+FBBBFBFLLR
+FFFFFBBLRR
+BFBFFFFLRR
+FBFBBFFLRL
+FBFFFBBRRR
+BBFBBBFLRL
+BFBBBFFLLR
+BFBFBBFRRL
+FBFFFFBLRL
+FBBFBFFRLR
+BFBFBBBLRR
+BFBFBBFLRL
+BBFFBFFRLL
+FBFFBBBLRL
+BFBFBFFLLR
+FFFBFFBLLR
+FFFBFBBRRR
+BBFBFFFLLR
+FBBBFBFRLR
+FBFFBBBLLL
+FFBFBBFLRR
+FBFBFFFLLL
+BBFFFFFLRL
+FBFBBFBLRL
+BBFFFBFLLR
+BBFBBBBRRR
+BFBBBFFRRR
+FFFBFFBRLL
+FBBBFFFRLR
+BBBFBFBLRL
+FBFFFFBRLR
+BFFFFFBLLL
+FBFFFFBLLR
+BFBBFFBLRR
+BFBFBBBRRR
+BBBFBFBRRR
+FFFBBFFRRR
+FBBBFFFLRR
+BBFBFFFRRL
+BFBFBBFRLR
+BFFFBFBRLL
+FBFFFFFLLL
+FFFBBBBLRL
+FFFBBFFLLL
+FBFFFFBRRR
+FFBFBFBRLR
+BFBFFFBLRR
+BFFFBFBLLL
+FBBFBFFRLL
+FBFBFFFRLL
+FBBBFFBRRR
+FBBBFFBRLL
+FFBBFBBLLL
+FBBBBFBRRR
+BFBBBFBLLR
+FBBBBBFLLR
+FFBBFBFLRR
+BFFBBFBLLR
+FBFFFFBLRR
+BFFBFFFRRR
+BFFFBBBRLL
+FBFBBBFRLL
+BFBBBFBRRL
+FFBFFFBRRL
+FBBFFFFRLR
+BFBFBFFLLL
+FFBFBFBLLL
+FBFBBFBRLL
+FBFBFFBRLR
+BFFFFFBLRR
+FBBBFFBRLR
+BFBBFBBLLL
+BBFFBFBRRR
+FFFBFBBRRL
+FFBBBFFRLL
+BFFFFFFRLL
+BFBFFFBRLL
+FFFFFBFRLL
+BBBFFFBRRL
+FFBBBBFRRL
+BFFFBBBLRL
+FFFFFBBLLR
+BFFFFBBLRR
+BFBFFFBLLL
+FFFFFBBRLR
+BBFBFBFLLL
+FBFBBBBRLR
+FBBFBFBRRL
+FFBFBFBRRR
+FBBBBBFLRL
+BBFBFFBLLL
+BBFFFFBRLL
+BBBFBFBRLR
+BBFBFBBLLL
+BFBBBBBLRR
+BBFFFBFRRR
+FFFBFBFRLL
+BFFBBFBLLL
+FBFFBBBRRR
+FFFBFBFLLL
+BBFFBBFLRL
+BBFFFFBRLR
+BFBFBBBRLR
+BBBFBFFLLR
+FFBBBBFRLR
+BBFFBFFRRL
+BBFBFFBRRR
+BFBFFBFLLR
+FBFFBBFRLL
+BBFFFFBLLR
+FBFBFFFRLR
+FFBFBFBLLR
+BFBBFFBRRL
+FBBFFBBRRL
+BBFFBFBRLR
+FFFFBFBLRR
+FFFFBBBLRR
+FFBFBFFLLL
+FFBBBFFRRL
+BBFFFBFRLL
+FBFBBBFLRR
+FBBFBFFRRR
+FBBFBFFLLR
+BFFBBBFLRR
+FBBFBBFRLR
+BFFBBBFLLL
+BBFBBFBRLL
+BBBFFBBLLR
+BBBFBFBRRL
+FBFBBBFRRL
+FBBFFFBRLR
+BFBBFBBLRL
+FFBBFFFRRR
+BFBFFFFRLR
+BBFFFFFLLR
+BBFBFFBRLR
+BBFBFBFLRL
+FBFFFFFLRL
+FFBBBFFLRL
+FBFBFBBLRR
+FFBFBBBRLL
+FFBFBFFRLR
+FBBBFBFLRR
+FBFFBFFLRR
+BBFFBFBRRL
+FBBFFFFLRL
+FFFFBBFLRL
+FFBBFFBLRR
+BFBFFFBLLR
+BFBFBBFLRR
+BFBFBFBLLR
+BFBBFBFRLL
+BFBBFFBRLR
+FBFFFBBLLL
+FFFBBBBRRL
+FBBFBFFLLL
+FBFFBFBRLL
+BFFBFFFRRL
+FBFBFFBLLR
+BBFFBBFLLL
+FFBBBFBLLR
+BFBBFFFLLR
+FBBBFBFRRR
+FBBBFFBRRL
+FFFFBBFRRR
+FFBFFFFLRL
+FBBFBBFLRR
+FFBBBFBLLL
+FBFFFBFRLR
+FFBFFBBRRL
+FFFFBBFRRL
+BBBFFFFLRL
+FBBFFFBLRL
+FFBFBFBLRR
+FFFFBFFRRR
+FFFBFBFRRR
+BBFBBBBLLL
+FFBBFFBRRR
+FBBFFBBLRR
+FBBFBBFLLL
+BBFBBBFRRL
+FFFBBBBLLR
+FFBFFBBLRR
+BBFBBFFRLL
+BFBBBBFRLL
+BBFBFFBRRL
+BFFFBBFRRL
+FBBBBBBLLL
+FFBBFFBLLL
+FFBBFBBLRR
+BFBFBFBLRR
+FBBBFBBLLR
+BBFBFBFRLL
+FBBFBFFLRR
+FBBBFBFLLL
+FFBBFFFLRR
+BFFBBBFRLL
+FBBBBFBLLR
+BFBFFFFLRL
+FFBFBBBLLL
+FFBFFFBLRR
+BFBFBFBRLL
+FBFBFBFRLL
+BFBBBBBLLL
+FFBFBFBRLL
+BFBFFFFLLR
+BFFBBBBLLL
+FFBBFBBRLL
+FFFFBFBRLR
+FBFBBFFLLR
+BFBFBBFRLL
+FFBFFFFLLL
+FBBFFBFLRR
+FFBFFFBRLL
+FFFFBBBLLR
+BFBBBBBRLL
+FBBFBBBLRL
+FBFFBBBRLL
+FBFFFBBLLR
+FFBBBFBLRL
+FFFFBFFRLL
+BBFFFBBLRL
+BFFFBFFRRL
+BFFBFBFLLL
+BBFFFBFLLL
+FFFFFBFLRL
+FBBFFFFRRR
+FBBBBBFLRR
+FFBFFFBRLR
+FBBBFFFLLL
+FFBFBBBLRL
+FFBFFFBLLL
+FBFFBBBLLR
+BBBFBFFRLR
+FFFBFFFRLR
+BBFBBBFLLR
+FFBBFFFRLR
+FFFFFBFRLR
+FBBFFFBRRL
+BFFBBBBRLR
+BFFBFFBRLL
+BFBBBFBRLL
+FBFFBBFRRR
+FBFBBFFLLL
+BBFBFBBLRL
+BBBFBBFLRL
+FBFBFFBLRR
+FBFFFFFRLL
+BFBBFBFRRR
+BFBFBBBLLL
+FFBBBFFLRR
+BFBBFBBLLR
+FBBBBFFRRR
+BFFFBFFLRL
+FFFFBFBRLL
+BFFFFBBLLL
+BFFBFBBLLL
+BFFBFBBRRL
+BBBFFFBLRL
+BBBFFFBRRR
+BFFFBBFLRR
+FFBBFBFRLL
+BFFBBFBRLR
+FFBFFBFLLR
+FBFBBBBLRL
+BFFBBFFRRL
+BBFFFBBRRR
+FBBBFBBRRR
+BFFFFBFRRL
+FFBFBBBRRL
+BFFFBBBRRR
+BFBBBFBRRR
+BFBFBFFRLR
+FFFFFBBRRR
+FBFBFBFLRL
+FFBBBBBLRR
+BBFFFFBLRL
+FFFBFFFLLR
+FFFBFFFRRL
+FBBBFBBLRL
+BBFFBBFLLR
+BBFFBFFLRR
+BFFFFFFRLR
+FBBFBBFRLL
+BFBBBBFRRR
+FBFBBBBLLR
+FFFBBFFRLR
+FBBFBBBRLR
+FBBFBFBRLR
+FBBBFFFLRL
+FFBBFBBRLR
+BFFFBBBLLL
+BBFBBFFRRR
+FBFBFFFLRR
+BBFFBBFRRR
+FBBFBFFRRL
+BFFFFBFLLL
+BBBFFBBLLL
+BFBBBBFRRL
+FBBFFFBRRR
+BFBBBBFLLL
+FFFBFFBRRL
+BFFBFFBLLR
+FFBBFBFRRL
+FBFFFBBRLR
+BFFFBBBLRR
+FFBFBFFRRR
+FBFBFFBRLL
+BFBBBBFLRL
+BFBBFFFRRR
+FBFBFBFRRL
+BBFBBFFLRL
+FBBFFFFLLL
+BBBFFBBRLL
+FBFFFBBRRL
+FFBFBFFLRL
+FBFFBBFLRL
+BFFBFBFLRR
+BFFFFBBLRL
+BBFBBBBLRL
+FFBFBBFRLL
+FBFFFBFLLL
+BFFBFFBLRL
+FBBFFFBLRR
+FFFFBFFRRL
+FBBFFBFRLR
+BFFFBFFRRR
+FFFFBFBRRL
+BBFFBFBLRL
+FBBFBFBRLL
+BFBBFFFLRL
+FFFBBBFRRR
+BFFFFFFLLR
+FBFBBFFRRR
+BFFFFFBRLL
+FFFFBBBRRL
+BFFBFBFLLR
+FFFFBFFRLR
+BFFBBBFRRL
+BFBBFBBRLL
+FFFFFBFRRL
+FFBBBBFLRL
+FFBBFBFLLR
+BBFFBBBRLL
+BFFBFFFLLR
+BBFBBBBRLL
+BFFBFBBRLR
+FFBFBFFRRL
+FBBFBBFLRL
+FFBFFBBLRL
+BFBFFFBRLR
+BFFBFFFLRR
+BFFBBBBLRL
+FFFBFBBRLR
+FBBBBBFRRR
+BFBFBFFLRL
+BFBFFFBLRL
+FBBBFBBRLL
+FBFBFBFLLL
+FBBFFBFRRR
+FFFBFBBLRR
+FFFBFFFLRL
+BFBFBFBRRR
+BFFBBFFLLL
+BFFBFBBRRR
+FFBFFBFRRL
+FBFFFBFRLL
+FFBFBBFLLL
+FFBBFFBLRL
+FBFBBBBRRL
+BFFBBFBRRL
+FBFBFBBLRL
+BBFBFBFRLR
+FBFFFFFLRR
+BBBFFBFRLL
+BFBFBFFRLL
+FBBFFBBLRL
+FBFBFBBRRL
+FFBBBBBRLR
+FBBFBBFLLR
+FFFBFBBRLL
+BBFFFFBRRL
+BFBFBFBLRL
+FBFBBFBLLR
+BBBFBFBLRR
+FFFFBBFRLL
+FFBBBBBRRR
+BFBBFFBRRR
+BFFFBBBLLR
+FBBBBBBRLL
+FFBFBBFRLR
+BBFFBBFRLL
+BFFBFFFLRL
+FFBBFFFLLL
+BFFBFBBLRL
+BBBFFFFRLL
+BBFBBBFRRR
+FBFFBFFRRR
+FBBFFFFRLL
+BFFFBBBRRL
+FBFBBBFLLL
+FFFFBBFLLR
+FBBFBBFRRR
+BBFFBBBRLR
+BBFBBFBLRR
+BFFFBFFLLL
+BBFBFBFRRR
+FFBFFFBLRL
+BBFFFBBRLR
+FBFBFBBRRR
+BFBBFFBLRL
+BFFFFBFRLL
+BBFBFBBRLL
+BFFFFBBRLL
+FFFFBFFLLR
+FFBBBBFLRR
+FBFBFFFRRR
+FFFBBFBLLR
+FFBBFBFRRR
+BFBBFBBRRR
+FFBFBBBLLR
+FFBFFBFLLL
+FFFFBBBLRL
+FFBFBFFLLR
+BFBBBFFLRR
+FBBFFFFLLR
+FBFFFFBRRL
+BFFBBFFLRR
+FFBBFBBRRR
+FFFFBFBRRR
+BFBBBBFLLR
+FBBFFBBRRR
+BBFBFBBLRR
+FFFBBBBLRR
+FBFFFBBLRR
+BFFBFBFRLR
+BFBFFBFRLR
+BFBBFFFRLR
+FFBBFFFLLR
+FFFFFBFLRR
+BFFBBFBLRR
+FFFFBBFRLR
+BFFFBBFLLR
+FBFBFFBRRR
+BBFBFBBRRL
+FBFBBFFLRR
+BFBFFBFLRR
+BBFFFBBLRR
+FBFFBBFRRL
+FBBBBBBLRL
+FBBFFBBLLL
+BFBFBBBLRL
+BBBFFFBLLR
+BFFFBFFLRR
+BBFFBBFRRL
+BFBFBBFLLL
+FFBBBFFLLR
+BFBBFBFRRL
+FBFFBFFRRL
+BFFFBFBLRR
+BFBBFBBRRL
+BBFBFFBLRL
+BFFBBBFRRR
+FBFBBFBLLL
+BBFFBFFRRR
+BBFFBFBRLL
+BBBFFBFLLR
+FFFBBFBLLL
+FBBBFFFRRL
+BFFBFFBLRR
+BBFBFBBLLR
+FFBBFBFRLR
+BBFFFFFRLR
+FBFFBFBLRR
+BFFFFFFRRR
+FFBBFBFLLL
+BFBBFBBLRR
+BBFFFBFRLR
+BBBFFBFRRR
+FFFFBBFLLL
+BBFFBFBLRR
+BFFBFBBRLL
+FBFFFBFLLR
+BFFFBBFRRR
+FFBFBBFRRL
+BFBFFBBLRR
+FBBFFBFRRL
+FFBBBBBLLR
+BFBFFBBLLL
+BFBBBBFLRR
+FFFFBBBRLR
+BFFBBBBLLR
+BFFFFFFLRR
+BFFFFBBRLR
+FFFBBBBRLL
+BFBBFFFLRR
+BFFBBBFRLR
+BFFBBFFRLL
+FBFBBBBLLL
+BFBFBFBRLR
+BBFBBFFLLL
+BBFBBBBLRR
+FFBBFBBLLR
+FBBFFFBRLL
+FBBBBFFRRL
+FFFBBFBLRR
+FFFBFBBLLR
+FFFFFBBRRL
+FBFBBBFRRR
+BBFFFBFLRL
+FBFBFFBLLL
+FBFBFFFRRL
+BFBFFFBRRL
+BBFFBFFRLR
+BBFFBFBLLR
+FFFBFBFLRR
+BBFBBBFLLL
+BFBBBFFRLL
+BFFFBFBRRL
+FFFFBFFLLL
+FBBBBBFRRL
+FBFBFFBLRL
+FBBBBBBLRR
+FFFBBBBRLR
+BFFBFBBLLR
+BBFFBBFLRR
+BFFFFFBLRL
+FFBBBBFLLL
+BFFBFBBLRR
+FFFBBBFLRR
+FFBFBBFLRL
+FBBFBFBLRL
+BBBFFFFRRL
+BBFBFBFLLR
+BFBBBFBLLL
+FFBFBBBLRR
+BFFBFFBRLR
+FFFBBBBLLL
+BFFFBFFRLR
+BFFFBBFLLL
+FBBBBFBLRR
+FBBFBBBRLL
+BFBFFBFRRL
+BFFFFBBRRR
+BBFFBBBLRL
+FBBBBFBRLL
+BFBBFFFRRL
+BBBFFBFLLL
+BFBFFBFRRR
+FFBFFBBRRR
+FFBFBBBRLR
+FBBBBFFLRR
+BFBFBFFLRR
+BFBBBBFRLR
+FFFFFBFRRR
+BFFBBFBRRR
+BFBBBBBRRL
+BFFBBFBLRL
+FFFBFBBLRL
+FFFBFBBLLL
+FFBBFBBLRL
+BBBFFFFLRR
+FFFFFBBLRL
+FBFFBFBLLR
+FBFBBBBRLL
+BFFBFBFRLL
+BFFFBFFRLL
+BFFFBFBRRR
+BBBFBFFLRL
+BFFBFFFLLL
+BBFFFFFRRL
+FBFBFFFLLR
+FFBFFBBLLL
+BBFFBFFLRL
+BBFFBBBLLL
+FFFFFBBLLL
+BFBBFFBLLL
+FFFBFFBRLR
+FBBFFBBRLL
+FBFBFBBRLL
+BFFBBBFLRL
+FFFBFFBLRR
+FBFBBFFRLR
+FFFBBFFLLR
+FBFBBBFLLR
+FBBFFFFRRL
+BBFBBBFLRR
+BFBBFBFRLR
+FFBFFFBLLR
+FFBFFBFLRL
+BBFFBBBRRR
+BBFFFFFLRR
+FBFFBFBRRL
+FBFFBFFLLR
+FBBBFFBLLL
+FBBBFFBLRR
+BFBBBBBRRR
+BBBFFFBRLL
+FBFFFFFRRR
+BBFBBFFRLR
+BBFFBBBLLR
+BBBFFBFLRL
+BBFFFBFLRR
+FFFBFFFLLL
+FFBFBBFLLR
+BBFFFFFRLL
+BBFBBFFRRL
+FBBFBBBLLL
+FFFBFFBRRR
+FBBBBFFLLL
+FFFBBFFLRR
+BBFFBBBRRL
+FFBBBFFLLL
+FBBBFBFLRL
+BBFBFFFLRL
+FFBFFFFRLL
+FFFBBBFRLL
+FBBBBBFLLL
+BFBFFFFLLL
diff --git a/2020/inputs/day6 b/2020/inputs/day6
new file mode 100644
index 0000000..22f2281
--- /dev/null
+++ b/2020/inputs/day6
@@ -0,0 +1,2197 @@
+rypdeiqkbgacnxwumhtozfjvs
+mhrqdwtxcfjuseknozipayvbg
+gunjdtebovsyihraczkmqxfpw
+pqcnduafgkbzjhvirxtwmesoy
+
+wmghxlzctojyspn
+jtohwzpvkmycs
+cuvkjoyheztmqswp
+
+detmwhk
+emklvdf
+yemupdxq
+
+hdxektmfycarwpio
+epiamhowxdcktfrvy
+octximeakfhrwdzpy
+
+pxwnzji
+jrpoawxiv
+wjiqxmp
+
+ch
+loct
+wxmtjeup
+hfyxktz
+birvsdq
+
+rluz
+zlwruq
+zlur
+lrzu
+
+omcwsj
+sqkjwruc
+cwpklf
+vtyadxcnwzg
+
+clfnzvjhpiybwoksxm
+snzxvyfopbmhijl
+nxymlhjvfzspbio
+
+jwevzxdhpyrifcuksqgt
+fglozbuswkmdr
+
+jvhgezpqurxalk
+qhizygwbtfupljcsmo
+
+jge
+r
+l
+rg
+
+icgh
+gihc
+ghpvdkic
+gwhcfi
+
+woerv
+ow
+powf
+
+zhqvdxburfmstkloiypgwj
+bpzcnvwudtkhfomsrqayiegjl
+
+bjhagpqxvnrlsufytz
+yjdnqhosbtuzexgpvar
+qbksyczativhgprnxmj
+
+vdmretq
+tmrevdq
+rdqemgv
+jnmqvedrzu
+dmgrqve
+
+namzrqsdlftvyexkopu
+fvtneaqyurozkpmxsdl
+xpznavflsetruykomdq
+sbxdlymekrqanvztfupo
+
+whjs
+hsjw
+shwj
+
+szpqmkodtfgeivxybchnjlr
+yzrpefkjichgmvbodxtns
+inxafhbszovdtmjgycrepk
+
+lnixphrqcuszfbtwyeod
+doupcibeqshyrfzlx
+oprqsdhixfuzyclbe
+
+ojnv
+jnv
+vjn
+ajnv
+
+ymtfzirplknbejwucdaqg
+eczmygatkuvwiprqjldnfb
+ydqbeflnikwjprmzutagc
+
+gvbithwxzdyfkoep
+ixyozwhevbgdftk
+fhpozxydktgbewivc
+wodpgnvektbqhxyfiz
+krxfwoystdgbizevh
+
+qnp
+npfq
+
+wylxqpgvuafbtjneid
+lfjamczetspkwvbdqoih
+
+hpbjdyiwsg
+dipwjhybg
+pcubgwmridjyh
+dgpyjihwb
+
+gcbxv
+vcbg
+
+pjgsyzteohwaibnc
+ohlwfgdvtczsnpejyxaqi
+pzmewhojayscbgint
+
+foytjxbhiwc
+nxfigpqyhuckm
+
+ta
+at
+ato
+tao
+etaf
+
+tyebulroispdqm
+cheqfk
+cxnqejfwag
+qaze
+
+xs
+mexs
+vfxls
+sehx
+
+plvqenkgiwj
+eihjplvnwkgq
+
+bcteiamnzljyrvhqxwpuo
+ctleshvprmknxibjyozgqwau
+venmchpqjxzwoultriyba
+malqychnozbxwtjepirvu
+
+qlvcexgauwkonr
+ysrvfxtigcnqmdjab
+nvlpxgzacohrq
+
+r
+r
+r
+r
+r
+
+sth
+tsh
+ths
+hts
+hst
+
+j
+j
+c
+j
+
+fptakxrwqzghcid
+hwudjvteyqnmsxbzrl
+
+fj
+fj
+fj
+
+qd
+e
+
+dfqagyzoluemikxhr
+hmfzegoyikalrbu
+
+amz
+zcwma
+zma
+zma
+zam
+
+iavezojwpxgf
+azxqivwsgufjo
+vfwaoguizjx
+
+vdytwaugpmn
+ywgtvdaunp
+rdujgtknywpav
+
+hcjobxdagvtzureimn
+egouxjizsrpmatncbv
+bovgcisajmzedturxn
+ymcauqenrwobtjvxzgk
+
+z
+k
+mt
+b
+
+onxdjc
+kij
+jekrlws
+pqmtyjvbz
+
+lrekpb
+cs
+f
+
+miukhetbgpcofnywld
+fgypmoutcnewkdlhib
+nmegdpfcbtkhuoyliw
+iewbnmufpltydcokhg
+
+fm
+zc
+
+q
+g
+q
+q
+
+d
+qov
+u
+
+vpekhuanwyitdbzq
+taivnxwfphzkbueyld
+
+ivuq
+iuqv
+viqu
+iquv
+uviq
+
+w
+x
+g
+
+aqvz
+msitp
+
+epigzysdnhvjwfl
+eiwvzspyfnjdghl
+ewizvgjnspfdylh
+ifpjzlwedysgvhn
+shzlefdvpgiynjw
+
+gfcpvheli
+leuizvgcfhpyw
+jrolbshdivfg
+
+nozm
+rzbe
+rzeb
+
+i
+i
+i
+i
+
+l
+i
+w
+xl
+cvd
+
+prezgubljmyq
+hdjgxymcrbqutzk
+ugsvrjqybzm
+rqbmwuzygj
+ioqzjaufbgrmy
+
+lvkwrpiafgehuj
+bighyasoqfk
+
+zjopywe
+yceowzjp
+qpijoyzew
+hbfgusynojvrezxwpadlk
+etzywpoj
+
+lyawqpmirognzstbduc
+luieajxqpzokvygftrbns
+
+xpbjvgmclwyaeui
+bmlxpsueqgciyjv
+tvcnmrlgybjeuipx
+vyeaxbjufomicpltg
+
+scbpelzjd
+qicbopdefs
+bescdp
+spbcejgd
+
+izqc
+zc
+vcz
+zc
+
+zxtpqjousimgwd
+ldjvupmykawohsxqf
+oupwbjqdexsm
+
+nldjubr
+jlrudbn
+ldnujrb
+unldbjr
+
+gvrhtzabkpjwin
+iylsvcqftb
+
+ieurvztojxs
+utwrozyhsjpv
+djtouzvr
+ufznbqkatjvcol
+
+lauocyjix
+oacxleiju
+jalucorshi
+
+y
+xyj
+yp
+y
+
+tzdopeirawxqj
+xfjitporuzwhmka
+owkfpxhtiazrj
+
+xabdw
+xcbadw
+dprybzwjxa
+bcxawdv
+
+qhmetwcuiagpv
+pvcmhigewqau
+wvqheiacumgp
+unmpjlciwehbgzqav
+haevgiqumcpw
+
+fndv
+dik
+nmcjhfbs
+lxzquaproeyw
+msjfgti
+
+rxcq
+cslmqje
+
+vkl
+v
+umr
+
+tgflck
+tbmafhgjx
+ctgwf
+gwtf
+
+afn
+anf
+fna
+fgan
+
+kbypmroflcgsijqt
+merbsy
+yuazxsnwrvmb
+
+mbqeotcwa
+wacbtzme
+
+ykgwomscpdr
+udsmiqophxgazc
+
+byhgswqf
+ziruakpdxenojt
+mlhyqcbfgv
+
+sjcpmgfnqkbtvh
+tjhaocknsqgvzmfxb
+hvskbjtmfncqg
+svgmbtkjfchqwn
+
+vxnyazclrhigju
+tzejprxgiuvnhl
+
+kfgrnpwahvuzbtdeosxycjl
+codeskpxziflhqmtnw
+nzpkocwlfexhdts
+
+amxeu
+xuem
+muxe
+xmue
+
+nfdekjvaswxhlizumqcr
+ahvenfjwmqukxrzslcdi
+amzhrqdvknuwfelcjixs
+ahzxsfnqcirwdvlejmku
+kmivhzfsdxrwueqcajln
+
+ahutglpcfobw
+inbgfhawctlu
+glxabyjwdersfhut
+glwnbvhtfqua
+
+tkvnhiguafzpbryomqs
+fjuqmyizhtdvrapbgok
+
+lavnu
+anuv
+nuva
+vnua
+avnu
+
+dsypquzvk
+yfvpuwkqxzd
+zaqdpkvuhoy
+
+hztcgilumwfjqvdx
+ljdzmfxhwnocukva
+wdzxlcphvfmruj
+vwtgemuhljsyfrqdxzbpc
+
+gylhmqsfo
+flhgsmqoy
+yflgmhosq
+yhsomlfqg
+
+njrtykmqhpsbl
+ehrqnbmtpkyloz
+tqnydrhcxmbkp
+eykmrhnqlpbt
+
+x
+t
+t
+
+xmbzthspyqiwkre
+kmertowqzhy
+wntlghzqvuaym
+
+anzmrgh
+hvbz
+ikcqewfo
+
+bmhkpvatlxsqe
+qhlsvmwkaxtbep
+afvyqxopmebkths
+kmaqhpbvxsect
+smhbqatxvekp
+
+rhlvqfi
+fhqlvir
+vlfqihr
+frvhqil
+hrfwaiyqvl
+
+kqp
+bkpq
+qknpb
+kfbnqp
+tmqlpk
+
+zamldqftosjchig
+sgoltqfzhcmida
+ilchsoqyzdafmteg
+omtzqschailgdf
+
+dqtzj
+qdzjt
+wjqbztd
+tqdzj
+
+f
+f
+
+a
+a
+e
+a
+
+lthopwunzesadc
+agcpuiqwbezrfm
+
+vecitwkr
+evrwktc
+twejkvcly
+tvweckr
+
+ivhprtaqxluznd
+czhpmktnbarjuqx
+hntzuxaqfwpr
+ztqfxhunpdagrsw
+
+yearmjzfvoglksutx
+ytxonejacwgkspvbl
+
+gctxse
+cjgetx
+xocetga
+
+uedfocpwivngk
+prxuiveon
+hpovnuimel
+pexivunoj
+
+cdsqhptunrmgjvfiozl
+srvuhlgimntpjfdoqcz
+hotpzrcfvsgdinqljum
+mtdfnzogrluvhsqjpic
+imshvtfzoprnqcjlgdu
+
+qvitpoadjkfe
+fhtwujgxmyvqp
+fvqtjp
+
+igcu
+cpzkirmaqeuvyjblt
+uwfhcio
+ufci
+
+olpayrzujbxigkmtdwfvs
+mnlajiogzfyvxdptbkr
+gxkjabvmdptlfyiozr
+
+ozuitjkyrplmwhx
+wqilxmrjzphk
+zmpflxwkrjhi
+
+xklnmyjz
+tbywrnecm
+qasm
+
+nmqezcib
+bqcine
+bqeiwnc
+
+gfwcuktlovqaxinrmsye
+apuxbreclsovh
+lrozacsuevxy
+
+sbirnjalhp
+sjlhabinpr
+spiyalnhjrb
+nlahrzjibspf
+phsinblragj
+
+qshiwtzunymecpkojgf
+ycintzem
+mtxbzyneicl
+ntmzacvdyie
+inledacymzt
+
+zikd
+wfrtoc
+xd
+
+b
+q
+
+jtgrvpc
+vnpob
+
+mxa
+bgpat
+av
+
+kluxigjtrnsqmbfypw
+gilnxrjwumoykbsfpth
+
+mxufknlzeria
+xraflenbiupmk
+dxlijrknueacmyf
+
+rcnby
+uhmilk
+
+feojnrqsdpwclkaiyt
+kowqnhfclimjztpybd
+xvcptleiwdofqkjnsy
+
+ugkailsnrj
+banglk
+unsglka
+nlvagkc
+
+dwgqjpsby
+huskprjxgvow
+
+psd
+aspdm
+dps
+dsp
+psd
+
+thnzwocdrfyeagim
+zmfuiecortkbgdyw
+
+twjeozqfdvsbcyiarmkguh
+oqtrmfsavdzwbejihyucgk
+
+turasdgcevhmxkp
+kxmcagstlh
+cbhmxkgats
+
+sxiezthakwvqb
+sewmhkiqzfxatvgbu
+vqathkezswxib
+xwthkbvziseqa
+
+ewxibk
+tpf
+rz
+
+nwztryqmofi
+rjyqwhmfzostc
+tlvaurxdpkbzfgmyeo
+
+imzerbtfdn
+teifxzny
+enytifz
+
+rcvuafzdqkxweg
+cgvaqxewzdyrfuk
+
+kbmjndsal
+adjlbisnm
+mdbsklnaj
+nbasdljm
+
+qvolp
+qckuzi
+qritmn
+
+lqcejxk
+wtxeqkcl
+jlxqekc
+
+vqregkolsbfdx
+qkvsoeuxrbf
+jkaixwvrqbfose
+
+ctogmvsxiauy
+szuhoqagtwcflikyd
+ctoyuagsnvi
+utygcranvosi
+citoygeusa
+
+fuwk
+yewkljpxi
+
+zarpyjehu
+putzh
+ptnkze
+zplgbvm
+zhstyqip
+
+hrxfvwopsaymtgc
+xfaywpovkgtcsmzunrjh
+vxgmrhcowsytafpi
+
+cipegfjmxbdzutorshn
+efvnwuaoipbyrjtgd
+
+wjtryvx
+rtxjbyw
+nkrpxjolqeu
+
+wqjmgluhebv
+jsgqirvulf
+
+hljupxyodbzrg
+lakmhpqogvucnxf
+
+yjuwmvanoxs
+swvadnujxm
+iwvzrutpsfgjxqnm
+
+pzdhvwcjekifnmb
+vnkmzhboiqdjp
+
+hqrpeaktlvsjmdcwufnyzbo
+qdvruncsmtyhoepwixkzgjf
+gqsdzvpmhrjntifcuywkoe
+
+xwszdpuln
+otbha
+tjo
+
+waqvmjecpsyhfztlbgodn
+gmaewohbzjnytvcfqp
+ofyaizgvhnbtjqmep
+odjygheabpfztnqmvk
+
+ezb
+buze
+zbe
+ebz
+zeb
+
+z
+z
+z
+
+vfcjbpaiut
+fjagupcio
+
+my
+ym
+my
+ym
+
+lhqavgbsef
+fvhqbegsla
+
+p
+pfojb
+
+gyavhelf
+plefo
+
+mirkdqulwbsctjvgxop
+bwptsyqrckfjgxliovm
+xdswvpuckjlqgibotrm
+qcwixtbvkplsjrgom
+
+lrjt
+ltr
+trl
+
+nzuy
+noy
+jbynz
+bn
+fkctn
+
+uxifynkerjas
+fxykznugtcj
+bfyknzuxchj
+qgkfmdjxynwu
+jduxknfyh
+
+rgq
+rg
+yp
+
+inbvhkjzegyau
+shxbcotnuda
+
+xtpyoswvjhueimdafcl
+odmjlhvepatuysxfbwci
+
+gfx
+f
+dfeikvhjqz
+f
+
+nryktcwsaixulom
+wusiydlktonmcxra
+xtikuqroycnsalwm
+
+mp
+m
+ztm
+m
+m
+
+lxohyprcwdgfz
+ownfhacrlzxydeg
+rhofgywdlxc
+fhcldyrgboxw
+qfhoygdxlcwr
+
+mrigdkbhzuonxvwtsejcp
+xrwnmbzohcteyfdkpisuqgj
+ngiobsrhvdzweukmtpxjc
+drocwhmseuxgkinbztpj
+
+xpuchemftsnyakqoljwrd
+dksrjfheqmcxuotwnglap
+tmjpalxnrswhuekdyocqf
+
+xftzuvoksbai
+ndgmechlpjti
+
+ygjwtmhqsierucdlkxfv
+ufriqgwdtysjevxhmkcl
+tokicjvdlmwfzxrasphqeg
+iyjtgwmcelhksrdxqvf
+
+rvzhcsjgd
+gdsjcvhrz
+hjvdsgczr
+vjhzdgcrs
+rchvjsgztd
+
+trezphilc
+yzfnqrbli
+
+qkofmyptcnwjsxlgaivbuzh
+vbostfpnwuzagmjirlhqck
+vasbchflkwjmngztopuiq
+utjikgmorpnfaqwvzchdbls
+ultmzaskwionhvgqpbcfj
+
+aivo
+n
+i
+mqergs
+pv
+
+rjgbw
+wjrbg
+gjwrb
+
+hwmxaigndkrvfzslo
+hiamrnksowxdgfzlv
+hkiornfwlmaxgzuvds
+mnvwkdfigshxalorz
+
+pkygn
+pygnzk
+kuvynp
+yknpg
+
+itxjom
+mtoreix
+omidqtgsnpc
+eukmyioth
+
+vdwjtnrsbcm
+smjtngvobycrwd
+cjtvdanswrmb
+bdrmcjtvsnw
+
+zoays
+isyzao
+flyzsoh
+sziyo
+
+mth
+mx
+vpwyd
+
+gyoarlze
+uziptwenxl
+aroezlv
+eclkz
+
+cevajtinmwfoukhsdzpyrx
+sjtrelpfmgxdzwkbch
+pcfjrleqxkzthsdmw
+
+siwrzbtkpgcy
+fpsobikx
+xsipkb
+pkudsbi
+ksbdnmphxi
+
+rt
+it
+ptsknv
+jt
+
+zcxwh
+rcifke
+chz
+
+jbadzfryviqumgsxcel
+vghfzqrxcmebyid
+egyzfbmtqrhdixvc
+
+qundsy
+nyquds
+snyeduq
+
+dyxm
+y
+
+xczlmdvehwarin
+dmxehrcviazlw
+
+qhzsntxcl
+hewbptlv
+trwlihs
+kgljmtudha
+hloft
+
+zugp
+plugh
+
+n
+n
+wen
+n
+
+ajnpdutlwqrm
+rkjmqgauwlndotx
+umtajnqdlwker
+
+rkfgeadhcoxzwtbqnjusilymp
+fbnrpwixalqzeskytgcmjoud
+nuomgcwzbyjqipfkrdaxtlse
+ykjbeigafqodmsxwcztlnpru
+
+sgpxdjumiwhetbl
+wagnkvylcmqrzxf
+
+qpwdnblezgkcas
+pzalvqnfebcdgksw
+wclkgspdbqnzae
+sgebqadzwclnpk
+
+hsdvxqrbegzpuak
+zvaprehkgdqbusx
+
+trhxk
+rokh
+uhkr
+rkh
+htmrkp
+
+ayjmlkhqefvrgiobswpzxut
+kgqdnvslwhpxjmryuaezto
+
+xdnobmsceipwgyqtvkazlu
+jzyougkeavxtmslficqpdrh
+aieoyslqxgvhzfdtkupcjm
+
+oekdcqtvhfsmwylaziubgjx
+cseyloawjthviqgudfkbz
+agqkrlebidofhtwujzyvscn
+
+ou
+oy
+oa
+you
+
+kjrzmptbna
+iacpmjzkhulot
+pmjanvkzte
+
+rpdqax
+apdrnziqb
+
+mochksjz
+chzskmjo
+cmkzhjos
+cjkshzom
+
+braqipxm
+pbamxrq
+maopqrxb
+
+sezkqwtljnoy
+stlnowkejqzy
+kyeljtnaqwdzso
+sleznjotwyqk
+
+a
+r
+c
+
+ymuxdtjlsovq
+kdomytxrqlhsjun
+xoylgbdstzjqmu
+spxqoytmujld
+lxtsmocuyqjd
+
+wktsrjxdlizaefqbo
+zjbxldwsqfoaertik
+lqwktdoesxfijbrza
+fkbshvtexolqrimajwd
+
+rplog
+jifvbd
+hus
+zpaymx
+
+dljqhy
+mshry
+iahwgyt
+lzhjkebyq
+rykph
+
+o
+l
+l
+
+rcxhypj
+jxhrcpy
+cvjwhxyr
+
+k
+k
+k
+k
+tk
+
+nckmsaqbyu
+amsqutbkcny
+qvkausncybm
+xkabdomuqyncs
+nbmsuzkyqica
+
+fmykuezs
+ymwkzspfrug
+isyfuvmknlz
+mfyknzivslu
+
+zjegqtakx
+eztjkxgamq
+kozgqxjiate
+aoegxjztqk
+evazknxdgjqpt
+
+vgsxdnkjbfhiaetcprluo
+dtnuvboigfpehkslxrca
+
+cwomixyvlubhk
+oaqsvyfhgxzenjdt
+
+zfm
+mz
+hixzmusvwrae
+mz
+cljzomp
+
+aimzewnqpdfy
+hwqfnrpjymatid
+pnweyqagxmifsd
+
+jagrtqsikbnm
+takgijrnmbsq
+tqkasinmgrjb
+kgrajsmtqbni
+njbtigamsqkr
+
+us
+su
+su
+
+oxdmjrcfluiwyz
+zqkmrgditwhocxfj
+
+nmdwq
+uwdqkvn
+jrneyiwoxat
+
+o
+o
+o
+
+thqpmc
+tzlqhbep
+qpeth
+wnjtdqvashgpo
+
+forgjwbimycezkaqsuv
+evsarxjwikbyguqofczm
+kmciyqvrgubsjazefow
+
+dnzjkpraybifesmgt
+gbnpizsfaetdryjmk
+tedmfpsajrznbiygk
+bjypsrntedmkiagfz
+ptugzdvlaeynbrimjkfs
+
+ahgfxmszervkt
+khnfsrdwexgzicm
+uoehlpmxyfrgszb
+
+a
+a
+qa
+
+bscjlkuietnfmvhqa
+zpmdysghcukrxwql
+
+ybxngswmtzlv
+tlrnfwbsgzxvm
+
+szdfxgvuiyjkola
+yfkgxdzisjlmau
+fujmxskalzgidy
+
+slgcrih
+rqhgl
+ctrylh
+zaholrxk
+ldqihr
+
+c
+z
+a
+
+l
+ol
+l
+l
+l
+
+yijuzlomvp
+mojpuylivz
+ozvmpyjliu
+zvjulmpoiy
+
+inxdohsz
+zosindxh
+qxnhsizdo
+
+nwxljyekmazfbh
+akwzqbylxdirjomg
+
+kowimsdrbjcnxtauhpzel
+mucayqfvogjwelnhtr
+
+d
+d
+d
+
+spnrxclg
+kcnprgsl
+lngcvrsp
+grnelshcp
+gnizpcjsrl
+
+cshdbjovlfnkaezmwqipt
+tkdpzrfiwhcbmveonlaqs
+wsmpkrlhvbieaonzdqtfc
+
+mjlotdgyzucrxnkp
+oyxumpbjngrldftkz
+lrtzmxjsguknoypd
+xmqrugyntjkpdzol
+kyojtmrpgudxznl
+
+cwvpnuyjxelgkabi
+ajliexnugckvpbwy
+xiebpgvnkwlayucmoj
+vlgewuabjkncxpyi
+
+cngbduwxzsa
+vbdjnpaczu
+zkjcandobyu
+boacduknz
+jcnuadbmzvp
+
+armxudckhoyjqbtli
+kcynhliroatmuxbqd
+abcroqxklidyhtm
+hlcmaxobrktydeifq
+lkqxichayojdrbmt
+
+slthvjp
+tsvhp
+sjhypgitv
+petvzhs
+svhipt
+
+xzmcwdjlnqtyboak
+dhwyjfxlqckmtozanb
+bczotlnmdkwaqxyj
+wqtybjxamkzldhcon
+qtnmgwdcyoakrvbzxslj
+
+gyrolihnftx
+ywlhbxfoumigr
+dfoihgrapeuxyl
+
+juredoybhpalsxkmztwvgnicqf
+yzuceqoikxgvpaflbrdjmwhstn
+
+mhwkugfvsr
+syicghpunw
+snphygwuc
+nusgwh
+
+nxystlabuqzcfwdik
+ucyaztnkdm
+zgcrndkatyuh
+oadutnkzcy
+
+rftpkiwz
+fwkczpt
+
+kwbpsjlvhrcumifgeaxn
+fbxgslwjmnucrpkeiav
+evikuwganplzrbxfjcms
+mfripxsbvaeckuwlgnj
+
+xlsekqbnoj
+keqjlxsoib
+gojbxelqsk
+
+tduwp
+udt
+
+fyivbg
+age
+lnpckwdumgoszq
+
+vtdm
+dmtv
+mtdv
+mtvd
+
+sxqcuwzdlpter
+uzpesxlrqdctw
+dcfmszreptwxqolu
+
+mlbezcfirsxnughtpajvwdq
+eswufgarhxmdvcybiznljt
+umgbwcadfiovrxknhszlejt
+
+hoif
+wrdvuxj
+kgloem
+bmngy
+
+ta
+ty
+fsgnmtbq
+
+wzucbvdygxeparqhslomjif
+rulbgvdpsmzihjqcwfyoexa
+glaicvjyhdwmupsebrozqfx
+qloepvwjszdahxbufykmgcri
+aqjexmwyuczgdhropibvlsf
+
+lsdikhoarexcmu
+ygdjrhzmku
+hkpjdrmub
+bhukrdgm
+
+xyrohb
+eg
+p
+e
+
+eqnbpzlhmxskrfy
+xtguwjadpciv
+
+k
+tb
+
+ipoyng
+phqfxkeyg
+
+mqfpoj
+mojfqp
+jpmofq
+jqpfmo
+mojqfp
+
+tsjrguiplcqnwxkdhfo
+lspukzenrgfhtqxdwoj
+ofxgqlduwnptrkjhs
+
+a
+x
+u
+
+bfpdkihjuz
+nqvgjyk
+olkjy
+
+zdkwbghexisn
+izwngysbdxhe
+dsebogwihxnz
+zhnxepwgbsdi
+snzhwdxegbi
+
+koupnhmi
+spkmut
+pgutkm
+
+qcytokhmwdarzx
+pktnxglqrsz
+rekxjqbuzsti
+
+vluoh
+abhoulv
+vhuodl
+uovlh
+
+xpqhfuimjzstyecvgla
+mfcgetpuhyzvljxqska
+itlyxguqmfahsecpvjzn
+xbgrtoazjulhscypemqf
+tjplsvandfzyemqcghux
+
+oudlrfq
+qofrdulz
+
+cqaxm
+mdyibnoxe
+
+pc
+cqm
+lrovgwjh
+xbzt
+
+r
+r
+r
+r
+
+wenypm
+tvzkqaihjrldusbcof
+
+qsjnkitvmogydzul
+bzqwxkg
+zceakgq
+cqkpfgzx
+kzqrhg
+
+xjk
+kxj
+jxk
+xkj
+xkj
+
+rpjwnm
+rpwnm
+
+foixgd
+xdgsi
+
+ldiwcrqgfztuonyespmjh
+cendtkpwuzoyfsgjharqi
+qztuedonysxfcwghjbrip
+cgtijqzbefnpovuhrsydw
+
+hnuojmr
+lmhnuj
+urvhjman
+gnuxpmchjk
+onumtjhy
+
+mksn
+qjsolvyktu
+
+jixlamkwrcotzfvnyup
+uwndpoetkfxzqcvgras
+
+mlurhwbpezjgayoki
+gjwcheubrlpkyozxm
+eysbprwjcukldohngmz
+oejmghpxkybzurldw
+goplbuhrymwekjz
+
+gdi
+v
+uao
+h
+j
+
+eotq
+yrfz
+
+xf
+zxfp
+xf
+
+jvcknhizeyopx
+abgfs
+
+xdhnia
+tdhiaxn
+xihnda
+hdnxia
+ahxdni
+
+cvfuohwdqmsj
+usjvqohdcmw
+qshwovcumjxd
+
+ewcxpunrfo
+ncfxeupowr
+neucwxprfo
+onxewrfcup
+
+h
+h
+h
+h
+h
+
+etqny
+tiuoqws
+vbfyqtzd
+kaqxmthgclp
+jrqtu
+
+tkylicfwajbmqz
+aqjwctliysokxfb
+
+pohmrbxse
+rspxeimobh
+
+topbkx
+akoxr
+oxbk
+
+rfixzuqejpco
+orecijpuqfx
+rixqejofucp
+fpurciqoexj
+xpqouicejfr
+
+irvl
+lv
+
+jlbtmhk
+tjahe
+
+fycatxuj
+efmsru
+vgbzwolufn
+fduyp
+
+qpovf
+oupvq
+pvobkq
+qzoplv
+
+uvbzsmd
+szdrobh
+
+sohcdqkxlb
+kbdoq
+qdbkzo
+qknodb
+qodbk
+
+wlikpav
+plnwzvreak
+klwjovpa
+ialpwsfvkj
+
+nzswdxachlvukeyprbqtmo
+aulktbvnzwoyehxmfcrqps
+
+cdbrvskoujqzlyxpfi
+pkljysocqvdrbueixfm
+ibsyupvkfjxoldqrc
+sprcluoxbfkdjqyizv
+
+dulfhtqpnszabcx
+ptibcnahdurlsfqx
+dxfaqcpbhstlnru
+bdxtfvmhlqasopnuc
+satpglqhfbcxudn
+
+fwmnrayciqxujegtlhzsk
+gyakijxmslrzwtqncuef
+rilkmgtxfwjszqanyceu
+hwmnsizfgqltyarjkcuxe
+pxutjdwsclbgfrmnaeyqkzi
+
+cdgvmqewjhobyt
+cibsqlxrk
+
+vzncysgojwrfqxi
+pgivscjroxnqwfyz
+zrijfowgsyvxnqc
+qygjhbnwfxozlvicsr
+oisgwxvnrjycfzq
+
+bzgdqm
+mgdfz
+gzmd
+dmqkzrg
+mstzlidjg
+
+lqfnedzwckxuamrsbhjip
+pzilqrxtfswogecdav
+
+s
+s
+z
+
+wm
+wm
+wim
+twjqm
+wim
+
+lrxagomjwhncfy
+hbfdjsolgymarwcx
+amuhoclgvfpzwxjryi
+nlfmwoahdgrjxcy
+
+ux
+a
+mwzc
+
+xhsapcqjkum
+vdkquacsxijpmt
+hpajmqklcxsgu
+
+rymaftlzunxocwhgs
+uxtwrncsfzohpgyl
+yohwnrtzfkcgsulx
+
+hzyflavwpnexbgr
+lzvfhgrxpebwa
+gzphbewafvlxr
+evgxhzbrpwlfa
+
+baygtmsorczixvejfh
+zgrjmytxefabishcvo
+jyvxgofmarisctwehzb
+
+ozbwxdfakrthqc
+kcxftawdrobqzh
+zqxahfdrtcwobk
+xczwfkaqdhbort
+akxfztqbrohcdw
+
+cklb
+kc
+
+iaymow
+muwoyi
+mihywo
+yaouikwm
+
+drtlioynkumajzshbpxcvq
+wdovutrflknzbmqchpsygje
+
+aunct
+jtasuf
+
+otybmvxqkeianrhpsw
+zkaphbuqxoywtvrei
+hlwkrtifbqyoaevxp
+rvkhasoxpebqwtyi
+
+mqpynkuoteafwcszhdxrg
+tuxkcrypafgbqmnohsew
+uymgxcnqeakwhfptrso
+
+nb
+k
+u
+
+oacmsvdy
+
+tlgeajvodcspqmnrzwixkhyubf
+lqhrinwycugfopbstjkezmxd
+
+bajwthnox
+phbtjna
+kicnbjtfaeh
+
+upcd
+rcuds
+cupnd
+dcpu
+
+usodtpgbxrleizwcnfvhakqy
+fhungotvpyrxdjkqziemcbla
+vlkezrqchjdbagfouityxpn
+
+enlctogvyz
+vczpwdgsoyqljknbrmt
+lcnvyotxgzu
+flgnvtyozc
+tzcyvneolg
+
+z
+t
+
+kzgwrn
+wzrisnk
+
+fcznyxtwa
+wczxnp
+
+modnyjbvgzck
+zncvfomkdbgyj
+mbcgyozvkinjd
+
+lpyvkoawcigmszdhunrtj
+oygwlmuhvjptzcrksinda
+pudhgtjkwaclsivmnryzfo
+
+av
+ajh
+avt
+
+apondg
+ngvef
+
+ipxhv
+wqdivtpxl
+irvx
+xiemubayv
+irxwv
+
+othvi
+vehz
+hvxldcez
+
+gcwksjv
+euxzbwgyfkjc
+ksjgwc
+kjgcw
+
+vsmpidclexktgoa
+xpkdcgmsetloa
+
+wmbphlzfisxg
+tovkbqyzsfpl
+
+pegjkcnywbhr
+lzkgjbenxwaqyc
+
+vnfgtzw
+ouhvagqycpsdtlwikne
+vwbzgnt
+nwvmbgt
+
+uzvjphxfcqg
+piqjfunmaxvkzes
+ufpjzxvq
+vzxfjgpuq
+puhjfvzwdqx
+
+gcn
+cgn
+inegk
+nguc
+
+nrtl
+ldthqxi
+thl
+dhltp
+
+lqopsckhyjtw
+kaqxicgdzywevfbu
+
+lpodcxkyjevg
+dvklycxgwpoeq
+pxelgdcoykv
+covedbykglpx
+brpcyexidgvkol
+
+tapwumcjxbeok
+jvaxthlypumkibce
+xipmyuecatk
+ectpdamxzquknh
+umxarptcgeks
+
+dhabkrtxyepluofsqn
+yfluxizrmepchjndsvak
+
+j
+se
+
+gahmztkwboqelpiu
+tlhqpmugawkoxzif
+
+tsquf
+qstf
+
+qalg
+zcij
+wsgvl
+
+wdbrxt
+wltx
+wlxt
+xwlt
+
+ovfegbwyxdq
+bwxqdmygtevuz
+gqxwdyvbe
+
+ohx
+oht
+hrzo
+hto
+
+cxfg
+jxf
+ifx
+lfx
+xf
+
+yguq
+gqyzu
+oqguts
+qgu
+ugq
+
+dchajzrwvkptfmsi
+zkrhavifwtcdsjmpx
+vtfpsckaimwrdhzj
+zpmscahjfvkwtrid
+dzawcriphmskvjft
+
+ebmwykdnfpqzlursx
+lcfhzqed
+vlzfqaed
+elfizqd
+ofqehzdl
+
+fhyzodpvjg
+dgwjybzov
+
+pfbzsvrw
+vbspwfz
+vanuzbpwfds
+sbzpvfw
+wpvftzbs
+
+sjtvukw
+wscktjuv
+ustjkwv
+jtwgukvs
+uwtvnskj
+
+ylkne
+jetb
+reo
+lpeor
+
+sutbnz
+dnts
+tsn
+
+riyn
+riy
+riy
+
+ygbzxlwfrp
+lxpwyfgzrb
+wrlzbxpgsyf
+
+slbkhm
+lbmschf
+
+u
+u
+u
+u
+qu
+
+lmdnixreobwgkz
+znigbyrdowxmekl
+emolgxwrkidbnz
+edbmlonrigkwzx
+kdbzworeigxmln
+
+wbvohcntuzgkiqle
+kjzvybxedwnpfrtc
+ktjwcmyvnsbez
+
+bprfjknlqxszmody
+nlxfmpzadjosrbqye
+fbmsaujxdirztyopwqln
+pnxqsmdhgoybzlvjcf
+fomtripxnljbdqzys
+
+kcpygiesudlbvtfzxham
+nrdlbxmgeaczitjuoqhw
+
+dg
+xnkt
+
+bfwdtrizlpheavuyqnjos
+ubydfogztjraphnevswilq
+
+w
+w
+ew
+w
+w
+
+a
+xd
+aj
+
+gbdzh
+dglqr
+
+vudclgx
+dkjhwel
+lrtsydb
+
+gxzqm
+oin
+
+yzpuwnrosctjgivd
+bgwmfkslpden
+pmasgdnewq
+
+nle
+en
+ne
+
+hbkdavilf
+bloxksadhvi
+hvjbudailk
+ivhjladbky
+
+vdscgflymnxubrjqaptwi
+tmgphwfsnikcruzbvejqyo
+
+zbplsicnrh
+glczrbps
+
+brntwcqvh
+nbqhctpwvr
+
+va
+prbzmhv
+
+l
+g
+q
+p
+
+jfu
+qjovgdfmu
+fju
+ujf
+juf
+
+nhajypktod
+hjietodnscxfk
+
+rxvemgzo
+woxmskrgyn
+
+bgra
+egrab
+rbga
+grmvqba
+gabr
+
+oblcizsupdm
+dxuolpbzrmic
+lpbucidzom
+plbzmodicu
+
+suivo
+v
+pnvt
+wv
+
+c
+uc
+c
+c
+c
+
+afu
+a
+
+ow
+wo
+wo
+ow
+oewu
+
+m
+iqm
+
+fatyhbmqngwcepkor
+lpixamknzesdvjo
+
+tgkqb
+mikub
+kb
+
+oad
+doyafpkh
+mshkdco
+sowd
+qidberovngj
+
+kaqvlfyijdozbt
+rqwsbfhoavzt
+atqfszvrnob
+
+svqrgkwuilhzxcmpyjf
+yihumlabkroxzcqswg
+xushykmcqzgtilwr
+ukwhlqsgirnxmyzc
+kgdrwxmlzuyicsqh
+
+xgcvbqyzdtn
+bxzvqdytgcn
+
+tejri
+jte
+etj
+etj
+jte
+
+ismgw
+wigsm
+gsdmwpi
+
+kdhuyt
+ypkhd
+kdhy
+kohdy
+hydk
+
+tseoqvwhuxbr
+ldykeurcijnfh
+
+ab
+ba
+
+ocm
+omcp
+wzjmfto
+mo
+
+vuzyadlnrgbos
+zojynudrsav
+dctmqfyevrixhpuzkans
+
+kwm
+k
+k
+k
+k
+
+sexvtzkumgnrl
+wxdfeiocglqnhmsb
+mnvaelgxksr
+
+numlhsatpefgdxrwjc
+tpgfejhnrdmlawcxs
+xdwracgsthmlfjpne
+
+jfnlsprcqha
+alzqjcnsrhpf
+hlfjrqcpna
+qacrflhjnp
+tcimfrdnhlqwxyjape
+
+bihwtnofygkmlrasjp
+nkmzwhagborfsjipu
+
+mbh
+hmbo
+qwjkvhziclput
+mrhb
+yxhe
+
+blqgwcin
+amxzqdwpbrhonyci
+neqcbiw
+wcnfiukqvb
+ciekwbtnqg
+
+ezsxhnrctpayukgfl
+uhfcxpyltzngksre
+xfqcpntyzuglreshk
+yxugczlrstkpeafhn
+nplzeygrhtskfxcu
+
+bhu
+hm
+h
+xh
+
+o
+o
+o
+o
+o
+
+zfeyitdlxj
+jeiqgo
+gjevqui
+eoikrsj
+
+eci
+ice
+orwbites
+
+linomaq
+mnqagilo
+qimlnoa
+nlgmquio
+lirmnqvho
+
+gvqiyfphlxbwcotrszame
+iberhzpovmxwytqlcfsga
+wzsyatgrmilpfbhocqxve
+
+qykaloifucdmsxh
+dilsfxmyurjqab
+
+fljib
+wuseoqk
+
+kryuaec
+hkuap
+ivkzwltojugf
+
+emrywzsgpkqtjuav
+kphozgjyrqsmavwt
+vjketymzpawqsgru
+zwrhvjyqakgmspt
+qkztgyrjavdfspwm
+
+cufk
+juck
+wcqkd
+kcosr
+
+wymkfrvugb
+brgkwvymu
+brukgswmy
+pmykbwugr
+rugnkmbyw
+
+cfzsnlvougeb
+krhatewdigj
+
+a
+jw
+w
+vkml
+w
+
+mbzltykicoxgnqjs
+jkbyiqcnmzgoaxstef
+bpghumytxjizcskqno
+
+ckq
+qkc
+ckq
+
+crygfszhdx
+xrzopcyhsd
+
+eshnuqkyid
+fvhdutyzec
+
+y
+y
+y
+co
+
+opifqrgwclbka
+ugqoibrawck
+caqufogmbipkrw
+gswcojayirqhbk
+
+kptv
+kprsal
+vslga
+wi
+zfcqhej
+
+mgxrjbkqpycvodwzsiet
+zwqkdbjsmtpeygvc
+qewtzbghpydcmvksj
+
+bnteshjdfwpl
+plcrqhdxn
+
+xezumahpsktiwjylq
+sjytilphzaqeuxm
+eulximpazqsyjht
+
+wofatncugil
+prd
+p
+shx
+exsj
+
+rbsyhmqilpuz
+hkjaotxcfe
+
+rvpdqnkbyshltegifxja
+vseaxdyqiktjhrbfnlg
+lxbtgqjaesyifvkndrhp
+laqyivwjmsbnxfdrktzgech
+
+khmoucji
+umkiohc
+
+axnjc
+acsjnx
+nxawcj
+cxanj
+nawjxc
+
+qhjtuv
+uqvjt
+jqtvu
+
+odbruemawlviy
+vwgery
+
+qnlwkidepuh
+ldqnkuefhw
+lthxdewqjkugaons
+
+lctym
+ycqthox
+
+moej
+ojeuz
+joe
+djyeo
+eoj
+
+fwdeqrzicj
+dcrewjzifqg
+qmcjfiezpwrvd
+ncwzqrdijfe
+
+kaczplh
+khxaplyc
+uhbdnckolaqgjp
+vhlrswcapk
+
+envxjbidtrkq
+bdkyrxntvizqme
+psrkdftwxqbnevli
+
+b
+b
+jg
+
+j
+byt
+hfsw
+t
+iy
+
+uexapjs
+caxdepujs
+suapejx
+pjsaexu
+useajxp
+
+qiuotlgvewkfbx
+eiovbxuwdtkflgq
+uwkiqvbrgpflte
+gfbvweihkqtlu
+kulgiwfqebtv
+
+ekd
+dke
+vkde
+kemdg
+dek
+
+kmhfyos
+fkyhsmo
+yosfmkh
+
+arubwxqszlvmhndtfygpi
+dpfvlgsytzqxnhmwabuir
+gvaiutxnbydzwqprfslmh
+wtgszuandpiyrbfvhmlqx
+
+prkfqibx
+fkrqxbpi
+rpixfbqka
+
+cmthfprlzxvg
+chzgaxjkpwrl
+dhybeprslocun
+
+pdrc
+rpcd
+dcpr
+
+nsi
+vlsig
+ins
+si
diff --git a/2020/inputs/day7 b/2020/inputs/day7
new file mode 100644
index 0000000..0dd7d3a
--- /dev/null
+++ b/2020/inputs/day7
@@ -0,0 +1,594 @@
+dark maroon bags contain 2 striped silver bags, 4 mirrored maroon bags, 5 shiny gold bags, 1 dotted gold bag.
+dark coral bags contain 4 pale blue bags, 3 wavy yellow bags, 4 vibrant tan bags, 3 striped purple bags.
+striped aqua bags contain 1 pale aqua bag, 2 muted yellow bags, 4 pale maroon bags, 2 shiny coral bags.
+wavy coral bags contain 4 pale purple bags, 2 bright olive bags.
+bright aqua bags contain 5 mirrored purple bags, 1 dull maroon bag.
+muted plum bags contain 1 dark beige bag.
+pale cyan bags contain 5 dull gray bags, 3 posh olive bags, 2 striped silver bags.
+muted aqua bags contain 3 muted black bags, 2 posh cyan bags.
+wavy fuchsia bags contain 5 light gray bags, 3 wavy beige bags.
+plaid orange bags contain 2 vibrant bronze bags, 3 pale silver bags, 1 shiny blue bag, 3 plaid maroon bags.
+dotted salmon bags contain 2 clear lavender bags.
+dark gray bags contain 3 plaid gray bags, 2 clear yellow bags, 5 posh gray bags.
+vibrant aqua bags contain 4 posh salmon bags.
+mirrored yellow bags contain 1 drab turquoise bag, 5 drab teal bags, 3 light cyan bags, 5 wavy gray bags.
+muted indigo bags contain 2 pale cyan bags, 5 striped brown bags, 3 striped red bags.
+striped white bags contain 4 pale maroon bags, 4 dull yellow bags, 3 mirrored white bags.
+light beige bags contain 3 clear cyan bags, 5 dull gold bags, 4 dark olive bags.
+mirrored turquoise bags contain 3 dull gray bags, 4 muted turquoise bags, 4 dull indigo bags.
+clear lime bags contain 2 dotted salmon bags.
+dull tomato bags contain 2 dim beige bags, 1 dotted brown bag, 3 faded magenta bags, 4 faded gray bags.
+muted red bags contain 4 dark orange bags, 3 light black bags.
+bright olive bags contain 4 pale green bags, 2 wavy red bags.
+muted cyan bags contain 1 mirrored lavender bag, 1 shiny blue bag.
+faded red bags contain 5 bright plum bags, 1 dull violet bag, 4 pale yellow bags, 3 pale coral bags.
+shiny white bags contain 2 dark beige bags, 4 clear aqua bags.
+dark tomato bags contain 3 pale yellow bags, 2 bright red bags.
+clear bronze bags contain 1 dull salmon bag.
+dark violet bags contain 4 dark purple bags.
+dim indigo bags contain 5 plaid gray bags, 4 pale maroon bags, 2 bright maroon bags, 3 dark fuchsia bags.
+striped beige bags contain 1 pale olive bag, 3 shiny purple bags, 1 dull salmon bag.
+bright yellow bags contain 1 pale gold bag, 5 shiny maroon bags.
+vibrant plum bags contain 5 dotted yellow bags, 2 plaid white bags, 5 drab red bags, 4 clear lavender bags.
+clear olive bags contain 3 mirrored magenta bags.
+bright lime bags contain 5 mirrored turquoise bags, 1 clear plum bag, 3 dull aqua bags, 1 drab green bag.
+bright tan bags contain 1 vibrant lavender bag, 1 vibrant salmon bag, 1 dim green bag.
+dull gold bags contain 5 dotted lavender bags.
+dull crimson bags contain 5 shiny tomato bags.
+dotted tomato bags contain 1 dark coral bag, 5 pale plum bags.
+shiny gold bags contain 5 muted orange bags, 2 faded tan bags, 3 faded orange bags, 1 dull brown bag.
+bright blue bags contain 1 plaid cyan bag, 4 dim magenta bags, 2 drab magenta bags.
+shiny tomato bags contain 5 vibrant aqua bags, 3 clear tan bags.
+pale silver bags contain 4 wavy orange bags, 4 dotted green bags, 3 drab silver bags.
+faded indigo bags contain 5 striped gold bags, 3 clear olive bags.
+faded gray bags contain 2 drab lime bags, 4 clear maroon bags, 1 mirrored silver bag, 1 shiny brown bag.
+faded magenta bags contain 3 dim gold bags, 5 wavy lavender bags, 3 posh brown bags.
+bright coral bags contain 3 drab tan bags, 4 pale beige bags, 4 clear turquoise bags, 1 faded white bag.
+plaid salmon bags contain 1 striped tan bag, 3 pale blue bags.
+drab aqua bags contain 3 wavy turquoise bags.
+mirrored silver bags contain 1 dull brown bag, 4 pale black bags, 2 mirrored plum bags, 1 dotted red bag.
+light salmon bags contain 4 dotted chartreuse bags.
+wavy crimson bags contain 2 dim olive bags, 4 mirrored black bags, 4 faded salmon bags.
+posh maroon bags contain 2 dark teal bags, 3 dim violet bags, 5 mirrored tan bags.
+light lavender bags contain 3 vibrant turquoise bags, 1 pale orange bag, 4 shiny orange bags, 3 drab turquoise bags.
+dark lavender bags contain 1 shiny salmon bag, 4 wavy cyan bags, 5 dim lavender bags.
+shiny green bags contain 3 shiny brown bags, 5 dim coral bags.
+pale violet bags contain 1 faded white bag.
+dotted silver bags contain 2 pale blue bags.
+posh olive bags contain 1 vibrant chartreuse bag, 4 posh salmon bags, 5 plaid coral bags.
+vibrant gray bags contain 5 wavy yellow bags.
+wavy brown bags contain 4 vibrant indigo bags, 2 vibrant green bags, 5 wavy blue bags, 3 dim magenta bags.
+wavy teal bags contain 4 vibrant indigo bags, 2 vibrant turquoise bags.
+mirrored black bags contain 5 vibrant turquoise bags, 1 drab salmon bag, 5 pale tan bags.
+faded maroon bags contain 2 wavy crimson bags, 3 faded white bags.
+mirrored salmon bags contain 4 striped purple bags, 1 vibrant black bag, 4 drab green bags.
+faded brown bags contain 3 wavy turquoise bags.
+drab tomato bags contain 3 pale brown bags.
+dotted violet bags contain 5 plaid chartreuse bags, 5 shiny beige bags, 2 clear tan bags.
+light orange bags contain 1 dull aqua bag, 2 clear silver bags, 3 bright tomato bags, 2 bright teal bags.
+drab salmon bags contain 3 dark coral bags, 2 wavy brown bags, 1 striped purple bag, 4 dull gray bags.
+dotted maroon bags contain 1 dark orange bag, 1 wavy brown bag.
+striped chartreuse bags contain 2 striped yellow bags, 1 shiny orange bag, 1 dotted turquoise bag, 2 pale violet bags.
+shiny tan bags contain 4 dim beige bags, 2 pale tomato bags.
+plaid purple bags contain 4 light coral bags, 4 faded salmon bags.
+wavy tan bags contain 2 vibrant tan bags.
+pale lavender bags contain 3 dotted red bags, 1 bright green bag, 1 bright violet bag.
+posh crimson bags contain 2 light white bags.
+dark lime bags contain 2 plaid white bags, 2 bright gray bags.
+light green bags contain 5 bright magenta bags, 1 light chartreuse bag.
+light coral bags contain 3 pale black bags, 1 vibrant indigo bag, 1 wavy olive bag.
+dark bronze bags contain 2 dim teal bags, 4 dark maroon bags.
+light brown bags contain 5 dim white bags, 3 muted green bags, 1 dull white bag.
+dim chartreuse bags contain 1 drab bronze bag, 2 mirrored maroon bags, 3 dark salmon bags, 5 light coral bags.
+posh tan bags contain 2 plaid tan bags, 5 drab red bags, 5 vibrant salmon bags, 1 plaid salmon bag.
+vibrant blue bags contain 2 dim turquoise bags, 4 plaid lime bags, 2 faded turquoise bags, 4 faded gold bags.
+dark indigo bags contain 3 pale gray bags, 4 mirrored orange bags, 1 vibrant gray bag.
+bright fuchsia bags contain 2 light cyan bags, 3 vibrant chartreuse bags, 4 wavy yellow bags, 2 vibrant olive bags.
+posh white bags contain 4 light lime bags, 1 muted teal bag, 1 dull aqua bag.
+clear blue bags contain 1 faded tan bag.
+drab gold bags contain 5 mirrored beige bags.
+posh blue bags contain 2 vibrant brown bags, 3 vibrant salmon bags.
+shiny magenta bags contain 2 dotted fuchsia bags.
+clear brown bags contain 3 posh olive bags, 1 drab silver bag, 5 dark purple bags.
+muted brown bags contain 5 wavy yellow bags.
+dim maroon bags contain 1 wavy crimson bag, 2 faded tan bags.
+clear gold bags contain 5 dark aqua bags, 1 shiny coral bag, 2 dim fuchsia bags, 1 mirrored blue bag.
+dull coral bags contain 4 faded salmon bags, 2 pale aqua bags, 5 dull aqua bags, 4 dull silver bags.
+vibrant chartreuse bags contain 5 dull gray bags, 2 bright purple bags.
+posh beige bags contain 2 dotted turquoise bags, 3 vibrant tan bags, 4 pale orange bags, 4 bright salmon bags.
+bright white bags contain 3 dotted purple bags, 5 bright violet bags.
+posh red bags contain 4 vibrant bronze bags, 4 wavy beige bags.
+drab tan bags contain 2 dull indigo bags, 3 faded tan bags.
+dull blue bags contain 5 dark maroon bags.
+wavy plum bags contain 1 clear gray bag, 4 dark teal bags, 5 faded gray bags.
+light tomato bags contain 4 muted red bags, 3 muted maroon bags, 1 dim teal bag.
+posh purple bags contain 2 wavy black bags, 4 vibrant salmon bags.
+dull lavender bags contain 5 posh tomato bags, 4 faded tan bags.
+light silver bags contain 3 mirrored salmon bags, 4 pale yellow bags, 4 clear silver bags, 2 dim olive bags.
+light black bags contain 2 wavy crimson bags, 1 dull salmon bag, 4 muted black bags.
+light purple bags contain 2 vibrant purple bags, 2 vibrant aqua bags.
+striped orange bags contain 3 clear aqua bags.
+mirrored plum bags contain 3 vibrant aqua bags, 3 vibrant turquoise bags, 5 faded orange bags, 1 bright violet bag.
+posh coral bags contain 5 drab yellow bags, 2 faded white bags.
+clear tomato bags contain 3 shiny turquoise bags, 1 wavy cyan bag, 1 bright bronze bag, 5 light red bags.
+posh bronze bags contain 3 dull orange bags, 4 dull salmon bags, 5 clear blue bags.
+shiny crimson bags contain 4 drab green bags, 3 posh lime bags, 2 striped magenta bags, 2 bright teal bags.
+drab chartreuse bags contain 1 wavy yellow bag, 4 mirrored beige bags, 4 dull gold bags, 5 dull plum bags.
+striped tomato bags contain 3 plaid tan bags, 3 pale bronze bags, 4 dull yellow bags, 3 drab magenta bags.
+wavy chartreuse bags contain 3 dim coral bags, 4 bright chartreuse bags, 5 pale plum bags.
+posh chartreuse bags contain 4 dark purple bags, 3 muted magenta bags, 2 faded black bags.
+dotted aqua bags contain 2 wavy green bags, 5 vibrant tomato bags.
+dotted red bags contain 5 bright purple bags, 1 dotted gold bag, 5 mirrored magenta bags, 2 plaid indigo bags.
+faded salmon bags contain 1 wavy yellow bag.
+vibrant fuchsia bags contain 3 mirrored coral bags.
+drab coral bags contain 5 mirrored brown bags, 5 dotted lavender bags, 1 drab bronze bag, 3 dim chartreuse bags.
+posh aqua bags contain 3 bright olive bags.
+dark chartreuse bags contain 5 plaid silver bags.
+vibrant maroon bags contain 5 shiny brown bags, 2 faded black bags, 1 drab silver bag.
+striped salmon bags contain 5 dark gray bags, 1 muted tomato bag.
+posh gray bags contain 2 clear plum bags.
+dotted gray bags contain 3 drab salmon bags, 1 dim coral bag.
+clear aqua bags contain 4 dotted lavender bags, 1 striped purple bag, 3 light purple bags.
+dark aqua bags contain 2 dark indigo bags, 5 bright bronze bags.
+bright brown bags contain 2 plaid salmon bags, 4 faded indigo bags.
+clear violet bags contain 3 pale cyan bags, 3 dull aqua bags, 4 pale brown bags, 5 dim plum bags.
+wavy salmon bags contain 4 clear tomato bags, 4 bright bronze bags, 5 posh purple bags, 5 faded black bags.
+drab green bags contain 4 mirrored maroon bags, 2 vibrant aqua bags, 4 dim olive bags.
+posh silver bags contain 4 muted black bags, 5 pale cyan bags, 2 dark plum bags, 1 shiny bronze bag.
+dull indigo bags contain 4 striped purple bags.
+pale magenta bags contain 1 drab coral bag, 5 plaid blue bags, 1 wavy yellow bag, 5 dark salmon bags.
+light olive bags contain 2 pale gold bags.
+muted crimson bags contain 1 striped cyan bag, 1 vibrant bronze bag, 1 dull coral bag, 4 vibrant black bags.
+plaid yellow bags contain 3 bright silver bags.
+vibrant gold bags contain 5 vibrant tan bags.
+bright beige bags contain 2 pale beige bags, 2 dark lavender bags, 1 dull teal bag.
+faded white bags contain 2 pale brown bags, 3 muted orange bags, 3 dull indigo bags.
+striped gray bags contain 5 pale chartreuse bags.
+plaid brown bags contain 4 dull teal bags, 2 wavy beige bags.
+wavy yellow bags contain no other bags.
+dotted green bags contain 5 posh gray bags.
+dull turquoise bags contain 3 faded coral bags, 2 bright green bags.
+faded plum bags contain 1 dull fuchsia bag.
+clear maroon bags contain 2 light purple bags, 2 dim crimson bags, 5 vibrant bronze bags.
+posh green bags contain 1 plaid silver bag.
+vibrant teal bags contain 5 dotted gold bags.
+faded coral bags contain 3 dull aqua bags, 3 wavy orange bags, 3 drab chartreuse bags, 4 muted olive bags.
+wavy beige bags contain 1 dark plum bag, 2 dull lavender bags, 2 drab green bags.
+dim magenta bags contain 2 plaid coral bags, 2 faded orange bags.
+striped teal bags contain 2 bright tan bags.
+drab crimson bags contain 2 clear salmon bags, 2 clear orange bags, 1 striped yellow bag.
+dotted yellow bags contain 4 dull gray bags.
+mirrored tan bags contain 1 dotted fuchsia bag, 2 vibrant lavender bags.
+wavy aqua bags contain 4 drab gray bags, 3 muted yellow bags, 5 shiny lavender bags, 2 plaid turquoise bags.
+wavy gray bags contain 5 dim green bags, 1 plaid blue bag.
+dull teal bags contain 3 mirrored black bags, 4 dark plum bags, 2 drab silver bags, 4 mirrored gray bags.
+striped indigo bags contain 4 clear violet bags, 5 dotted yellow bags, 4 clear tomato bags.
+dim brown bags contain 1 drab bronze bag, 5 shiny yellow bags, 1 pale olive bag, 2 drab silver bags.
+mirrored teal bags contain 3 faded orange bags.
+dull salmon bags contain 3 dark indigo bags, 2 striped gray bags.
+dark tan bags contain 5 striped lime bags, 1 dark purple bag, 5 faded gold bags.
+clear teal bags contain 3 dark crimson bags, 1 bright tomato bag.
+dark olive bags contain 4 striped gold bags, 1 striped gray bag, 1 bright tomato bag.
+posh indigo bags contain 1 mirrored maroon bag, 4 striped indigo bags.
+drab yellow bags contain 5 dull teal bags, 2 plaid turquoise bags.
+faded bronze bags contain 3 dull orange bags.
+dull chartreuse bags contain 2 dull bronze bags, 3 light gold bags, 2 striped white bags.
+posh orange bags contain 5 pale crimson bags, 1 bright blue bag, 5 clear green bags.
+striped coral bags contain 4 pale gray bags.
+clear tan bags contain 4 dark plum bags, 1 posh olive bag.
+dotted tan bags contain 1 faded aqua bag, 3 pale brown bags, 5 dim chartreuse bags.
+striped brown bags contain 5 dark black bags.
+clear red bags contain 4 faded lime bags, 3 striped blue bags, 3 light fuchsia bags, 4 drab turquoise bags.
+plaid gold bags contain 5 dim chartreuse bags.
+plaid cyan bags contain no other bags.
+muted tomato bags contain 2 pale blue bags, 2 shiny bronze bags, 1 light teal bag.
+dotted crimson bags contain 2 dark maroon bags.
+light turquoise bags contain 3 wavy orange bags, 5 drab red bags, 5 plaid yellow bags.
+wavy cyan bags contain 1 dim magenta bag, 2 shiny blue bags.
+dim coral bags contain 3 vibrant indigo bags, 4 vibrant turquoise bags.
+dark blue bags contain 3 clear teal bags, 1 dim bronze bag, 4 light tan bags, 4 wavy indigo bags.
+faded gold bags contain 2 posh salmon bags, 4 plaid white bags, 2 dull cyan bags.
+vibrant turquoise bags contain no other bags.
+dim fuchsia bags contain 3 shiny blue bags, 1 dark bronze bag, 2 wavy yellow bags.
+muted blue bags contain 4 shiny violet bags, 5 muted tomato bags, 5 light salmon bags.
+plaid bronze bags contain 4 dull green bags.
+mirrored maroon bags contain 3 dark coral bags, 4 clear plum bags.
+muted olive bags contain 2 dark brown bags, 5 bright white bags.
+pale crimson bags contain 1 pale blue bag, 4 clear plum bags, 5 wavy yellow bags, 1 dotted purple bag.
+striped crimson bags contain 4 muted teal bags.
+dark orange bags contain 5 dark maroon bags, 2 drab cyan bags, 1 dotted chartreuse bag, 5 shiny green bags.
+light white bags contain 5 faded gray bags, 1 dim beige bag, 5 bright violet bags.
+plaid white bags contain 1 pale brown bag.
+dim orange bags contain 3 faded blue bags.
+vibrant green bags contain 4 posh salmon bags, 4 plaid cyan bags, 3 clear plum bags.
+dotted beige bags contain 5 posh black bags, 2 mirrored yellow bags, 3 mirrored salmon bags.
+dim black bags contain 2 vibrant cyan bags, 3 shiny turquoise bags, 2 dotted turquoise bags, 1 muted orange bag.
+mirrored tomato bags contain 4 dotted plum bags.
+dim violet bags contain 1 dotted chartreuse bag.
+pale coral bags contain 5 dim silver bags, 3 clear gray bags.
+vibrant lavender bags contain 3 dim bronze bags.
+dark crimson bags contain 1 shiny brown bag.
+bright orange bags contain 3 muted tomato bags, 2 pale black bags.
+clear yellow bags contain 4 striped purple bags, 5 mirrored black bags, 4 posh gray bags.
+posh violet bags contain 3 clear red bags.
+plaid tan bags contain 1 pale cyan bag.
+pale gold bags contain 5 striped olive bags.
+muted lavender bags contain 1 clear crimson bag, 5 light white bags.
+faded crimson bags contain 3 clear coral bags.
+wavy blue bags contain no other bags.
+faded purple bags contain 5 dark crimson bags.
+dim silver bags contain 5 mirrored silver bags, 1 vibrant turquoise bag, 5 wavy turquoise bags.
+pale gray bags contain 4 wavy yellow bags, 2 vibrant tan bags, 2 pale tan bags, 1 dark coral bag.
+dim purple bags contain 2 striped silver bags, 1 plaid blue bag, 5 pale cyan bags.
+striped purple bags contain no other bags.
+plaid red bags contain 4 faded coral bags.
+dull bronze bags contain 5 bright coral bags.
+light teal bags contain 2 dotted green bags, 4 pale purple bags.
+mirrored blue bags contain 2 striped silver bags.
+muted green bags contain 2 drab red bags, 1 drab tan bag.
+muted gray bags contain 2 muted coral bags.
+light fuchsia bags contain 2 dim indigo bags.
+shiny orange bags contain 2 bright green bags, 4 shiny lime bags, 1 striped red bag, 5 dull turquoise bags.
+bright purple bags contain 1 striped purple bag, 3 shiny brown bags, 4 vibrant indigo bags.
+dotted brown bags contain 2 faded blue bags, 5 shiny lavender bags, 4 clear lavender bags, 1 bright bronze bag.
+light maroon bags contain 4 muted brown bags, 4 striped orange bags, 1 clear plum bag, 3 dull lavender bags.
+wavy green bags contain 1 dull brown bag, 1 clear plum bag.
+dull fuchsia bags contain 2 dark coral bags, 3 light coral bags.
+dotted purple bags contain no other bags.
+light plum bags contain 4 muted gold bags, 1 muted crimson bag.
+light red bags contain 5 dull magenta bags, 2 wavy olive bags, 3 drab silver bags, 1 dim magenta bag.
+faded green bags contain 3 dotted turquoise bags, 2 dull bronze bags, 2 muted green bags.
+posh lime bags contain 3 faded brown bags, 4 wavy brown bags.
+shiny black bags contain 2 plaid blue bags, 5 drab salmon bags.
+muted teal bags contain 5 bright violet bags, 4 pale cyan bags.
+light cyan bags contain 2 muted silver bags, 3 faded salmon bags, 5 shiny brown bags, 5 drab magenta bags.
+faded beige bags contain 2 muted red bags.
+mirrored aqua bags contain 4 faded silver bags, 4 dull maroon bags, 3 dull olive bags, 4 dim bronze bags.
+muted silver bags contain 3 dotted cyan bags, 3 muted fuchsia bags, 5 plaid purple bags.
+plaid teal bags contain 4 mirrored magenta bags, 3 dotted red bags.
+bright teal bags contain 1 shiny brown bag, 4 vibrant tan bags.
+dark red bags contain 3 wavy red bags, 4 dotted violet bags, 5 pale tomato bags.
+muted maroon bags contain 1 plaid indigo bag.
+dark fuchsia bags contain 4 bright teal bags, 4 dim blue bags, 5 vibrant lavender bags, 4 striped yellow bags.
+dark white bags contain 1 drab green bag, 4 dotted chartreuse bags.
+drab maroon bags contain 1 faded salmon bag, 1 dotted orange bag, 1 faded fuchsia bag.
+dull violet bags contain 2 dotted tan bags, 4 pale cyan bags.
+shiny violet bags contain 1 dull red bag, 4 wavy indigo bags, 1 clear violet bag, 2 dotted white bags.
+posh teal bags contain 5 muted green bags, 1 dotted brown bag.
+dotted teal bags contain 4 pale olive bags, 5 mirrored crimson bags.
+dim olive bags contain 3 pale white bags, 1 posh olive bag, 3 striped orange bags, 1 striped silver bag.
+shiny purple bags contain 3 shiny salmon bags, 5 posh plum bags, 1 striped white bag, 5 shiny black bags.
+mirrored white bags contain 3 muted turquoise bags, 5 striped gray bags, 1 faded lime bag.
+mirrored indigo bags contain 1 dim teal bag, 3 drab lavender bags, 1 plaid coral bag, 5 posh orange bags.
+wavy orange bags contain 2 mirrored maroon bags, 1 striped silver bag, 2 wavy yellow bags, 2 dim crimson bags.
+light indigo bags contain 2 vibrant cyan bags, 2 vibrant gray bags.
+dark cyan bags contain 3 clear tomato bags.
+dim lime bags contain 5 dull indigo bags, 1 wavy olive bag.
+pale beige bags contain 2 muted red bags, 2 clear tomato bags, 3 posh olive bags.
+plaid silver bags contain 4 dim plum bags, 1 dim beige bag, 3 plaid salmon bags.
+wavy silver bags contain 1 plaid indigo bag.
+wavy violet bags contain 4 posh chartreuse bags, 2 mirrored tomato bags.
+clear beige bags contain 4 dark maroon bags.
+vibrant cyan bags contain 1 striped purple bag, 4 muted black bags.
+faded teal bags contain 4 dark blue bags, 1 pale brown bag.
+drab gray bags contain 3 striped crimson bags, 2 shiny gold bags, 2 shiny magenta bags.
+clear turquoise bags contain 5 light crimson bags, 4 dotted cyan bags.
+plaid lime bags contain 4 dotted chartreuse bags, 2 plaid orange bags, 4 shiny fuchsia bags.
+faded tan bags contain 5 vibrant green bags.
+dotted indigo bags contain 3 light violet bags, 4 dull fuchsia bags.
+muted turquoise bags contain 5 pale tan bags, 4 dim olive bags, 2 plaid indigo bags.
+vibrant orange bags contain 4 dotted yellow bags, 4 plaid cyan bags.
+drab fuchsia bags contain 1 dim plum bag, 1 striped red bag, 2 vibrant cyan bags.
+clear green bags contain 1 dull magenta bag, 5 wavy blue bags, 1 vibrant olive bag, 1 vibrant tan bag.
+light magenta bags contain 3 posh bronze bags.
+dull black bags contain 4 drab bronze bags.
+dull beige bags contain 3 dull lime bags, 2 wavy coral bags, 1 plaid yellow bag.
+dotted plum bags contain 4 posh salmon bags, 3 vibrant chartreuse bags, 5 dim green bags.
+vibrant salmon bags contain 4 dim purple bags.
+mirrored crimson bags contain 2 faded tomato bags, 1 striped blue bag, 3 vibrant green bags, 3 striped turquoise bags.
+dotted fuchsia bags contain 2 plaid coral bags, 5 dull brown bags, 1 dark maroon bag.
+posh salmon bags contain no other bags.
+dotted cyan bags contain 4 clear aqua bags, 5 plaid gray bags, 3 bright bronze bags.
+mirrored bronze bags contain 3 vibrant black bags, 3 faded maroon bags, 1 drab coral bag, 1 muted black bag.
+bright magenta bags contain 2 dim magenta bags, 3 dotted gold bags, 4 posh gold bags.
+faded violet bags contain 1 light red bag.
+dim yellow bags contain 1 dull orange bag, 1 muted purple bag, 2 faded indigo bags, 5 dotted plum bags.
+wavy lime bags contain 1 clear blue bag.
+mirrored coral bags contain 3 dull maroon bags, 1 striped orange bag.
+wavy maroon bags contain 4 dark gold bags.
+bright gold bags contain 3 dim orange bags, 5 dark gray bags, 2 clear fuchsia bags, 5 clear maroon bags.
+dotted turquoise bags contain 3 dim olive bags, 3 light red bags, 3 dull fuchsia bags.
+striped plum bags contain 4 dark tan bags, 2 mirrored teal bags, 1 striped brown bag.
+shiny fuchsia bags contain 5 clear green bags, 5 muted tomato bags, 1 dark coral bag, 5 wavy blue bags.
+vibrant white bags contain 1 dim olive bag, 2 bright silver bags, 2 muted blue bags.
+dull cyan bags contain 2 clear teal bags, 4 plaid blue bags.
+drab teal bags contain 4 clear crimson bags, 5 wavy lime bags, 4 plaid turquoise bags.
+posh turquoise bags contain 5 plaid fuchsia bags, 5 pale blue bags, 3 vibrant green bags.
+bright red bags contain 1 clear magenta bag, 4 striped aqua bags, 2 posh cyan bags, 1 dull salmon bag.
+dark teal bags contain 3 dull yellow bags, 3 plaid white bags, 3 clear cyan bags, 4 striped red bags.
+vibrant beige bags contain 3 drab silver bags, 4 wavy orange bags, 3 pale brown bags, 2 faded orange bags.
+clear purple bags contain 5 faded indigo bags, 3 striped maroon bags, 4 vibrant plum bags, 3 light red bags.
+pale lime bags contain 2 plaid blue bags, 1 bright violet bag, 5 faded bronze bags, 1 dotted plum bag.
+shiny lavender bags contain 5 mirrored plum bags.
+posh brown bags contain 1 drab yellow bag.
+dark black bags contain 5 dull salmon bags, 3 pale silver bags, 2 vibrant turquoise bags.
+shiny turquoise bags contain 3 plaid blue bags, 3 dim salmon bags, 5 dull gold bags.
+dim green bags contain 3 vibrant turquoise bags, 5 faded tan bags.
+pale maroon bags contain 3 dull fuchsia bags.
+dull purple bags contain 2 vibrant aqua bags, 2 bright blue bags.
+dull magenta bags contain 4 pale blue bags, 2 shiny bronze bags, 2 pale lavender bags, 3 pale chartreuse bags.
+light gray bags contain 4 bright orange bags, 5 dull gray bags.
+faded black bags contain 2 clear crimson bags, 4 posh gray bags.
+plaid tomato bags contain 1 light bronze bag, 2 posh plum bags.
+faded aqua bags contain 4 shiny gold bags, 5 pale tomato bags, 1 plaid blue bag, 1 faded coral bag.
+muted tan bags contain 2 muted tomato bags, 2 light white bags, 4 wavy lavender bags, 2 dim turquoise bags.
+dark turquoise bags contain 4 dotted silver bags, 3 vibrant chartreuse bags, 4 striped green bags, 2 dotted black bags.
+dim lavender bags contain 3 dark indigo bags, 3 wavy orange bags, 5 faded orange bags, 2 striped orange bags.
+plaid black bags contain 3 light violet bags, 3 mirrored bronze bags, 1 clear blue bag, 5 clear olive bags.
+clear lavender bags contain 1 dim bronze bag.
+pale blue bags contain no other bags.
+mirrored magenta bags contain 1 vibrant tan bag, 1 wavy turquoise bag, 4 clear aqua bags.
+shiny gray bags contain 3 wavy indigo bags, 5 striped gold bags, 1 drab cyan bag.
+light bronze bags contain 3 dark aqua bags, 4 striped gold bags.
+muted black bags contain 3 faded white bags, 5 pale crimson bags, 3 muted brown bags, 1 vibrant tan bag.
+wavy purple bags contain 3 pale bronze bags, 5 shiny maroon bags, 4 dotted teal bags, 4 pale indigo bags.
+muted orange bags contain 1 dotted chartreuse bag, 2 pale blue bags, 3 muted brown bags, 1 posh tomato bag.
+wavy turquoise bags contain 2 drab silver bags, 2 vibrant purple bags, 3 faded tan bags.
+dull plum bags contain 3 striped silver bags, 4 clear violet bags.
+mirrored olive bags contain 4 shiny violet bags.
+shiny teal bags contain 5 dim purple bags, 3 faded violet bags, 5 plaid crimson bags.
+dotted coral bags contain 4 dull indigo bags, 5 muted silver bags, 1 faded white bag.
+striped olive bags contain 5 posh tomato bags, 1 pale purple bag.
+shiny beige bags contain 2 wavy red bags.
+plaid aqua bags contain 2 muted teal bags.
+shiny silver bags contain 1 dotted gold bag, 4 plaid tomato bags.
+muted chartreuse bags contain 2 pale crimson bags, 2 mirrored black bags, 5 dark purple bags, 3 wavy tan bags.
+shiny lime bags contain 1 light tan bag.
+vibrant coral bags contain 1 dotted violet bag, 3 faded gray bags, 3 pale magenta bags.
+clear orange bags contain 4 mirrored brown bags, 1 posh turquoise bag.
+pale white bags contain 2 dotted gold bags, 3 dotted lavender bags.
+dark green bags contain 5 clear tan bags.
+pale olive bags contain 4 mirrored black bags, 1 dull magenta bag.
+faded blue bags contain 5 dull magenta bags.
+dull gray bags contain 4 vibrant indigo bags, 2 pale crimson bags, 2 clear plum bags.
+dull lime bags contain 4 dim salmon bags.
+bright green bags contain 1 drab silver bag, 5 bright bronze bags.
+dim salmon bags contain 3 dotted silver bags.
+dim red bags contain 1 vibrant green bag, 2 drab tan bags, 1 mirrored brown bag.
+clear magenta bags contain 1 clear cyan bag, 3 light bronze bags.
+dotted bronze bags contain 2 striped yellow bags, 3 dark maroon bags.
+dotted blue bags contain 3 dotted tan bags, 4 muted violet bags.
+bright cyan bags contain 4 pale turquoise bags, 4 dull yellow bags.
+drab lavender bags contain 1 shiny green bag.
+bright black bags contain 3 mirrored lime bags.
+wavy black bags contain 1 faded indigo bag, 4 dim salmon bags, 1 drab aqua bag, 5 dull maroon bags.
+clear gray bags contain 2 muted fuchsia bags, 4 clear yellow bags.
+bright chartreuse bags contain 2 bright tomato bags.
+posh black bags contain 5 dotted tan bags, 3 muted orange bags, 2 dim purple bags, 1 shiny cyan bag.
+dull green bags contain 1 striped tan bag, 1 dull magenta bag.
+mirrored green bags contain 3 posh salmon bags, 5 mirrored purple bags, 4 vibrant magenta bags.
+dull olive bags contain 1 dim maroon bag, 4 striped gold bags, 2 shiny white bags, 3 clear tomato bags.
+pale purple bags contain 3 dull salmon bags, 1 drab cyan bag, 5 bright green bags, 5 drab salmon bags.
+mirrored lime bags contain 2 posh white bags.
+drab blue bags contain 3 pale tomato bags, 1 shiny plum bag.
+dim plum bags contain 2 vibrant indigo bags, 4 faded orange bags, 3 wavy cyan bags.
+wavy magenta bags contain 1 muted fuchsia bag.
+wavy lavender bags contain 3 shiny lime bags.
+plaid beige bags contain 5 bright beige bags, 4 pale black bags.
+mirrored gold bags contain 4 muted salmon bags, 3 striped black bags, 3 dotted red bags, 3 dim orange bags.
+clear salmon bags contain 1 striped turquoise bag, 1 muted silver bag.
+vibrant purple bags contain 5 vibrant aqua bags.
+pale turquoise bags contain 4 wavy maroon bags.
+dull brown bags contain 5 dotted purple bags, 5 vibrant turquoise bags.
+drab lime bags contain 3 dim magenta bags.
+vibrant black bags contain 1 drab magenta bag.
+striped silver bags contain 2 shiny bronze bags, 5 striped purple bags.
+dim turquoise bags contain 2 pale brown bags, 4 bright green bags, 1 drab salmon bag.
+shiny red bags contain 4 light purple bags, 2 dull orange bags, 4 striped magenta bags, 3 dull red bags.
+dotted magenta bags contain 3 faded silver bags, 3 dull purple bags, 5 dotted tan bags.
+dotted lavender bags contain 2 vibrant indigo bags, 1 clear plum bag.
+shiny indigo bags contain 1 dull lavender bag, 3 vibrant tan bags, 4 faded lime bags, 5 drab tan bags.
+striped violet bags contain 1 muted tomato bag.
+muted salmon bags contain 2 light cyan bags, 4 dull tomato bags, 2 pale chartreuse bags, 1 dotted gray bag.
+mirrored fuchsia bags contain 4 faded silver bags, 4 plaid gray bags, 4 dotted purple bags.
+light aqua bags contain 4 striped gold bags, 1 dark blue bag, 3 dim red bags, 2 wavy gold bags.
+dark yellow bags contain 2 pale gray bags, 1 shiny blue bag, 4 faded turquoise bags.
+striped fuchsia bags contain 4 muted magenta bags.
+clear silver bags contain 2 plaid purple bags, 2 plaid indigo bags, 1 muted orange bag, 3 clear plum bags.
+posh yellow bags contain 1 posh silver bag, 3 dotted gold bags.
+dark magenta bags contain 1 drab violet bag, 2 bright purple bags, 4 shiny coral bags, 5 striped tan bags.
+bright tomato bags contain 1 dotted purple bag, 2 dotted chartreuse bags, 2 wavy yellow bags.
+bright plum bags contain 1 bright blue bag, 2 faded orange bags, 2 dim coral bags, 3 dotted cyan bags.
+shiny maroon bags contain 3 dotted crimson bags, 5 bright teal bags, 5 dotted fuchsia bags, 4 dull green bags.
+pale yellow bags contain 4 muted silver bags, 4 dull teal bags, 4 muted purple bags.
+plaid fuchsia bags contain 3 dull lavender bags.
+clear white bags contain 5 light turquoise bags.
+striped lavender bags contain 2 plaid lime bags, 4 dark white bags.
+posh cyan bags contain 3 faded coral bags, 5 light maroon bags, 3 faded indigo bags.
+faded lime bags contain 2 wavy yellow bags.
+striped red bags contain 1 plaid indigo bag.
+light tan bags contain 4 wavy blue bags.
+vibrant violet bags contain 4 striped purple bags, 4 light cyan bags, 5 faded tan bags, 4 light yellow bags.
+dotted gold bags contain 4 vibrant indigo bags, 2 bright bronze bags, 2 drab silver bags, 5 muted brown bags.
+shiny plum bags contain 1 faded lime bag, 4 faded orange bags, 2 vibrant beige bags, 2 striped orange bags.
+striped cyan bags contain 5 clear beige bags.
+striped yellow bags contain 3 dim teal bags, 5 clear maroon bags, 1 light cyan bag.
+muted yellow bags contain 3 drab bronze bags, 2 pale gray bags.
+clear indigo bags contain 1 clear beige bag, 2 bright silver bags, 1 dim salmon bag.
+striped green bags contain 1 mirrored red bag, 3 shiny blue bags.
+plaid plum bags contain 1 drab cyan bag, 5 light lime bags, 4 muted lavender bags.
+pale green bags contain 2 dotted chartreuse bags, 3 plaid magenta bags.
+wavy bronze bags contain 2 pale purple bags, 1 pale teal bag, 1 muted bronze bag, 1 mirrored beige bag.
+clear black bags contain 4 vibrant brown bags, 5 pale tomato bags, 4 bright teal bags, 3 wavy brown bags.
+pale fuchsia bags contain 3 pale beige bags, 5 plaid blue bags, 3 light violet bags, 3 striped blue bags.
+vibrant magenta bags contain 5 posh plum bags, 2 mirrored turquoise bags, 2 light red bags, 2 pale plum bags.
+drab olive bags contain 5 vibrant green bags, 4 dull turquoise bags, 4 muted fuchsia bags.
+bright salmon bags contain 1 muted silver bag, 1 drab purple bag, 5 pale cyan bags.
+shiny coral bags contain 4 wavy magenta bags, 5 dark olive bags.
+mirrored cyan bags contain 3 dim chartreuse bags, 4 pale aqua bags.
+plaid blue bags contain 5 bright purple bags.
+vibrant tomato bags contain 5 faded tomato bags, 3 muted silver bags, 5 dotted turquoise bags.
+mirrored brown bags contain 2 pale black bags.
+shiny olive bags contain 3 plaid teal bags, 3 vibrant fuchsia bags.
+shiny blue bags contain 3 dark coral bags, 4 bright purple bags, 2 pale cyan bags, 5 plaid indigo bags.
+plaid crimson bags contain 5 wavy crimson bags, 5 clear crimson bags, 4 vibrant red bags.
+striped black bags contain 1 faded chartreuse bag, 2 dull brown bags, 4 clear cyan bags, 1 light teal bag.
+wavy gold bags contain 2 dull gray bags, 1 dark lavender bag, 3 pale gray bags.
+faded turquoise bags contain 3 bright white bags, 4 pale bronze bags, 5 pale lavender bags.
+dull maroon bags contain 2 bright orange bags, 5 vibrant bronze bags, 4 drab chartreuse bags.
+striped bronze bags contain 2 pale lavender bags, 1 dull brown bag.
+plaid violet bags contain 5 mirrored plum bags.
+light violet bags contain 4 drab blue bags, 2 plaid beige bags, 3 pale crimson bags.
+posh lavender bags contain 2 faded tomato bags, 4 dim crimson bags.
+dark salmon bags contain 1 pale crimson bag.
+dotted black bags contain 4 wavy lime bags, 1 faded salmon bag, 3 pale blue bags, 5 wavy blue bags.
+shiny aqua bags contain 1 bright blue bag, 4 drab green bags, 2 light teal bags, 2 dotted green bags.
+shiny salmon bags contain 3 dim magenta bags.
+dark silver bags contain 1 shiny tan bag, 3 wavy yellow bags, 4 drab violet bags.
+pale red bags contain 4 mirrored cyan bags, 4 clear gray bags, 2 dotted tan bags.
+dark brown bags contain 1 plaid indigo bag.
+drab cyan bags contain 2 wavy green bags, 2 pale gray bags, 2 dotted purple bags, 3 dark beige bags.
+dim gray bags contain 2 bright salmon bags, 2 clear silver bags, 2 light turquoise bags, 4 drab plum bags.
+pale black bags contain 1 plaid coral bag, 4 vibrant turquoise bags, 1 pale brown bag.
+dotted olive bags contain 2 faded blue bags, 2 dull maroon bags, 3 dim fuchsia bags, 5 light fuchsia bags.
+posh fuchsia bags contain 5 dark lavender bags.
+pale orange bags contain 2 vibrant aqua bags, 2 vibrant green bags, 1 bright coral bag.
+faded cyan bags contain 4 clear orange bags, 5 dull orange bags, 4 dotted bronze bags.
+dim tan bags contain 2 dim chartreuse bags, 3 vibrant turquoise bags, 2 faded coral bags, 2 dim coral bags.
+dim gold bags contain 2 wavy magenta bags.
+dull aqua bags contain 2 wavy yellow bags.
+posh tomato bags contain 1 muted brown bag.
+dark gold bags contain 4 muted fuchsia bags, 4 light salmon bags.
+clear chartreuse bags contain 3 light coral bags.
+plaid chartreuse bags contain 1 light silver bag, 5 vibrant green bags, 3 wavy lavender bags, 4 vibrant turquoise bags.
+mirrored red bags contain 5 plaid aqua bags, 4 clear cyan bags, 1 mirrored magenta bag.
+dim beige bags contain 4 dull green bags, 2 dim green bags.
+mirrored beige bags contain 1 drab magenta bag, 4 clear tan bags, 5 mirrored turquoise bags, 4 drab tan bags.
+bright maroon bags contain 3 vibrant green bags, 5 shiny gold bags.
+dim aqua bags contain 4 faded coral bags.
+dim blue bags contain 3 posh silver bags.
+drab silver bags contain 1 vibrant aqua bag, 5 vibrant tan bags.
+drab turquoise bags contain 3 light gold bags, 1 striped blue bag, 2 dark maroon bags.
+posh gold bags contain 5 dotted red bags.
+muted violet bags contain 3 bright fuchsia bags, 1 muted tomato bag, 4 drab lime bags, 2 dim olive bags.
+drab orange bags contain 5 vibrant brown bags, 5 striped bronze bags.
+faded orange bags contain 4 bright bronze bags.
+clear plum bags contain no other bags.
+drab black bags contain 3 mirrored bronze bags, 1 dotted bronze bag, 5 light gray bags.
+pale salmon bags contain 4 plaid coral bags, 5 wavy yellow bags, 2 light coral bags.
+dim teal bags contain 5 dark brown bags, 5 dark crimson bags, 5 dull aqua bags.
+bright silver bags contain 3 pale beige bags, 4 bright beige bags, 3 wavy maroon bags, 1 drab chartreuse bag.
+dull white bags contain 4 dim chartreuse bags, 5 vibrant coral bags, 2 muted indigo bags.
+wavy tomato bags contain 3 bright fuchsia bags, 2 dull fuchsia bags, 4 pale brown bags.
+striped magenta bags contain 2 shiny white bags, 1 shiny brown bag, 2 bright tomato bags.
+shiny chartreuse bags contain 3 mirrored green bags, 3 dark salmon bags.
+vibrant silver bags contain 2 faded gray bags, 3 mirrored orange bags, 4 clear black bags, 2 pale lavender bags.
+dull tan bags contain 3 light black bags, 4 faded brown bags, 2 pale bronze bags, 3 shiny lavender bags.
+light gold bags contain 2 wavy beige bags, 5 plaid salmon bags, 3 shiny cyan bags.
+posh plum bags contain 3 dim beige bags, 1 wavy magenta bag, 3 dull fuchsia bags, 4 dull gold bags.
+dull red bags contain 1 striped teal bag, 2 dark violet bags, 1 shiny tomato bag, 1 striped yellow bag.
+plaid lavender bags contain 2 light purple bags.
+faded chartreuse bags contain 4 vibrant yellow bags.
+shiny brown bags contain no other bags.
+light crimson bags contain 3 wavy orange bags, 3 pale white bags, 4 vibrant turquoise bags.
+mirrored chartreuse bags contain 2 muted maroon bags.
+wavy white bags contain 3 striped maroon bags, 5 striped aqua bags, 4 dull fuchsia bags, 1 wavy orange bag.
+plaid gray bags contain 1 muted brown bag, 3 shiny brown bags.
+drab white bags contain 5 muted yellow bags.
+mirrored gray bags contain 3 light tan bags.
+bright lavender bags contain 1 drab lime bag, 4 plaid olive bags, 3 pale blue bags.
+shiny yellow bags contain 5 muted orange bags.
+pale bronze bags contain 4 mirrored coral bags, 2 muted red bags.
+drab beige bags contain 2 plaid purple bags, 5 clear magenta bags, 3 faded coral bags, 2 clear beige bags.
+vibrant yellow bags contain 2 mirrored lavender bags, 1 light orange bag.
+vibrant red bags contain 3 vibrant salmon bags, 2 plaid teal bags, 2 dull gray bags, 2 vibrant gray bags.
+wavy olive bags contain 1 shiny bronze bag, 5 plaid coral bags, 3 dotted gold bags, 1 pale brown bag.
+muted white bags contain 3 plaid violet bags, 1 dim black bag.
+faded olive bags contain 4 mirrored chartreuse bags.
+muted gold bags contain 1 dim orange bag.
+mirrored orange bags contain 3 light purple bags, 4 dull lavender bags, 1 bright bronze bag, 4 pale black bags.
+light chartreuse bags contain 3 muted red bags, 3 bright violet bags.
+pale teal bags contain 4 dim lime bags, 4 pale crimson bags, 2 clear lavender bags.
+muted coral bags contain 3 dark green bags.
+shiny bronze bags contain 1 pale blue bag.
+dim crimson bags contain 1 vibrant indigo bag, 4 pale crimson bags.
+striped gold bags contain 3 dotted gray bags.
+light lime bags contain 4 mirrored teal bags, 4 dotted cyan bags.
+posh magenta bags contain 3 posh salmon bags, 5 bright bronze bags, 5 mirrored maroon bags, 2 vibrant purple bags.
+pale chartreuse bags contain 4 bright purple bags, 1 posh salmon bag.
+mirrored violet bags contain 2 mirrored magenta bags, 1 dotted cyan bag, 2 dark beige bags, 1 mirrored plum bag.
+shiny cyan bags contain 4 bright violet bags.
+bright indigo bags contain 1 muted teal bag, 4 faded silver bags, 3 dim indigo bags.
+striped maroon bags contain 5 shiny magenta bags.
+muted bronze bags contain 2 drab salmon bags, 1 mirrored orange bag, 2 light coral bags, 4 clear plum bags.
+dotted white bags contain 2 bright plum bags, 3 pale lavender bags, 2 muted red bags.
+pale indigo bags contain 1 dull green bag, 5 drab olive bags, 5 dull salmon bags, 5 dark cyan bags.
+dark plum bags contain 2 pale white bags, 5 dim plum bags.
+clear crimson bags contain 4 wavy blue bags, 5 dim chartreuse bags, 1 plaid maroon bag, 4 dull cyan bags.
+striped lime bags contain 2 bright chartreuse bags, 2 striped orange bags.
+dark beige bags contain 5 mirrored black bags, 3 dim purple bags, 5 light purple bags, 5 dark brown bags.
+clear cyan bags contain 4 mirrored plum bags, 3 dotted purple bags, 1 dull fuchsia bag, 5 bright teal bags.
+plaid olive bags contain 5 posh tomato bags, 3 faded bronze bags, 4 pale white bags.
+plaid indigo bags contain 4 drab silver bags, 2 dotted purple bags, 3 vibrant green bags, 2 vibrant aqua bags.
+drab purple bags contain 1 shiny green bag, 5 wavy gray bags.
+bright violet bags contain 4 posh salmon bags, 1 shiny bronze bag, 1 vibrant indigo bag.
+dark purple bags contain 4 dotted purple bags, 3 striped yellow bags, 5 vibrant purple bags, 3 mirrored lavender bags.
+dull silver bags contain 3 clear turquoise bags, 3 dim salmon bags.
+drab red bags contain 2 muted tomato bags, 3 dim bronze bags, 2 mirrored black bags, 4 faded salmon bags.
+light yellow bags contain 2 mirrored orange bags, 4 vibrant fuchsia bags, 5 drab purple bags.
+dim white bags contain 5 mirrored white bags.
+dotted lime bags contain 5 dotted magenta bags, 5 dark maroon bags.
+striped blue bags contain 3 pale white bags.
+pale tomato bags contain 3 dull teal bags, 4 vibrant green bags, 1 bright crimson bag.
+mirrored lavender bags contain 1 wavy cyan bag, 2 drab cyan bags, 1 striped olive bag.
+dull orange bags contain 2 pale salmon bags, 2 posh olive bags, 2 dark coral bags, 1 plaid coral bag.
+pale tan bags contain 1 shiny bronze bag, 4 dim coral bags, 4 vibrant green bags, 4 dotted gold bags.
+drab brown bags contain 3 striped teal bags.
+dim bronze bags contain 1 drab magenta bag, 1 mirrored gray bag, 2 striped purple bags.
+clear fuchsia bags contain 4 plaid brown bags, 4 dim bronze bags, 1 posh lime bag.
+faded lavender bags contain 2 posh gray bags, 3 dark cyan bags, 4 muted tan bags.
+bright turquoise bags contain 3 pale white bags.
+muted lime bags contain 5 plaid olive bags, 4 muted orange bags.
+vibrant bronze bags contain 5 dim silver bags, 4 dotted fuchsia bags, 1 vibrant gray bag, 1 muted brown bag.
+drab violet bags contain 3 bright turquoise bags, 1 posh olive bag, 2 wavy olive bags.
+drab plum bags contain 2 clear turquoise bags, 5 striped violet bags, 5 muted black bags.
+vibrant tan bags contain 2 dull brown bags, 1 vibrant indigo bag, 1 dim crimson bag.
+bright gray bags contain 2 wavy gray bags, 4 clear maroon bags.
+faded fuchsia bags contain 4 faded tan bags, 1 clear silver bag, 1 faded tomato bag.
+muted magenta bags contain 3 shiny green bags, 4 pale aqua bags.
+plaid green bags contain 2 wavy red bags, 1 pale yellow bag, 5 posh black bags.
+dotted orange bags contain 5 clear crimson bags, 2 bright gold bags, 2 dim violet bags, 3 faded gray bags.
+faded tomato bags contain 4 drab coral bags, 5 bright lime bags, 2 light black bags, 2 muted olive bags.
+pale aqua bags contain 3 light bronze bags.
+wavy indigo bags contain 4 bright crimson bags.
+drab magenta bags contain 1 plaid coral bag.
+dim tomato bags contain 4 clear gold bags, 4 bright crimson bags, 4 light beige bags, 4 striped white bags.
+striped turquoise bags contain 5 bright green bags, 5 dark bronze bags, 3 pale crimson bags.
+vibrant lime bags contain 4 shiny maroon bags, 2 shiny plum bags, 3 dull green bags.
+muted fuchsia bags contain 3 dim purple bags, 2 pale cyan bags, 4 pale gray bags, 3 drab salmon bags.
+dim cyan bags contain 4 shiny salmon bags, 3 striped white bags, 3 plaid chartreuse bags.
+mirrored purple bags contain 5 posh plum bags, 1 light purple bag, 2 plaid aqua bags, 5 striped gold bags.
+plaid coral bags contain 4 vibrant indigo bags, 3 bright bronze bags, 1 dotted purple bag.
+plaid maroon bags contain 3 wavy olive bags, 5 pale plum bags, 2 dark beige bags, 4 striped white bags.
+plaid turquoise bags contain 2 pale tomato bags, 4 faded white bags, 4 bright teal bags.
+drab bronze bags contain 1 mirrored brown bag.
+clear coral bags contain 5 plaid maroon bags.
+vibrant indigo bags contain 2 striped purple bags, 4 vibrant green bags, 3 dotted purple bags, 1 vibrant turquoise bag.
+bright bronze bags contain 5 dotted purple bags, 4 shiny brown bags.
+striped tan bags contain 2 light purple bags, 3 mirrored blue bags, 5 dim magenta bags.
+pale brown bags contain 4 wavy green bags, 1 wavy yellow bag.
+faded yellow bags contain 4 dotted red bags.
+plaid magenta bags contain 5 striped magenta bags.
+bright crimson bags contain 4 vibrant tan bags, 2 dotted gold bags, 5 striped purple bags.
+dull yellow bags contain 3 clear cyan bags.
+dotted chartreuse bags contain 5 dim coral bags, 1 dull gray bag, 2 posh tomato bags.
+vibrant crimson bags contain 2 pale black bags, 5 mirrored silver bags, 1 clear beige bag, 5 drab yellow bags.
+wavy red bags contain 2 drab silver bags, 3 shiny salmon bags.
+light blue bags contain 4 posh black bags, 2 clear magenta bags.
+vibrant brown bags contain 4 dim red bags.
+drab indigo bags contain 3 shiny aqua bags, 4 dotted lavender bags, 4 dim brown bags, 2 faded purple bags.
+pale plum bags contain 4 wavy blue bags, 3 posh bronze bags, 4 pale lime bags.
+muted beige bags contain 5 bright bronze bags, 3 dull olive bags.
+muted purple bags contain 4 striped purple bags.
+faded silver bags contain 1 light purple bag, 3 bright tomato bags, 1 mirrored magenta bag.
+vibrant olive bags contain 3 muted turquoise bags, 5 wavy blue bags, 1 dotted silver bag, 5 striped tan bags.
diff --git a/2020/inputs/day8 b/2020/inputs/day8
new file mode 100644
index 0000000..62e61dd
--- /dev/null
+++ b/2020/inputs/day8
@@ -0,0 +1,634 @@
+acc +15
+acc +2
+acc -14
+jmp +362
+acc +22
+nop +236
+jmp +474
+acc +10
+jmp +1
+acc +0
+jmp +236
+acc +10
+acc +14
+jmp +334
+acc +12
+acc -1
+jmp +478
+jmp +90
+jmp +208
+acc +49
+jmp +94
+acc +2
+acc -8
+jmp +375
+nop +21
+acc +0
+acc +10
+nop +25
+jmp +492
+nop +182
+acc +49
+acc -12
+jmp -14
+acc -16
+jmp +140
+acc -3
+acc -18
+acc +28
+acc -6
+jmp +558
+acc +2
+acc +27
+nop +438
+acc +41
+jmp +508
+acc +13
+jmp +117
+acc +21
+acc -13
+acc +34
+jmp +1
+jmp +1
+nop +451
+acc +28
+acc +31
+acc +31
+jmp +280
+acc +32
+acc +35
+acc -18
+jmp +509
+acc -15
+acc -8
+nop +288
+acc -16
+jmp +376
+acc -19
+acc -8
+acc +11
+acc +10
+jmp +50
+acc +19
+nop -58
+acc -9
+jmp +43
+acc +10
+acc +2
+nop -63
+jmp +280
+acc -7
+jmp +175
+jmp +69
+acc +16
+acc +9
+acc -2
+acc -5
+jmp +276
+nop +195
+acc +50
+acc -8
+jmp -55
+nop +1
+nop -78
+acc +31
+jmp +535
+acc +9
+acc +33
+acc +4
+acc +48
+jmp +8
+acc +30
+acc +42
+acc +18
+acc +37
+jmp -69
+nop +121
+jmp +44
+acc +3
+acc +33
+acc -6
+acc +37
+jmp +403
+acc -6
+jmp +245
+jmp -93
+acc +5
+jmp +406
+jmp -26
+nop -47
+jmp +239
+acc +7
+acc +31
+acc +14
+acc +0
+jmp +291
+acc +46
+jmp +394
+acc +44
+acc +36
+nop +45
+jmp +137
+acc -16
+acc +10
+acc -4
+acc +7
+jmp +76
+acc +24
+jmp +93
+acc +17
+acc +0
+acc +6
+acc +4
+jmp +385
+acc -8
+acc +49
+acc +28
+jmp +95
+nop +12
+acc +33
+jmp +153
+nop +254
+acc +18
+acc -16
+acc +50
+jmp +299
+acc +27
+acc +47
+acc -17
+jmp -15
+acc +35
+acc +14
+jmp +204
+jmp +93
+acc +46
+nop -5
+nop -158
+jmp +221
+jmp +321
+acc -2
+acc +49
+acc +3
+acc -17
+jmp -52
+jmp +7
+nop +52
+acc +25
+jmp +376
+acc -3
+nop -133
+jmp +32
+jmp +328
+nop +374
+acc +37
+acc +6
+jmp +92
+acc +47
+nop +394
+jmp -13
+jmp -170
+acc +9
+jmp -47
+acc -18
+acc +27
+jmp +1
+acc +3
+acc -5
+jmp +337
+acc +21
+jmp +364
+acc +24
+acc +43
+acc +50
+jmp +58
+jmp -18
+acc +30
+jmp +144
+nop +5
+acc +50
+nop +245
+nop +133
+jmp +270
+jmp -22
+nop -76
+jmp +398
+acc +40
+acc +30
+jmp +361
+acc +36
+acc +30
+jmp +392
+acc -17
+nop +71
+acc -12
+jmp +102
+acc +17
+jmp +283
+acc -16
+jmp +65
+nop -2
+jmp +149
+jmp -103
+jmp -179
+acc +46
+jmp +289
+acc +48
+jmp +114
+acc +13
+jmp +114
+nop +215
+nop -89
+jmp +337
+acc -2
+acc +2
+acc -7
+jmp -18
+jmp -51
+acc +30
+acc +43
+acc +28
+jmp -188
+acc +36
+acc +7
+acc -5
+acc +38
+jmp +88
+jmp +225
+acc -14
+acc -3
+acc -15
+jmp +66
+acc +7
+acc +43
+nop -210
+acc -9
+jmp +109
+acc -10
+jmp +242
+acc -5
+acc +15
+acc +8
+jmp +310
+acc +31
+acc -2
+acc +11
+acc -15
+jmp +103
+acc +32
+jmp -92
+acc -10
+acc +6
+acc -1
+jmp -131
+acc +43
+acc +30
+acc +13
+acc +33
+jmp +25
+acc +9
+acc -14
+acc +19
+acc +44
+jmp -50
+acc -8
+acc +9
+jmp +312
+jmp -96
+acc -3
+acc -3
+acc +24
+jmp +94
+acc -15
+jmp +61
+acc +19
+nop -89
+acc +24
+nop -94
+jmp +5
+acc -13
+acc +25
+acc +42
+jmp +1
+jmp +137
+acc +44
+acc +44
+acc +41
+jmp +152
+jmp +144
+acc -1
+nop +293
+jmp -120
+acc -17
+nop -171
+acc +27
+jmp -173
+jmp +231
+acc +3
+jmp +109
+acc +18
+acc +32
+acc -14
+acc -8
+jmp +177
+acc +28
+jmp -134
+nop +277
+jmp -124
+jmp +167
+nop +274
+acc +6
+acc +43
+acc +10
+jmp -320
+acc +28
+acc -9
+acc +22
+jmp -90
+jmp -203
+jmp -133
+jmp -6
+jmp -181
+jmp +170
+acc +40
+acc +5
+jmp -274
+acc +36
+acc +24
+nop +6
+jmp -339
+jmp -251
+acc +10
+acc +10
+jmp -347
+jmp +263
+acc +37
+jmp -201
+acc -11
+acc +42
+jmp +153
+nop -179
+acc -9
+jmp +8
+jmp -289
+jmp -25
+acc +45
+jmp -142
+acc +42
+acc -10
+jmp +83
+acc +43
+acc +3
+acc -6
+jmp -222
+acc +41
+acc +14
+acc +7
+acc +2
+jmp -35
+jmp +168
+acc +11
+acc +18
+acc +8
+acc -4
+jmp -203
+acc +44
+jmp +10
+nop -184
+acc +0
+jmp +91
+acc -5
+nop +226
+acc +46
+acc -10
+jmp -15
+jmp -321
+acc +0
+acc +33
+jmp +82
+jmp +1
+acc -12
+acc +30
+jmp +152
+acc +6
+jmp -208
+acc +43
+jmp +39
+acc +23
+acc +23
+acc +24
+acc +26
+jmp -390
+acc +15
+acc +3
+acc +14
+acc +46
+jmp -239
+acc -10
+acc +19
+jmp +167
+acc +46
+acc +0
+jmp -280
+acc -7
+jmp -107
+acc +13
+jmp -76
+acc +48
+jmp -65
+nop +23
+nop -89
+acc +47
+jmp -304
+acc -5
+jmp +1
+acc +50
+acc +37
+jmp -129
+acc +27
+jmp +1
+jmp -212
+acc +18
+acc +29
+acc +1
+jmp -74
+acc +24
+acc -12
+jmp -173
+acc -18
+acc -6
+nop -156
+jmp -309
+acc +46
+acc -13
+acc +41
+acc +11
+jmp -188
+acc +32
+jmp -190
+acc +31
+acc +30
+jmp -122
+acc -7
+jmp +37
+acc +2
+acc +16
+acc +45
+acc +44
+jmp -376
+acc +47
+jmp +1
+jmp -147
+acc +47
+acc -18
+acc -1
+acc +2
+jmp -152
+acc +12
+acc -8
+jmp +90
+nop +67
+acc +9
+jmp +1
+jmp -377
+jmp +1
+jmp -238
+jmp +1
+acc +47
+acc +7
+acc +31
+jmp -427
+acc +10
+acc +13
+nop +13
+jmp -8
+nop -292
+acc +11
+nop -203
+jmp -164
+jmp -19
+acc +31
+jmp -289
+acc -7
+acc -16
+acc +35
+jmp -333
+jmp -500
+acc +32
+acc +29
+acc +18
+acc +14
+jmp -161
+jmp -60
+jmp +6
+acc +4
+nop -108
+acc +27
+jmp +2
+jmp -133
+acc +2
+jmp -103
+acc +40
+nop -512
+acc +48
+jmp -196
+acc +47
+acc +40
+nop -346
+acc -2
+jmp -530
+acc +17
+nop -31
+acc +1
+jmp -74
+acc -15
+acc +4
+nop -330
+acc +32
+jmp -115
+acc -3
+jmp +1
+acc +14
+acc +31
+jmp -352
+jmp -10
+acc +18
+jmp -322
+acc +41
+jmp +59
+acc -16
+nop -359
+acc +29
+acc +26
+jmp -418
+acc +10
+acc +47
+jmp -519
+acc -5
+nop +40
+acc +30
+jmp -195
+acc +31
+acc +3
+acc +8
+jmp -10
+acc -12
+acc +21
+acc -1
+jmp +30
+jmp -341
+acc -5
+jmp -405
+acc -13
+jmp -170
+acc +24
+acc -16
+acc +20
+acc +17
+jmp -145
+acc +42
+acc +33
+jmp -395
+nop -142
+acc +45
+acc +15
+jmp -399
+nop -223
+jmp -299
+jmp -453
+acc -6
+nop -498
+acc +42
+jmp -112
+acc +39
+acc +46
+acc +4
+acc +27
+jmp -234
+jmp +1
+acc +45
+acc +47
+jmp -307
+jmp -378
+jmp -431
+acc +13
+acc +29
+jmp -282
+acc +4
+acc -3
+acc +37
+acc +40
+jmp -32
+nop -148
+acc +38
+acc +40
+acc +18
+jmp -171
+nop -546
+jmp -490
+acc +36
+jmp -514
+acc +27
+acc -10
+nop -560
+acc +44
+jmp +1
diff --git a/2020/inputs/day8_patch b/2020/inputs/day8_patch
new file mode 100644
index 0000000..2ce31b8
--- /dev/null
+++ b/2020/inputs/day8_patch
@@ -0,0 +1,634 @@
+acc +15
+acc +2
+acc -14
+jmp +362
+acc +22
+nop +236
+jmp +474
+acc +10
+jmp +1
+acc +0
+jmp +236
+acc +10
+acc +14
+jmp +334
+acc +12
+acc -1
+jmp +478
+jmp +90
+jmp +208
+acc +49
+jmp +94
+acc +2
+acc -8
+jmp +375
+nop +21
+acc +0
+acc +10
+nop +25
+jmp +492
+nop +182
+acc +49
+acc -12
+jmp -14
+acc -16
+jmp +140
+acc -3
+acc -18
+acc +28
+acc -6
+jmp +558
+acc +2
+acc +27
+nop +438
+acc +41
+jmp +508
+acc +13
+jmp +117
+acc +21
+acc -13
+acc +34
+jmp +1
+jmp +1
+nop +451
+acc +28
+acc +31
+acc +31
+jmp +280
+acc +32
+acc +35
+acc -18
+jmp +509
+acc -15
+acc -8
+nop +288
+acc -16
+jmp +376
+acc -19
+acc -8
+acc +11
+acc +10
+jmp +50
+acc +19
+nop -58
+acc -9
+jmp +43
+acc +10
+acc +2
+nop -63
+jmp +280
+acc -7
+jmp +175
+jmp +69
+acc +16
+acc +9
+acc -2
+acc -5
+jmp +276
+nop +195
+acc +50
+acc -8
+jmp -55
+nop +1
+nop -78
+acc +31
+jmp +535
+acc +9
+acc +33
+acc +4
+acc +48
+jmp +8
+acc +30
+acc +42
+acc +18
+acc +37
+jmp -69
+nop +121
+jmp +44
+acc +3
+acc +33
+acc -6
+acc +37
+jmp +403
+acc -6
+jmp +245
+jmp -93
+acc +5
+jmp +406
+jmp -26
+nop -47
+jmp +239
+acc +7
+acc +31
+acc +14
+acc +0
+jmp +291
+acc +46
+jmp +394
+acc +44
+acc +36
+nop +45
+jmp +137
+acc -16
+acc +10
+acc -4
+acc +7
+jmp +76
+acc +24
+jmp +93
+acc +17
+acc +0
+acc +6
+acc +4
+jmp +385
+acc -8
+acc +49
+acc +28
+jmp +95
+nop +12
+acc +33
+jmp +153
+nop +254
+acc +18
+acc -16
+acc +50
+jmp +299
+acc +27
+acc +47
+acc -17
+jmp -15
+acc +35
+acc +14
+jmp +204
+jmp +93
+acc +46
+nop -5
+nop -158
+jmp +221
+jmp +321
+acc -2
+acc +49
+acc +3
+acc -17
+jmp -52
+jmp +7
+nop +52
+acc +25
+jmp +376
+acc -3
+nop -133
+jmp +32
+jmp +328
+nop +374
+acc +37
+acc +6
+jmp +92
+acc +47
+nop +394
+jmp -13
+jmp -170
+acc +9
+jmp -47
+acc -18
+acc +27
+jmp +1
+acc +3
+acc -5
+jmp +337
+acc +21
+jmp +364
+acc +24
+acc +43
+acc +50
+jmp +58
+jmp -18
+acc +30
+jmp +144
+nop +5
+acc +50
+nop +245
+nop +133
+jmp +270
+jmp -22
+nop -76
+jmp +398
+acc +40
+acc +30
+jmp +361
+acc +36
+acc +30
+jmp +392
+acc -17
+nop +71
+acc -12
+jmp +102
+acc +17
+jmp +283
+acc -16
+jmp +65
+nop -2
+jmp +149
+jmp -103
+jmp -179
+acc +46
+jmp +289
+acc +48
+jmp +114
+acc +13
+jmp +114
+nop +215
+nop -89
+jmp +337
+acc -2
+acc +2
+acc -7
+jmp -18
+jmp -51
+acc +30
+acc +43
+acc +28
+jmp -188
+acc +36
+acc +7
+acc -5
+acc +38
+jmp +88
+jmp +225
+acc -14
+acc -3
+acc -15
+jmp +66
+acc +7
+acc +43
+nop -210
+acc -9
+jmp +109
+acc -10
+jmp +242
+acc -5
+acc +15
+acc +8
+jmp +310
+acc +31
+acc -2
+acc +11
+acc -15
+jmp +103
+acc +32
+jmp -92
+acc -10
+acc +6
+acc -1
+jmp -131
+acc +43
+acc +30
+acc +13
+acc +33
+jmp +25
+acc +9
+acc -14
+acc +19
+acc +44
+jmp -50
+acc -8
+acc +9
+jmp +312
+jmp -96
+acc -3
+acc -3
+acc +24
+jmp +94
+acc -15
+jmp +61
+acc +19
+nop -89
+acc +24
+nop -94
+jmp +5
+acc -13
+acc +25
+acc +42
+jmp +1
+jmp +137
+acc +44
+acc +44
+acc +41
+jmp +152
+jmp +144
+acc -1
+nop +293
+jmp -120
+acc -17
+nop -171
+acc +27
+jmp -173
+jmp +231
+acc +3
+jmp +109
+acc +18
+acc +32
+acc -14
+acc -8
+jmp +177
+acc +28
+jmp -134
+nop +277
+jmp -124
+jmp +167
+nop +274
+acc +6
+acc +43
+acc +10
+jmp -320
+acc +28
+acc -9
+acc +22
+jmp -90
+jmp -203
+jmp -133
+jmp -6
+jmp -181
+jmp +170
+acc +40
+acc +5
+jmp -274
+acc +36
+acc +24
+nop +6
+jmp -339
+jmp -251
+acc +10
+acc +10
+jmp -347
+jmp +263
+acc +37
+jmp -201
+acc -11
+acc +42
+jmp +153
+nop -179
+acc -9
+jmp +8
+jmp -289
+jmp -25
+acc +45
+jmp -142
+acc +42
+acc -10
+jmp +83
+acc +43
+acc +3
+acc -6
+jmp -222
+acc +41
+acc +14
+acc +7
+acc +2
+jmp -35
+jmp +168
+acc +11
+acc +18
+acc +8
+acc -4
+jmp -203
+acc +44
+jmp +10
+nop -184
+acc +0
+jmp +91
+acc -5
+nop +226
+acc +46
+acc -10
+jmp -15
+jmp -321
+acc +0
+acc +33
+jmp +82
+jmp +1
+acc -12
+acc +30
+jmp +152
+acc +6
+jmp -208
+acc +43
+jmp +39
+acc +23
+acc +23
+acc +24
+acc +26
+jmp -390
+acc +15
+acc +3
+acc +14
+acc +46
+jmp -239
+acc -10
+acc +19
+jmp +167
+acc +46
+acc +0
+jmp -280
+acc -7
+nop -107
+acc +13
+jmp -76
+acc +48
+jmp -65
+nop +23
+nop -89
+acc +47
+jmp -304
+acc -5
+jmp +1
+acc +50
+acc +37
+jmp -129
+acc +27
+jmp +1
+jmp -212
+acc +18
+acc +29
+acc +1
+jmp -74
+acc +24
+acc -12
+jmp -173
+acc -18
+acc -6
+nop -156
+jmp -309
+acc +46
+acc -13
+acc +41
+acc +11
+jmp -188
+acc +32
+jmp -190
+acc +31
+acc +30
+jmp -122
+acc -7
+jmp +37
+acc +2
+acc +16
+acc +45
+acc +44
+jmp -376
+acc +47
+jmp +1
+jmp -147
+acc +47
+acc -18
+acc -1
+acc +2
+jmp -152
+acc +12
+acc -8
+jmp +90
+nop +67
+acc +9
+jmp +1
+jmp -377
+jmp +1
+jmp -238
+jmp +1
+acc +47
+acc +7
+acc +31
+jmp -427
+acc +10
+acc +13
+nop +13
+jmp -8
+nop -292
+acc +11
+nop -203
+jmp -164
+jmp -19
+acc +31
+jmp -289
+acc -7
+acc -16
+acc +35
+jmp -333
+jmp -500
+acc +32
+acc +29
+acc +18
+acc +14
+jmp -161
+jmp -60
+jmp +6
+acc +4
+nop -108
+acc +27
+jmp +2
+jmp -133
+acc +2
+jmp -103
+acc +40
+nop -512
+acc +48
+jmp -196
+acc +47
+acc +40
+nop -346
+acc -2
+jmp -530
+acc +17
+nop -31
+acc +1
+jmp -74
+acc -15
+acc +4
+nop -330
+acc +32
+jmp -115
+acc -3
+jmp +1
+acc +14
+acc +31
+jmp -352
+jmp -10
+acc +18
+jmp -322
+acc +41
+jmp +59
+acc -16
+nop -359
+acc +29
+acc +26
+jmp -418
+acc +10
+acc +47
+jmp -519
+acc -5
+nop +40
+acc +30
+jmp -195
+acc +31
+acc +3
+acc +8
+jmp -10
+acc -12
+acc +21
+acc -1
+jmp +30
+jmp -341
+acc -5
+jmp -405
+acc -13
+jmp -170
+acc +24
+acc -16
+acc +20
+acc +17
+jmp -145
+acc +42
+acc +33
+jmp -395
+nop -142
+acc +45
+acc +15
+jmp -399
+nop -223
+jmp -299
+jmp -453
+acc -6
+nop -498
+acc +42
+jmp -112
+acc +39
+acc +46
+acc +4
+acc +27
+jmp -234
+jmp +1
+acc +45
+acc +47
+jmp -307
+jmp -378
+jmp -431
+acc +13
+acc +29
+jmp -282
+acc +4
+acc -3
+acc +37
+acc +40
+jmp -32
+nop -148
+acc +38
+acc +40
+acc +18
+jmp -171
+nop -546
+jmp -490
+acc +36
+jmp -514
+acc +27
+acc -10
+nop -560
+acc +44
+jmp +1
diff --git a/2020/inputs/day9 b/2020/inputs/day9
new file mode 100644
index 0000000..e31938e
--- /dev/null
+++ b/2020/inputs/day9
@@ -0,0 +1,1000 @@
+18
+19
+46
+14
+29
+45
+40
+47
+25
+43
+36
+22
+21
+4
+32
+33
+37
+38
+26
+2
+42
+15
+5
+13
+31
+9
+6
+30
+7
+14
+10
+8
+69
+11
+12
+25
+16
+17
+22
+19
+18
+20
+51
+21
+24
+23
+26
+15
+60
+13
+29
+27
+44
+42
+28
+38
+30
+36
+31
+32
+33
+34
+35
+37
+55
+39
+40
+70
+41
+43
+78
+58
+73
+101
+60
+56
+57
+75
+59
+67
+71
+61
+68
+110
+69
+80
+72
+112
+76
+79
+144
+129
+114
+84
+99
+113
+132
+115
+148
+116
+118
+120
+128
+126
+187
+130
+190
+152
+229
+141
+151
+155
+299
+209
+163
+239
+183
+197
+331
+212
+228
+270
+231
+234
+236
+244
+246
+355
+256
+392
+271
+342
+292
+360
+296
+306
+318
+346
+602
+375
+380
+395
+534
+456
+440
+459
+470
+502
+478
+480
+490
+517
+527
+548
+563
+1082
+1136
+896
+1044
+614
+693
+698
+988
+755
+1065
+1352
+835
+899
+915
+942
+929
+1173
+958
+1043
+970
+1007
+1075
+1090
+1529
+1750
+1663
+1307
+1312
+1533
+1369
+1391
+1705
+1590
+1654
+1734
+1764
+1805
+2923
+2649
+1936
+1899
+2633
+1928
+2681
+1977
+3956
+2165
+2981
+2619
+3926
+2676
+2840
+2703
+4292
+4547
+4383
+4628
+3244
+3388
+3539
+6659
+6602
+5143
+3827
+5316
+8558
+3905
+5322
+4142
+4817
+4784
+9069
+5379
+11206
+5516
+7536
+10701
+6242
+7293
+6632
+15190
+11260
+7366
+7732
+7681
+7969
+8959
+9521
+8611
+8047
+10139
+8689
+16605
+8926
+10300
+10163
+10895
+15262
+12148
+13925
+12874
+15025
+13974
+19229
+14313
+15047
+15098
+15335
+15413
+16370
+16016
+16658
+27899
+16736
+18852
+35245
+17615
+19089
+19821
+29984
+23769
+23043
+30309
+31705
+26799
+26848
+35105
+28287
+30382
+42183
+30748
+30433
+31351
+31429
+32386
+32674
+33394
+44635
+34351
+50281
+36704
+60293
+69456
+42864
+49891
+46812
+49842
+53647
+55086
+85047
+119298
+60961
+75099
+62099
+73297
+94916
+61784
+62780
+63815
+75250
+96654
+67745
+104928
+71055
+111242
+133358
+89676
+92706
+151460
+134938
+101898
+158753
+108733
+122831
+122745
+123060
+293691
+126595
+165971
+142995
+125599
+130525
+146305
+194115
+402424
+179788
+138800
+226064
+160731
+182382
+235256
+191574
+194604
+210631
+224643
+269464
+231478
+231564
+245576
+253585
+248659
+252194
+276830
+256124
+411266
+371362
+299531
+354846
+654618
+340519
+330374
+459212
+343113
+695365
+431041
+386178
+402205
+405235
+435274
+456121
+633683
+504783
+477140
+586095
+701736
+500853
+508318
+654377
+555655
+640050
+741024
+642644
+673487
+1288060
+802325
+716552
+729291
+1497690
+1073685
+1273733
+821452
+807440
+891395
+912414
+933261
+977993
+1117190
+1140903
+1210054
+1009171
+1143497
+1063973
+1445843
+1195705
+1282694
+2428963
+1316131
+1390039
+1518877
+2095183
+2337706
+1536731
+1628892
+1698835
+2076758
+1712847
+1803809
+1824656
+1845675
+2962865
+1987164
+2073144
+2150074
+2152668
+2204876
+2207470
+2981529
+2478399
+3128369
+2908916
+4192040
+2706170
+2926770
+3055608
+3790973
+3165623
+3235566
+3327727
+3502644
+5835686
+3516656
+3628465
+3670331
+7131109
+5941736
+5116386
+4278020
+4913640
+4412346
+5186405
+4685869
+7293617
+5834539
+5615086
+6383335
+5632940
+9001309
+5982378
+6221231
+6401189
+6493350
+6563293
+6830371
+8188513
+7145121
+10907100
+10354082
+7948351
+11998421
+8690366
+9528732
+8963889
+15987022
+10318809
+9872274
+13376235
+16136864
+11248026
+12016275
+14983687
+17469257
+12203609
+12383567
+26433146
+12894539
+13056643
+13393664
+13975492
+15093472
+26270774
+16638717
+16912240
+18492621
+17654255
+22066601
+25440210
+18836163
+20191083
+21120300
+23264301
+26870031
+33085622
+23451635
+24399842
+24587176
+25098148
+51578243
+35095792
+34176943
+37980840
+35460265
+27369156
+29068964
+37160073
+33550957
+36146876
+62568016
+47164749
+41311383
+44778259
+45631293
+39027246
+52333265
+55938995
+48549783
+50321666
+77431413
+47851477
+48987018
+65898559
+52467304
+83311625
+68646749
+74487511
+69011222
+80925135
+76187319
+62619921
+115214565
+167547830
+136864130
+91943008
+131266670
+80338629
+83805505
+86878723
+87577029
+100184742
+117561005
+139346027
+116498226
+96838495
+129912153
+101454322
+115087225
+213051449
+150674830
+246410379
+154562929
+216668887
+138807240
+195425854
+142958550
+164144134
+267732572
+167217352
+167915658
+170684228
+185259827
+171382534
+244412872
+184415524
+265598456
+198292817
+211925720
+213336721
+334233094
+216541547
+240261562
+253894465
+369675351
+281765790
+335133010
+323222764
+505860018
+328218377
+354884270
+307102684
+331361486
+337901580
+379143072
+338599886
+342066762
+456803109
+355798058
+382708341
+594634061
+410218537
+536559485
+425262441
+429878268
+547903033
+523644231
+535660255
+585255951
+753480818
+588868474
+630325448
+662900742
+788164595
+635321061
+638464170
+645004264
+669263066
+734941130
+680666648
+694397944
+1055587889
+1363661010
+738506399
+792926878
+945878792
+1277125049
+1108900182
+1357298686
+1298221803
+776203571
+1275329712
+1124528729
+1174124425
+1343567390
+1219193922
+1310992096
+1759849790
+1527868008
+1428247939
+1283468434
+1314267330
+1349929714
+1375064592
+1917455607
+2517415725
+1531433277
+1514709970
+2328094104
+2959681216
+1722082363
+2811336442
+1885103753
+1900732300
+2126133285
+1950327996
+2884378519
+2552776668
+2549189017
+2502662356
+2530186018
+2594460530
+2633398148
+2597735764
+2658533026
+5542911545
+2664197044
+2724994306
+4032125695
+3046143247
+4048849002
+3236792333
+3399813723
+3607186116
+6636606056
+3622814663
+6048128775
+6109848472
+3851060296
+4076461281
+7094992249
+5032848374
+5051851373
+5079375035
+5097122886
+5124646548
+5192196294
+5231133912
+6843978449
+5322730070
+5771137553
+7268918028
+7448662725
+6445956970
+7122604528
+6859606996
+7006999839
+7022628386
+10068771633
+14029628225
+7473874959
+10514926364
+13866606835
+7927521577
+9109309655
+10084699747
+12705008871
+12219727414
+10176497921
+10316842842
+10355780460
+12253762298
+10553863982
+19522680326
+21340481794
+12630744549
+13305563966
+13452956809
+13468585356
+13882235382
+14480874798
+14934521416
+17199126307
+19663173637
+15401396536
+16583184614
+17036831232
+23021851713
+18104019498
+32584894296
+24022449338
+37475406147
+30076544308
+20672623302
+37709454534
+20909644442
+22807626280
+23184608531
+25936308515
+26083701358
+27187799348
+28240085382
+26921542165
+28403106772
+28363110180
+29415396214
+46507126270
+48026283817
+35140850730
+40058682945
+41059280570
+43480249582
+43694475015
+38776642800
+49268309889
+46993345800
+41582267744
+43717270722
+55590906120
+49272754622
+44094252973
+71720334964
+49120917046
+92815392061
+53005243523
+54109341513
+91506533399
+55284652345
+79835923370
+104405569391
+76408742014
+91720758832
+73917493530
+78835325745
+85769988600
+80358910544
+140841675878
+124053385559
+113302602708
+120126012736
+85299538466
+123190248152
+142088146683
+125529659060
+93367007595
+236492850860
+107114585036
+102126160569
+108289895868
+130518083527
+174235354249
+165424026929
+140584190811
+170556084577
+150326235544
+161708280480
+192137928453
+180961486314
+205425551202
+166128899144
+165658449010
+178666546061
+200481592631
+233951198406
+307551711771
+187425699035
+306713089955
+201656903463
+195493168164
+209240745605
+366092245096
+238807979395
+210416056437
+366610491775
+302292471291
+290910426355
+374535389217
+311140275388
+312034516024
+331787348154
+327366729490
+402138496094
+344324995071
+344795445205
+353084148045
+387907291666
+374159714225
+491392018986
+434301147559
+382918867199
+389082602498
+503949374754
+397150071627
+715274021156
+419656802042
+449224035832
+512708527728
+612554552531
+593202897646
+776673885311
+685675664605
+623174791412
+638507004878
+736003015244
+659154077644
+886868241953
+733878047703
+763981797113
+1269787109152
+750234219672
+763242316723
+1248711542972
+780068938826
+1048236680142
+1862990006798
+1418575943704
+1620746289656
+2003665156855
+2198644882530
+868880837874
+2005790124396
+1205757450177
+1216377689058
+1297661082522
+1324182669483
+3868780131194
+1261681796290
+1372385052581
+1393032125347
+1409388297316
+1497120364426
+1484112267375
+1513476536395
+1530303158498
+1543311255549
+1632123154597
+1648949776700
+1828305618968
+2532348947517
+2241265890455
+2946610859222
+2074638288051
+2193063507357
+2517830614574
+2085258526932
+2422135139235
+2585864465773
+2514038771580
+2654713921637
+2893804950887
+2634066848871
+2745794063665
+2765417177928
+4424108109385
+2893500564691
+2981232631801
+7009972575158
+3043779694893
+3073614414047
+3175434410146
+6249048824193
+4606987235568
+4250440758203
+4827130356228
+4159896814983
+7588219867369
+4599297298512
+7672911712559
+4507393666167
+10418705776224
+5076849060872
+5099903237353
+5689473181726
+5527871799758
+5399484026799
+14682884287717
+5511211241593
+5658917742619
+7497722523432
+5874733196492
+6025012326694
+6117394108940
+7425875168349
+7233511229030
+7335331225129
+8410337573186
+9327289819075
+10127169098270
+8987027171211
+12734815251928
+19190277953884
+9906877692966
+22180606811149
+9584242727039
+12825359195148
+10176752298225
+15596350874692
+10910695268392
+11170128984212
+11058401769418
+11385944438085
+11533650939111
+11683930069313
+14435349899880
+13210064421621
+28298000920089
+13350905337970
+21660820037381
+16560801048105
+16919573952168
+20713234257160
+18314316990286
+18571269898250
+24120759690013
+19491120420005
+19760995025264
+20083629991191
+20494937995431
+20642644496457
+29372718759704
+21235154067643
+31146939463349
+31469574429276
+39831651859200
+31553339764849
+23069874507398
+26560969759591
+45904924329156
+50681729449604
+32842025757975
+30270479290138
+31665222328256
+33480375000273
+34875118038391
+55785982018269
+40255933020695
+36885586888536
+38062390318255
+39252115445269
+39844625016455
+40403639521721
+47055907755022
+67698552251479
+41877798564100
+53340353797536
+59297544385898
+49630844266989
+54539448936674
+62321989952667
+54623214272247
+83941494643558
+72686650774430
+63112505048113
+113794234497717
+123786119660013
+68355493038664
+88215471835927
+98549659831167
+71760704926927
diff --git a/2021/.envrc b/2021/.envrc
new file mode 100644
index 0000000..051d09d
--- /dev/null
+++ b/2021/.envrc
@@ -0,0 +1 @@
+eval "$(lorri direnv)"
diff --git a/2021/.gitignore b/2021/.gitignore
new file mode 100644
index 0000000..889aef8
--- /dev/null
+++ b/2021/.gitignore
@@ -0,0 +1,57 @@
+inputs/
+
+# Created by https://www.toptal.com/developers/gitignore/api/racket
+# Edit at https://www.toptal.com/developers/gitignore?templates=racket
+
+### Racket ###
+# gitignore template for the Racket language
+# website: http://www.racket-lang.org/
+
+# DrRacket autosave files
+*.rkt~
+*.rkt.bak
+\#*.rkt#
+\#*.rkt#*#
+
+# Compiled racket bytecode
+compiled/
+*.zo
+
+# Dependency tracking files
+*.dep
+
+# End of https://www.toptal.com/developers/gitignore/api/racket
+
+*/input
+*/input_test
+
+
+# Created by https://www.toptal.com/developers/gitignore/api/haskell
+# Edit at https://www.toptal.com/developers/gitignore?templates=haskell
+
+### Haskell ###
+dist
+dist-*
+cabal-dev
+*.o
+*.hi
+*.hie
+*.chi
+*.chs.h
+*.dyn_o
+*.dyn_hi
+.hpc
+.hsenv
+.cabal-sandbox/
+cabal.sandbox.config
+*.prof
+*.aux
+*.hp
+*.eventlog
+.stack-work/
+cabal.project.local
+cabal.project.local~
+.HTF/
+.ghc.environment.*
+
+# End of https://www.toptal.com/developers/gitignore/api/haskell
diff --git a/2021/day1/01a.rkt b/2021/day1/01a.rkt
new file mode 100644
index 0000000..5f3ea26
--- /dev/null
+++ b/2021/day1/01a.rkt
@@ -0,0 +1,18 @@
+#lang racket
+(require threading)
+
+(define input (file->lines "input"))
+
+(define (map-differing-lengths f . arrs)
+ (define minLength (apply min (map length arrs)))
+ (define newLists (map (lambda (x) (take x minLength)) arrs))
+ (apply map (cons f newLists)))
+
+(define (diff-pairs xs)
+ (map-differing-lengths - (cdr xs) xs))
+
+(~>> input
+ (map string->number)
+ (diff-pairs)
+ (filter positive?)
+ (length _))
diff --git a/2021/day1/01b.rkt b/2021/day1/01b.rkt
new file mode 100644
index 0000000..40337a4
--- /dev/null
+++ b/2021/day1/01b.rkt
@@ -0,0 +1,23 @@
+#lang racket
+(require threading)
+
+(define input (file->lines "input"))
+
+(define (map-differing-lengths f . arrs)
+ (define minLength (apply min (map length arrs)))
+ (define newLists (map (lambda (x) (take x minLength)) arrs))
+ (apply map (cons f newLists)))
+
+(define (build-windows xs)
+ (map-differing-lengths list xs (cdr xs) (drop xs 2)))
+
+(define (diff-pairs xs)
+ (map-differing-lengths - (cdr xs) xs))
+
+(~>> input
+ (map string->number)
+ (build-windows)
+ (map (lambda (x) (apply + x)))
+ (diff-pairs)
+ (filter positive?)
+ (length _))
diff --git a/2021/day10/10a.hs b/2021/day10/10a.hs
new file mode 100644
index 0000000..7dadbce
--- /dev/null
+++ b/2021/day10/10a.hs
@@ -0,0 +1,50 @@
+module Main where
+
+isStartParen :: Char -> Bool
+isStartParen '(' = True
+isStartParen '[' = True
+isStartParen '{' = True
+isStartParen '<' = True
+isStartParen _ = False
+
+isEndParen :: Char -> Bool
+isEndParen ')' = True
+isEndParen ']' = True
+isEndParen '}' = True
+isEndParen '>' = True
+isEndParen _ = False
+
+flipParen :: Char -> Char
+flipParen '(' = ')'
+flipParen ')' = '('
+flipParen '[' = ']'
+flipParen ']' = '['
+flipParen '{' = '}'
+flipParen '}' = '{'
+flipParen '<' = '>'
+flipParen '>' = '<'
+flipParen _ = undefined
+
+getScore :: Char -> Int
+getScore ')' = 3
+getScore ']' = 57
+getScore '}' = 1197
+getScore '>' = 25137
+
+consumeBlock :: Char -> String -> Either Char String
+consumeBlock t "" = Right ""
+consumeBlock t (c:cs) | c == flipParen t = Right cs
+ | isStartParen c = (consumeBlock c cs) >>= (consumeBlock t)
+ | otherwise = Left c
+
+corruptionScore :: String -> Int
+corruptionScore "" = 0
+corruptionScore (c:cs) = case consumeBlock c cs of
+ Left c -> getScore c
+ Right s -> corruptionScore s
+
+main :: IO ()
+main = do
+ s <- readFile "./input"
+ let notCorrupted = foldr (+) 0 $ map corruptionScore (lines s)
+ print notCorrupted
diff --git a/2021/day10/10b.hs b/2021/day10/10b.hs
new file mode 100644
index 0000000..39b427f
--- /dev/null
+++ b/2021/day10/10b.hs
@@ -0,0 +1,66 @@
+module Main where
+
+import Data.List (sort)
+
+isStartParen :: Char -> Bool
+isStartParen '(' = True
+isStartParen '[' = True
+isStartParen '{' = True
+isStartParen '<' = True
+isStartParen _ = False
+
+isEndParen :: Char -> Bool
+isEndParen ')' = True
+isEndParen ']' = True
+isEndParen '}' = True
+isEndParen '>' = True
+isEndParen _ = False
+
+flipParen :: Char -> Char
+flipParen '(' = ')'
+flipParen ')' = '('
+flipParen '[' = ']'
+flipParen ']' = '['
+flipParen '{' = '}'
+flipParen '}' = '{'
+flipParen '<' = '>'
+flipParen '>' = '<'
+flipParen _ = undefined
+
+getScore :: Char -> Int
+getScore ')' = 3
+getScore ']' = 57
+getScore '}' = 1197
+getScore '>' = 25137
+
+completionScore :: Char -> Int
+completionScore ')' = 1
+completionScore ']' = 2
+completionScore '}' = 3
+completionScore '>' = 4
+completionScore _ = undefined
+
+consumeBlock :: Char -> String -> Either Char String
+consumeBlock t "" = Right ""
+consumeBlock t (c:cs) | c == flipParen t = Right cs
+ | isStartParen c = (consumeBlock c cs) >>= (consumeBlock t)
+ | otherwise = Left c
+
+corruptionScore :: String -> Int
+corruptionScore "" = 0
+corruptionScore (c:cs) = case consumeBlock c cs of
+ Left c -> getScore c
+ Right s -> corruptionScore s
+
+getCompletion :: String -> String -> String
+getCompletion stack "" = map flipParen stack
+getCompletion stack (c:cs) | isStartParen c = getCompletion (c : stack) cs
+ | otherwise = getCompletion (tail stack) cs
+
+main :: IO ()
+main = do
+ s <- readFile "./input"
+ let notCorrupted = filter ((== 0) . corruptionScore) (lines s)
+ let scores = sort $ map ((foldl (\acc x -> (acc * 5) + (completionScore x)) 0) . getCompletion "") notCorrupted
+
+ print $ scores !! (div (length scores) 2)
diff --git a/2021/day11/11a.py b/2021/day11/11a.py
new file mode 100644
index 0000000..1c6d096
--- /dev/null
+++ b/2021/day11/11a.py
@@ -0,0 +1,42 @@
+def adjacent(coord, arr):
+ x, y = coord
+ max_x = len(arr[y]) - 1
+ max_y = len(arr) - 1
+ for dx in [-1, 0, 1]:
+ for dy in [-1, 0, 1]:
+ xp, yp = (x + dx, y + dy)
+ if ((xp, yp) == coord or min(xp, yp) < 0 or xp > max_x or yp > max_y):
+ continue
+ yield (xp, yp)
+
+def flash(coord, arr, flashed):
+ flashed.add(coord)
+ for (x, y) in adjacent(coord, arr):
+ arr[y][x] += 1
+ visit((x, y), arr, flashed)
+
+def visit(coord, arr, flashed):
+ x, y = coord
+ v = arr[y][x]
+ if v > 9 and coord not in flashed:
+ flash(coord, arr, flashed)
+
+def step(arr):
+ flashed = set()
+ for (x,y) in ((x,y) for (y,l) in enumerate(arr) for (x,_) in enumerate(l)):
+ arr[y][x] = arr[y][x] + 1
+ visit((x,y), arr, flashed)
+ for (x,y) in flashed:
+ arr[y][x] = 0
+ return len(flashed)
+
+def print_board(arr):
+ print("\n".join(["".join(map(str, l)) for l in arr]))
+
+state = [[int(n) for n in l] for l in open("./input").read().strip().split("\n")]
+total_flashes = 0
+for _ in range(0, 100):
+ flashes = step(state)
+ total_flashes += flashes
+
+print(total_flashes)
diff --git a/2021/day11/11b.py b/2021/day11/11b.py
new file mode 100644
index 0000000..18b45d4
--- /dev/null
+++ b/2021/day11/11b.py
@@ -0,0 +1,44 @@
+def adjacent(coord, arr):
+ x, y = coord
+ max_x = len(arr[y]) - 1
+ max_y = len(arr) - 1
+ for dx in [-1, 0, 1]:
+ for dy in [-1, 0, 1]:
+ xp, yp = (x + dx, y + dy)
+ if ((xp, yp) == coord or min(xp, yp) < 0 or xp > max_x or yp > max_y):
+ continue
+ yield (xp, yp)
+
+def flash(coord, arr, flashed):
+ flashed.add(coord)
+ for (x, y) in adjacent(coord, arr):
+ arr[y][x] += 1
+ visit((x, y), arr, flashed)
+
+def visit(coord, arr, flashed):
+ x, y = coord
+ v = arr[y][x]
+ if v > 9 and coord not in flashed:
+ flash(coord, arr, flashed)
+
+def step(arr):
+ flashed = set()
+ for (x,y) in ((x,y) for (y,l) in enumerate(arr) for (x,_) in enumerate(l)):
+ arr[y][x] = arr[y][x] + 1
+ visit((x,y), arr, flashed)
+ for (x,y) in flashed:
+ arr[y][x] = 0
+ return len(flashed)
+
+def print_board(arr):
+ print("\n".join(["".join(map(str, l)) for l in arr]))
+
+state = [[int(n) for n in l] for l in open("./input").read().strip().split("\n")]
+total_squares = sum([len(l) for l in state])
+n = 0
+while True:
+ n += 1
+ if step(state) == total_squares:
+ break
+
+print(n)
diff --git a/2021/day12/12a.py b/2021/day12/12a.py
new file mode 100644
index 0000000..5d1adba
--- /dev/null
+++ b/2021/day12/12a.py
@@ -0,0 +1,34 @@
+from collections import deque
+
+def parseInput(contents):
+ edges = [l.split("-") for l in contents.strip().split("\n")]
+ edges_set = set([])
+ for (f, t) in edges:
+ edges_set.add((f, t))
+ if t != "end" and f != "start":
+ edges_set.add((t, f))
+
+ return edges_set
+
+def visitableNeighbours(edges, loc):
+ fr = loc[0]
+ banned = [e for e in loc if e.islower()]
+ for (f, t) in edges:
+ if f == fr and t not in banned:
+ yield t
+
+
+edges = parseInput(open("./input").read())
+
+locs = deque() # each element is a list of all the visited nodes
+finished = set()
+locs.append(["start"])
+while len(locs) > 0:
+ l = locs.pop()
+ if l[0] == "end":
+ finished.add("-".join(l))
+ else:
+ for neighbour in visitableNeighbours(edges, l):
+ locs.append([neighbour] + l)
+
+print(len(finished))
diff --git a/2021/day12/12b.py b/2021/day12/12b.py
new file mode 100644
index 0000000..149749e
--- /dev/null
+++ b/2021/day12/12b.py
@@ -0,0 +1,32 @@
+from collections import deque
+
+def parseInput(contents):
+ edges = [l.split("-") for l in contents.strip().split("\n")]
+ edges_set = set([])
+ for (f, t) in edges:
+ edges_set.add((f, t))
+ if t != "end" and f != "start":
+ edges_set.add((t, f))
+
+ return edges_set
+
+def visitableNeighbours(edges, path, doubleVisited):
+ curr = path[0]
+ banned = [e for e in path if e.islower()] if doubleVisited else ["start"]
+ for (f, t) in edges:
+ if f == curr and t not in banned:
+ yield t
+
+
+edges = parseInput(open("./input").read())
+
+locs = deque() # each element is a tuple of (double visited, list of all the visited nodes)
+finished = set()
+locs.append((False, ["start"]))
+while len(locs) > 0:
+ doubleVisited, path = locs.pop()
+ if path[0] == "end":
+ finished.add("-".join(path))
+ else:
+ for neighbour in visitableNeighbours(edges, path, doubleVisited):
+ locs.append((doubleVisited or (neighbour.islower() and neighbour in path), [neighbour] + path))
diff --git a/2021/day13/13a.hs b/2021/day13/13a.hs
new file mode 100644
index 0000000..79af7ae
--- /dev/null
+++ b/2021/day13/13a.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import qualified Data.Text as T
+import Data.Set (Set)
+import Data.List
+import qualified Data.Set as S
+
+type Coord = (Int, Int)
+data FoldInstr = Fold Axis Int deriving (Show, Eq, Ord)
+data Axis = XAxis | YAxis deriving (Show, Eq, Ord)
+
+parseCoords :: String -> Coord
+parseCoords s = (read x, read y)
+ where [x, y] = map T.unpack $ T.splitOn "," (T.pack s)
+
+parseFold :: String -> FoldInstr
+parseFold (stripPrefix "fold along y=" -> Just cs) = Fold YAxis (read cs)
+parseFold (stripPrefix "fold along x=" -> Just cs) = Fold XAxis (read cs)
+
+parseFile :: String -> (Set Coord, [FoldInstr])
+parseFile s = (S.fromList $ map parseCoords (lines coordSection), map parseFold (lines foldSection))
+ where [coordSection, foldSection] = map T.unpack $ T.splitOn "\n\n" (T.pack s)
+
+performFold :: Set Coord -> FoldInstr -> Set Coord
+performFold coords (Fold YAxis ye) = S.map (\(x, y) -> (x, -(abs (y - ye)) + ye)) coords
+performFold coords (Fold XAxis xe) = S.map (\(x, y) -> (-(abs (x - xe)) + xe, y)) coords
+
+main :: IO ()
+main = do
+ f <- readFile "./input"
+ let (coords, instrs) = parseFile f;
+ print $ length $ performFold coords (head instrs)
diff --git a/2021/day13/13b.hs b/2021/day13/13b.hs
new file mode 100644
index 0000000..32d29de
--- /dev/null
+++ b/2021/day13/13b.hs
@@ -0,0 +1,45 @@
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import qualified Data.Text as T
+import Data.Set (Set)
+import Data.List
+import qualified Data.Set as S
+
+type Coord = (Int, Int)
+data FoldInstr = Fold Axis Int deriving (Show, Eq, Ord)
+data Axis = XAxis | YAxis deriving (Show, Eq, Ord)
+
+parseCoords :: String -> Coord
+parseCoords s = (read x, read y)
+ where [x, y] = map T.unpack $ T.splitOn "," (T.pack s)
+
+parseFold :: String -> FoldInstr
+parseFold (stripPrefix "fold along y=" -> Just cs) = Fold YAxis (read cs)
+parseFold (stripPrefix "fold along x=" -> Just cs) = Fold XAxis (read cs)
+
+parseFile :: String -> (Set Coord, [FoldInstr])
+parseFile s = (S.fromList $ map parseCoords (lines coordSection), map parseFold (lines foldSection))
+ where [coordSection, foldSection] = map T.unpack $ T.splitOn "\n\n" (T.pack s)
+
+performFold :: Set Coord -> FoldInstr -> Set Coord
+performFold coords (Fold YAxis ye) = S.map (\(x, y) -> (x, -(abs (y - ye)) + ye)) coords
+performFold coords (Fold XAxis xe) = S.map (\(x, y) -> (-(abs (x - xe)) + xe, y)) coords
+
+displayCoords :: Set Coord -> String
+displayCoords coords = intercalate "\n" (map displayLine [sy..ey])
+ where sx = minimum (S.map fst coords)
+ ex = maximum (S.map fst coords)
+ sy = minimum (S.map snd coords)
+ ey = maximum (S.map snd coords)
+ displayLine y = map (displayCoord y) [sx..ex]
+ displayCoord y x | S.member (x, y) coords = '#'
+ | otherwise = '.'
+
+main :: IO ()
+main = do
+ f <- readFile "./input"
+ let (coords, instrs) = parseFile f;
+ let result = foldl performFold coords instrs;
+ putStrLn $ displayCoords result
diff --git a/2021/day14/14.hs b/2021/day14/14.hs
new file mode 100644
index 0000000..3221655
--- /dev/null
+++ b/2021/day14/14.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Data.Map (Map)
+import qualified Data.Map as M
+import qualified Data.Text as T
+
+type Pair = (Char, Char)
+
+doSubstitutions :: Map Pair Char -> Map Pair Int -> Map Pair Int
+doSubstitutions rules s = M.fromListWith (+) $ concatMap checkPair (M.toList s)
+ where checkPair ((a, b), count) = case M.lookup (a, b) rules of
+ Just v -> [((a, v), count), ((v, b), count)]
+ Nothing -> [((a, b), count)]
+
+stringToPairs :: String -> Map Pair Int
+stringToPairs s = M.fromListWith (+) $ [((a, b), 1) | (a, b) <- (zip s (tail s))] ++ [((last s, '_'), 1)]
+
+countLetters :: Map Pair Int -> Map Char Int
+countLetters m = M.fromListWith (+) [(a, count) | ((a, _), count) <- M.toList m]
+
+parseRuleEntry :: String -> (Pair, Char)
+parseRuleEntry s = ((a, b), head $ T.unpack r)
+ where [t, r] = T.splitOn " -> " (T.pack s)
+ [a, b] = T.unpack t
+
+parseFile :: String -> (Map Pair Int, Map Pair Char)
+parseFile s = (stringToPairs (T.unpack initial), M.fromList $ map parseRuleEntry rules)
+ where [initial, rulesSection] = T.splitOn "\n\n" (T.pack s)
+ rules = lines (T.unpack rulesSection)
+
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let (initial, rules) = parseFile input
+ let result = foldr (\_ acc -> doSubstitutions rules acc) initial [1..40]
+ let counts = countLetters result
+
+ let mx = maximum (M.elems counts)
+ let mi = minimum (M.elems counts)
+ print (mx, mi)
+ print $ mx - mi
diff --git a/2021/day15/15a.py b/2021/day15/15a.py
new file mode 100644
index 0000000..d7c984b
--- /dev/null
+++ b/2021/day15/15a.py
@@ -0,0 +1,63 @@
+import heapq
+
+grid = [[int(x) for x in l] for l in open("./input").read().strip().split("\n")]
+
+def in_bounds(c):
+ x, y = c
+ return x >= 0 and y >= 0 and y < len(grid) and x < len(grid[y])
+
+def next_steps(path):
+ sx, sy = path[0]
+ for c in [(sx + 1, sy), (sx - 1, sy), (sx, sy + 1), (sx, sy - 1)]:
+ if c not in path and in_bounds(c):
+ yield c
+
+def step_path(path):
+ for c in next_steps(path):
+ yield [c] + path
+
+def total_risk(path):
+ acc = 0
+ for x, y in path:
+ if (x, y) == (0, 0):
+ continue
+ risk = grid[y][x]
+ acc += risk
+
+ return acc
+
+def manhattan(a, b):
+ dx = abs(a[0] - b[0])
+ dy = abs(a[1] - b[1])
+ return dx + dy
+
+def heuristic(path):
+ return total_risk(path) - manhattan(path[0], (len(grid), len(grid[0])))
+
+class HeapItem:
+ def __init__(self, path):
+ self.heur = heuristic(path)
+ self.path = path
+
+ def __lt__(self, other):
+ return self.heur < other.heur
+
+def find_path(start):
+ q = []
+ visited = set()
+ heapq.heappush(q, HeapItem([start]))
+ while True:
+ path = heapq.heappop(q).path
+ if path[0] == (len(grid) - 1, len(grid[0]) - 1):
+ return path
+
+ if path[0] in visited:
+ continue
+ visited.add(path[0])
+
+ for new in step_path(path):
+ heapq.heappush(q, HeapItem(new))
+
+path = find_path((0, 0))
+print(path)
+print(total_risk(path))
diff --git a/2021/day15/15b.py b/2021/day15/15b.py
new file mode 100644
index 0000000..534eb3f
--- /dev/null
+++ b/2021/day15/15b.py
@@ -0,0 +1,80 @@
+import heapq
+
+grid = [[int(x) for x in l] for l in open("./input").read().strip().split("\n")]
+GRID_SIZE_X = len(grid)
+GRID_SIZE_Y = len(grid[0])
+
+def in_bounds(c, tiles):
+ x, y = c
+ return x >= 0 and y >= 0 and y < (GRID_SIZE_Y * tiles) and x < (GRID_SIZE_X * tiles)
+
+def next_steps(path, tiles):
+ sx, sy = path[0]
+ for c in [(sx + 1, sy), (sx - 1, sy), (sx, sy + 1), (sx, sy - 1)]:
+ if c not in path and in_bounds(c, tiles):
+ yield c
+
+def step_path(path, tiles):
+ for c in next_steps(path, tiles):
+ yield [c] + path
+
+def risk_for(x, y):
+ tile_x = x // GRID_SIZE_X
+ tile_y = y // GRID_SIZE_Y
+ delta = tile_x + tile_y
+ risk = grid[y % GRID_SIZE_Y][x % GRID_SIZE_X] + delta
+ while risk > 9:
+ risk -= 9
+ return risk
+
+def total_risk(path):
+ acc = 0
+ for x, y in path:
+ if (x, y) == (0, 0):
+ continue
+ risk = risk_for(x, y)
+ acc += risk
+
+ return acc
+
+def manhattan(a, b):
+ dx = abs(a[0] - b[0])
+ dy = abs(a[1] - b[1])
+ return dx + dy
+
+def heuristic(path, dst):
+ return total_risk(path) - manhattan(path[0], dst)
+
+class HeapItem:
+ def __init__(self, heur, path):
+ self.heur = heur
+ self.path = path
+
+ def __lt__(self, other):
+ return self.heur < other.heur
+
+def find_path(start, tiles):
+ q = []
+ max_x = (GRID_SIZE_X * tiles) - 1
+ max_y = (GRID_SIZE_Y * tiles) - 1
+ dst = (max_x, max_y)
+ visited = set()
+ heapq.heappush(q, HeapItem(0, [start]))
+ while True:
+ i = heapq.heappop(q)
+ heur = i.heur
+ path = i.path
+ if path[0] == (max_x, max_y):
+ return path
+
+ if path[0] in visited:
+ continue
+ visited.add(path[0])
+
+ for new in step_path(path, tiles):
+ loc = new[0]
+ heapq.heappush(q, HeapItem(heur + risk_for(loc[0], loc[1]), new))
+
+path = find_path((0, 0), 5)
+print(path)
+print(total_risk(path))
diff --git a/2021/day16/16.hs b/2021/day16/16.hs
new file mode 100644
index 0000000..f38240a
--- /dev/null
+++ b/2021/day16/16.hs
@@ -0,0 +1,87 @@
+module Main where
+
+import Numeric (readHex)
+import Text.Printf (printf)
+import Data.Char (digitToInt)
+import Data.List (foldl')
+
+
+readInt :: Int -> [Bool] -> (Integer, [Bool])
+readInt n bs = (foldl' (\acc x -> acc * 2 + boolToDigit x) 0 (take n bs), drop n bs)
+ where boolToDigit True = 1
+ boolToDigit False = 0
+
+hexToBits :: String -> [Bool]
+hexToBits "" = []
+hexToBits (c:cs) = case readHex [c] of
+ (x, _):_ -> (map binToBool $ printf "%04b" (x :: Int)) ++ hexToBits cs
+ _ -> []
+ where binToBool '1' = True
+ binToBool _ = False
+
+data Packet = Literal Integer Integer Integer |
+ Operator Integer Integer [Packet] |
+ Padding
+ deriving (Show, Eq, Ord)
+
+
+parseHexPacket :: String -> (Packet, [Bool])
+parseHexPacket = parsePacket . hexToBits
+
+parseHeader :: [Bool] -> (Integer, Integer, [Bool])
+parseHeader bs = (version, typ, body)
+ where (version, afterVersion) = readInt 3 bs
+ (typ, body) = readInt 3 afterVersion
+
+parsePacket :: [Bool] -> (Packet, [Bool])
+parsePacket bs = case parseHeader bs of
+ (ver, 4, body) -> let (val, rest) = readLiteralInner body
+ in (Literal ver 4 val, rest)
+ (ver, op, body) -> let (val, rest) = readOpInner body
+ in (Operator ver op val, rest)
+
+readLiteralInner :: [Bool] -> (Integer, [Bool])
+readLiteralInner bs = readLiteralBlock 0 bs
+ where readLiteralBlock acc (cont:bs) | cont = readLiteralBlock acc' rest
+ | otherwise = (acc', rest)
+ where (val, rest) = readInt 4 bs
+ acc' = (16 * acc) + val
+
+readOpInner :: [Bool] -> ([Packet], [Bool])
+readOpInner (False:header) = (parseAllPackets (take (fromIntegral len) body), drop (fromIntegral len) body)
+ where (len, body) = readInt 15 header
+ parseAllPackets [] = []
+ parseAllPackets bs = let (parsed, remaining) = parsePacket bs
+ in parsed : parseAllPackets remaining
+readOpInner (True:header) = parseNPackets n body
+ where (n, body) = readInt 11 header
+ parseNPackets 0 b = ([], b)
+ parseNPackets n bs = let (parsed, remaining) = parsePacket bs
+ (restParsed, endRemaining) = parseNPackets (n - 1) remaining
+ in (parsed : restParsed, endRemaining)
+
+sumVersion :: Packet -> Integer
+sumVersion (Literal v _ _) = v
+sumVersion (Operator v _ ps) = v + (foldr (+) 0 (map sumVersion ps))
+sumVersion Padding = 0
+
+eval :: Packet -> Integer
+eval (Literal _ _ v) = v
+eval (Operator _ 0 ps) = sum (map eval ps)
+eval (Operator _ 1 ps) = product (map eval ps)
+eval (Operator _ 2 ps) = minimum (map eval ps)
+eval (Operator _ 3 ps) = maximum (map eval ps)
+eval (Operator _ 5 ps) = if a > b then 1 else 0
+ where [a, b] = map eval ps
+eval (Operator _ 6 ps) = if a < b then 1 else 0
+ where [a, b] = map eval ps
+eval (Operator _ 7 ps) = if a == b then 1 else 0
+ where [a, b] = map eval ps
+
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let (parsed, _) = parseHexPacket input
+ print $ sumVersion parsed
+ print $ eval parsed
diff --git a/2021/day17/.gitignore b/2021/day17/.gitignore
new file mode 100644
index 0000000..9f97022
--- /dev/null
+++ b/2021/day17/.gitignore
@@ -0,0 +1 @@
+target/ \ No newline at end of file
diff --git a/2021/day17/Cargo.lock b/2021/day17/Cargo.lock
new file mode 100644
index 0000000..b5feb35
--- /dev/null
+++ b/2021/day17/Cargo.lock
@@ -0,0 +1,42 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aho-corasick"
+version = "0.7.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "day17"
+version = "0.1.0"
+dependencies = [
+ "regex",
+]
+
+[[package]]
+name = "memchr"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+
+[[package]]
+name = "regex"
+version = "1.5.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.6.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
diff --git a/2021/day17/Cargo.toml b/2021/day17/Cargo.toml
new file mode 100644
index 0000000..0f39b6d
--- /dev/null
+++ b/2021/day17/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "day17"
+version = "0.1.0"
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+regex = "1"
diff --git a/2021/day17/src/main.rs b/2021/day17/src/main.rs
new file mode 100644
index 0000000..641962e
--- /dev/null
+++ b/2021/day17/src/main.rs
@@ -0,0 +1,90 @@
+use regex::Regex;
+use std::{fs::read_to_string, ops::Range};
+
+#[derive(Debug, Clone, Copy)]
+struct Coord(isize, isize);
+
+#[derive(Debug, Clone)]
+struct TargetArea(pub Range<isize>, pub Range<isize>);
+impl TargetArea {
+ fn contains(&self, c: Coord) -> bool {
+ self.0.contains(&c.0) && self.1.contains(&c.1)
+ }
+}
+
+fn parse_target_area(line: &str) -> TargetArea {
+ let x_caps = Regex::new(r"x=([-\d]*)..([-\d]*)")
+ .unwrap()
+ .captures(line)
+ .unwrap();
+ let y_caps = Regex::new(r"y=([-\d]*)..([-\d]*)")
+ .unwrap()
+ .captures(line)
+ .unwrap();
+
+ TargetArea(
+ x_caps[1].parse().unwrap()..x_caps[2].parse::<isize>().unwrap() + 1isize,
+ y_caps[1].parse().unwrap()..y_caps[2].parse::<isize>().unwrap() + 1isize,
+ )
+}
+
+fn does_intersect(mut vx: isize, mut vy: isize, area: &TargetArea) -> bool {
+ let mut x = 0;
+ let mut y = 0;
+ for _ in 0.. {
+ x += vx;
+ y += vy;
+
+ vx = if vx > 0 {
+ vx - 1
+ } else if vx < 0 {
+ vx + 1
+ } else {
+ 0
+ };
+ vy -= 1;
+ if area.contains(Coord(x, y)) {
+ return true;
+ } else if x > area.0.end || y < area.1.start {
+ return false;
+ }
+ }
+
+ unreachable!()
+}
+
+fn max_y(mut vy: isize) -> isize {
+ let mut y = 0;
+ for _ in 0.. {
+ y += vy;
+ vy -= 1;
+
+ if vy <= 0 {
+ return y;
+ }
+ }
+
+ unreachable!()
+}
+
+fn main() {
+ let area = parse_target_area(&read_to_string("./input").unwrap());
+
+ let mut max_y_found = 0;
+ let mut max_y_vel = Coord(0, 0);
+ let mut num_valid = 0;
+ for vx in 0..=area.0.end * 2 {
+ for vy in -area.1.start.abs() * 2..=area.1.start.abs() * 2 {
+ if does_intersect(vx, vy, &area) {
+ if max_y(vy) > max_y_found {
+ max_y_found = max_y(vy);
+ max_y_vel = Coord(vx, vy);
+ }
+ num_valid += 1;
+ }
+ }
+ }
+
+ println!("part 1: {} with velocity {:?}", max_y_found, max_y_vel);
+ println!("part 2: {} possible velocities", num_valid);
+}
diff --git a/2021/day18/18.py b/2021/day18/18.py
new file mode 100644
index 0000000..88ebf5e
--- /dev/null
+++ b/2021/day18/18.py
@@ -0,0 +1,132 @@
+from math import ceil
+
+class SnailfishItem:
+ def __init__(self, parent, contents):
+ self.parent = parent
+ self.atomic = not isinstance(contents, list)
+ if not self.atomic:
+ if isinstance(contents[0], SnailfishItem):
+ self.left = contents[0]
+ self.left.parent = self
+ else:
+ self.left = SnailfishItem(self, contents[0])
+ if isinstance(contents[1], SnailfishItem):
+ self.right = contents[1]
+ self.right.parent = self
+ else:
+ self.right = SnailfishItem(self, contents[1])
+ else:
+ self.contents = contents
+
+ def __str__(self):
+ if self.atomic:
+ return str(self.contents)
+ else:
+ return "[%s, %s]" % (str(self.left), str(self.right))
+
+ def add(self, other):
+ if self.atomic and other.atomic:
+ self.contents += other.contents
+ else:
+ if self.atomic:
+ self.left = SnailfishItem(self, self.contents)
+ else:
+ self.left = SnailfishItem(self, [self.left, self.right])
+ self.atomic = False
+ self.right = other
+ other.parent = self
+ self.contents = None
+ while self.reduce():
+ pass
+
+ def check_explodes(self, n=0):
+ if self.atomic:
+ return False
+ elif n < 4:
+ return self.left.check_explodes(n+1) or self.right.check_explodes(n+1)
+
+ self.explode_left()
+ self.explode_right()
+
+ self.atomic = True
+ self.contents = 0
+ self.left = None
+ self.right = None
+
+ return True
+
+ def check_splits(self):
+ if not self.atomic:
+ return self.left.check_splits() or self.right.check_splits()
+ elif self.contents < 10:
+ return False
+
+ self.atomic = False
+ self.left = SnailfishItem(self, self.contents // 2)
+ self.right = SnailfishItem(self, ceil(self.contents / 2))
+ self.contents = None
+ return True
+
+ def reduce(self, n=0):
+ if not self.atomic:
+ return self.check_explodes(n) or self.check_splits()
+ else:
+ return self.check_splits()
+
+ def explode_left(self):
+ last_node = self
+ node = self.parent
+ while node != None and node.left == last_node:
+ last_node = node
+ node = last_node.parent
+
+ if node == None:
+ return # leftmost element of tree
+
+ node = node.left
+ while not node.atomic:
+ node = node.right
+
+ node.add(self.left)
+
+ def explode_right(self):
+ last_node = self
+ node = self.parent
+ while node != None and node.right == last_node:
+ last_node = node
+ node = last_node.parent
+
+ if node == None:
+ return # rightmost element of tree
+
+ node = node.right
+ while not node.atomic:
+ node = node.left
+
+ node.add(self.right)
+
+ def magnitude(self):
+ if self.atomic:
+ return self.contents
+ else:
+ return (3 * self.left.magnitude()) + (2 * self.right.magnitude())
+
+lines = open("./input").read().strip().split("\n")
+val = SnailfishItem(None, eval(lines[0])) # cope, seethe, mald, etc.
+for line in lines[1:]:
+ val.add(SnailfishItem(None, eval(line)))
+
+print("Part 1: %d" % val.magnitude())
+
+max_mag = 0
+for x_str in lines:
+ for y_str in lines:
+ if x_str == y_str:
+ continue
+ x = SnailfishItem(None, eval(x_str))
+ x.add(SnailfishItem(None, eval(y_str)))
+
+ if x.magnitude() > max_mag:
+ max_mag = x.magnitude()
+
+print("Part 2: %d" % max_mag)
diff --git a/2021/day19/19.hs b/2021/day19/19.hs
new file mode 100644
index 0000000..a2cabb3
--- /dev/null
+++ b/2021/day19/19.hs
@@ -0,0 +1,108 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Data.Monoid (Endo (Endo), appEndo)
+import Data.Maybe (listToMaybe, isJust)
+import Data.List (isPrefixOf)
+import Linear.Vector ((^+^), (^-^))
+import Linear.V3 (V3 (V3))
+
+import Data.Set (Set)
+
+import qualified Data.Set as S
+import qualified Data.Map as M
+import qualified Data.Text as T
+
+type Vec3 = V3 Integer
+type Transform = Endo Vec3
+data Scanner = Scanner { beacons :: [Vec3]
+ } deriving (Show, Eq)
+data PositionedScanner = PositionedScanner { scanner :: Scanner
+ ,originOffset :: Vec3
+ } deriving (Show)
+
+instance Show Transform where
+ show c = show $ appEndo c (V3 0 0 0)
+
+nullTrans = Endo id
+rotX = Endo \(V3 x y z) -> V3 x (- z) y
+rotY = Endo \(V3 x y z) -> V3 z y (- x)
+rotZ = Endo \(V3 x y z) -> V3 (- y) x z
+translate v = Endo (v ^+^)
+
+rotations :: [Transform]
+rotations = [a <> b | a <- ras, b <- rbs]
+ where ras = [ nullTrans, rotY, rotY <> rotY, rotY <> rotY <> rotY
+ , rotZ, rotZ <> rotZ <> rotZ]
+ rbs = [nullTrans, rotX, rotX <> rotX, rotX <> rotX <> rotX]
+
+threshold :: Integer
+threshold = 12
+
+firstJust :: [Maybe a] -> Maybe a
+firstJust xs | null js = Nothing
+ | otherwise = (head js)
+ where js = filter isJust xs
+
+parseFile :: String -> [[Vec3]]
+parseFile s = reverse $ parseLines (tail $ lines s) [[]]
+ where parseLines [] cs = cs
+ parseLines (l:ls) (c:cs) | "---" `isPrefixOf` l = parseLines ls ([] : c : cs)
+ | null l = parseLines ls (c : cs)
+ | otherwise = parseLines ls ((parseLine l : c) : cs)
+ parseLine l = V3 x y z
+ where [x, y, z] = map (read . T.unpack) $ T.splitOn "," $ T.pack l
+
+commonOffset :: [Vec3] -> [Vec3] -> Maybe Vec3
+commonOffset ys xs = listToMaybe aboveThreshold >>= (Just . fst)
+ where dists = [x ^-^ y | x <- xs, y <- ys]
+ distCounts = M.toList $ M.fromListWith (+) [(d, 1) | d <- dists]
+ aboveThreshold = filter ((>= threshold) . snd) distCounts
+
+applyTransform :: Transform -> Scanner -> Scanner
+applyTransform t (Scanner bs) = Scanner (map (appEndo t) bs)
+
+-- attempt to get a's offset from b
+offsetFrom :: Scanner -> Scanner -> Maybe (Vec3, Scanner)
+offsetFrom a b = listToMaybe successes
+ where attempts = [attemptWith rot | rot <- rotations]
+ successes = [(a, b) | (Just a, b) <- attempts]
+ attemptWith rot = (commonOffset (beacons a') (beacons b), a')
+ where a' = applyTransform rot a
+
+adjustedOffsetFrom :: PositionedScanner -> Scanner -> Maybe PositionedScanner
+adjustedOffsetFrom b a = case a `offsetFrom` (scanner b) of
+ Just (off, sc) -> Just $ PositionedScanner sc (off ^+^ (originOffset b))
+ Nothing -> Nothing
+
+solveMore :: [PositionedScanner] -> [Scanner] -> ([PositionedScanner], [Scanner])
+solveMore ks us = foldr solveOne (ks, us) us
+ where solveOne s (ks', us') = case firstJust (map (\k -> adjustedOffsetFrom k s) ks') of
+ Just d -> (d : ks', filter (/= s) us')
+ Nothing -> (ks', us')
+
+calcAllOffsets :: [Scanner] -> [PositionedScanner]
+calcAllOffsets (s:ss) = keepSolvingMore ([PositionedScanner s (V3 0 0 0)], ss)
+ where keepSolvingMore (ks,[]) = ks
+ keepSolvingMore (ks,us) = keepSolvingMore (solveMore ks us)
+
+absoluteBeacons :: PositionedScanner -> Set Vec3
+absoluteBeacons (PositionedScanner sc pos) = S.fromList $ map (pos ^+^) (beacons sc)
+
+manhattan :: Vec3 -> Vec3 -> Integer
+manhattan (V3 x y z) (V3 x' y' z') = (abs (x' -x)) + (abs (y' - y)) + (abs (z' - z))
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let parsed = map Scanner $ parseFile input
+ let positioned = calcAllOffsets parsed
+ let beacons = foldr S.union S.empty $ map absoluteBeacons positioned
+
+ print $ "Part 1: " ++ (show $ S.size beacons)
+
+ let scannerPositions = map originOffset positioned
+ print $ "Part 2: " ++ (show $ maximum [manhattan a b | a <- scannerPositions, b <- scannerPositions])
diff --git a/2021/day2/02a.rkt b/2021/day2/02a.rkt
new file mode 100644
index 0000000..2317a9a
--- /dev/null
+++ b/2021/day2/02a.rkt
@@ -0,0 +1,25 @@
+#lang racket
+
+(define (parse-line line)
+ (define split (string-split line " "))
+ (cond [(empty? split)
+ (datum->syntax #f "")]
+ [else (define command (car split))
+ (define arg (second split))
+ (datum->syntax #f `(,(string->symbol command) ,(string->number arg)))]))
+
+(define (read-syntax path port)
+ (define src-datums (map parse-line (port->lines port)))
+ (datum->syntax #f `(module day2 racket
+ (define depth 0)
+ (define pos 0)
+ (define (forward x)
+ (set! pos (+ pos x)))
+ (define (down x)
+ (set! depth (+ depth x)))
+ (define (up x)
+ (set! depth (- depth x)))
+ ,@src-datums
+ (* depth pos))))
+
+(provide read-syntax)
diff --git a/2021/day2/02b.rkt b/2021/day2/02b.rkt
new file mode 100644
index 0000000..7688c1d
--- /dev/null
+++ b/2021/day2/02b.rkt
@@ -0,0 +1,27 @@
+#lang racket
+
+(define (parse-line line)
+ (define split (string-split line " "))
+ (cond [(empty? split)
+ (datum->syntax #f "")]
+ [else (define command (car split))
+ (define arg (second split))
+ (datum->syntax #f `(,(string->symbol command) ,(string->number arg)))]))
+
+(define (read-syntax path port)
+ (define src-datums (map parse-line (port->lines port)))
+ (datum->syntax #f `(module day2 racket
+ (define depth 0)
+ (define pos 0)
+ (define aim 0)
+ (define (forward x)
+ (set! pos (+ pos x))
+ (set! depth (+ depth (* aim x))))
+ (define (down x)
+ (set! aim (+ aim x)))
+ (define (up x)
+ (set! aim (- aim x)))
+ ,@src-datums
+ (* depth pos))))
+
+(provide read-syntax)
diff --git a/2021/day20/20.hs b/2021/day20/20.hs
new file mode 100644
index 0000000..2798214
--- /dev/null
+++ b/2021/day20/20.hs
@@ -0,0 +1,61 @@
+module Main where
+
+import Data.List (foldl', intercalate)
+import Data.Maybe (fromMaybe)
+
+type Picture = ([[Bool]], Bool) -- Visible region, colour of all pixels not visible
+
+readInteger :: [Bool] -> Int
+readInteger = foldl' (\acc x -> acc * 2 + boolToDigit x) 0
+ where boolToDigit True = 1
+ boolToDigit False = 0
+
+parseLine :: String -> [Bool]
+parseLine = map charToBool
+ where charToBool '#' = True
+ charToBool '.' = False
+
+(!?) :: [a] -> Int -> Maybe a
+xs !? n | n < 0 || n >= (length xs) = Nothing
+ | otherwise = Just (xs!!n)
+
+getPixel :: Picture -> Int -> Int -> Bool
+getPixel (p, d) x y = fromMaybe d $ (p !? y) >>= (!? x)
+
+getNeighbours :: Picture -> Int -> Int -> [Bool]
+getNeighbours p x y = [getPixel p (x + dx) (y + dy) | dy <- [(-1)..1], dx <- [(-1)..1]]
+
+getNewPixel :: Picture -> [Bool] -> Int -> Int -> Bool
+getNewPixel p alg x y = alg !! (readInteger $ getNeighbours p x y)
+
+printPic :: Picture -> String
+printPic = (intercalate "\n") . (map printLine) . fst
+ where printLine = map printBool
+ printBool True = '#'
+ printBool False = '.'
+
+newDefault :: Bool -> [Bool] -> Bool
+newDefault True alg = alg!!511
+newDefault False alg = alg!!0
+
+applyAlgorithm :: Picture -> [Bool] -> Picture
+applyAlgorithm pic@(vis, def) alg = ([[getNewPixel pic alg x y | x <- [(-1)..mx]] | y <- [(-1)..my]], newDefault def alg)
+ where mx = length (vis!!0) + 1
+ my = length vis + 1
+
+parseFile :: String -> ([Bool], Picture)
+parseFile s = (parseLine alg, (map parseLine ls, False))
+ where (alg:_:ls) = lines s
+
+countPixels :: Picture -> Int
+countPixels = foldr (+) 0 . map (length . filter id) . fst
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let (alg, pic) = parseFile input
+ let pic2 = foldr (\_ p -> applyAlgorithm p alg) pic [1..2]
+ putStrLn $ "Part 1: " ++ (show $ countPixels pic2)
+
+ let pic50 = foldr (\_ p -> applyAlgorithm p alg) pic [1..50]
+ putStrLn $ "Part 2: " ++ (show $ countPixels pic50)
diff --git a/2021/day21/21.py b/2021/day21/21.py
new file mode 100644
index 0000000..8cd8307
--- /dev/null
+++ b/2021/day21/21.py
@@ -0,0 +1,52 @@
+
+die_val = 1
+rolls = 0
+def roll():
+ global die_val, rolls
+ x = die_val
+
+ die_val += 1
+ if die_val > 100:
+ die_val = 1
+
+ rolls += 1
+
+ return x
+
+
+class Player:
+ def __init__(self, pos):
+ self.pos = pos
+ self.score = 0
+
+ def move(self, roll):
+ self.pos += roll
+ while self.pos > 10:
+ self.pos -= 10
+
+ def take_turn(self):
+ r = sum([roll() for _ in range(0, 3)])
+ self.move(r)
+ self.score += self.pos
+
+ def __str__(self):
+ return "<Player pos=%d score=%d>" % (self.pos, self.score)
+
+inp = open("./input").read().split("\n")
+p1_start = int(inp[0].split(": ")[1])
+p2_start = int(inp[1].split(": ")[1])
+
+p1 = Player(p1_start)
+p2 = Player(p2_start)
+turn = p1
+while p1.score < 1000 and p2.score < 1000:
+ turn.take_turn()
+ if turn == p1:
+ turn = p2
+ else:
+ turn = p1
+
+ans = p1.score * rolls
+if p1.score >= 1000:
+ ans = p2.score * rolls
+print("Part 1: %d" % ans)
diff --git a/2021/day21/21b.py b/2021/day21/21b.py
new file mode 100644
index 0000000..3404c22
--- /dev/null
+++ b/2021/day21/21b.py
@@ -0,0 +1,55 @@
+from collections import defaultdict
+
+POSSIBLE_ROLLS = [a + b + c for a in range(1, 4) for b in range(1, 4) for c in range(1, 4)]
+
+def move(p, roll):
+ pos, score = p
+ pos += roll
+ while pos > 10:
+ pos -= 10
+
+ return (pos, score + pos)
+
+def won(p):
+ return p[1] >= 21
+
+P1_WON_KEY = (-1, -1, True)
+P2_WON_KEY = (-1, -1, False)
+
+def step_universes(d):
+ nxt = defaultdict(lambda: 0)
+ nxt[P1_WON_KEY] = d[P1_WON_KEY]
+ nxt[P2_WON_KEY] = d[P2_WON_KEY]
+ for ((p1, p2, p1_turn), count) in d.items():
+ if p1 == -1:
+ continue
+ elif won(p1):
+ nxt[P1_WON_KEY] += count
+ continue
+ elif won(p2):
+ nxt[P2_WON_KEY] += count
+ continue
+
+ for roll in POSSIBLE_ROLLS:
+ if p1_turn:
+ nxt[(move(p1, roll), p2, False)] += count
+ else:
+ nxt[(p1, move(p2, roll), True)] += count
+
+ return nxt
+
+inp = open("./input").read().split("\n")
+p1_start = int(inp[0].split(": ")[1])
+p2_start = int(inp[1].split(": ")[1])
+
+d = defaultdict(lambda: 0)
+d[((p1_start, 0), (p2_start, 0), True)] = 1
+d = step_universes(d)
+
+while len(d) > 2:
+ d = step_universes(d)
+
+w1 = d[P1_WON_KEY]
+w2 = d[P2_WON_KEY]
+print("Part 2: %d" % max([w1, w2]))
+
diff --git a/2021/day22/22a.hs b/2021/day22/22a.hs
new file mode 100644
index 0000000..bcf826f
--- /dev/null
+++ b/2021/day22/22a.hs
@@ -0,0 +1,110 @@
+module Main where
+
+import Text.Parsec
+import Data.Set (Set)
+import qualified Data.Set as S
+import Debug.Trace (trace)
+
+type Coord = (Int, Int, Int)
+data Cuboid = Cuboid Coord Coord deriving (Show, Eq)
+data Command = Command Bool Cuboid deriving (Show, Eq)
+
+onOff = toBool <$> (try (string "on") <|> string "off")
+ where toBool "on" = True
+ toBool _ = False
+
+number = do
+ sign <- (option '0' (char '-'))
+ num <- many1 digit
+ return $ read (sign : num)
+
+range = do
+ start <- number
+ string ".."
+ end <- number
+
+ return $ (start, end)
+
+parseLine = do
+ val <- onOff
+ string " x="
+ (sx, ex) <- range
+ string ",y="
+ (sy, ey) <- range
+ string ",z="
+ (sz, ez) <- range
+
+ let c = Cuboid (sx, sy, sz) (ex, ey, ez)
+ return $ Command val c
+parseFile = endBy parseLine (char '\n')
+
+intersects1D :: (Int, Int) -> (Int, Int) -> Bool
+intersects1D (a1, a2) (b1, b2) = a2 > b1 && b2 > a1
+
+zipCoords :: Coord -> Coord -> [(Int, Int)]
+zipCoords (x, y, z) (x', y', z') = [(x, x'), (y, y'), (z, z')]
+
+intersects :: Cuboid -> Cuboid -> Bool
+intersects (Cuboid s e) (Cuboid s' e') = any (uncurry intersects1D) (zip (zipCoords s e) (zipCoords s' e'))
+
+cEmpty :: Cuboid -> Bool
+cEmpty (Cuboid (sx, sy, sz) (ex, ey, ez)) = sx > ex || sy > ey || sz > ez
+
+cVolume :: Cuboid -> Int
+cVolume (Cuboid (sx, sy, sz) (ex, ey, ez)) = vx * vy * vz
+ where vx = abs (sx - (ex + 1))
+ vy = abs (sy - (ey + 1))
+ vz = abs (sz - (ez + 1))
+
+ccVolume :: ChargedCuboid -> Int
+ccVolume c | charge c = cVolume (cuboid c)
+ | otherwise = -(cVolume (cuboid c))
+
+cIntersection :: Cuboid -> Cuboid -> Cuboid
+cIntersection c1@(Cuboid s1 e1) c2@(Cuboid s2 e2) | not $ intersects c1 c2 = nullCuboid
+ | otherwise = (Cuboid s' e')
+ where s' = map3 (uncurry max) (zip3t s1 s2)
+ e' = map3 (uncurry min) (zip3t e1 e2)
+
+data ChargedCuboid = ChargedCuboid { charge :: Bool
+ ,cuboid :: Cuboid
+ } deriving (Show, Eq)
+
+performCommand :: [ChargedCuboid] -> Command -> [ChargedCuboid]
+performCommand cs (Command val c) | val = (ChargedCuboid val c) : (cs ++ overlaps)
+ | otherwise = cs ++ overlaps
+ where overlaps = filter (not . cEmpty . cuboid) $ map invertedIntersection cs
+ invertedIntersection cc = ChargedCuboid (not (charge cc)) ((cuboid cc) `cIntersection` c)
+
+threshold = 50
+
+interestedCuboid :: Cuboid
+interestedCuboid = Cuboid ((-threshold), (-threshold), (-threshold)) (threshold, threshold, threshold)
+
+nullCuboid :: Cuboid
+nullCuboid = Cuboid (0, 0, 0) ((-1), (-1), (-1))
+
+map3 :: (a -> b) -> (a, a, a) -> (b, b, b)
+map3 f (a, b, c) = (f a, f b, f c)
+
+zip3t :: (a, a, a) -> (b, b, b) -> ((a, b), (a, b), (a, b))
+zip3t (x, y, z) (x', y', z') = ((x, x'), (y, y'), (z, z'))
+
+cClamp :: Cuboid -> Cuboid
+cClamp (Cuboid ss es) = Cuboid (sx', sy', sz') (ex', ey', ez')
+ where (sx', sy', sz') = map3 (max (-threshold)) ss
+ (ex', ey', ez') = map3 (min threshold) es
+
+minifyCommand :: Command -> Command
+minifyCommand (Command v cb) | cEmpty clamped = Command False nullCuboid
+ | otherwise = Command v (cClamp cb)
+ where clamped = cClamp cb
+
+main = do
+ input <- readFile "./input"
+ let (Right parsed) = parse parseFile "input" input
+ let cmds = map minifyCommand parsed
+
+ let cs = foldl performCommand [] cmds
+ let vol = foldr (+) 0 $ map ccVolume cs
+ print vol
diff --git a/2021/day22/22b.hs b/2021/day22/22b.hs
new file mode 100644
index 0000000..9773717
--- /dev/null
+++ b/2021/day22/22b.hs
@@ -0,0 +1,94 @@
+module Main where
+
+import Text.Parsec
+import Data.Set (Set)
+import qualified Data.Set as S
+import Debug.Trace (trace)
+
+type Coord = (Int, Int, Int)
+data Cuboid = Cuboid Coord Coord deriving (Show, Eq)
+data Command = Command Bool Cuboid deriving (Show, Eq)
+
+onOff = toBool <$> (try (string "on") <|> string "off")
+ where toBool "on" = True
+ toBool _ = False
+
+number = do
+ sign <- (option '0' (char '-'))
+ num <- many1 digit
+ return $ read (sign : num)
+
+range = do
+ start <- number
+ string ".."
+ end <- number
+
+ return $ (start, end)
+
+parseLine = do
+ val <- onOff
+ string " x="
+ (sx, ex) <- range
+ string ",y="
+ (sy, ey) <- range
+ string ",z="
+ (sz, ez) <- range
+
+ let c = Cuboid (sx, sy, sz) (ex, ey, ez)
+ return $ Command val c
+parseFile = endBy parseLine (char '\n')
+
+intersects1D :: (Int, Int) -> (Int, Int) -> Bool
+intersects1D (a1, a2) (b1, b2) = a2 > b1 && b2 > a1
+
+zipCoords :: Coord -> Coord -> [(Int, Int)]
+zipCoords (x, y, z) (x', y', z') = [(x, x'), (y, y'), (z, z')]
+
+intersects :: Cuboid -> Cuboid -> Bool
+intersects (Cuboid s e) (Cuboid s' e') = any (uncurry intersects1D) (zip (zipCoords s e) (zipCoords s' e'))
+
+cEmpty :: Cuboid -> Bool
+cEmpty (Cuboid (sx, sy, sz) (ex, ey, ez)) = sx > ex || sy > ey || sz > ez
+
+cVolume :: Cuboid -> Int
+cVolume (Cuboid (sx, sy, sz) (ex, ey, ez)) = vx * vy * vz
+ where vx = abs (sx - (ex + 1))
+ vy = abs (sy - (ey + 1))
+ vz = abs (sz - (ez + 1))
+
+ccVolume :: ChargedCuboid -> Int
+ccVolume c | charge c = cVolume (cuboid c)
+ | otherwise = -(cVolume (cuboid c))
+
+cIntersection :: Cuboid -> Cuboid -> Cuboid
+cIntersection c1@(Cuboid s1 e1) c2@(Cuboid s2 e2) | not $ intersects c1 c2 = nullCuboid
+ | otherwise = (Cuboid s' e')
+ where s' = map3 (uncurry max) (zip3t s1 s2)
+ e' = map3 (uncurry min) (zip3t e1 e2)
+
+data ChargedCuboid = ChargedCuboid { charge :: Bool
+ ,cuboid :: Cuboid
+ } deriving (Show, Eq)
+
+performCommand :: [ChargedCuboid] -> Command -> [ChargedCuboid]
+performCommand cs (Command val c) | val = (ChargedCuboid val c) : (cs ++ overlaps)
+ | otherwise = cs ++ overlaps
+ where overlaps = filter (not . cEmpty . cuboid) $ map invertedIntersection cs
+ invertedIntersection cc = ChargedCuboid (not (charge cc)) ((cuboid cc) `cIntersection` c)
+
+nullCuboid :: Cuboid
+nullCuboid = Cuboid (0, 0, 0) ((-1), (-1), (-1))
+
+map3 :: (a -> b) -> (a, a, a) -> (b, b, b)
+map3 f (a, b, c) = (f a, f b, f c)
+
+zip3t :: (a, a, a) -> (b, b, b) -> ((a, b), (a, b), (a, b))
+zip3t (x, y, z) (x', y', z') = ((x, x'), (y, y'), (z, z'))
+
+main = do
+ input <- readFile "./input"
+ let (Right cmds) = parse parseFile "input" input
+
+ let cs = foldl performCommand [] cmds
+ let vol = foldr (+) 0 $ map ccVolume cs
+ print vol
diff --git a/2021/day23/Setup.hs b/2021/day23/Setup.hs
new file mode 100644
index 0000000..9a994af
--- /dev/null
+++ b/2021/day23/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/2021/day23/app/Main.hs b/2021/day23/app/Main.hs
new file mode 100644
index 0000000..fbce993
--- /dev/null
+++ b/2021/day23/app/Main.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE TupleSections #-}
+module Main where
+
+import Algorithm.Search (dijkstraAssoc)
+import qualified Data.Text as T
+import Data.Maybe (listToMaybe, catMaybes)
+import Data.List (intercalate, transpose)
+import Data.Char (isLetter)
+import Data.Map (Map)
+import qualified Data.Map as M
+import Data.Set (Set)
+import qualified Data.Set as S
+
+data Species = Am | Br | Co | De deriving (Show, Eq, Ord)
+type Coord = (Int, Int)
+type Board = Map Coord Species
+
+toSpecies :: Char -> Species
+toSpecies 'A' = Am
+toSpecies 'B' = Br
+toSpecies 'C' = Co
+toSpecies 'D' = De
+
+cost :: Species -> Int
+cost Am = 1
+cost Br = 10
+cost Co = 100
+cost De = 1000
+
+roomX :: Species -> Int
+roomX Am = 1
+roomX Br = 3
+roomX Co = 5
+roomX De = 7
+
+isRoomX :: Int -> Bool
+isRoomX 1 = True
+isRoomX 3 = True
+isRoomX 5 = True
+isRoomX 7 = True
+isRoomX _ = False
+
+lowerBound = (-1)
+upperBound = 9
+lowestY = 4
+
+inBounds :: Coord -> Bool
+inBounds (x, _) = x >= lowerBound && x <= upperBound
+
+parseFile :: String -> Board
+parseFile s = foldl insertRoom M.empty rooms
+ where letters = transpose $ map (map toSpecies . filter isLetter . T.unpack) $ T.splitOn "\n" (T.pack s)
+ rooms = zip [Am, Br, Co, De] letters
+ insertRoom m (s, cs) = (M.fromList [((roomX s, y), c) | (y, c) <- zip [1..] cs]) `M.union` m
+
+topOfRoom :: Board -> Int -> Maybe Coord
+topOfRoom b x = listToMaybe $ filter (`M.member` b) [(x, y) | y <- [1..lowestY]]
+
+availableHallwaySpaces :: Board -> Int -> [Coord]
+availableHallwaySpaces b sx = (exploreWith (+ 1) sx) ++ (exploreWith (+ (-1)) (sx - 1))
+ where exploreWith f x | isRoomX x = exploreWith f (f x)
+ | not (inBounds (x, 0)) = []
+ | (x, 0) `M.member` b = []
+ | otherwise = (x, 0) : exploreWith f (f x)
+
+pathToRoom :: Coord -> Species -> [Coord]
+pathToRoom (sx, _) es | sx <= ex = map (, 0) [sx + 1..ex]
+ | otherwise = map (, 0) [ex..sx - 1]
+ where ex = roomX es
+
+pathClear :: Board -> [Coord] -> Bool
+pathClear b path = all (`M.notMember` b) path
+
+toTopOfRoom :: Int -> Int
+toTopOfRoom x = x - 1
+
+movingFromRoom :: Board -> Species -> [(Board, Int)]
+movingFromRoom b s = case topOfRoom b (roomX s) of
+ Just (x, y) -> let withoutTop = (x, y) `M.delete` b
+ extraCost = toTopOfRoom y
+ Just movingOut = (x, y) `M.lookup` b
+ in [(M.insert c movingOut withoutTop, (abs ((fst c) - x) + 1 + extraCost) * cost movingOut) | c <- availableHallwaySpaces b x]
+ Nothing -> []
+
+roomPositions = [1..lowestY]
+
+movingIntoRoom :: Board -> [(Board, Int)]
+movingIntoRoom b = concatMap attemptMoveToRoom [((c, 0), (c, 0) `M.lookup` b) | c <- [lowerBound..upperBound]]
+ where attemptMoveToRoom (_, Nothing) = []
+ attemptMoveToRoom (c, Just s) | not clear = []
+ | otherwise = [(b', (length p + 1 + extraCost) * (cost s))]
+ where p = pathToRoom c s
+ clear = pathClear b p && hasSpace && isCorrect
+ occupants = catMaybes [(roomX s, y) `M.lookup` b | y <- roomPositions]
+ hasSpace = length occupants < lowestY
+ isCorrect = all (== s) occupants
+ y' = lowestY - (length occupants)
+ extraCost = toTopOfRoom y'
+ c' = (roomX s, y')
+ b' = M.insert c' s $ M.delete c b
+
+species = [Am, Br, Co, De]
+
+nextMoves :: Board -> [(Board, Int)]
+nextMoves b = (concatMap (movingFromRoom b) species) ++ movingIntoRoom b
+
+isFinished :: Board -> Bool
+isFinished b = all id [(M.lookup (roomX s, rp) b) == Just s | s <- species, rp <- roomPositions]
+
+solve :: Board -> Maybe (Int, [Board])
+solve = dijkstraAssoc nextMoves isFinished
+
+printBoard :: Board -> String
+printBoard b = intercalate "\n" [printLine l | l <- [0..lowestY]]
+ where printLine l = [toChar ((x, l) `M.lookup` b) | x <- [lowerBound..upperBound]]
+ toChar Nothing = ' '
+ toChar (Just Am) = 'A'
+ toChar (Just Br) = 'B'
+ toChar (Just Co) = 'C'
+ toChar (Just De) = 'D'
+
+printNexts :: [(Board, Int)] -> IO [()]
+printNexts = sequence . map printNext
+
+printNext :: (Board, Int) -> IO ()
+printNext (b, c) = do
+ putStrLn $ printBoard b
+ print c
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let parsed = parseFile input
+ let Just (cost, path) = solve parsed
+ putStrLn $ intercalate "\n---\n" $ map printBoard path
+ print path
+ print cost
diff --git a/2021/day23/day23.cabal b/2021/day23/day23.cabal
new file mode 100644
index 0000000..51b4ad5
--- /dev/null
+++ b/2021/day23/day23.cabal
@@ -0,0 +1,52 @@
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.34.5.
+--
+-- see: https://github.com/sol/hpack
+
+name: day23
+version: 0.1.0.0
+description: Please see the README on GitHub at <https://github.com/githubuser/day23#readme>
+homepage: https://github.com/githubuser/day23#readme
+bug-reports: https://github.com/githubuser/day23/issues
+author: Author name here
+maintainer: example@example.com
+copyright: 2021 Author name here
+license: BSD3
+build-type: Simple
+extra-source-files:
+ README.md
+ ChangeLog.md
+
+source-repository head
+ type: git
+ location: https://github.com/githubuser/day23
+
+library
+ exposed-modules:
+ Lib
+ other-modules:
+ Paths_day23
+ hs-source-dirs:
+ src
+ build-depends:
+ base >=4.7 && <5
+ , containers
+ , search-algorithms
+ , text
+ default-language: Haskell2010
+
+executable day23-exe
+ main-is: Main.hs
+ other-modules:
+ Paths_day23
+ hs-source-dirs:
+ app
+ ghc-options: -threaded -rtsopts -with-rtsopts=-N
+ build-depends:
+ base >=4.7 && <5
+ , containers
+ , day23
+ , search-algorithms
+ , text
+ default-language: Haskell2010
diff --git a/2021/day23/package.yaml b/2021/day23/package.yaml
new file mode 100644
index 0000000..a41ad1f
--- /dev/null
+++ b/2021/day23/package.yaml
@@ -0,0 +1,40 @@
+name: day23
+version: 0.1.0.0
+github: "githubuser/day23"
+license: BSD3
+author: "Author name here"
+maintainer: "example@example.com"
+copyright: "2021 Author name here"
+
+extra-source-files:
+- README.md
+- ChangeLog.md
+
+# Metadata used when publishing your package
+# synopsis: Short description of your package
+# category: Web
+
+# To avoid duplicated efforts in documentation and dealing with the
+# complications of embedding Haddock markup inside cabal files, it is
+# common to point users to the README.md file.
+description: Please see the README on GitHub at <https://github.com/githubuser/day23#readme>
+
+dependencies:
+- base >= 4.7 && < 5
+- containers
+- text
+- search-algorithms
+
+library:
+ source-dirs: src
+
+executables:
+ day23-exe:
+ main: Main.hs
+ source-dirs: app
+ ghc-options:
+ - -threaded
+ - -rtsopts
+ - -with-rtsopts=-N
+ dependencies:
+ - day23
diff --git a/2021/day23/src/Lib.hs b/2021/day23/src/Lib.hs
new file mode 100644
index 0000000..d36ff27
--- /dev/null
+++ b/2021/day23/src/Lib.hs
@@ -0,0 +1,6 @@
+module Lib
+ ( someFunc
+ ) where
+
+someFunc :: IO ()
+someFunc = putStrLn "someFunc"
diff --git a/2021/day23/stack.yaml b/2021/day23/stack.yaml
new file mode 100644
index 0000000..920ab59
--- /dev/null
+++ b/2021/day23/stack.yaml
@@ -0,0 +1,68 @@
+# This file was automatically generated by 'stack init'
+#
+# Some commonly used options have been documented as comments in this file.
+# For advanced use and comprehensive documentation of the format, please see:
+# https://docs.haskellstack.org/en/stable/yaml_configuration/
+
+# Resolver to choose a 'specific' stackage snapshot or a compiler version.
+# A snapshot resolver dictates the compiler version and the set of packages
+# to be used for project dependencies. For example:
+#
+# resolver: lts-3.5
+# resolver: nightly-2015-09-21
+# resolver: ghc-7.10.2
+#
+# The location of a snapshot can be provided as a file or url. Stack assumes
+# a snapshot provided as a file might change, whereas a url resource does not.
+#
+# resolver: ./custom-snapshot.yaml
+# resolver: https://example.com/snapshots/2018-01-01.yaml
+resolver:
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml
+
+# User packages to be built.
+# Various formats can be used as shown in the example below.
+#
+# packages:
+# - some-directory
+# - https://example.com/foo/bar/baz-0.0.2.tar.gz
+# subdirs:
+# - auto-update
+# - wai
+packages:
+- .
+# Dependency packages to be pulled from upstream that are not in the resolver.
+# These entries can reference officially published versions as well as
+# forks / in-progress versions pinned to a git hash. For example:
+#
+# extra-deps:
+# - acme-missiles-0.3
+# - git: https://github.com/commercialhaskell/stack.git
+# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a
+#
+extra-deps:
+ - search-algorithms-0.3.2
+
+# Override default flag values for local packages and extra-deps
+# flags: {}
+
+# Extra package databases containing global packages
+# extra-package-dbs: []
+
+# Control whether we use the GHC we find on the path
+# system-ghc: true
+#
+# Require a specific version of stack, using version ranges
+# require-stack-version: -any # Default
+# require-stack-version: ">=2.7"
+#
+# Override the architecture used by stack, especially useful on Windows
+# arch: i386
+# arch: x86_64
+#
+# Extra directories used by stack for building
+# extra-include-dirs: [/path/to/dir]
+# extra-lib-dirs: [/path/to/dir]
+#
+# Allow a newer minor version of GHC than the snapshot specifies
+# compiler-check: newer-minor
diff --git a/2021/day23/stack.yaml.lock b/2021/day23/stack.yaml.lock
new file mode 100644
index 0000000..1f94557
--- /dev/null
+++ b/2021/day23/stack.yaml.lock
@@ -0,0 +1,20 @@
+# This file was autogenerated by Stack.
+# You should not edit this file by hand.
+# For more information, please see the documentation at:
+# https://docs.haskellstack.org/en/stable/lock_files
+
+packages:
+- completed:
+ hackage: search-algorithms-0.3.2@sha256:9d224b9c6b5875598e6fc91497a178f3ca6e45768c637d07d4f874e6211a331b,2203
+ pantry-tree:
+ size: 557
+ sha256: 43e9d4344d57a3bad78f67d085156531e0a9b38a14dce9f5137940561fdb3582
+ original:
+ hackage: search-algorithms-0.3.2
+snapshots:
+- completed:
+ size: 586106
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml
+ sha256: 8699812d2b2c1f83d6ad1261de9cf628ed36a1cfc14f19d67188e005e7a3a39d
+ original:
+ url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/18/20.yaml
diff --git a/2021/day24/24_convert.py b/2021/day24/24_convert.py
new file mode 100644
index 0000000..c538e1b
--- /dev/null
+++ b/2021/day24/24_convert.py
@@ -0,0 +1,27 @@
+# Converts input to a .dzn file
+# Usage: python 24_convert.py | minizinc 24a.mzn -
+
+cmds = open("./input").read().strip().split("\n")
+
+def convert_ops(cmds):
+ for c in cmds:
+ yield "i_" + c.split(" ")[0]
+
+def convert_arg(a):
+ cons = "R" if a in {"x", "y", "z", "w"} else "Imm"
+ return "%s(%s)" % (cons, a)
+
+def convert_args(cmds):
+ for c in cmds:
+ spl = c.split(" ")[1:]
+ if len(spl) == 1:
+ yield (convert_arg(spl[0]), "None")
+ else:
+ yield (convert_arg(spl[0]), convert_arg(spl[1]))
+
+
+inp_ops = list(convert_ops(cmds))
+inp_args = list(convert_args(cmds))
+
+print("inp_ops = [ %s ];" % ", ".join(inp_ops))
+print("inp_args = [| %s |];" % "|".join([",".join(x) for x in inp_args]))
diff --git a/2021/day24/24a.mzn b/2021/day24/24a.mzn
new file mode 100644
index 0000000..4ad0d82
--- /dev/null
+++ b/2021/day24/24a.mzn
@@ -0,0 +1,117 @@
+include "globals.mzn";
+
+% Types
+enum Operation = {
+ i_inp,
+ i_add,
+ i_mul,
+ i_div,
+ i_mod,
+ i_eql
+};
+enum Pos = { Arg1, Arg2 };
+enum Arg = R(Registers) ++ Imm(Immediates) ++ { None };
+
+enum Registers = {x, y, z, w};
+
+set of int: Immediates = -127..127;
+set of int: Digits = 0..9;
+
+% Input
+array[int] of Operation: inp_ops;
+array[int, Pos] of Arg: inp_args;
+
+% Properties derived from input
+set of int: Steps = index_set(inp_ops);
+set of int: Inputs = 1..count(inp_ops, i_inp);
+
+set of int: ExtendedSteps = min(Steps)..max(Steps) + 1;
+set of int: ExtendedInputs = min(Inputs)..max(Inputs) + 1;
+
+% State
+array[ExtendedSteps, Registers] of var int: regs;
+array[Inputs] of var Digits: inputs;
+
+% Everything is 0 to start with
+constraint forall (r in Registers) (
+ regs[min(Steps), r] = 0
+);
+
+% All registers unaffected by the instruction at a given step
+function set of Registers: unaffected(Steps: step) = {
+ r | r in Registers where R(r) != inp_args[step, Arg1]
+};
+
+% The argument at pos addressed by the instruction at i_step, pointing to the registers at r_step
+function var int: arg(Steps: i_step, ExtendedSteps: r_step, Pos: pos) =
+ if inp_args[i_step, pos] in R(Registers) then
+ regs[r_step, R^-1(inp_args[i_step, pos])]
+ elseif inp_args[i_step, pos] in Imm(Immediates) then
+ Imm^-1(inp_args[i_step, pos])
+ else
+ assert(false, "no value for argument of instruction at step")
+ endif;
+
+% Where to write the result of an instruction
+function var int: writearg(Steps: step) = arg(step, step + 1, Arg1);
+
+% Read the argument at pos of instruction at step
+function var int: readarg(Steps: step, Pos: pos) = arg(step, step, pos);
+
+predicate interpret(Steps: step, ExtendedInputs: next_input) = (
+ % Constrain state based on instruction at step
+ if inp_ops[step] = i_inp then
+ writearg(step) = inputs[next_input]
+ else
+ let {
+ Operation: o = inp_ops[step],
+ var int: a = readarg(step, Arg1),
+ var int: b = readarg(step, Arg2),
+ var int: x = writearg(step),
+ } in
+ if o = i_add then
+ x = a + b
+ elseif o = i_mul then
+ x = a * b
+ elseif o = i_div then
+ b != 0 /\
+ x * b = a - (a mod b)
+ elseif o = i_mod then
+ a >= 0 /\
+ b > 0 /\
+ x = a mod b
+ elseif o = i_eql then
+ x = (a = b)
+ else
+ assert(false, "unimplemented instruction at ")
+ endif
+ endif /\
+ % Leave the rest unchanged
+ forall (r in unaffected(step)) (
+ regs[step + 1, r] = regs[step, r]
+ ) /\
+ % Perform induction
+ if step + 1 in Steps then
+ interpret(step + 1, next_input + (inp_ops[step] = i_inp))
+ else
+ true
+ endif
+);
+
+constraint interpret(min(Steps), min(Inputs));
+
+% Finish with z = 0
+constraint regs[max(ExtendedSteps), z] = 0;
+
+% No 0s in serial number
+constraint forall (i in Inputs) (
+ inputs[i] != 0
+);
+
+% Find the largest first
+solve :: int_search(inputs, input_order, indomain_max) satisfy;
+
+output [
+ "inputs: ", show(inputs), "\n",
+ "final registers: ", show(regs[max(ExtendedSteps), ..]), "\n",
+]; \ No newline at end of file
diff --git a/2021/day24/24b.mzn b/2021/day24/24b.mzn
new file mode 100644
index 0000000..2e8a9a4
--- /dev/null
+++ b/2021/day24/24b.mzn
@@ -0,0 +1,117 @@
+include "globals.mzn";
+
+% Types
+enum Operation = {
+ i_inp,
+ i_add,
+ i_mul,
+ i_div,
+ i_mod,
+ i_eql
+};
+enum Pos = { Arg1, Arg2 };
+enum Arg = R(Registers) ++ Imm(Immediates) ++ { None };
+
+enum Registers = {x, y, z, w};
+
+set of int: Immediates = -127..127;
+set of int: Digits = 0..9;
+
+% Input
+array[int] of Operation: inp_ops;
+array[int, Pos] of Arg: inp_args;
+
+% Properties derived from input
+set of int: Steps = index_set(inp_ops);
+set of int: Inputs = 1..count(inp_ops, i_inp);
+
+set of int: ExtendedSteps = min(Steps)..max(Steps) + 1;
+set of int: ExtendedInputs = min(Inputs)..max(Inputs) + 1;
+
+% State
+array[ExtendedSteps, Registers] of var int: regs;
+array[Inputs] of var Digits: inputs;
+
+% Everything is 0 to start with
+constraint forall (r in Registers) (
+ regs[min(Steps), r] = 0
+);
+
+% All registers unaffected by the instruction at a given step
+function set of Registers: unaffected(Steps: step) = {
+ r | r in Registers where R(r) != inp_args[step, Arg1]
+};
+
+% The argument at pos addressed by the instruction at i_step, pointing to the registers at r_step
+function var int: arg(Steps: i_step, ExtendedSteps: r_step, Pos: pos) =
+ if inp_args[i_step, pos] in R(Registers) then
+ regs[r_step, R^-1(inp_args[i_step, pos])]
+ elseif inp_args[i_step, pos] in Imm(Immediates) then
+ Imm^-1(inp_args[i_step, pos])
+ else
+ assert(false, "no value for argument of instruction at step")
+ endif;
+
+% Where to write the result of an instruction
+function var int: writearg(Steps: step) = arg(step, step + 1, Arg1);
+
+% Read the argument at pos of instruction at step
+function var int: readarg(Steps: step, Pos: pos) = arg(step, step, pos);
+
+predicate interpret(Steps: step, ExtendedInputs: next_input) = (
+ % Constrain state based on instruction at step
+ if inp_ops[step] = i_inp then
+ writearg(step) = inputs[next_input]
+ else
+ let {
+ Operation: o = inp_ops[step],
+ var int: a = readarg(step, Arg1),
+ var int: b = readarg(step, Arg2),
+ var int: x = writearg(step),
+ } in
+ if o = i_add then
+ x = a + b
+ elseif o = i_mul then
+ x = a * b
+ elseif o = i_div then
+ b != 0 /\
+ x * b = a - (a mod b)
+ elseif o = i_mod then
+ a >= 0 /\
+ b > 0 /\
+ x = a mod b
+ elseif o = i_eql then
+ x = (a = b)
+ else
+ assert(false, "unimplemented instruction at ")
+ endif
+ endif /\
+ % Leave the rest unchanged
+ forall (r in unaffected(step)) (
+ regs[step + 1, r] = regs[step, r]
+ ) /\
+ % Perform induction
+ if step + 1 in Steps then
+ interpret(step + 1, next_input + (inp_ops[step] = i_inp))
+ else
+ true
+ endif
+);
+
+constraint interpret(min(Steps), min(Inputs));
+
+% Finish with z = 0
+constraint regs[max(ExtendedSteps), z] = 0;
+
+% No 0s in serial number
+constraint forall (i in Inputs) (
+ inputs[i] != 0
+);
+
+% Find the largest first
+solve :: int_search(inputs, input_order, indomain_min) satisfy;
+
+output [
+ "inputs: ", show(inputs), "\n",
+ "final registers: ", show(regs[max(ExtendedSteps), ..]), "\n",
+]; \ No newline at end of file
diff --git a/2021/day25/25a.hs b/2021/day25/25a.hs
new file mode 100644
index 0000000..6f0cf1a
--- /dev/null
+++ b/2021/day25/25a.hs
@@ -0,0 +1,87 @@
+module Main where
+
+import Data.List (intercalate)
+import Data.Maybe (fromMaybe)
+import Data.Set (Set)
+import qualified Data.Set as S
+
+data Direction = East | South deriving (Show, Eq, Ord)
+
+type Coord = (Int, Int)
+
+type Board = Set (Coord, Direction)
+
+spaceFilled :: Board -> Coord -> Bool
+spaceFilled b c = S.member (c, East) b || S.member (c, South) b
+
+getDirection :: Board -> Coord -> Direction
+getDirection b c
+ | (c, East) `S.member` b = East
+ | (c, South) `S.member` b = South
+ | otherwise = undefined
+
+wrapAround :: Board -> Coord -> Coord
+wrapAround b (x, y) = (x', y')
+ where
+ x' = if x > mx then 0 else x
+ y' = if y > my then 0 else y
+ mx = 138
+ my = 136
+
+stepOne :: Board -> (Coord, Direction) -> (Coord, Direction)
+stepOne b (c@(x, y), d) = (if canMove then newCoord else c, d)
+ where
+ newCoord = case d of
+ East -> wrapAround b (x + 1, y)
+ South -> wrapAround b (x, y + 1)
+ canMove = not $ spaceFilled b newCoord
+
+stepAll :: Board -> Board
+stepAll ib = S.map (stepSouth eastStepped) eastStepped
+ where
+ eastStepped = S.map (stepEast ib) ib
+ stepEast b x@(_, East) = stepOne b x
+ stepEast b x = x
+ stepSouth b x@(_, South) = stepOne b x
+ stepSouth b x = x
+
+stepTillStationary :: Board -> (Board, Int)
+stepTillStationary ib = keepStepping ib 0
+ where
+ keepStepping b n
+ | b == b' = (b, n + 1)
+ | otherwise = keepStepping b' (n + 1)
+ where
+ b' = stepAll b
+
+parseFile :: String -> Board
+parseFile str = S.fromList $ getFilled str 0 0
+ where
+ getFilled [] x y = []
+ getFilled ('.' : cs) x y = getFilled cs (x + 1) y
+ getFilled ('\n' : cs) x y = getFilled cs 0 (y + 1)
+ getFilled ('>' : cs) x y = ((x, y), East) : getFilled cs (x + 1) y
+ getFilled ('v' : cs) x y = ((x, y), South) : getFilled cs (x + 1) y
+ getFilled (_ : cs) x y = undefined
+
+printBoard :: Board -> String
+printBoard b = intercalate "\n" $ map printLine [0 .. 10]
+ where
+ printLine y = map (printCell y) [0 .. 10]
+ printCell y x
+ | spaceFilled b (x, y) = case getDirection b (x, y) of
+ East -> '>'
+ South -> 'v'
+ | otherwise = '.'
+
+main :: IO ()
+main = do
+ input <- readFile "./input"
+ let parsed = parseFile input
+ print $ fromMaybe 0 $ S.lookupMax $ S.map (fst . fst) parsed
+ print $ fromMaybe 0 $ S.lookupMax $ S.map (snd . fst) parsed
+ -- putStrLn $ printBoard parsed
+ -- putStrLn "---"
+ -- putStrLn $ printBoard $ foldr (\x b -> stepAll b) parsed [0 .. 0]
+
+ print $ snd $ stepTillStationary parsed \ No newline at end of file
diff --git a/2021/day3/03a.rkt b/2021/day3/03a.rkt
new file mode 100644
index 0000000..bb42d83
--- /dev/null
+++ b/2021/day3/03a.rkt
@@ -0,0 +1,30 @@
+#lang racket
+(define (mode xs)
+ (define ht (make-hash))
+ (define max-key '0)
+ (for ([x xs])
+ (define new-val (+ 1 (hash-ref ht x 0)))
+ (hash-set! ht x new-val)
+ (if (> new-val (hash-ref ht max-key 0)) (set! max-key x) 3))
+ max-key)
+
+(define (transpose xss)
+ (apply map list xss))
+
+(define (flip x)
+ (cond [(string=? x "0") "1"]
+ [else "0"]))
+
+(define input (open-input-file "input"))
+(define bit-positions
+ (transpose (map (lambda (xs)
+ (map (curry make-string 1) (string->list xs)))
+ (port->lines input))))
+
+(define gamma-str (foldr string-append "" (map mode bit-positions)))
+(define epsilon-str (foldr string-append "" (map (compose flip mode) bit-positions)))
+
+(define gamma (string->number gamma-str 2))
+(define epsilon (string->number epsilon-str 2))
+
+(* gamma epsilon)
diff --git a/2021/day3/03b.rkt b/2021/day3/03b.rkt
new file mode 100644
index 0000000..aea9c86
--- /dev/null
+++ b/2021/day3/03b.rkt
@@ -0,0 +1,35 @@
+#lang racket
+
+(define (mode xs)
+ (define ht (make-hash))
+ (define max-key '0)
+ (for ([x xs])
+ (define new-val (+ 1 (hash-ref ht x 0)))
+ (hash-set! ht x new-val)
+ (if (> new-val (hash-ref ht max-key 0)) (set! max-key x) 3))
+ (cond [(= (hash-ref ht #\0 0) (hash-ref ht #\1 0)) #f]
+ [else max-key]))
+
+(define (flip x)
+ (cond [(char=? x #\0) #\1]
+ [else #\0]))
+
+(define (bit-criteria lines least [fallback (cond [least #\0] [else #\1])] [n 0])
+ (cond [(= (length lines) 1) (car lines)]
+ [else
+ (define bits (map (curryr string-ref n) lines))
+ (define bMode (mode bits))
+ (define criteria (cond [(not bMode) fallback]
+ [least (flip bMode)]
+ [else bMode]))
+ (bit-criteria (filter (lambda (x) (char=? criteria (string-ref x n)))
+ lines)
+ least fallback (+ n 1))]))
+
+(define input (open-input-file "input"))
+(define lines (port->lines input))
+
+(define oxy (string->number (bit-criteria lines #f) 2))
+(define co2 (string->number (bit-criteria lines #t) 2))
+
+(* oxy co2)
diff --git a/2021/day4/04a-alt.rkt b/2021/day4/04a-alt.rkt
new file mode 100644
index 0000000..db03881
--- /dev/null
+++ b/2021/day4/04a-alt.rkt
@@ -0,0 +1,49 @@
+#lang racket
+
+(require racket/file)
+
+(define (parse-row x)
+ (map string->number (filter (lambda (x) (< 0 (string-length x))) (regexp-split #rx" +" x))))
+
+(define (parse-board x)
+ (map parse-row (string-split x "\n")))
+
+(define (get-numbers x)
+ (define number-line (car (string-split x "\n\n")))
+ (map string->number (string-split number-line ",")))
+
+(define (get-boards x)
+ (define boards (cdr (string-split x "\n\n")))
+ (map parse-board boards))
+
+(define (subsetOf xs ys)
+ (subset? (list->set xs) (list->set ys)))
+
+(define (transpose xs)
+ (apply map list xs))
+
+(define (check-win board numbers)
+ (define winningColumns (filter (lambda (x) (subsetOf x numbers)) board))
+ (define winningRows (filter (lambda (x) (subsetOf x numbers)) (transpose board)))
+ (cond [(not (null? winningColumns)) (car winningColumns)]
+ [(not (null? winningRows)) (car winningRows)]
+ [else #f]))
+
+(define input (file->string "./input"))
+(define numbers (get-numbers input))
+(define boards (get-boards input))
+
+(define winningBoard #f)
+(define winningRun #f)
+(define wonOnRound 0)
+(for* ([rnd (length numbers)]
+ [board boards]
+ #:unless winningRun
+ )
+ (set! winningRun (check-win board (take numbers rnd)))
+ (set! winningBoard board)
+ (set! wonOnRound rnd))
+
+(*
+ (foldr + 0 (filter (lambda (x) (not (member x (take numbers wonOnRound)))) (flatten winningBoard)))
+ (list-ref numbers (- wonOnRound 1)))
diff --git a/2021/day4/04b-alt.rkt b/2021/day4/04b-alt.rkt
new file mode 100644
index 0000000..ab32bc2
--- /dev/null
+++ b/2021/day4/04b-alt.rkt
@@ -0,0 +1,49 @@
+#lang racket
+
+(require racket/file)
+
+(define (parse-row x)
+ (map string->number (filter (lambda (x) (< 0 (string-length x))) (regexp-split #rx" +" x))))
+
+(define (parse-board x)
+ (map parse-row (string-split x "\n")))
+
+(define (get-numbers x)
+ (define number-line (car (string-split x "\n\n")))
+ (map string->number (string-split number-line ",")))
+
+(define (get-boards x)
+ (define boards (cdr (string-split x "\n\n")))
+ (map parse-board boards))
+
+(define (subsetOf xs ys)
+ (subset? (list->set xs) (list->set ys)))
+
+(define (transpose xs)
+ (apply map list xs))
+
+(define (check-win board numbers)
+ (define winningColumns (filter (lambda (x) (subsetOf x numbers)) board))
+ (define winningRows (filter (lambda (x) (subsetOf x numbers)) (transpose board)))
+ (cond [(not (null? winningColumns)) (car winningColumns)]
+ [(not (null? winningRows)) (car winningRows)]
+ [else #f]))
+
+(define input (file->string "./input"))
+(define numbers (get-numbers input))
+(define boards (get-boards input))
+
+(define ht (make-hash))
+(for* ([rnd (length numbers)]
+ [board boards]
+ #:unless (hash-ref ht board #f)
+ )
+ (cond [(check-win board (take numbers rnd)) (hash-set! ht board rnd)]))
+
+(define maxTurn 0)
+(define lastBoard #f)
+(hash-for-each ht (lambda (k v) (cond [(> v maxTurn) (set! maxTurn v) (set! lastBoard k)])))
+
+(*
+ (foldr + 0 (filter (lambda (x) (not (member x (take numbers maxTurn)))) (flatten lastBoard)))
+ (list-ref numbers (- maxTurn 1)))
diff --git a/2021/day4/04t.rkt b/2021/day4/04t.rkt
new file mode 100644
index 0000000..b3f10ad
--- /dev/null
+++ b/2021/day4/04t.rkt
@@ -0,0 +1,9 @@
+#lang reader "reader.rkt"
+7,4,9,5,11,17,23,2,0,14,21,24,10,16,13,6,15,25,12,22,18,20,8,19,3,26,1
+
+22 13 17 11 0
+ 8 2 23 4 24
+21 9 14 16 7
+ 6 10 3 18 5
+1 12 20 15 19
+
diff --git a/2021/day4/parser.rkt b/2021/day4/parser.rkt
new file mode 100644
index 0000000..449d886
--- /dev/null
+++ b/2021/day4/parser.rkt
@@ -0,0 +1,8 @@
+#lang brag
+file: numbers "\n" "\n" boards
+numbers: number ("," number)*
+number: digit+
+digit: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+boards: board ("\n" board)*
+board: row "\n" row "\n" row "\n" row "\n" row "\n"
+row: " "+ number " "+ number " "+ number " "+ number " "+ number
diff --git a/2021/day4/reader.rkt b/2021/day4/reader.rkt
new file mode 100644
index 0000000..b777f92
--- /dev/null
+++ b/2021/day4/reader.rkt
@@ -0,0 +1,21 @@
+#lang racket
+
+(require "parser.rkt")
+(require brag/support)
+
+(define (make-tokenizer port)
+ (define (next-token)
+ (define bf-lexer
+ (lexer
+ [(char-set "\n1234567890, ") lexeme]
+ [any-char (next-token)]))
+ (bf-lexer port))
+ next-token)
+
+(define (read-syntax path port)
+ (define parse-tree (parse path (make-tokenizer port)))
+ (define module-datum `(module day4 racket
+ ,parse-tree))
+ (datum->syntax #f module-datum))
+
+(provide read-syntax)
diff --git a/2021/day5/05a.rkt b/2021/day5/05a.rkt
new file mode 100644
index 0000000..c24cb49
--- /dev/null
+++ b/2021/day5/05a.rkt
@@ -0,0 +1,36 @@
+#lang racket
+
+(require "./05a_grammar.rkt")
+
+(define ventCounts (make-hash))
+
+(define (digit x)
+ x)
+
+(define (number . DIGITS)
+ (string->number (foldr string-append "" DIGITS)))
+
+(define (coord a _a b)
+ (list a b))
+
+(define (line c1 _b _c _d _e c2)
+ (define steps (max (abs (- (car c2) (car c1)))
+ (abs (- (second c2) (second c1)))))
+ (define mx (/ (- (car c2) (car c1)) steps))
+ (define my (/ (- (second c2) (second c1)) steps))
+ (cond [(or (= 0 mx) (= 0 my)) (for ([s (+ 1 steps)])
+ (define v (list (+ (car c1) (* mx s)) (+ (second c1) (* my s))))
+ (hash-set! ventCounts v (+ 1 (hash-ref ventCounts v 0))))]
+ [else 0]))
+
+
+(define (vents l _a . ls)
+ (cond [(null? ls) l]
+ [else (cons l (apply vents ls))]))
+
+(define-namespace-anchor anc)
+(define ns (namespace-anchor->namespace anc))
+(define parsed (parse-to-datum (file->string "./input")))
+(void (eval parsed ns))
+
+(length (filter (curry <= 2) (hash-values ventCounts)))
diff --git a/2021/day5/05a_grammar.rkt b/2021/day5/05a_grammar.rkt
new file mode 100644
index 0000000..cc78e6a
--- /dev/null
+++ b/2021/day5/05a_grammar.rkt
@@ -0,0 +1,6 @@
+#lang brag
+vents: (line "\n")* ["\n"]
+line: coord " " "-" ">" " " coord
+coord: number "," number
+number: digit*
+digit: "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
diff --git a/2021/day5/05b.rkt b/2021/day5/05b.rkt
new file mode 100644
index 0000000..25d6fd6
--- /dev/null
+++ b/2021/day5/05b.rkt
@@ -0,0 +1,39 @@
+#lang racket
+
+(require "./05a_grammar.rkt")
+
+(define ventCounts (make-hash))
+
+(define (digit x)
+ x)
+
+(define (number . DIGITS)
+ (string->number (foldr string-append "" DIGITS)))
+
+(define (coord a _a b)
+ (list a b))
+
+(define (line c1 _b _c _d _e c2)
+ (define steps (max (abs (- (car c2) (car c1)))
+ (abs (- (second c2) (second c1)))))
+ (define mx (/ (- (car c2) (car c1)) steps))
+ (define my (/ (- (second c2) (second c1)) steps))
+ (for ([s (+ 1 steps)])
+ (define v (list (+ (car c1) (* mx s)) (+ (second c1) (* my s))))
+ (hash-set! ventCounts v (+ 1 (hash-ref ventCounts v 0)))))
+
+(define (vents l _a . ls)
+ (cond [(null? ls) l]
+ [else (cons l (apply vents ls))]))
+
+(define (print-board ex ey)
+ (for ([y ey])
+ (for ([x ex])
+ (display (hash-ref ventCounts (list x y) ".")))
+ (display "\n")))
+
+(define-namespace-anchor anc)
+(define ns (namespace-anchor->namespace anc))
+(define parsed (parse-to-datum (file->string "./input")))
+(void (eval parsed ns))
+(length (filter (curry <= 2) (hash-values ventCounts)))
diff --git a/2021/day6/06.clj b/2021/day6/06.clj
new file mode 100644
index 0000000..9531425
--- /dev/null
+++ b/2021/day6/06.clj
@@ -0,0 +1,30 @@
+(ns day-6)
+
+(require '[clojure.string :as str])
+
+(defn add-fish [h days count]
+ (assoc h days (+ count (or (h days) 0))))
+
+(defn simulate-fish [h [days count]]
+ (if (= 0 days) (-> (add-fish h 6 count)
+ (add-fish 8 count))
+ (add-fish h (- days 1) count)))
+
+(defn simulate-fishes [h]
+ (reduce simulate-fish {} h))
+
+(def input (as-> (slurp "./input") x
+ (str/split x #",")
+ (map str/trim x)
+ (map #(. Integer parseInt %) x)))
+
+(def inputMap (reduce (fn [acc days] (add-fish acc days 1)) {} input))
+
+(def resultA (reduce (fn [acc _] (simulate-fishes acc)) inputMap (range 80)))
+(def resultB (reduce (fn [acc _] (simulate-fishes acc)) inputMap (range 256)))
+
+(def countA (reduce (fn [acc [_ count]] (+ acc count)) 0 resultA))
+(def countB (reduce (fn [acc [_ count]] (+ acc count)) 0 resultB))
+
+(println countA)
+(println countB)
diff --git a/2021/day7/07a.clj b/2021/day7/07a.clj
new file mode 100644
index 0000000..d9cb0f7
--- /dev/null
+++ b/2021/day7/07a.clj
@@ -0,0 +1,19 @@
+(ns day-7)
+
+(require '[clojure.string :as str])
+
+(defn totalDelta [xs dst]
+ (reduce + (map (fn [x] (Math/abs ^int (- x dst))) xs)))
+
+(defn calcIdealPos [xs start]
+ (def thisDelta (totalDelta xs start))
+ (def nextDelta (totalDelta xs (+ 1 start)))
+ (cond (> nextDelta thisDelta) start
+ :else (calcIdealDst xs (+ 1 start))))
+
+(def input (as-> (slurp "./input") x
+ (str/split x #",")
+ (map str/trim x)
+ (map #(. Integer parseInt %) x)))
+
+(totalDelta input (calcIdealPos input (apply min input)))
diff --git a/2021/day7/07b.clj b/2021/day7/07b.clj
new file mode 100644
index 0000000..9e248c8
--- /dev/null
+++ b/2021/day7/07b.clj
@@ -0,0 +1,22 @@
+(ns day-7)
+
+(require '[clojure.string :as str])
+
+(defn fuelCost [x]
+ (/ (* x (+ 1 x)) 2))
+
+(defn totalDelta [xs dst]
+ (reduce + (map (fn [x] (fuelCost (Math/abs ^int (- x dst)))) xs)))
+
+(defn calcIdealPos [xs start]
+ (def thisDelta (totalDelta xs start))
+ (def nextDelta (totalDelta xs (+ 1 start)))
+ (cond (> nextDelta thisDelta) start
+ :else (calcIdealDst xs (+ 1 start))))
+
+(def input (as-> (slurp "./input") x
+ (str/split x #",")
+ (map str/trim x)
+ (map #(. Integer parseInt %) x)))
+
+(totalDelta input (calcIdealPos input (apply min input)))
diff --git a/2021/day8/08a.clj b/2021/day8/08a.clj
new file mode 100644
index 0000000..dc261e5
--- /dev/null
+++ b/2021/day8/08a.clj
@@ -0,0 +1,12 @@
+(ns day-8)
+
+(require '[clojure.string :as str])
+
+(def input (as-> (slurp "./input") x
+ (str/split x #"\n")
+ (map (fn [l]
+ (map (fn [p] (str/split (str/trim p) #" ")) (str/split l #"\|"))) x)))
+
+(def onlyOutputs (flatten (map second input)))
+(def knownDigits (filter (fn [xs] (contains? (set '(2 4 3 7)) (count xs))) onlyOutputs))
+(println (count knownDigits))
diff --git a/2021/day8/08b.clj b/2021/day8/08b.clj
new file mode 100644
index 0000000..067f802
--- /dev/null
+++ b/2021/day8/08b.clj
@@ -0,0 +1,69 @@
+(ns day-8)
+
+(require '[clojure.string :as str])
+(require '[clojure.set :as set])
+
+(def ALPHABET #{\a \b \c \d \e \f \g})
+(defn decodeWith [signal mapping]
+ (cond (every? (fn [x] (contains? mapping x)) signal) (set (map (fn [x] (get mapping x)) signal))
+ :else false))
+
+(def SIGNAL_TO_NUM {#{\a \b \c \e \f \g} 0
+ #{\c \f} 1
+ #{\a \c \d \e \g} 2
+ #{\a \c \d \f \g} 3
+ #{\b \c \d \f} 4
+ #{\a \b \d \f \g} 5
+ #{\a \b \d \e \f \g} 6
+ #{\a \c \f} 7
+ #{\a \b \c \d \e \f \g} 8
+ #{\a \b \c \d \f \g} 9})
+
+(defn decodedArrToNum [arr]
+ (reduce + (map-indexed (fn [idx sig] (* (Math/pow 10 (- (count arr) idx 1)) (SIGNAL_TO_NUM sig))) arr)))
+
+; characters that haven't been mapped (ie the mapping doesnt specify what they actually should be)
+(defn unmappedChars [mapping]
+ (set/difference ALPHABET (keys mapping)))
+
+; characters that haven't been used (ie there is no character in the mapping that results in them)
+(defn unusedChars [mapping]
+ (set/difference ALPHABET (vals mapping)))
+
+(defn validResult [x]
+ (contains? #{#{\a \b \c \e \f \g} #{\c \f} #{\a \c \d \e \g} #{\a \c \d \f \g} #{\b \c \d \f} #{\a \b \d \f \g} #{\a \b \d \e \f \g}#{\a \c \f} #{\a \b \c \d \e \f \g} #{\a \b \c \d \f \g}} x))
+
+(defn tryWith [signals mapping knownValues]
+ (cond
+ (not (every? (fn [[in expected]]
+ (def attemptedDecode (decodeWith in mapping))
+ (or (= false attemptedDecode) (= expected attemptedDecode)))
+ knownValues)) false ; stop considering path if it breaks any known values
+ (not (every? (fn [in]
+ (def attemptedDecode (decodeWith in mapping))
+ (or (= false attemptedDecode) (validResult attemptedDecode)))
+ signals)) false ; stop when any of the fully resolved signals are invalid
+ (every? validResult (map (fn [x] (decodeWith x mapping)) signals)) mapping ; base case - all resolved to valid values
+ :else (let [tryingToMap (first (unmappedChars mapping))]
+ (first (filter (comp true? boolean) (for [candidate (unusedChars mapping)]
+ (do
+ (tryWith signals (assoc mapping tryingToMap candidate) knownValues))))))))
+
+(def KNOWN_VALUES {2 #{\c \f} 4 #{\b \c \d \f} 3 #{\a \c \f} 7 #{\a \b \c \d \e \f \g}})
+
+(defn extractKnownValues [signals]
+ (reduce (fn [m s] (cond (contains? KNOWN_VALUES (count s)) (assoc m s (get KNOWN_VALUES (count s)))
+ :else m)) {} signals))
+
+(def input (as-> (slurp "./input") x
+ (str/split x #"\n")
+ (map (fn [l]
+ (map (fn [p] (map set (str/split (str/trim p) #" "))) (str/split l #"\|"))) x)))
+
+(def lineMappings (map (fn [l] (let [signals (set (flatten l))]
+ (tryWith signals {} (extractKnownValues signals)))) input))
+(def decodedOutputs (map (fn [l m] (let [signals (second l)]
+ (map (fn [x] (decodeWith x m)) signals))) input lineMappings))
+(def outputs (map decodedArrToNum decodedOutputs))
+
+(println (reduce + outputs))
diff --git a/2021/day9/09.cpp b/2021/day9/09.cpp
new file mode 100644
index 0000000..5026a77
--- /dev/null
+++ b/2021/day9/09.cpp
@@ -0,0 +1,154 @@
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <cerrno>
+#include <vector>
+#include <set>
+#include <queue>
+#include <algorithm>
+
+using namespace std;
+
+std::string get_file_contents(const char *filename)
+{
+ std::ifstream in(filename, std::ios::in | std::ios::binary);
+ if (!in)
+ {
+ throw(errno);
+ }
+
+ std::string contents;
+ in.seekg(0, std::ios::end);
+ contents.resize(in.tellg());
+ in.seekg(0, std::ios::beg);
+
+ in.read(&contents[0], contents.size());
+ in.close();
+ return contents;
+}
+
+using heightmap_t = vector<vector<int>>;
+
+heightmap_t parse_height_map(const char* input, int len){
+ vector<vector<int>> output;
+ vector<int> currRow;
+ for (int i = 0; i < len; i++) {
+ if (input[i] == '\n') {
+ output.push_back(currRow);
+ currRow = vector<int>();
+ } else {
+ currRow.push_back(input[i] - '0');
+ }
+ }
+ if (currRow.size() > 0) {
+ output.push_back(currRow);
+ }
+
+ return output;
+}
+
+bool isLowPoint(const heightmap_t &heightmap, int x, int y) {
+ int point = heightmap[y][x];
+ for (int dx = -1; dx < 2; dx++) {
+ for (int dy = -1; dy < 2; dy++) {
+ int checkX = x + dx;
+ int checkY = y + dy;
+ if ((checkX == x && checkY == y) ||
+ checkX < 0 || checkY < 0 ||
+ checkY >= heightmap.size() || checkX >= heightmap[checkY].size())
+ continue;
+ if (heightmap[checkY][checkX] <= point) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+struct coord {
+ int x;
+ int y;
+
+
+ coord(int x, int y) {
+ this->x = x;
+ this->y = y;
+ }
+
+ int hash() const {
+ return this->x << 16 | this->y;
+ }
+
+ bool operator==(const coord &a) const {
+ return a.x == x && a.y == y;
+ }
+
+ bool operator<(const coord &a) const {
+ return this->hash() < a.hash();
+ }
+};
+
+int findBasinSize(const heightmap_t &heightmap, int startX, int startY) {
+ set<coord> visited;
+ queue<coord> queue;
+ queue.emplace(startX, startY);
+
+ int totalSize = 0;
+ while(!queue.empty()) {
+ int x = queue.front().x;
+ int y = queue.front().y;
+ queue.pop();
+ if (x < 0 || y < 0 || y >= heightmap.size() || x >= heightmap[y].size() || heightmap[y][x] == 9 || visited.count({x, y})) {
+ continue;
+ }
+
+ totalSize++;
+ visited.insert({x, y});
+
+ for (int dx = -1; dx < 2; dx++) {
+ for (int dy = -1; dy < 2; dy++) {
+ int checkX = x + dx;
+ int checkY = y + dy;
+ if (dx != 0 && dy != 0) // dont allow diagonals / {x, y}
+ continue;
+ queue.emplace(checkX, checkY);
+ }
+ }
+ }
+
+ return totalSize;
+}
+
+int main() {
+ std::string input = get_file_contents("input");
+ auto heightmap = parse_height_map(input.c_str(), input.length());
+
+ int lowPointCount = 0;
+ int totalRisk = 0;
+ int topBasins[] = {0, 0, 0};
+ for (int y = 0; y < heightmap.size(); y++) {
+ for (int x = 0; x < heightmap[y].size(); x++) {
+ if (isLowPoint(heightmap, x, y)) {
+ lowPointCount++;
+ totalRisk += heightmap[y][x] + 1;
+
+ int basinSize = findBasinSize(heightmap, x, y);
+ for (int i = 0; i < 3; i++) {
+ if (topBasins[i] < basinSize) {
+ topBasins[i] = basinSize;
+ break;
+ }
+ }
+ sort(topBasins, topBasins + 3);
+ }
+ }
+ }
+
+ int acc = 1;
+ for (int i = 0; i < 3; i++) {
+ acc *= topBasins[i];
+ }
+ printf("Total low points: %d\n", lowPointCount);
+ printf("Total risk: %d\n", totalRisk);
+ printf("Part B answer: %d\n", acc);
+}
diff --git a/2021/shell.nix b/2021/shell.nix
new file mode 100644
index 0000000..9e6b4cb
--- /dev/null
+++ b/2021/shell.nix
@@ -0,0 +1,35 @@
+{ pkgs ? import <nixpkgs> {} }:
+
+pkgs.mkShell {
+ buildInputs = with pkgs; [
+ emacs
+ (haskellPackages.ghcWithPackages (p: [
+ p.linear
+ p.parsec
+ ]))
+ python3
+ stack
+ racket
+ clojure
+ leiningen
+ (minizinc.overrideAttrs (old: let rev = "adaa07456233d9ffe0a1f848917dde41e8c54710"; in {
+ version = "develop-${rev}";
+ src = pkgs.fetchFromGitHub {
+ owner = "MiniZinc";
+ repo = "libminizinc";
+
+ rev = rev;
+ sha256 = "sha256-t5/reUj38cc3H7CE1iPWgYD9m+190E5ihFHhft8+Bns=";
+ };
+ }))
+ (gecode.overrideAttrs (old: let rev = "fec7e9fd99bca98f146416ba8ea8adc278f5a95a"; in {
+ version = "develop-${rev}";
+ src = pkgs.fetchFromGitHub {
+ owner = "Gecode";
+ repo = "gecode";
+ sha256 = "sha256-HiYO74RnxY6ga7uppjR3DXMFOgE/8Gs0dvi86qUQcjo=";
+ rev = rev;
+ };
+ }))
+ ];
+}
diff --git a/2022/.cargo/config.toml b/2022/.cargo/config.toml
new file mode 100644
index 0000000..435ed75
--- /dev/null
+++ b/2022/.cargo/config.toml
@@ -0,0 +1,2 @@
+[build]
+target = "wasm32-unknown-unknown" \ No newline at end of file
diff --git a/2022/.gitignore b/2022/.gitignore
new file mode 100644
index 0000000..d7ecf3b
--- /dev/null
+++ b/2022/.gitignore
@@ -0,0 +1,6 @@
+.envrc
+.direnv
+inputs
+target/
+dist/
+public/ \ No newline at end of file
diff --git a/2022/.gitlab-ci.yml b/2022/.gitlab-ci.yml
new file mode 100644
index 0000000..48a1625
--- /dev/null
+++ b/2022/.gitlab-ci.yml
@@ -0,0 +1,26 @@
+image: rust:latest
+
+variables:
+ CARGO_HOME: $CI_PROJECT_DIR/.cargo
+ TRUNK_VERSION: v0.16.0
+
+stages:
+ - build
+
+pages:
+ stage: build
+ image: rust:latest
+ before_script:
+ - rustup target add wasm32-unknown-unknown
+ - wget -qO- https://github.com/thedodd/trunk/releases/download/${TRUNK_VERSION}/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf-
+ script:
+ - mkdir -p public/
+ - ./trunk build -d public/day9 --release --public-url /aoc-2022/day9 src/day09.html
+ - ./trunk build -d public/day14 --release --public-url /aoc-2022/day14 src/day14.html
+ artifacts:
+ paths:
+ - public/
+ cache:
+ paths:
+ - target/
+ - .cargo/
diff --git a/2022/Cargo.lock b/2022/Cargo.lock
new file mode 100644
index 0000000..0d15d2c
--- /dev/null
+++ b/2022/Cargo.lock
@@ -0,0 +1,2078 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "ab_glyph"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcdbc68024b653943864d436fe8a24b028095bc1cf91a8926f8241e4aaffe59"
+dependencies = [
+ "ab_glyph_rasterizer",
+ "owned_ttf_parser",
+]
+
+[[package]]
+name = "ab_glyph_rasterizer"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "330223a1aecc308757b9926e9391c9b47f8ef2dbd8aea9df88312aea18c5e8d6"
+
+[[package]]
+name = "accesskit"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3083ac5a97521e35388ca80cf365b6be5210962cc59f11ee238cd92ac2fa9524"
+dependencies = [
+ "enumset",
+ "kurbo",
+]
+
+[[package]]
+name = "accesskit_consumer"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df122220244ca3ab93f6a42da59a5f8b379c8846dbcaedf922d95636d22c4e10"
+dependencies = [
+ "accesskit",
+ "parking_lot",
+]
+
+[[package]]
+name = "accesskit_macos"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "55c97d7b5cbb2409e05b016406a1bd057237d120205cb63220ca86c2ea3790a1"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "objc2",
+ "once_cell",
+ "parking_lot",
+]
+
+[[package]]
+name = "accesskit_windows"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b0cfda25182b83b24e350434a3f63676252a00a295f32760a14d3f55feb8493"
+dependencies = [
+ "accesskit",
+ "accesskit_consumer",
+ "arrayvec 0.7.2",
+ "once_cell",
+ "parking_lot",
+ "paste",
+ "windows",
+]
+
+[[package]]
+name = "accesskit_winit"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdf20fecd6573e03bebcb4de267f82431e5ea39a293b62aa51a45bdfd69ef39b"
+dependencies = [
+ "accesskit",
+ "accesskit_macos",
+ "accesskit_windows",
+ "parking_lot",
+ "winit",
+]
+
+[[package]]
+name = "adler"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
+
+[[package]]
+name = "ahash"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf6ccdb167abbf410dcb915cabd428929d7f6a04980b54a11f26a39f1c7f7107"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "arboard"
+version = "3.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6041616acea41d67c4a984709ddab1587fd0b10efe5cc563fee954d2f011854"
+dependencies = [
+ "clipboard-win",
+ "log",
+ "objc",
+ "objc-foundation",
+ "objc_id",
+ "once_cell",
+ "parking_lot",
+ "thiserror",
+ "winapi",
+ "x11rb",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
+
+[[package]]
+name = "arrayvec"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
+
+[[package]]
+name = "atomic_refcell"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d"
+
+[[package]]
+name = "autocfg"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "block"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
+
+[[package]]
+name = "block-sys"
+version = "0.1.0-beta.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa55741ee90902547802152aaf3f8e5248aab7e21468089560d4c8840561146"
+dependencies = [
+ "objc-sys",
+]
+
+[[package]]
+name = "block2"
+version = "0.2.0-alpha.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8dd9e63c1744f755c2f60332b88de39d341e5e86239014ad839bd71c106dec42"
+dependencies = [
+ "block-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
+
+[[package]]
+name = "bytemuck"
+version = "1.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aaa3a8d9a1ca92e282c96a32d6511b695d7d994d1d102ba85d279f9b2756947f"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5fe233b960f12f8007e3db2d136e3cb1c291bfd7396e384ee76025fc1a3932b4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "bytes"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
+
+[[package]]
+name = "calloop"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19457a0da465234abd76134a5c2a910c14bd3c5558463e4396ab9a37a328e465"
+dependencies = [
+ "log",
+ "nix 0.25.1",
+ "slotmap",
+ "thiserror",
+ "vec_map",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.77"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
+
+[[package]]
+name = "cesu8"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "cgl"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "clipboard-win"
+version = "4.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4ab1b92798304eedc095b53942963240037c0516452cb11aeba709d420b2219"
+dependencies = [
+ "error-code",
+ "str-buf",
+ "winapi",
+]
+
+[[package]]
+name = "cmake"
+version = "0.1.49"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c"
+dependencies = [
+ "cc",
+]
+
+[[package]]
+name = "cocoa"
+version = "0.24.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f425db7937052c684daec3bd6375c8abe2d146dca4b8b143d6db777c39138f3a"
+dependencies = [
+ "bitflags",
+ "block",
+ "cocoa-foundation",
+ "core-foundation",
+ "core-graphics",
+ "foreign-types 0.3.2",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "cocoa-foundation"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
+dependencies = [
+ "bitflags",
+ "block",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types 0.3.2",
+ "libc",
+ "objc",
+]
+
+[[package]]
+name = "combine"
+version = "4.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
+dependencies = [
+ "bytes",
+ "memchr",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "core-foundation"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
+[[package]]
+name = "core-foundation-sys"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
+
+[[package]]
+name = "core-graphics"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "core-graphics-types",
+ "foreign-types 0.3.2",
+ "libc",
+]
+
+[[package]]
+name = "core-graphics-types"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
+dependencies = [
+ "bitflags",
+ "core-foundation",
+ "foreign-types 0.3.2",
+ "libc",
+]
+
+[[package]]
+name = "core-text"
+version = "19.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "99d74ada66e07c1cefa18f8abfba765b486f250de2e4a999e5727fc0dd4b4a25"
+dependencies = [
+ "core-foundation",
+ "core-graphics",
+ "foreign-types 0.3.2",
+ "libc",
+]
+
+[[package]]
+name = "crc32fast"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "crossfont"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "21fd3add36ea31aba1520aa5288714dd63be506106753226d0eb387a93bc9c45"
+dependencies = [
+ "cocoa",
+ "core-foundation",
+ "core-foundation-sys",
+ "core-graphics",
+ "core-text",
+ "dwrote",
+ "foreign-types 0.5.0",
+ "freetype-rs",
+ "libc",
+ "log",
+ "objc",
+ "once_cell",
+ "pkg-config",
+ "servo-fontconfig",
+ "winapi",
+]
+
+[[package]]
+name = "cty"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35"
+
+[[package]]
+name = "darling"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
+dependencies = [
+ "darling_core 0.13.4",
+ "darling_macro 0.13.4",
+]
+
+[[package]]
+name = "darling"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0dd3cd20dc6b5a876612a6e5accfe7f3dd883db6d07acfbf14c128f61550dfa"
+dependencies = [
+ "darling_core 0.14.2",
+ "darling_macro 0.14.2",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a784d2ccaf7c98501746bf0be29b2022ba41fd62a2e622af997a03e9f972859f"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.13.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
+dependencies = [
+ "darling_core 0.13.4",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.14.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7618812407e9402654622dd402b0a89dff9ba93badd6540781526117b92aab7e"
+dependencies = [
+ "darling_core 0.14.2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "dispatch"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b"
+
+[[package]]
+name = "dlib"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794"
+dependencies = [
+ "libloading",
+]
+
+[[package]]
+name = "downcast-rs"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
+
+[[package]]
+name = "dwrote"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "439a1c2ba5611ad3ed731280541d36d2e9c4ac5e7fb818a27b604bdc5a6aa65b"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "serde",
+ "serde_derive",
+ "winapi",
+ "wio",
+]
+
+[[package]]
+name = "ecolor"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b601108bca3af7650440ace4ca55b2daf52c36f2635be3587d77b16efd8d0691"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "eframe"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea929ec5819fef373728bb0e55003ce921975039cfec3ca8305bb024e5b7b32"
+dependencies = [
+ "bytemuck",
+ "egui",
+ "egui-winit",
+ "egui_glow",
+ "glow",
+ "glutin",
+ "js-sys",
+ "percent-encoding",
+ "raw-window-handle 0.5.0",
+ "tracing",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+ "winit",
+]
+
+[[package]]
+name = "egui"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "65a5e883a316e53866977450eecfbcac9c48109c2ab3394af29feb83fcde4ea9"
+dependencies = [
+ "accesskit",
+ "ahash",
+ "epaint",
+ "nohash-hasher",
+ "tracing",
+]
+
+[[package]]
+name = "egui-winit"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5696bdbe60898b81157f07ae34fe02dbfd522174bd6e620942c269cd7307901f"
+dependencies = [
+ "accesskit_winit",
+ "arboard",
+ "egui",
+ "instant",
+ "smithay-clipboard",
+ "tracing",
+ "webbrowser",
+ "winit",
+]
+
+[[package]]
+name = "egui_glow"
+version = "0.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d4b5960cb1bae1c403a6c9027a745210a41913433b10c73b6e7d76a1017f8b4"
+dependencies = [
+ "bytemuck",
+ "egui",
+ "glow",
+ "memoffset",
+ "tracing",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "emath"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5277249c8c3430e7127e4f2c40a77485e7baf11ae132ce9b3253a8ed710df0a0"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "enumset"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19be8061a06ab6f3a6cf21106c873578bf01bd42ad15e0311a9c76161cb1c753"
+dependencies = [
+ "enumset_derive",
+]
+
+[[package]]
+name = "enumset_derive"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03e7b551eba279bf0fa88b83a46330168c1560a52a94f5126f892f0b364ab3e0"
+dependencies = [
+ "darling 0.14.2",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "epaint"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de14b65fe5e423e0058f77a8beb2c863b056d0566d6c4ce0d097aa5814cb705a"
+dependencies = [
+ "ab_glyph",
+ "ahash",
+ "atomic_refcell",
+ "bytemuck",
+ "ecolor",
+ "emath",
+ "nohash-hasher",
+ "parking_lot",
+]
+
+[[package]]
+name = "error-code"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64f18991e7bf11e7ffee451b5318b5c1a73c52d0d0ada6e5a3017c8c1ced6a21"
+dependencies = [
+ "libc",
+ "str-buf",
+]
+
+[[package]]
+name = "expat-sys"
+version = "2.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "658f19728920138342f68408b7cf7644d90d4784353d8ebc32e7e8663dbe45fa"
+dependencies = [
+ "cmake",
+ "pkg-config",
+]
+
+[[package]]
+name = "flate2"
+version = "1.0.25"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
+dependencies = [
+ "crc32fast",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "foreign-types"
+version = "0.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
+dependencies = [
+ "foreign-types-shared 0.1.1",
+]
+
+[[package]]
+name = "foreign-types"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965"
+dependencies = [
+ "foreign-types-macros",
+ "foreign-types-shared 0.3.1",
+]
+
+[[package]]
+name = "foreign-types-macros"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
+
+[[package]]
+name = "foreign-types-shared"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "freetype-rs"
+version = "0.26.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74eadec9d0a5c28c54bb9882e54787275152a4e36ce206b45d7451384e5bf5fb"
+dependencies = [
+ "bitflags",
+ "freetype-sys",
+ "libc",
+]
+
+[[package]]
+name = "freetype-sys"
+version = "0.13.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a37d4011c0cc628dfa766fcc195454f4b068d7afdc2adfd28861191d866e731a"
+dependencies = [
+ "cmake",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "gethostname"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e"
+dependencies = [
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "gl_generator"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d"
+dependencies = [
+ "khronos_api",
+ "log",
+ "xml-rs",
+]
+
+[[package]]
+name = "glow"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8bd5877156a19b8ac83a29b2306fe20537429d318f3ff0a1a2119f8d9c61919"
+dependencies = [
+ "js-sys",
+ "slotmap",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "glutin"
+version = "0.30.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "524d807cd49a0c56a53ef9a6738cd15e7c8c4e9d37a3b7fdb3c250c1cd5bf7a3"
+dependencies = [
+ "bitflags",
+ "cfg_aliases",
+ "cgl",
+ "cocoa",
+ "core-foundation",
+ "glutin_egl_sys",
+ "glutin_glx_sys",
+ "glutin_wgl_sys",
+ "libloading",
+ "objc",
+ "once_cell",
+ "raw-window-handle 0.5.0",
+ "wayland-sys 0.30.1",
+ "windows-sys 0.36.1",
+ "x11-dl",
+]
+
+[[package]]
+name = "glutin_egl_sys"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3adbb8fec0e18e340f990c78f79f5f0e142d0d83f46b10909aaa7d251c00afdf"
+dependencies = [
+ "gl_generator",
+ "windows-sys 0.36.1",
+]
+
+[[package]]
+name = "glutin_glx_sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "947c4850c58211c9627969c2b4e2674764b81ae5b47bab2c9a477d7942f96e0f"
+dependencies = [
+ "gl_generator",
+ "x11-dl",
+]
+
+[[package]]
+name = "glutin_wgl_sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "20c33975a6c9d49d72c8f032a60079bf8df536954fbf9e4cee90396ace815c57"
+dependencies = [
+ "gl_generator",
+]
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "idna"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+]
+
+[[package]]
+name = "instant"
+version = "0.1.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "jni"
+version = "0.20.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
+dependencies = [
+ "cesu8",
+ "combine",
+ "jni-sys",
+ "log",
+ "thiserror",
+ "walkdir",
+]
+
+[[package]]
+name = "jni-sys"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
+
+[[package]]
+name = "js-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "khronos_api"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc"
+
+[[package]]
+name = "kurbo"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449"
+dependencies = [
+ "arrayvec 0.7.2",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.138"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
+
+[[package]]
+name = "libloading"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+dependencies = [
+ "cfg-if",
+ "winapi",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
+dependencies = [
+ "cfg-if",
+]
+
+[[package]]
+name = "malloc_buf"
+version = "0.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memchr"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+
+[[package]]
+name = "memmap2"
+version = "0.5.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "minimal-lexical"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
+
+[[package]]
+name = "miniz_oxide"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+dependencies = [
+ "adler",
+]
+
+[[package]]
+name = "mio"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
+dependencies = [
+ "libc",
+ "log",
+ "wasi",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "ndk"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
+dependencies = [
+ "bitflags",
+ "jni-sys",
+ "ndk-sys",
+ "num_enum",
+ "raw-window-handle 0.5.0",
+ "thiserror",
+]
+
+[[package]]
+name = "ndk-context"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
+
+[[package]]
+name = "ndk-glue"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0434fabdd2c15e0aab768ca31d5b7b333717f03cf02037d5a0a3ff3c278ed67f"
+dependencies = [
+ "libc",
+ "log",
+ "ndk",
+ "ndk-context",
+ "ndk-macro",
+ "ndk-sys",
+ "once_cell",
+ "parking_lot",
+]
+
+[[package]]
+name = "ndk-macro"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0df7ac00c4672f9d5aece54ee3347520b7e20f158656c7db2e6de01902eb7a6c"
+dependencies = [
+ "darling 0.13.4",
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "ndk-sys"
+version = "0.4.1+23.1.7779620"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3"
+dependencies = [
+ "jni-sys",
+]
+
+[[package]]
+name = "nix"
+version = "0.24.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069"
+dependencies = [
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "nix"
+version = "0.25.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
+dependencies = [
+ "autocfg",
+ "bitflags",
+ "cfg-if",
+ "libc",
+ "memoffset",
+]
+
+[[package]]
+name = "nohash-hasher"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451"
+
+[[package]]
+name = "nom"
+version = "7.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36"
+dependencies = [
+ "memchr",
+ "minimal-lexical",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.5.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "objc"
+version = "0.2.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
+dependencies = [
+ "malloc_buf",
+]
+
+[[package]]
+name = "objc-foundation"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
+dependencies = [
+ "block",
+ "objc",
+ "objc_id",
+]
+
+[[package]]
+name = "objc-sys"
+version = "0.2.0-beta.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df3b9834c1e95694a05a828b59f55fa2afec6288359cda67146126b3f90a55d7"
+
+[[package]]
+name = "objc2"
+version = "0.3.0-beta.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe31e5425d3d0b89a15982c024392815da40689aceb34bad364d58732bcfd649"
+dependencies = [
+ "block2",
+ "objc-sys",
+ "objc2-encode",
+]
+
+[[package]]
+name = "objc2-encode"
+version = "2.0.0-pre.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "abfcac41015b00a120608fdaa6938c44cb983fee294351cc4bac7638b4e50512"
+dependencies = [
+ "objc-sys",
+]
+
+[[package]]
+name = "objc_id"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
+dependencies = [
+ "objc",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
+
+[[package]]
+name = "owned_ttf_parser"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "18904d3c65493a9f0d7542293d1a7f69bfdc309a6b9ef4f46dc3e58b0577edc5"
+dependencies = [
+ "ttf-parser",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf1c2c742266c2f1041c914ba65355a83ae8747b05f208319784083583494b4b"
+
+[[package]]
+name = "percent-encoding"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
+[[package]]
+name = "pkg-config"
+version = "0.3.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
+
+[[package]]
+name = "png"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638"
+dependencies = [
+ "bitflags",
+ "crc32fast",
+ "flate2",
+ "miniz_oxide",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
+dependencies = [
+ "once_cell",
+ "thiserror",
+ "toml",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.47"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quick-start-simple"
+version = "0.1.0"
+dependencies = [
+ "bumpalo",
+ "console_error_panic_hook",
+ "eframe",
+ "egui",
+ "nom",
+ "wasm-bindgen-futures",
+ "wasm-rs-dbg",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b800beb9b6e7d2df1fe337c9e3d04e3af22a124460fb4c30fcc22c9117cefb41"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "raw-window-handle"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a"
+dependencies = [
+ "cty",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.2.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "safe_arch"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c1ff3d6d9696af502cc3110dacce942840fb06ff4514cad92236ecc455f2ce05"
+dependencies = [
+ "bytemuck",
+]
+
+[[package]]
+name = "same-file"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "scoped-tls"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+
+[[package]]
+name = "scopeguard"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
+
+[[package]]
+name = "sctk-adwaita"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61270629cc6b4d77ec1907db1033d5c2e1a404c412743621981a871dc9c12339"
+dependencies = [
+ "crossfont",
+ "log",
+ "smithay-client-toolkit",
+ "tiny-skia",
+]
+
+[[package]]
+name = "serde"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e326c9ec8042f1b5da33252c8a37e9ffbd2c9bef0155215b6e6c80c790e05f91"
+
+[[package]]
+name = "serde_derive"
+version = "1.0.150"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42a3df25b0713732468deadad63ab9da1f1fd75a48a15024b50363f128db627e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "servo-fontconfig"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c7e3e22fe5fd73d04ebf0daa049d3efe3eae55369ce38ab16d07ddd9ac5c217c"
+dependencies = [
+ "libc",
+ "servo-fontconfig-sys",
+]
+
+[[package]]
+name = "servo-fontconfig-sys"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e36b879db9892dfa40f95da1c38a835d41634b825fbd8c4c418093d53c24b388"
+dependencies = [
+ "expat-sys",
+ "freetype-sys",
+ "pkg-config",
+]
+
+[[package]]
+name = "slotmap"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e1e08e261d0e8f5c43123b7adf3e4ca1690d655377ac93a03b2c9d3e98de1342"
+dependencies = [
+ "version_check",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
+name = "smithay-client-toolkit"
+version = "0.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f307c47d32d2715eb2e0ece5589057820e0e5e70d07c247d1063e844e107f454"
+dependencies = [
+ "bitflags",
+ "calloop",
+ "dlib",
+ "lazy_static",
+ "log",
+ "memmap2",
+ "nix 0.24.3",
+ "pkg-config",
+ "wayland-client",
+ "wayland-cursor",
+ "wayland-protocols",
+]
+
+[[package]]
+name = "smithay-clipboard"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0a345c870a1fae0b1b779085e81b51e614767c239e93503588e54c5b17f4b0e8"
+dependencies = [
+ "smithay-client-toolkit",
+ "wayland-client",
+]
+
+[[package]]
+name = "str-buf"
+version = "1.0.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0"
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "syn"
+version = "1.0.105"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tiny-skia"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "642680569bb895b16e4b9d181c60be1ed136fa0c9c7f11d004daf053ba89bf82"
+dependencies = [
+ "arrayref",
+ "arrayvec 0.5.2",
+ "bytemuck",
+ "cfg-if",
+ "png",
+ "safe_arch",
+ "tiny-skia-path",
+]
+
+[[package]]
+name = "tiny-skia-path"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c114d32f0c2ee43d585367cb013dfaba967ab9f62b90d9af0d696e955e70fa6c"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
+
+[[package]]
+name = "toml"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1333c76748e868a4d9d1017b5ab53171dfd095f70c712fdb4653a406547f598f"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "tracing"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+dependencies = [
+ "cfg-if",
+ "pin-project-lite",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
+dependencies = [
+ "once_cell",
+]
+
+[[package]]
+name = "ttf-parser"
+version = "0.17.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "375812fa44dab6df41c195cd2f7fecb488f6c09fbaafb62807488cefab642bff"
+
+[[package]]
+name = "unicode-bidi"
+version = "0.3.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "url"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
+dependencies = [
+ "form_urlencoded",
+ "idna",
+ "percent-encoding",
+]
+
+[[package]]
+name = "vec_map"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "walkdir"
+version = "2.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+dependencies = [
+ "same-file",
+ "winapi",
+ "winapi-util",
+]
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-futures"
+version = "0.4.33"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.83"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f"
+
+[[package]]
+name = "wasm-rs-dbg"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61e5fe4ac478ca5cf1db842029f41a5881da39e70320deb0006912f226ea63f4"
+dependencies = [
+ "web-sys",
+]
+
+[[package]]
+name = "wayland-client"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f3b068c05a039c9f755f881dc50f01732214f5685e379829759088967c46715"
+dependencies = [
+ "bitflags",
+ "downcast-rs",
+ "libc",
+ "nix 0.24.3",
+ "scoped-tls",
+ "wayland-commons",
+ "wayland-scanner",
+ "wayland-sys 0.29.5",
+]
+
+[[package]]
+name = "wayland-commons"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8691f134d584a33a6606d9d717b95c4fa20065605f798a3f350d78dced02a902"
+dependencies = [
+ "nix 0.24.3",
+ "once_cell",
+ "smallvec",
+ "wayland-sys 0.29.5",
+]
+
+[[package]]
+name = "wayland-cursor"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6865c6b66f13d6257bef1cd40cbfe8ef2f150fb8ebbdb1e8e873455931377661"
+dependencies = [
+ "nix 0.24.3",
+ "wayland-client",
+ "xcursor",
+]
+
+[[package]]
+name = "wayland-protocols"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b950621f9354b322ee817a23474e479b34be96c2e909c14f7bc0100e9a970bc6"
+dependencies = [
+ "bitflags",
+ "wayland-client",
+ "wayland-commons",
+ "wayland-scanner",
+]
+
+[[package]]
+name = "wayland-scanner"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f4303d8fa22ab852f789e75a967f0a2cdc430a607751c0499bada3e451cbd53"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "xml-rs",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.29.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be12ce1a3c39ec7dba25594b97b42cb3195d54953ddb9d3d95a7c3902bc6e9d4"
+dependencies = [
+ "dlib",
+ "lazy_static",
+ "pkg-config",
+]
+
+[[package]]
+name = "wayland-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96b2a02ac608e07132978689a6f9bf4214949c85998c247abadd4f4129b1aa06"
+dependencies = [
+ "dlib",
+ "lazy_static",
+ "log",
+ "pkg-config",
+]
+
+[[package]]
+name = "web-sys"
+version = "0.3.60"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "webbrowser"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a0cc7962b5aaa0dfcebaeef0161eec6edf5f4606c12e6777fd7d392f52033a5"
+dependencies = [
+ "jni",
+ "ndk-context",
+ "objc",
+ "raw-window-handle 0.5.0",
+ "url",
+ "web-sys",
+ "widestring",
+ "winapi",
+]
+
+[[package]]
+name = "widestring"
+version = "1.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "653f141f39ec16bba3c5abe400a0c60da7468261cc2cbf36805022876bc721a8"
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-wsapoll"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44c17110f57155602a80dca10be03852116403c9ff3cd25b079d666f2aa3df6e"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0286ba339aa753e70765d521bb0242cc48e1194562bfa2a2ad7ac8a6de28f5d5"
+dependencies = [
+ "windows-implement",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
+]
+
+[[package]]
+name = "windows-implement"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9539b6bd3eadbd9de66c9666b22d802b833da7e996bc06896142e09854a61767"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
+dependencies = [
+ "windows_aarch64_msvc 0.36.1",
+ "windows_i686_gnu 0.36.1",
+ "windows_i686_msvc 0.36.1",
+ "windows_x86_64_gnu 0.36.1",
+ "windows_x86_64_msvc 0.36.1",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.36.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
+[[package]]
+name = "winit"
+version = "0.27.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb796d6fbd86b2fd896c9471e6f04d39d750076ebe5680a3958f00f5ab97657c"
+dependencies = [
+ "bitflags",
+ "cocoa",
+ "core-foundation",
+ "core-graphics",
+ "dispatch",
+ "instant",
+ "libc",
+ "log",
+ "mio",
+ "ndk",
+ "ndk-glue",
+ "objc",
+ "once_cell",
+ "parking_lot",
+ "percent-encoding",
+ "raw-window-handle 0.4.3",
+ "raw-window-handle 0.5.0",
+ "sctk-adwaita",
+ "smithay-client-toolkit",
+ "wasm-bindgen",
+ "wayland-client",
+ "wayland-protocols",
+ "web-sys",
+ "windows-sys 0.36.1",
+ "x11-dl",
+]
+
+[[package]]
+name = "wio"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "x11-dl"
+version = "2.20.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1536d6965a5d4e573c7ef73a2c15ebcd0b2de3347bdf526c34c297c00ac40f0"
+dependencies = [
+ "lazy_static",
+ "libc",
+ "pkg-config",
+]
+
+[[package]]
+name = "x11rb"
+version = "0.10.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "592b4883219f345e712b3209c62654ebda0bb50887f330cbd018d0f654bfd507"
+dependencies = [
+ "gethostname",
+ "nix 0.24.3",
+ "winapi",
+ "winapi-wsapoll",
+ "x11rb-protocol",
+]
+
+[[package]]
+name = "x11rb-protocol"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56b245751c0ac9db0e006dc812031482784e434630205a93c73cfefcaabeac67"
+dependencies = [
+ "nix 0.24.3",
+]
+
+[[package]]
+name = "xcursor"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "463705a63313cd4301184381c5e8042f0a7e9b4bb63653f216311d4ae74690b7"
+dependencies = [
+ "nom",
+]
+
+[[package]]
+name = "xml-rs"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3"
diff --git a/2022/Cargo.toml b/2022/Cargo.toml
new file mode 100644
index 0000000..3f1332d
--- /dev/null
+++ b/2022/Cargo.toml
@@ -0,0 +1,71 @@
+[package]
+name = "quick-start-simple"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bumpalo = "^3"
+nom = "^7"
+egui = "^0.20"
+eframe = "^0.20"
+wasm-bindgen-futures = "^0.4"
+console_error_panic_hook = "^0.1"
+wasm-rs-dbg = "0.1.2"
+
+[[bin]]
+name = "day1"
+path = "src/day01.rs"
+
+[[bin]]
+name = "day2"
+path = "src/day02.rs"
+
+[[bin]]
+name = "day3"
+path = "src/day03.rs"
+
+[[bin]]
+name = "day4"
+path = "src/day04.rs"
+
+[[bin]]
+name = "day5"
+path = "src/day05.rs"
+
+[[bin]]
+name = "day6"
+path = "src/day06.rs"
+
+[[bin]]
+name = "day7"
+path = "src/day07.rs"
+
+[[bin]]
+name = "day8"
+path = "src/day08.rs"
+
+[[bin]]
+name = "day9"
+path = "src/day09.rs"
+
+[[bin]]
+name = "day10"
+path = "src/day10.rs"
+
+[[bin]]
+name = "day11"
+path = "src/day11.rs"
+
+[[bin]]
+name = "day12"
+path = "src/day12.rs"
+
+[[bin]]
+name = "day13"
+path = "src/day13.rs"
+
+[[bin]]
+name = "day14"
+path = "src/day14.rs" \ No newline at end of file
diff --git a/2022/fake_inputs/day14 b/2022/fake_inputs/day14
new file mode 100644
index 0000000..436b23f
--- /dev/null
+++ b/2022/fake_inputs/day14
@@ -0,0 +1,148 @@
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+502,32 -> 507,32
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+516,32 -> 521,32
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+512,30 -> 517,30
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+506,34 -> 511,34
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+512,173 -> 517,173
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+545,94 -> 550,94
+539,100 -> 544,100
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+553,100 -> 558,100
+501,170 -> 506,170
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+546,100 -> 551,100
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+542,97 -> 547,97
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+535,97 -> 540,97
+533,108 -> 533,109 -> 538,109 -> 538,108
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+509,32 -> 514,32
+513,34 -> 518,34
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+507,164 -> 512,164
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+557,103 -> 562,103
+538,94 -> 543,94
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+501,28 -> 506,28
+505,173 -> 510,173
+531,87 -> 531,88 -> 543,88
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+524,126 -> 524,127 -> 528,127 -> 528,126
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+508,28 -> 513,28
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+511,167 -> 516,167
+549,97 -> 554,97
+541,91 -> 546,91
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+520,34 -> 525,34
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+505,30 -> 510,30
+543,103 -> 548,103
+510,146 -> 515,146
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+498,173 -> 503,173
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+498,13 -> 498,15 -> 492,15 -> 492,23 -> 506,23 -> 506,15 -> 501,15 -> 501,13
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+533,108 -> 533,109 -> 538,109 -> 538,108
+517,146 -> 522,146
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+513,144 -> 518,144
+515,170 -> 520,170
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+519,173 -> 524,173
+532,100 -> 537,100
+524,126 -> 524,127 -> 528,127 -> 528,126
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+521,148 -> 526,148
+504,167 -> 509,167
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+520,130 -> 520,133 -> 515,133 -> 515,138 -> 533,138 -> 533,133 -> 525,133 -> 525,130
+514,148 -> 519,148
+510,141 -> 515,141
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+533,108 -> 533,109 -> 538,109 -> 538,108
+524,126 -> 524,127 -> 528,127 -> 528,126
+550,103 -> 555,103
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+529,103 -> 534,103
+504,26 -> 509,26
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+508,170 -> 513,170
+523,63 -> 523,66 -> 515,66 -> 515,71 -> 529,71 -> 529,66 -> 528,66 -> 528,63
+499,34 -> 504,34
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112
+495,32 -> 500,32
+507,148 -> 512,148
+515,60 -> 515,52 -> 515,60 -> 517,60 -> 517,55 -> 517,60 -> 519,60 -> 519,50 -> 519,60 -> 521,60 -> 521,56 -> 521,60 -> 523,60 -> 523,53 -> 523,60 -> 525,60 -> 525,53 -> 525,60
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+531,87 -> 531,88 -> 543,88
+536,103 -> 541,103
+501,161 -> 501,152 -> 501,161 -> 503,161 -> 503,157 -> 503,161 -> 505,161 -> 505,155 -> 505,161 -> 507,161 -> 507,154 -> 507,161 -> 509,161 -> 509,155 -> 509,161
+522,84 -> 522,76 -> 522,84 -> 524,84 -> 524,75 -> 524,84 -> 526,84 -> 526,81 -> 526,84 -> 528,84 -> 528,74 -> 528,84 -> 530,84 -> 530,79 -> 530,84 -> 532,84 -> 532,77 -> 532,84 -> 534,84 -> 534,78 -> 534,84 -> 536,84 -> 536,80 -> 536,84
+522,47 -> 522,43 -> 522,47 -> 524,47 -> 524,41 -> 524,47 -> 526,47 -> 526,39 -> 526,47 -> 528,47 -> 528,39 -> 528,47
+498,30 -> 503,30
+492,34 -> 497,34
+529,112 -> 529,116 -> 526,116 -> 526,122 -> 541,122 -> 541,116 -> 535,116 -> 535,112 \ No newline at end of file
diff --git a/2022/fake_inputs/day9 b/2022/fake_inputs/day9
new file mode 100644
index 0000000..27249a2
--- /dev/null
+++ b/2022/fake_inputs/day9
@@ -0,0 +1,2000 @@
+D 17
+D 5
+R 2
+R 2
+U 9
+U 8
+L 7
+R 4
+D 1
+D 7
+U 1
+R 10
+U 15
+D 5
+U 9
+L 9
+R 2
+D 2
+D 2
+D 2
+U 1
+R 9
+L 4
+L 9
+D 1
+D 2
+D 2
+U 11
+R 7
+R 5
+D 2
+R 5
+U 2
+R 6
+L 8
+L 10
+L 3
+D 5
+U 8
+L 3
+L 7
+D 4
+D 1
+D 4
+D 4
+U 14
+R 1
+U 7
+L 4
+R 3
+D 8
+L 4
+D 4
+R 7
+D 7
+R 6
+U 8
+R 2
+R 5
+L 2
+R 12
+U 13
+D 4
+L 3
+R 2
+U 9
+L 7
+R 5
+D 3
+L 8
+D 5
+U 11
+U 6
+U 3
+U 5
+R 10
+U 2
+R 1
+D 2
+R 3
+U 4
+R 14
+R 1
+L 15
+D 1
+D 1
+D 7
+L 6
+L 6
+D 2
+U 1
+U 3
+R 11
+R 11
+L 1
+L 8
+L 13
+U 4
+R 11
+L 1
+D 1
+U 6
+L 1
+U 3
+R 15
+L 2
+U 1
+L 3
+L 8
+U 1
+R 11
+D 1
+D 1
+U 1
+R 2
+R 11
+R 7
+U 10
+L 1
+U 3
+D 9
+D 1
+L 11
+U 5
+L 4
+D 1
+U 4
+R 2
+L 3
+L 19
+U 4
+D 13
+D 11
+L 6
+U 10
+U 8
+R 2
+L 4
+U 2
+R 9
+U 15
+L 5
+R 10
+U 5
+R 8
+L 2
+R 6
+D 3
+L 4
+L 7
+U 10
+L 3
+R 4
+D 8
+R 3
+R 8
+D 16
+R 5
+L 5
+D 5
+R 11
+L 5
+L 5
+L 1
+U 6
+U 12
+U 17
+L 4
+L 12
+L 6
+L 9
+L 12
+D 15
+L 2
+D 10
+L 3
+U 1
+U 5
+L 4
+L 3
+L 4
+U 1
+R 2
+U 16
+L 3
+D 10
+U 2
+D 12
+L 12
+U 13
+D 4
+R 9
+U 6
+U 14
+U 3
+D 3
+R 2
+D 10
+U 2
+U 1
+U 8
+L 15
+U 9
+L 6
+D 1
+D 1
+L 4
+R 5
+R 7
+D 4
+R 1
+D 6
+D 10
+U 1
+R 4
+R 9
+L 17
+L 4
+R 1
+D 7
+L 5
+R 2
+U 13
+U 3
+R 5
+U 14
+D 3
+L 15
+U 17
+D 1
+R 7
+R 10
+R 1
+R 1
+U 11
+L 3
+R 13
+D 5
+D 1
+L 6
+L 17
+D 1
+L 2
+D 10
+L 12
+U 9
+L 3
+L 7
+U 3
+U 3
+D 3
+R 5
+D 12
+R 10
+D 6
+U 7
+R 1
+U 4
+R 2
+U 4
+U 12
+U 3
+L 1
+R 4
+R 1
+L 2
+D 5
+D 7
+L 3
+U 1
+D 5
+D 12
+R 1
+D 6
+L 11
+U 9
+U 15
+D 2
+D 5
+U 1
+R 5
+D 3
+R 2
+D 10
+U 13
+R 15
+U 3
+R 2
+D 6
+U 2
+U 13
+R 6
+R 6
+L 5
+U 6
+R 6
+U 3
+U 4
+R 7
+D 5
+L 2
+R 2
+D 1
+D 8
+U 2
+R 9
+D 8
+D 6
+U 1
+R 1
+R 2
+L 2
+L 1
+R 2
+R 17
+R 6
+U 7
+R 4
+D 11
+D 3
+R 3
+D 8
+U 13
+R 1
+U 9
+U 17
+U 3
+D 6
+D 1
+D 4
+R 1
+D 7
+L 3
+L 12
+L 6
+D 2
+R 1
+D 15
+D 2
+U 2
+L 5
+R 5
+L 16
+R 2
+L 3
+U 1
+D 15
+R 15
+R 8
+R 1
+D 5
+L 8
+D 12
+R 3
+L 5
+L 5
+U 6
+L 12
+U 4
+L 1
+U 10
+U 6
+U 2
+D 3
+D 4
+D 3
+U 11
+L 5
+D 1
+L 15
+L 10
+L 2
+L 4
+R 8
+U 5
+D 7
+U 10
+D 6
+R 9
+R 6
+L 3
+D 3
+U 8
+D 6
+R 15
+D 3
+U 6
+L 2
+R 4
+U 2
+U 4
+D 4
+D 11
+L 7
+D 7
+U 3
+U 6
+U 3
+D 7
+R 2
+L 1
+R 13
+R 12
+R 1
+U 3
+R 14
+L 2
+R 6
+D 2
+L 2
+L 5
+D 2
+R 7
+R 12
+L 3
+U 5
+U 1
+U 4
+L 3
+D 11
+L 4
+D 6
+D 6
+U 4
+U 4
+D 2
+U 16
+R 3
+D 9
+L 6
+U 1
+U 13
+D 2
+U 2
+D 4
+U 3
+D 2
+L 7
+R 1
+L 2
+R 12
+U 1
+L 1
+D 1
+U 11
+U 5
+L 4
+L 11
+R 10
+L 14
+R 1
+U 2
+D 2
+D 11
+D 3
+D 14
+D 10
+D 2
+U 13
+L 2
+L 4
+D 4
+L 6
+L 6
+R 4
+R 1
+L 5
+D 12
+R 18
+D 4
+D 6
+U 5
+U 2
+R 11
+U 3
+U 5
+R 9
+R 2
+U 2
+R 4
+L 6
+D 4
+D 2
+D 4
+D 2
+D 6
+R 9
+D 1
+D 3
+R 5
+D 7
+L 12
+R 5
+R 1
+U 11
+U 14
+L 6
+L 10
+L 4
+R 4
+L 2
+U 4
+L 4
+U 5
+R 3
+D 4
+U 5
+R 9
+L 7
+D 15
+U 15
+R 2
+R 3
+U 5
+U 3
+D 2
+D 6
+U 7
+R 10
+L 1
+U 2
+L 4
+R 6
+U 6
+L 3
+L 3
+L 1
+R 1
+R 2
+L 7
+D 5
+L 7
+R 2
+R 4
+L 8
+D 1
+L 3
+U 8
+L 10
+D 8
+D 12
+D 2
+U 6
+L 4
+L 2
+D 5
+D 5
+R 6
+R 8
+D 1
+D 1
+R 1
+U 3
+L 7
+L 8
+D 5
+L 3
+D 3
+R 4
+D 4
+U 1
+R 3
+R 2
+D 10
+L 13
+D 2
+D 1
+R 1
+L 3
+L 6
+R 5
+U 6
+D 1
+U 2
+D 3
+L 2
+D 4
+L 7
+R 12
+U 4
+D 10
+L 5
+L 4
+U 19
+L 2
+L 3
+R 3
+U 5
+U 4
+L 1
+R 9
+D 9
+R 11
+R 3
+R 12
+R 8
+D 1
+R 4
+L 16
+R 4
+U 2
+R 2
+L 1
+L 6
+U 6
+U 3
+U 1
+L 5
+R 13
+U 3
+L 1
+U 6
+U 4
+D 6
+L 14
+L 11
+U 2
+U 10
+D 5
+L 2
+R 2
+U 2
+L 2
+L 2
+R 4
+D 7
+U 1
+R 10
+L 10
+U 1
+D 5
+R 3
+L 8
+L 5
+L 5
+L 6
+U 5
+D 10
+L 4
+U 1
+D 5
+L 3
+D 4
+D 14
+L 2
+R 7
+R 18
+D 2
+U 18
+U 8
+L 3
+D 7
+D 4
+L 14
+L 3
+D 6
+L 13
+R 4
+L 13
+L 4
+L 12
+R 3
+L 11
+D 11
+D 3
+R 8
+L 8
+U 13
+D 10
+D 1
+L 16
+L 5
+D 3
+R 12
+R 12
+L 5
+U 1
+L 8
+D 3
+R 5
+R 5
+D 1
+R 5
+L 3
+U 8
+L 5
+D 11
+R 2
+U 16
+D 4
+L 5
+L 15
+R 14
+D 1
+L 2
+D 1
+R 4
+L 1
+U 17
+R 5
+L 15
+R 8
+D 5
+D 8
+D 2
+R 3
+L 3
+U 2
+D 1
+R 6
+U 9
+D 4
+R 1
+D 1
+L 8
+U 10
+L 3
+R 2
+R 4
+D 3
+R 8
+L 4
+D 9
+D 11
+L 7
+R 2
+U 17
+D 3
+D 7
+L 6
+L 11
+R 12
+R 12
+D 8
+D 2
+L 12
+U 4
+R 13
+L 12
+L 4
+D 5
+R 11
+D 7
+U 2
+L 6
+U 3
+D 1
+R 13
+D 12
+U 6
+D 1
+U 1
+L 5
+U 1
+D 12
+R 15
+L 3
+U 15
+L 10
+U 2
+R 6
+L 2
+U 7
+R 9
+L 5
+U 5
+R 8
+R 3
+L 10
+U 10
+R 10
+L 17
+D 3
+U 5
+D 1
+L 4
+R 5
+L 2
+D 10
+L 11
+R 13
+D 1
+R 9
+R 9
+U 2
+L 7
+R 1
+D 3
+D 3
+U 4
+D 8
+L 4
+L 4
+D 5
+U 1
+U 6
+D 6
+R 1
+D 3
+L 8
+L 10
+L 4
+L 1
+D 8
+D 11
+U 5
+L 1
+U 3
+U 3
+L 4
+R 1
+D 10
+R 2
+R 3
+U 6
+L 13
+L 4
+R 6
+D 6
+L 2
+D 1
+U 7
+D 5
+U 17
+U 9
+L 1
+L 3
+D 18
+U 5
+D 18
+R 1
+D 13
+D 1
+U 2
+U 1
+U 3
+U 19
+D 4
+L 1
+U 7
+U 5
+R 2
+U 4
+D 14
+L 10
+L 2
+L 6
+R 6
+L 7
+L 3
+L 2
+L 2
+D 10
+U 16
+U 12
+L 2
+D 1
+R 6
+R 6
+R 7
+D 2
+L 8
+L 2
+L 1
+L 5
+U 3
+U 9
+R 5
+L 1
+D 3
+D 3
+L 7
+D 13
+D 16
+U 2
+R 1
+U 1
+R 2
+U 2
+U 2
+U 2
+R 11
+U 3
+L 12
+U 4
+D 3
+R 6
+D 2
+D 4
+D 4
+D 4
+U 2
+L 3
+D 1
+U 1
+R 7
+U 1
+R 4
+U 6
+R 14
+L 10
+R 8
+R 5
+D 4
+U 1
+R 11
+R 1
+D 11
+L 2
+U 16
+R 3
+R 1
+L 2
+U 4
+U 4
+U 1
+D 1
+L 9
+R 1
+D 1
+D 4
+L 7
+U 2
+L 2
+U 10
+L 7
+U 2
+U 15
+U 2
+U 5
+R 3
+U 2
+R 6
+U 6
+R 1
+D 2
+D 2
+R 13
+R 18
+U 2
+D 3
+L 2
+L 9
+D 10
+U 1
+U 11
+D 3
+R 6
+R 1
+U 2
+U 1
+U 12
+U 8
+D 13
+U 2
+D 12
+L 13
+D 1
+L 2
+D 4
+R 4
+L 5
+D 10
+R 4
+R 6
+R 1
+U 3
+R 5
+R 8
+D 9
+L 2
+U 1
+R 4
+R 2
+R 7
+L 9
+R 1
+D 3
+L 14
+R 1
+U 11
+L 2
+D 4
+U 19
+U 3
+L 6
+D 1
+R 3
+R 14
+D 6
+L 6
+R 16
+U 11
+L 2
+L 13
+U 2
+D 5
+U 8
+U 9
+R 14
+U 3
+L 14
+U 5
+L 9
+D 1
+R 8
+U 8
+U 13
+D 6
+R 18
+U 5
+L 14
+D 3
+R 5
+R 2
+L 2
+U 3
+R 4
+R 13
+R 8
+D 10
+U 5
+R 3
+R 5
+R 3
+R 9
+R 8
+D 16
+D 2
+R 8
+D 12
+D 3
+R 3
+L 4
+U 6
+L 3
+L 1
+L 10
+L 8
+R 3
+L 2
+U 6
+R 10
+D 12
+D 4
+R 9
+D 2
+D 2
+L 6
+R 9
+R 3
+L 4
+U 7
+R 16
+R 8
+U 3
+L 4
+U 2
+L 7
+D 5
+L 6
+R 1
+D 7
+D 4
+L 1
+L 12
+U 7
+L 4
+D 2
+L 5
+L 17
+R 5
+D 2
+L 2
+R 3
+L 2
+R 1
+D 7
+L 3
+L 13
+L 5
+D 11
+D 11
+D 3
+R 1
+R 5
+U 8
+D 11
+L 1
+L 2
+U 6
+D 2
+D 2
+R 8
+U 13
+U 1
+R 1
+R 4
+L 3
+R 4
+U 12
+U 1
+D 5
+D 15
+L 2
+U 5
+L 7
+U 1
+D 2
+L 7
+R 4
+U 8
+L 2
+U 3
+D 8
+R 15
+U 2
+D 8
+L 6
+L 8
+U 14
+D 3
+U 15
+L 4
+U 6
+L 1
+U 2
+D 7
+L 4
+L 12
+L 14
+L 10
+U 7
+L 10
+U 4
+R 3
+L 4
+D 1
+U 6
+U 4
+D 6
+L 4
+R 11
+L 4
+D 9
+R 2
+R 13
+R 3
+R 4
+R 5
+L 2
+L 4
+U 3
+U 1
+U 2
+U 3
+D 10
+D 1
+R 5
+D 9
+R 13
+R 1
+L 2
+L 5
+L 1
+L 6
+L 8
+U 2
+D 2
+D 8
+L 5
+D 7
+U 6
+R 10
+U 3
+L 15
+R 7
+L 12
+L 8
+U 1
+L 11
+U 1
+L 2
+D 7
+R 9
+D 14
+R 11
+U 7
+U 5
+R 3
+L 6
+R 15
+D 10
+U 2
+U 4
+L 5
+R 12
+L 6
+L 17
+U 4
+L 8
+L 6
+R 3
+R 3
+D 8
+R 3
+U 17
+L 1
+L 1
+R 4
+U 4
+L 12
+R 9
+D 9
+D 8
+D 4
+R 8
+R 5
+D 11
+D 7
+D 5
+R 1
+R 2
+R 2
+R 2
+L 3
+U 3
+D 12
+L 8
+D 5
+U 7
+D 5
+U 5
+R 1
+U 1
+D 2
+U 12
+D 1
+D 3
+L 8
+D 8
+L 5
+R 5
+R 1
+R 12
+R 2
+R 8
+R 1
+L 9
+D 5
+U 2
+L 11
+L 2
+R 4
+R 4
+L 11
+L 2
+U 8
+D 9
+U 7
+R 10
+U 1
+D 7
+R 11
+L 3
+D 4
+L 3
+U 11
+L 16
+U 4
+L 3
+U 17
+U 1
+U 6
+R 1
+D 4
+D 2
+R 5
+R 5
+U 2
+L 3
+D 7
+R 6
+L 1
+U 5
+L 4
+L 2
+R 4
+R 7
+R 3
+U 10
+U 1
+L 11
+L 3
+L 9
+L 7
+R 12
+U 6
+U 2
+L 3
+D 1
+L 5
+L 2
+R 1
+R 3
+D 4
+R 2
+U 7
+U 12
+U 1
+D 2
+U 1
+L 7
+U 15
+U 7
+U 3
+U 3
+D 6
+D 8
+U 6
+U 4
+U 6
+D 4
+U 6
+U 1
+R 9
+L 10
+L 2
+L 3
+D 16
+D 2
+L 3
+L 12
+L 7
+R 6
+L 2
+R 11
+U 2
+U 9
+R 3
+D 5
+R 3
+R 1
+R 1
+U 4
+D 4
+D 2
+U 9
+R 4
+R 11
+R 2
+L 2
+U 9
+L 8
+D 7
+L 6
+R 3
+L 4
+D 6
+D 4
+R 5
+R 4
+U 7
+L 4
+R 7
+L 6
+R 2
+D 15
+U 1
+D 18
+R 3
+L 5
+D 3
+L 1
+L 5
+D 1
+U 1
+R 4
+D 3
+R 1
+D 1
+D 1
+L 3
+R 1
+U 9
+U 3
+R 4
+L 3
+U 2
+D 13
+L 1
+R 4
+L 2
+U 7
+U 7
+U 6
+U 4
+R 4
+U 11
+L 3
+R 2
+D 6
+R 6
+R 8
+R 12
+R 8
+R 8
+R 1
+U 8
+R 4
+U 12
+L 9
+L 7
+U 6
+D 3
+R 8
+R 8
+R 2
+D 5
+D 17
+R 3
+R 4
+D 6
+R 1
+R 18
+R 15
+U 5
+R 2
+U 1
+D 5
+D 3
+R 6
+R 11
+L 1
+L 16
+R 3
+L 14
+L 7
+U 1
+D 10
+D 8
+L 3
+U 2
+R 7
+L 4
+R 8
+U 7
+U 2
+L 3
+D 1
+R 4
+D 1
+U 4
+L 11
+U 2
+L 2
+U 10
+L 5
+D 1
+R 2
+U 7
+D 5
+L 2
+U 12
+D 8
+L 1
+U 1
+D 4
+U 5
+U 1
+D 9
+U 6
+U 3
+R 12
+R 8
+R 3
+U 4
+D 5
+R 1
+L 2
+R 14
+U 7
+R 10
+R 11
+U 6
+D 1
+L 7
+R 4
+R 7
+R 3
+R 1
+D 4
+D 15
+L 10
+R 9
+L 3
+D 9
+U 1
+D 8
+D 6
+L 8
+D 5
+U 8
+U 9
+D 8
+R 4
+R 7
+R 1
+U 9
+R 8
+R 9
+L 10
+L 5
+D 11
+L 1
+U 3
+D 3
+L 2
+L 5
+L 9
+R 8
+D 8
+L 2
+L 5
+U 6
+R 7
+L 7
+D 1
+L 2
+R 3
+L 13
+L 9
+U 15
+D 17
+L 2
+L 1
+R 3
+D 4
+D 9
+L 3
+R 6
+L 4
+U 2
+U 2
+U 3
+U 6
+R 12
+L 12
+L 16
+D 1
+R 1
+R 6
+L 1
+R 9
+R 3
+U 2
+D 9
+R 1
+L 8
+R 2
+U 1
+R 4
+R 8
+U 6
+L 9
+R 2
+U 3
+R 8
+U 10
+D 5
+R 12
+U 4
+L 5
+R 17
+D 14
+L 16
+R 2
+L 4
+R 3
+R 1
+D 15
+R 3
+R 12
+U 14
+U 6
+R 9
+D 4
+U 3
+D 7
+D 2
+D 16
+R 12
+L 4
+R 2
+D 12
+R 1
+D 3
+D 4
+D 10
+D 7
+R 5
+D 12
+R 3
+D 1
+R 1
+L 4
+U 1
+D 2
+D 3
+R 5
+D 14
+D 3
+L 1
+D 1
+L 4
+U 2
+L 8
+R 10
+D 2
+U 3
+D 2
+L 2
+U 9
+R 1
+D 2
+L 5
+R 8
+U 1
+R 6
+L 7
+R 13
+R 9
+L 4
+R 3
+D 18
+R 2
+U 5
+U 7
+D 1
+D 13
+R 15
+R 2
+D 6
+R 8
+D 1
+L 15
+L 2
+L 1
+L 3
+D 11
+R 5
+L 3
+D 1
+U 8
+U 10
+U 10
+D 1
+U 15
+R 2
+R 8
+R 4
+R 1
+L 3
+D 10
+D 17
+U 7
+D 9
+L 16
+L 8
+L 1
+D 1
+R 5
+R 8
+R 1
+U 2
+U 5
+U 5
+U 5
+L 4
+L 5
+D 8
+L 9
+D 5
+D 2
+D 18
+R 11
+U 9
+U 5
+R 1
+D 5
+U 3
+L 9
+L 7
+U 4
+D 7
+L 3
+R 7
+D 2
+D 8
+D 6
+U 1
+D 6
+L 3
+L 2
+R 8
+L 8
+L 4
+U 2
+R 4
+L 4
+R 6
+U 1
+R 8
+R 1
+U 2
+R 2
+L 2
+D 7
+D 12
+L 8
+U 5
+U 5
+R 10
+U 6
+R 6
+D 1
+D 2
+R 2
+L 2
+U 9
+L 11
+R 3
+U 5
+L 11
+L 7
+R 2
+D 8
+L 2
+L 8
+U 9
+R 10
+U 1
+L 11
+U 3
+R 4
+R 9
+L 10
+L 3
+D 3
+R 5
+D 1
+R 1
+R 4
+D 4
+L 1
+U 6
+D 3
+R 2
+U 1
+U 1
+L 10
+L 9
+U 9
+L 3
+L 7
+D 15
+D 3
+L 1
+R 2
+D 12
+D 6
+U 1
+L 2
+L 9
+R 1
+D 1
+R 4
+R 6
+R 4
+U 4
+U 10
+L 5
+U 6
+R 13
+L 5
+L 9
+U 6
+U 9
+L 1
+R 1
+L 3
+U 10
+R 2
+L 5
+D 8
+L 8
+R 8
+D 6
+R 1
+U 4
+R 2
+D 4
+U 2
+L 3
+L 2
+U 6
+D 3
+D 9
+R 9
+D 6
+D 6
+R 7
+D 2
+D 6
+U 1
+U 8
+U 1
+L 5
+R 6
+L 3
+R 5
+U 7
+D 1
+R 4
+L 1
+D 2
+L 5
+R 2
+U 1
+R 4
+R 4
+R 18
+R 9
+U 5
+U 6
+U 12
+R 5
+U 4
+L 1
+D 2
+R 1
+U 5
+D 7
+R 12
+R 18
+D 2
+R 5
+L 5
+D 17
+U 9
+D 1
+R 16
+U 6
+D 2
+L 1
+R 4
+D 4
+U 1
+L 5
+D 12
+R 6
+R 8
+L 9
+R 6
+D 3
+L 15
+U 8
+L 5
+D 5
+L 2
+L 6
+D 3
+D 4
+R 2
+L 4
+U 1
+D 8
+L 13
+U 11
+U 17
+D 11
+L 2
+D 6
+R 12
+R 7
+D 2
+U 12
+L 6
+D 6
+U 2
+D 2
+D 10
+D 4
+L 2
+L 5
+L 3
+U 2
+U 1
+L 6
+R 6
+L 2
+R 12
+D 5
+U 6
+U 4
+L 13
+U 5
+U 1
+D 1
+L 3
+L 14
+D 5
+D 7
+R 4
+L 16
+D 15
+L 2
+D 5
+U 4
+D 6
+U 1
+L 6
+U 14
+D 6
+R 2
+R 1
+R 13
+U 2
+D 3
+R 2
+L 2
+D 10
+R 10
+R 1
+L 5
+D 6
+R 10
+U 15
+U 8
+U 3
+L 11
+L 1
+U 4
+R 4
+R 10
+R 9
+L 1
+R 5
+D 8
+D 8
+U 1
+R 14
+R 1
+R 10
+U 4
+D 2
+U 7
+L 10
+D 3
+D 10
+D 3
+L 1
+U 7
+L 2
+D 2
+U 7
+L 9
+U 13
+U 9
+D 7
+U 3
+D 3
+D 6
+L 16
+U 6
+D 3
+L 1
+L 3
+D 5
+L 3
+R 12
+U 11
+R 5
+L 15
+L 3
+D 9
+D 1
+D 2
+D 2
+U 11
+D 7
+U 6
+D 4
+L 10
+U 1
+L 16
+R 7
+U 5
+R 10
+D 4 \ No newline at end of file
diff --git a/2022/flake.lock b/2022/flake.lock
new file mode 100644
index 0000000..6cd4e18
--- /dev/null
+++ b/2022/flake.lock
@@ -0,0 +1,147 @@
+{
+ "nodes": {
+ "crane": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "flake-utils": "flake-utils",
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "rust-overlay": "rust-overlay"
+ },
+ "locked": {
+ "lastModified": 1669853699,
+ "narHash": "sha256-SvyPRwJeET7PCifBOvu+reQUUlyc4Ya1K37GrtZyiXY=",
+ "owner": "ipetkov",
+ "repo": "crane",
+ "rev": "0428181b7b8f619e71095cf2fab051bccdf10041",
+ "type": "github"
+ },
+ "original": {
+ "owner": "ipetkov",
+ "repo": "crane",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1650374568,
+ "narHash": "sha256-Z+s0J8/r907g149rllvwhb4pKi8Wam5ij0st8PwAh+E=",
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "rev": "b4a34015c698c7793d592d66adbab377907a2be8",
+ "type": "github"
+ },
+ "original": {
+ "owner": "edolstra",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "flake-utils": {
+ "locked": {
+ "lastModified": 1667395993,
+ "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "flake-utils_2": {
+ "locked": {
+ "lastModified": 1667395993,
+ "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1669867399,
+ "narHash": "sha256-Z8RXSFYOsIsTG96ROKtV0eZ8Q7u4irFWm6ELqfw7mT8=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "38e591dd05ffc8bdf79dc752ba78b05e370416fa",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "crane": "crane",
+ "flake-utils": "flake-utils_2",
+ "nixpkgs": "nixpkgs",
+ "rust-overlay": "rust-overlay_2"
+ }
+ },
+ "rust-overlay": {
+ "inputs": {
+ "flake-utils": [
+ "crane",
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "crane",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1667487142,
+ "narHash": "sha256-bVuzLs1ZVggJAbJmEDVO9G6p8BH3HRaolK70KXvnWnU=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "cf668f737ac986c0a89e83b6b2e3c5ddbd8cf33b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ },
+ "rust-overlay_2": {
+ "inputs": {
+ "flake-utils": [
+ "flake-utils"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1669862269,
+ "narHash": "sha256-/ar+cbAKAxd2Ng9b7EhrIMz9CP353RbmLecvyOidyUM=",
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "rev": "bfdf688742cf984c4837dbbe1c6cbca550365613",
+ "type": "github"
+ },
+ "original": {
+ "owner": "oxalica",
+ "repo": "rust-overlay",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/2022/flake.nix b/2022/flake.nix
new file mode 100644
index 0000000..7d55163
--- /dev/null
+++ b/2022/flake.nix
@@ -0,0 +1,72 @@
+{
+ description = "AOC 2022";
+
+ inputs = {
+ nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+
+ crane = {
+ url = "github:ipetkov/crane";
+ inputs.nixpkgs.follows = "nixpkgs";
+ };
+
+ flake-utils.url = "github:numtide/flake-utils";
+
+ rust-overlay = {
+ url = "github:oxalica/rust-overlay";
+ inputs = {
+ nixpkgs.follows = "nixpkgs";
+ flake-utils.follows = "flake-utils";
+ };
+ };
+ };
+
+ outputs = { self, nixpkgs, crane, flake-utils, rust-overlay, ... }:
+ flake-utils.lib.eachDefaultSystem (system:
+ let
+ pkgs = import nixpkgs {
+ inherit system;
+ overlays = [ (import rust-overlay) ];
+ };
+
+ toolchain = pkgs.rust-bin.nightly.latest.default.override {
+ targets = ["wasm32-unknown-unknown"];
+ };
+ craneLib = (crane.mkLib pkgs).overrideToolchain toolchain;
+ buildInputs = [
+ pkgs.cmake
+ pkgs.pkg-config
+ pkgs.fontconfig
+ pkgs.trunk
+ ];
+ my-crate = craneLib.buildPackage {
+ src = craneLib.cleanCargoSource ./.;
+ doCheck = false;
+
+ buildInputs = buildInputs ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [
+ # Additional darwin specific inputs can be set here
+ pkgs.libiconv
+ ];
+ };
+ in
+ {
+ checks = {
+ inherit my-crate;
+ };
+
+ packages.default = my-crate;
+
+ apps.default = flake-utils.lib.mkApp {
+ drv = my-crate;
+ };
+
+ devShells.default = pkgs.mkShell {
+ inputsFrom = builtins.attrValues self.checks;
+
+ nativeBuildInputs = buildInputs ++ (with pkgs; [
+ (toolchain.override {
+ extensions = ["rust-analyzer" "rust-src" "miri"];
+ })
+ ]);
+ };
+ });
+}
diff --git a/2022/src/day01.rs b/2022/src/day01.rs
new file mode 100644
index 0000000..a328975
--- /dev/null
+++ b/2022/src/day01.rs
@@ -0,0 +1,21 @@
+use crate::utils::max_n;
+
+mod utils;
+
+fn main() {
+ let input = utils::read_input();
+
+ let mut elf_cal_counts: Vec<usize> = input
+ .split("\n\n")
+ .map(|xs| {
+ xs.lines()
+ .map(|x| x.parse::<usize>().unwrap())
+ .sum::<usize>()
+ })
+ .collect();
+
+ let top_3 = max_n(&mut elf_cal_counts, 3);
+
+ println!("Max: {}", top_3.last().unwrap());
+ println!("Sum of top 3: {}", top_3.iter().sum::<usize>());
+}
diff --git a/2022/src/day02.rs b/2022/src/day02.rs
new file mode 100644
index 0000000..d0b0c5f
--- /dev/null
+++ b/2022/src/day02.rs
@@ -0,0 +1,105 @@
+mod utils;
+
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let turns_both_moves: Vec<_> = input
+ .lines()
+ .map(|xs| {
+ let mut parts = xs.split(' ').take(2).map(Move::parse);
+ (parts.next().unwrap(), parts.next().unwrap())
+ })
+ .collect();
+
+ let total_score_p1: usize = turns_both_moves
+ .iter()
+ .map(|(them, us)| score(*them, *us))
+ .sum();
+
+ let total_score_p2: usize = turns_both_moves
+ .into_iter()
+ .map(|(them, us)| (them, us.to_outcome()))
+ .map(|(them, outcome)| (them, them.to_get(outcome)))
+ .map(|(them, us)| score(them, us))
+ .sum();
+
+ println!("Part 1: {}", total_score_p1);
+ println!("Part 2: {}", total_score_p2);
+}
+
+fn score(them: Move, us: Move) -> usize {
+ let won_val = match (them.beats(us), us.beats(them)) {
+ (true, false) => 0,
+ (false, true) => 6,
+ (false, false) => 3,
+ (a, b) => unreachable!("they beat us: {}, we beat them: {}", a, b),
+ };
+ us.value() + won_val
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Move {
+ Rock,
+ Paper,
+ Scissors,
+}
+
+impl Move {
+ fn parse(inp: &str) -> Self {
+ match inp {
+ "A" => Move::Rock,
+ "B" => Move::Paper,
+ "C" => Move::Scissors,
+ "X" => Move::Rock,
+ "Y" => Move::Paper,
+ "Z" => Move::Scissors,
+ _ => panic!("unrecognised move: {}", inp),
+ }
+ }
+
+ fn to_outcome(self) -> Outcome {
+ match self {
+ Move::Rock => Outcome::Lose,
+ Move::Paper => Outcome::Draw,
+ Move::Scissors => Outcome::Win,
+ }
+ }
+
+ fn beats(self, other: Move) -> bool {
+ matches!(
+ (self, other),
+ (Move::Paper, Move::Rock)
+ | (Move::Rock, Move::Scissors)
+ | (Move::Scissors, Move::Paper)
+ )
+ }
+
+ fn to_get(self, outcome: Outcome) -> Self {
+ match (self, outcome) {
+ (_, Outcome::Draw) => self,
+ (Move::Rock, Outcome::Win) => Move::Paper,
+ (Move::Paper, Outcome::Win) => Move::Scissors,
+ (Move::Scissors, Outcome::Win) => Move::Rock,
+ (Move::Rock, Outcome::Lose) => Move::Scissors,
+ (Move::Paper, Outcome::Lose) => Move::Rock,
+ (Move::Scissors, Outcome::Lose) => Move::Paper,
+ }
+ }
+
+ fn value(self) -> usize {
+ match self {
+ Move::Rock => 1,
+ Move::Paper => 2,
+ Move::Scissors => 3,
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Outcome {
+ Win,
+ Draw,
+ Lose,
+}
diff --git a/2022/src/day03.rs b/2022/src/day03.rs
new file mode 100644
index 0000000..7e245de
--- /dev/null
+++ b/2022/src/day03.rs
@@ -0,0 +1,62 @@
+mod utils;
+
+use std::collections::HashSet;
+
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ // Convert each line to a tuple of hashsets, one for each backpack pocket
+ let rucksack_items: Vec<_> = input
+ .lines()
+ .map(|line| (&line[..line.len() / 2], &line[line.len() / 2..]))
+ .map(|(a, b)| -> (HashSet<char>, HashSet<char>) {
+ (a.chars().collect(), b.chars().collect())
+ })
+ .collect();
+
+ let sum_error_priorities: u32 = rucksack_items
+ .iter()
+ .map(|(a, b)| {
+ *a.intersection(b)
+ .next()
+ .expect("no common item between two backpack segments!")
+ }) // Get common item
+ .map(priority)
+ .sum();
+
+ let sum_badge_priorities: u32 = rucksack_items // Construct chunked iterator
+ .iter()
+ .step_by(3)
+ .zip(rucksack_items.iter().skip(1).step_by(3))
+ .zip(rucksack_items.iter().skip(2).step_by(3))
+ .map(|(((e1l, e1r), (e2l, e2r)), (e3l, e3r))| {
+ for item in e1l.union(e1r) {
+ if (e2l.contains(item) || e2r.contains(item))
+ && (e3l.contains(item) || e3r.contains(item))
+ {
+ return *item;
+ }
+ }
+ panic!(
+ "group has no badge! {:?}",
+ ((e1l, e1r), (e2l, e2r), (e3l, e3r))
+ )
+ })
+ .map(priority)
+ .sum();
+
+ println!("Part 1: {}", sum_error_priorities);
+ println!("Part 2: {}", sum_badge_priorities);
+}
+
+fn priority(chr: char) -> u32 {
+ if chr.is_ascii_lowercase() {
+ chr as u32 - 96
+ } else if chr.is_ascii_uppercase() {
+ chr as u32 - 38
+ } else {
+ panic!("unrecognised item {}", chr)
+ }
+}
diff --git a/2022/src/day04.rs b/2022/src/day04.rs
new file mode 100644
index 0000000..052dde1
--- /dev/null
+++ b/2022/src/day04.rs
@@ -0,0 +1,35 @@
+mod utils;
+
+use std::ops::RangeInclusive;
+
+use utils::{iter_pair, read_input};
+
+fn main() {
+ let input = read_input();
+
+ let pairs = input.lines().map(|x| {
+ iter_pair(x.split(',').map(|x| -> RangeInclusive<usize> {
+ let (start, end) = iter_pair(x.split('-'));
+ start.parse().unwrap()..=end.parse().unwrap()
+ }))
+ });
+
+ let (fully_contains, partially_contains) = pairs
+ .map(|(a, b)| (fully_overlap(&a, &b), partially_overlap(&a, &b)))
+ .fold((0, 0), |(acc_full, acc_part), (full, part)| {
+ (acc_full + full as usize, acc_part + part as usize)
+ });
+
+ println!("Part 1: {}", fully_contains);
+ println!("Part 2: {}", partially_contains);
+}
+
+#[inline(always)]
+fn fully_overlap<T: PartialOrd>(a: &RangeInclusive<T>, b: &RangeInclusive<T>) -> bool {
+ (a.contains(b.start()) && a.contains(b.end())) || (b.contains(a.start()) && b.contains(a.end()))
+}
+
+#[inline(always)]
+fn partially_overlap<T: PartialOrd>(a: &RangeInclusive<T>, b: &RangeInclusive<T>) -> bool {
+ a.contains(b.start()) || a.contains(b.end()) || b.contains(a.start()) || b.contains(a.end())
+}
diff --git a/2022/src/day05.rs b/2022/src/day05.rs
new file mode 100644
index 0000000..f45cd0a
--- /dev/null
+++ b/2022/src/day05.rs
@@ -0,0 +1,145 @@
+//! Day 5: Supply Stacks
+
+extern crate bumpalo;
+
+mod utils;
+
+use bumpalo::Bump;
+use std::cell::Cell;
+use utils::{parse_num, parse_static, read_input};
+
+/// Base type for a crate
+#[derive(Debug, Clone)]
+struct Crate<'a> {
+ letter: char,
+ below: Cell<Option<&'a Crate<'a>>>,
+}
+
+impl Default for Crate<'_> {
+ fn default() -> Self {
+ Crate {
+ letter: ' ',
+ below: None.into(),
+ }
+ }
+}
+
+/// A move the crane may make
+#[derive(Debug, Clone, Copy)]
+struct Move {
+ reps: usize,
+ from: usize,
+ to: usize,
+}
+type Tops<'arena> = Vec<Option<&'arena Crate<'arena>>>;
+
+fn main() {
+ let input = read_input();
+
+ {
+ let arena = Bump::new();
+ let mut tops = construct_piles(&input, &arena);
+ for mv in parse_moves(&input) {
+ perform_move_9000(&mut tops, mv);
+ }
+
+ println!("Part 1: {}", top_letters(tops));
+ }
+
+ {
+ let arena = Bump::new();
+ let mut tops = construct_piles(&input, &arena);
+ for mv in parse_moves(&input) {
+ perform_move_9001(&mut tops, mv);
+ }
+
+ println!("Part 2: {}", top_letters(tops));
+ }
+}
+
+/// Get the message / the top letters of each stack
+fn top_letters(tops: Tops<'_>) -> String {
+ tops.iter().map(|x| x.as_ref().unwrap().letter).collect()
+}
+
+/// Perform a move for part 1
+fn perform_move_9000(tops: &mut Tops<'_>, mv: Move) {
+ for _ in 0..mv.reps {
+ let from = tops[mv.from].take().unwrap();
+ let to = tops[mv.to].take();
+
+ tops[mv.from] = from.below.replace(to);
+ tops[mv.to] = Some(from);
+ }
+}
+
+/// Perform a move for part 2
+fn perform_move_9001(tops: &mut Tops<'_>, mv: Move) {
+ let pickup_top = tops[mv.from].take().unwrap();
+
+ let mut pickup_bot = pickup_top;
+ for _ in 1..mv.reps {
+ pickup_bot = pickup_bot.below.get().as_ref().unwrap();
+ }
+
+ let to = tops[mv.to].take();
+
+ tops[mv.from] = pickup_bot.below.replace(to);
+ tops[mv.to] = Some(pickup_top);
+}
+
+// Annoying parsing code!
+
+fn construct_piles<'a>(input: &str, arena: &'a Bump) -> Tops<'a> {
+ let mut piles = Vec::new();
+ for layer_iter in input
+ .lines()
+ .take_while(|x| x.chars().find(|x| *x != ' ').unwrap() == '[')
+ .map(|x| x.chars().skip(1).step_by(4))
+ {
+ for (stack, chr) in layer_iter.enumerate() {
+ if piles.len() < stack + 1 {
+ piles.resize(stack + 1, None);
+ }
+
+ if chr != ' ' {
+ let val = &*arena.alloc(Crate {
+ letter: chr,
+ below: None.into(),
+ });
+ if piles[stack].is_none() {
+ piles[stack] = Some(val);
+ } else {
+ let mut top = *piles[stack].as_ref().unwrap();
+ while let Some(below) = top.below.get() {
+ top = below;
+ }
+
+ top.below.set(Some(val));
+ }
+ }
+ }
+ }
+
+ piles
+}
+
+fn parse_moves(input: &str) -> impl Iterator<Item = Move> + '_ {
+ input
+ .lines()
+ .skip_while(|line| !line.starts_with('m'))
+ .map(|line| {
+ let line = parse_static("move ", line);
+ let (reps, line) = parse_num(line);
+ let line = parse_static(" from ", line);
+ let (from, line) = parse_num::<usize>(line);
+ let line = parse_static(" to ", line);
+ let (to, _) = parse_num::<usize>(line);
+
+ Move {
+ reps,
+ from: from - 1,
+ to: to - 1,
+ }
+ })
+}
diff --git a/2022/src/day06.rs b/2022/src/day06.rs
new file mode 100644
index 0000000..8bbfe6d
--- /dev/null
+++ b/2022/src/day06.rs
@@ -0,0 +1,47 @@
+mod utils;
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ println!("Part 1: {}", find_chunk_nodup::<4>(&input));
+ println!("Part 2: {}", find_chunk_nodup::<14>(&input));
+}
+
+fn find_chunk_nodup<const N: usize>(input: &str) -> usize {
+ let mut window = ['a'; N];
+ let mut chars = input.chars();
+
+ // Fill up initial window
+ for item in window.iter_mut() {
+ *item = chars.next().unwrap();
+ }
+
+ for i in 0..input.len() {
+ // Shuffle everything in window down
+ for j in 0..N - 1 {
+ window[j] = window[j + 1];
+ }
+ window[N - 1] = chars.next().unwrap();
+
+ if window
+ .iter()
+ .fold(Some(0), |acc, chr| add_char(acc?, *chr))
+ .is_some()
+ {
+ return i + N + 1;
+ }
+ }
+
+ panic!("no solution!")
+}
+
+#[inline]
+fn add_char(bits: u32, chr: char) -> Option<u32> {
+ let add = 1 << (chr.to_ascii_lowercase() as u32 - 97);
+ if (bits | add) != bits {
+ Some(bits | add)
+ } else {
+ None
+ }
+}
diff --git a/2022/src/day07.rs b/2022/src/day07.rs
new file mode 100644
index 0000000..88bb647
--- /dev/null
+++ b/2022/src/day07.rs
@@ -0,0 +1,110 @@
+mod utils;
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let mut unused = 0;
+ let mut sum_under_threshold = 0;
+
+ for size in DirectorySizes::new(&input) {
+ if size < 100_000 {
+ sum_under_threshold += size;
+ }
+ unused = 70_000_000 - size;
+ }
+
+ println!("Part 1: {}", sum_under_threshold);
+ let deficit = 30_000_000 - unused;
+ println!(
+ "Part 2: {}",
+ DirectorySizes::new(&input)
+ .filter(|x| *x > deficit)
+ .min()
+ .unwrap()
+ );
+}
+
+struct DirectorySizes<'a> {
+ lines: std::str::Lines<'a>,
+ directory_stack: [usize; 64],
+ stack_top: usize,
+}
+
+impl<'a> DirectorySizes<'a> {
+ fn new(input: &'a str) -> Self {
+ let mut lines = input.lines();
+ assert_eq!(lines.next(), Some("$ cd /"));
+
+ DirectorySizes {
+ lines,
+ directory_stack: [0; 64],
+ stack_top: 0,
+ }
+ }
+}
+
+impl Iterator for DirectorySizes<'_> {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ for line in self.lines.by_ref() {
+ let line: Line = line.into();
+
+ match line {
+ Line::Cd(up) => {
+ if up {
+ self.directory_stack[self.stack_top - 1] +=
+ self.directory_stack[self.stack_top];
+ self.stack_top -= 1;
+ return Some(self.directory_stack[self.stack_top + 1]);
+ } else {
+ self.stack_top += 1;
+ self.directory_stack[self.stack_top] = 0;
+ }
+ }
+ Line::FileSize(size) => {
+ self.directory_stack[self.stack_top] += size;
+ }
+ Line::Ls => (),
+ Line::Dir => (),
+ };
+ }
+
+ if self.stack_top > 0 {
+ self.directory_stack[self.stack_top - 1] += self.directory_stack[self.stack_top];
+ self.stack_top -= 1;
+ Some(self.directory_stack[self.stack_top + 1])
+ } else if self.directory_stack[0] != 0 {
+ Some(std::mem::replace(&mut self.directory_stack[0], 0))
+ } else {
+ None
+ }
+ }
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Line {
+ /// True = .., False = other
+ Cd(bool),
+ Ls,
+ FileSize(usize),
+ Dir,
+}
+
+impl From<&str> for Line {
+ fn from(value: &str) -> Self {
+ if value.starts_with("$ cd ") {
+ let mut args = value.split("cd ");
+ args.next().unwrap();
+ Line::Cd(args.next().unwrap() == "..")
+ } else if value.starts_with("$ ls") {
+ Line::Ls
+ } else if value.starts_with("dir") {
+ Line::Dir
+ } else {
+ let num_index = value.chars().take_while(|chr| chr.is_numeric()).count();
+ Line::FileSize(value[..num_index].parse().unwrap())
+ }
+ }
+}
diff --git a/2022/src/day08.rs b/2022/src/day08.rs
new file mode 100644
index 0000000..514cb21
--- /dev/null
+++ b/2022/src/day08.rs
@@ -0,0 +1,110 @@
+mod utils;
+
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let mut grid: Vec<Vec<_>> = input
+ .lines()
+ .map(|x| {
+ x.chars()
+ .map(|x| (x.to_digit(10).unwrap() as u8, false))
+ .collect()
+ })
+ .collect();
+ in_all_directions!(check_vis_along_run, grid);
+
+ println!(
+ "Part 1: {}",
+ grid.iter()
+ .map(|x| x.iter().filter(|x| x.1).count())
+ .sum::<usize>()
+ );
+
+ let mut grid: Vec<Vec<(u8, u32)>> = grid
+ .into_iter()
+ .map(|x| x.into_iter().map(|(x, _)| (x, 1)).collect())
+ .collect();
+ in_all_directions!(vis_score_along_run, grid);
+
+ println!(
+ "Part 2: {}",
+ grid.iter()
+ .map(|row| row.iter().map(|(_, vis)| vis).max().unwrap())
+ .max()
+ .unwrap()
+ );
+}
+
+fn check_vis_along_run(
+ mut run: impl Iterator<Item = (usize, usize)>,
+ grid: &mut [Vec<(u8, bool)>],
+) {
+ let mut curr_height = {
+ let (row_idx, col_idx) = run.next().unwrap();
+
+ grid[row_idx][col_idx].1 = true;
+
+ grid[row_idx][col_idx].0
+ };
+ for (row_idx, col_idx) in run {
+ let height = grid[row_idx][col_idx].0;
+ if height > curr_height {
+ curr_height = height;
+ grid[row_idx][col_idx].1 = true;
+ }
+ }
+}
+
+fn vis_score_along_run(run: impl Iterator<Item = (usize, usize)>, grid: &mut [Vec<(u8, u32)>]) {
+ let mut next_values = [0; 10];
+ for (row_idx, col_idx) in run {
+ let height = grid[row_idx][col_idx].0;
+ grid[row_idx][col_idx].1 *= next_values[height as usize];
+
+ for (val, score) in next_values.iter_mut().enumerate() {
+ *score = if *score == 0 || val > height as usize {
+ *score + 1
+ } else {
+ 1
+ };
+ }
+ }
+}
+
+#[macro_use]
+mod codegen {
+ #[macro_export]
+ macro_rules! in_all_directions {
+ ($f:ident, $grid: ident) => {
+ let grid_rows = $grid.len();
+ let grid_cols = $grid[0].len();
+
+ (0..grid_rows).for_each(|grid_row| {
+ $f(
+ (0..grid_cols).map(move |grid_col| (grid_row, grid_col)),
+ &mut $grid,
+ );
+ $f(
+ (0..grid_cols)
+ .rev()
+ .map(move |grid_col| (grid_row, grid_col)),
+ &mut $grid,
+ )
+ });
+ (0..grid_cols).for_each(|grid_col| {
+ $f(
+ (0..grid_rows).map(move |grid_row| (grid_row, grid_col)),
+ &mut $grid,
+ );
+ $f(
+ (0..grid_rows)
+ .rev()
+ .map(move |grid_row| (grid_row, grid_col)),
+ &mut $grid,
+ )
+ });
+ };
+ }
+}
diff --git a/2022/src/day09.html b/2022/src/day09.html
new file mode 100644
index 0000000..d3ed12b
--- /dev/null
+++ b/2022/src/day09.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <link data-trunk rel="rust" data-wasm-opt="2" href="../Cargo.toml" data-bin="day9" />
+
+ <style>
+ html {
+ /* Remove touch delay: */
+ touch-action: manipulation;
+ }
+
+ html,
+ body {
+ overflow: hidden;
+ margin: 0 !important;
+ padding: 0 !important;
+ height: 100%;
+ width: 100%;
+ }
+
+ canvas {
+ margin-right: auto;
+ margin-left: auto;
+ display: block;
+ position: absolute;
+ top: 0%;
+ left: 50%;
+ transform: translate(-50%, 0%);
+ }
+ </style>
+</head>
+
+<body>
+ <canvas id="canvas"></canvas>
+</body>
+
+</html>
diff --git a/2022/src/day09.rs b/2022/src/day09.rs
new file mode 100644
index 0000000..23b08b3
--- /dev/null
+++ b/2022/src/day09.rs
@@ -0,0 +1,238 @@
+mod utils;
+use std::{
+ cmp::min,
+ collections::{HashSet, VecDeque},
+ time::Duration,
+};
+
+use egui::{Color32, Sense, Stroke};
+use utils::{iter_pair, read_input};
+
+#[cfg(target_arch = "wasm32")]
+fn main() {
+ console_error_panic_hook::set_once();
+
+ let input = include_str!("../fake_inputs/day9");
+ let input = parse_moves(&input).collect();
+
+ let options = eframe::WebOptions::default();
+ wasm_bindgen_futures::spawn_local(async {
+ eframe::start_web("canvas", options, Box::new(|_cc| Box::new(App::new(input))))
+ .await
+ .expect("unable to start eframe");
+ });
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+fn main() {
+ let input = read_input();
+
+ println!("Part 1: {}", visited_from_moves::<2>(parse_moves(&input)));
+ println!("Part 2: {}", visited_from_moves::<10>(parse_moves(&input)));
+}
+
+type Pos = (i32, i32);
+type Move = (Direction, u8);
+
+fn visited_from_moves<const N: usize>(moves: impl Iterator<Item = Move>) -> usize {
+ let mut tail_visited = HashSet::new();
+ tail_visited.insert((0, 0));
+ let mut knots = [(0, 0); N];
+ for mv in moves {
+ make_move(mv, &mut knots, &mut tail_visited);
+ }
+
+ tail_visited.len()
+}
+
+fn make_move(mv: Move, knots: &mut [Pos], tail_visited: &mut HashSet<Pos>) {
+ let (dir, count) = mv;
+
+ for _ in 0..count {
+ // Move head of rope
+ match dir {
+ Direction::Up => knots[0].1 += 1,
+ Direction::Down => knots[0].1 -= 1,
+ Direction::Right => knots[0].0 += 1,
+ Direction::Left => knots[0].0 -= 1,
+ };
+
+ for front_idx in 0..knots.len() - 1 {
+ let (fx, fy) = knots[front_idx];
+ let (bx, by) = &mut knots[front_idx + 1];
+ let (dx, dy) = (fx - *bx, fy - *by);
+ if (dx.abs() == 2 && dy == 0) || (dy.abs() == 2 && dx == 0) || (dy.abs() + dx.abs() > 2)
+ {
+ *bx += (dx.signum()) * min(dx.abs(), 1);
+ *by += (dy.signum()) * min(dy.abs(), 1);
+ }
+ }
+ tail_visited.insert(knots[knots.len() - 1]);
+ }
+}
+
+fn parse_moves(input: &str) -> impl Iterator<Item = Move> + '_ {
+ input.lines().map(|x| {
+ let (dir, count) = iter_pair(x.split(' '));
+ let count = count.parse().unwrap();
+
+ (
+ match dir {
+ "L" => Direction::Left,
+ "R" => Direction::Right,
+ "U" => Direction::Up,
+ "D" => Direction::Down,
+ _ => panic!("invalid direction, {}", dir),
+ },
+ count,
+ )
+ })
+}
+
+#[derive(Debug, Clone, Copy)]
+enum Direction {
+ Up,
+ Down,
+ Left,
+ Right,
+}
+
+struct App {
+ orig_input: VecDeque<Move>,
+ input: VecDeque<Move>,
+ knots: Vec<Pos>,
+ tail_visited: HashSet<Pos>,
+ desired_knot_count: usize,
+ speed: usize,
+}
+
+impl App {
+ fn new(input: VecDeque<Move>) -> Self {
+ App {
+ orig_input: input.clone(),
+ input,
+ knots: vec![],
+ tail_visited: HashSet::new(),
+ desired_knot_count: 2,
+ speed: 0,
+ }
+ }
+
+ fn reset_knots(&mut self) {
+ self.input = self.orig_input.clone();
+ self.knots = vec![(0, 0); self.desired_knot_count];
+ self.tail_visited.clear();
+ self.tail_visited.insert((0, 0));
+ }
+
+ fn step(&mut self) {
+ match self.input.pop_front() {
+ Some(mv) => make_move(mv, &mut self.knots, &mut self.tail_visited),
+ None => (),
+ }
+ }
+}
+
+impl eframe::App for App {
+ fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
+ if self.desired_knot_count != self.knots.len() {
+ self.reset_knots()
+ }
+ egui::SidePanel::right("instructions").show(ctx, |ui| {
+ egui::ScrollArea::vertical().show(ui, |ui| {
+ if ui.button("Step").clicked() {
+ self.step();
+ }
+ if ui.button("Reset").clicked() {
+ self.reset_knots()
+ }
+ ui.label(format!("Tail Visited: {}", self.tail_visited.len()));
+ ui.add(egui::Slider::new(&mut self.desired_knot_count, 2..=20).text("Knot count"));
+ ui.add(egui::Slider::new(&mut self.speed, 0..=20).text("Speed"));
+ ui.heading("Instructions:");
+ for (i, ins) in self.input.iter().take(20).enumerate() {
+ let arrow = match ins.0 {
+ Direction::Up => "⬆",
+ Direction::Down => "⬇",
+ Direction::Right => "➡",
+ Direction::Left => "⬅",
+ };
+ if i == 0 {
+ ui.colored_label(Color32::YELLOW, arrow.repeat(ins.1 as _));
+ } else {
+ ui.label(arrow.repeat(ins.1 as _));
+ }
+ }
+ if self.input.len() > 20 {
+ ui.label(format!("+ {} more", self.input.len() - 20));
+ }
+ })
+ });
+
+ if self.speed > 0 && self.input.len() > 0 {
+ for _ in 0..self.speed {
+ self.step();
+ }
+ ctx.request_repaint_after(Duration::from_millis(100))
+ }
+
+ egui::CentralPanel::default().show(ctx, |ui| {
+ let mut painter_size = ui.available_size_before_wrap();
+ if !painter_size.is_finite() {
+ painter_size = egui::vec2(500.0, 500.0);
+ }
+
+ const SIDE: f32 = 5.0;
+
+ let (res, painter) = ui.allocate_painter(painter_size, Sense::hover());
+ let center = res.rect.center().to_vec2();
+
+ let to_panel_pos = |pos: &Pos| {
+ (egui::vec2(pos.0 as f32 * SIDE, pos.1 as f32 * SIDE) + center).to_pos2()
+ };
+
+ let half_width = (painter_size.x / SIDE).floor() as i32;
+ let half_height = (painter_size.y / SIDE).floor() as i32;
+
+ for x in -half_width..half_width {
+ for y in -half_height..half_height {
+ let dot = (x, y);
+ let color = if dot == (0, 0) {
+ Color32::WHITE
+ } else if self.tail_visited.contains(&dot) {
+ Color32::DARK_RED
+ } else {
+ continue;
+ };
+
+ let dot_pos = to_panel_pos(&dot);
+ painter.circle_stroke(dot_pos, 1.0, Stroke::new(1.0, color));
+ }
+ }
+
+ // paint the head
+ painter.circle_stroke(
+ to_panel_pos(&self.knots[0]),
+ SIDE / 2.0,
+ Stroke::new(SIDE / 2.0, Color32::GREEN),
+ );
+ for knot in self.knots.iter().skip(1) {
+ painter.circle_stroke(
+ to_panel_pos(knot),
+ SIDE / 2.0,
+ Stroke::new(SIDE / 2.0, Color32::YELLOW),
+ );
+ }
+
+ for (a, b) in self.knots.iter().zip(self.knots.iter().skip(1)) {
+ let head_pos = to_panel_pos(a);
+ let tail_pos = to_panel_pos(b);
+ painter.arrow(
+ tail_pos,
+ head_pos - tail_pos,
+ Stroke::new(1.0, Color32::YELLOW),
+ )
+ }
+ });
+ }
+}
diff --git a/2022/src/day10.rs b/2022/src/day10.rs
new file mode 100644
index 0000000..4c74444
--- /dev/null
+++ b/2022/src/day10.rs
@@ -0,0 +1,82 @@
+mod utils;
+use utils::{parse_num, parse_static, read_input};
+
+fn main() {
+ let input = read_input();
+
+ let mut cmds = input.lines().map(parse_cmd);
+ let mut state = State {
+ x: 1,
+ add_next: None,
+ add_next_start: None,
+ crt_pos: 0,
+ };
+
+ let mut acc = 0;
+ run_steps::<20>(&mut state, &mut cmds);
+ acc += state.x * 20;
+ for i in 1..=5 {
+ run_steps::<40>(&mut state, &mut cmds);
+ acc += state.x * (20 + (i * 40));
+ }
+
+ run_steps::<{ TOTAL_STEPS - 220 }>(&mut state, &mut cmds);
+
+ println!("Part 1: {}", acc);
+}
+
+struct State {
+ x: isize,
+ add_next: Option<isize>,
+ add_next_start: Option<isize>,
+ crt_pos: usize,
+}
+
+const CRT_WIDTH: usize = 40;
+const CRT_HEIGHT: usize = 6;
+const TOTAL_STEPS: usize = CRT_WIDTH * CRT_HEIGHT;
+
+fn run_steps<const N: usize>(state: &mut State, cmd: &mut impl Iterator<Item = Command>) {
+ for _ in 0..N {
+ if let Some(add) = state.add_next_start.take() {
+ state.x += add;
+ }
+
+ if (state.x - (state.crt_pos % CRT_WIDTH) as isize).abs() < 2 {
+ print!("█");
+ } else {
+ print!(" ");
+ }
+ state.crt_pos += 1;
+ if (state.crt_pos % CRT_WIDTH) == 0 {
+ println!();
+ }
+
+ if let Some(add) = state.add_next.take() {
+ state.add_next_start = Some(add);
+ } else {
+ match cmd.next() {
+ Some(Command::NoOp) => (),
+ Some(Command::AddX(add)) => state.add_next = Some(add),
+ None => (),
+ }
+ }
+ }
+}
+
+fn parse_cmd(cmd: &str) -> Command {
+ if cmd == "noop" {
+ Command::NoOp
+ } else {
+ let cmd = parse_static("addx ", cmd);
+ let (add, _) = parse_num(cmd);
+
+ Command::AddX(add)
+ }
+}
+
+#[derive(Debug)]
+enum Command {
+ NoOp,
+ AddX(isize),
+}
diff --git a/2022/src/day11.rs b/2022/src/day11.rs
new file mode 100644
index 0000000..aad0b48
--- /dev/null
+++ b/2022/src/day11.rs
@@ -0,0 +1,127 @@
+mod utils;
+extern crate nom;
+use nom::{
+ branch::alt,
+ bytes::complete::{tag, take_until},
+ character::complete::{digit0, u32},
+ multi::separated_list0,
+ IResult,
+};
+use utils::{max_n, read_input};
+
+fn main() {
+ let input = read_input();
+
+ let (_, monkeys_items) = separated_list0(tag("\n\n"), Monkey::parse)(&input).unwrap();
+ let (monkeys, items): (Vec<_>, Vec<_>) = monkeys_items.into_iter().unzip();
+
+ println!(
+ "Part 1: {}",
+ monkey_business::<3, 20>(&monkeys, items.clone(), usize::MAX),
+ );
+ println!(
+ "Part 2: {}",
+ monkey_business::<1, 10000>(&monkeys, items, monkeys.iter().map(|x| x.test).product())
+ );
+}
+
+fn monkey_business<const REDUCER: usize, const ROUNDS: usize>(
+ monkeys: &[Monkey],
+ mut items: Vec<Vec<usize>>,
+ additional_reducer: usize,
+) -> usize {
+ let mut inspections = vec![0; monkeys.len()];
+ for _ in 0..ROUNDS {
+ for monkey_idx in 0..monkeys.len() {
+ let curr_monkey = &monkeys[monkey_idx];
+ while let Some(worry) = items[monkey_idx].pop() {
+ let new_worry = (curr_monkey.do_op(worry) / REDUCER) % additional_reducer;
+ inspections[monkey_idx] += 1;
+ let throw_to = curr_monkey.throw_to(new_worry);
+
+ items[throw_to].push(new_worry);
+ }
+ }
+ }
+
+ max_n(&mut inspections, 2).iter().product::<usize>()
+}
+
+#[derive(Debug)]
+struct Monkey {
+ op: Operation,
+ test: usize,
+ next_monkey: (usize, usize),
+}
+
+impl Monkey {
+ fn parse(i: &str) -> IResult<&str, (Monkey, Vec<usize>)> {
+ let (i, _) = tag("Monkey ")(i)?;
+ let (i, _) = digit0(i)?;
+ let (i, _) = tag(":\n Starting items: ")(i)?;
+ let (i, items) = separated_list0(tag(", "), u32)(i)?;
+ let (i, _) = tag("\n Operation: new = ")(i)?;
+ let (i, op) = Operation::parse(i)?;
+ let (i, _) = take_until("\n")(i)?;
+ let (i, _) = tag("\n Test: divisible by ")(i)?;
+ let (i, test) = u32(i)?;
+ let (i, _) = tag("\n If true: throw to monkey ")(i)?;
+ let (i, monkey_t) = u32(i)?;
+ let (i, _) = tag("\n If false: throw to monkey ")(i)?;
+ let (i, monkey_f) = u32(i)?;
+
+ Ok((
+ i,
+ (
+ Monkey {
+ op,
+ test: test as usize,
+ next_monkey: (monkey_t as usize, monkey_f as usize),
+ },
+ items.into_iter().map(|x| x as usize).collect(),
+ ),
+ ))
+ }
+
+ fn do_op(&self, x: usize) -> usize {
+ match self.op {
+ Operation::Square => x * x,
+ Operation::Add(c) => x + c,
+ Operation::Mult(c) => x * c,
+ }
+ }
+ fn throw_to(&self, x: usize) -> usize {
+ if (x % self.test) == 0 {
+ self.next_monkey.0
+ } else {
+ self.next_monkey.1
+ }
+ }
+}
+
+#[derive(Debug)]
+enum Operation {
+ Square,
+ Add(usize),
+ Mult(usize),
+}
+
+impl Operation {
+ fn parse(i: &str) -> IResult<&str, Operation> {
+ let (i, _) = tag("old ")(i)?;
+ let (i, op) = alt((tag("* "), tag("+ ")))(i)?;
+ if let Ok((i, _)) = tag::<&str, &str, (&str, nom::error::ErrorKind)>("old")(i) {
+ Ok((i, Operation::Square))
+ } else {
+ let (i, x) = u32(i)?;
+ Ok((
+ i,
+ match op {
+ "* " => Operation::Mult(x as usize),
+ "+ " => Operation::Add(x as usize),
+ _ => unreachable!(),
+ },
+ ))
+ }
+ }
+}
diff --git a/2022/src/day12.rs b/2022/src/day12.rs
new file mode 100644
index 0000000..c446c74
--- /dev/null
+++ b/2022/src/day12.rs
@@ -0,0 +1,141 @@
+mod utils;
+use std::collections::BinaryHeap;
+
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let width = input.lines().next().unwrap().len();
+ let height = input.lines().count();
+ let mut heights = vec![0; width * height];
+
+ let mut start = (0, 0);
+ let mut end = (0, 0);
+
+ for (y, line) in input.lines().enumerate() {
+ for (x, c) in line.chars().enumerate() {
+ let val = if c == 'S' {
+ start = (x as isize, y as isize);
+ 0
+ } else if c == 'E' {
+ end = (x as isize, y as isize);
+ 25
+ } else {
+ c.to_ascii_lowercase() as isize - 97
+ };
+ heights[(y * width) + x] = val;
+ }
+ }
+
+ let cost = pathfind(&heights, width, end);
+
+ println!("Part 1: {:?}", cost[pos_to_index(&start, width)]);
+ println!(
+ "Part 2: {:?}",
+ (0..height as isize)
+ .map(|y| (0..width as isize)
+ .map(|x| pos_to_index(&(x, y), width))
+ .filter(|idx| heights[*idx] == 0)
+ .map(|idx| cost[idx])
+ .min()
+ .unwrap())
+ .min()
+ .unwrap()
+ )
+}
+
+type HeightMap = Vec<isize>;
+type Pos = (isize, isize);
+
+fn pathfind(heights: &HeightMap, width: usize, end: Pos) -> Vec<usize> {
+ let mut min_cost = vec![usize::MAX; heights.len()];
+ let mut frontier: BinaryHeap<GraphPos> = BinaryHeap::new();
+ frontier.push(GraphPos { pos: end, moves: 0 });
+ while let Some(curr) = frontier.pop() {
+ let idx = pos_to_index(&curr.pos, width);
+ if curr.moves >= min_cost[idx] {
+ continue;
+ } else {
+ min_cost[idx] = curr.moves;
+ }
+
+ for neighbour in CanReach::new(heights, width, curr.pos) {
+ frontier.push(GraphPos {
+ pos: neighbour,
+ moves: curr.moves + 1,
+ })
+ }
+ }
+
+ min_cost
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+struct GraphPos {
+ pos: Pos,
+ moves: usize,
+}
+
+impl PartialOrd for GraphPos {
+ fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+ self.moves.partial_cmp(&other.moves).map(|x| x.reverse())
+ }
+}
+
+impl Ord for GraphPos {
+ fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+ self.moves.cmp(&other.moves).reverse()
+ }
+}
+
+struct CanReach<'a> {
+ heights: &'a HeightMap,
+ curr: Pos,
+ step: usize,
+ width: usize,
+}
+
+impl<'a> CanReach<'a> {
+ fn new(heights: &'a HeightMap, width: usize, pos: Pos) -> Self {
+ CanReach {
+ heights,
+ curr: pos,
+ step: 0,
+ width,
+ }
+ }
+}
+impl Iterator for CanReach<'_> {
+ type Item = Pos;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ let (curr_x, curr_y) = self.curr;
+ loop {
+ let (x, y) = match self.step {
+ 0 => (curr_x + 1, curr_y),
+ 1 => (curr_x - 1, curr_y),
+ 2 => (curr_x, curr_y + 1),
+ 3 => (curr_x, curr_y - 1),
+ _ => break,
+ };
+ self.step += 1;
+
+ if (x >= 0
+ && x < self.width as isize
+ && y >= 0
+ && y < (self.heights.len() / self.width) as isize)
+ && self.heights[pos_to_index(&(x, y), self.width)]
+ >= self.heights[pos_to_index(&(curr_x, curr_y), self.width)] - 1
+ {
+ return Some((x, y));
+ }
+ }
+ None
+ }
+}
+
+#[inline(always)]
+fn pos_to_index(pos: &Pos, width: usize) -> usize {
+ ((pos.1 * width as isize) + pos.0) as usize
+}
diff --git a/2022/src/day13.rs b/2022/src/day13.rs
new file mode 100644
index 0000000..17b55eb
--- /dev/null
+++ b/2022/src/day13.rs
@@ -0,0 +1,132 @@
+mod utils;
+use std::{
+ cmp::Ordering,
+ iter::{once, Peekable},
+};
+
+extern crate nom;
+use nom::{bytes::complete::tag, character::complete::u32};
+use utils::read_input;
+
+fn main() {
+ let input = read_input();
+
+ let mut full: Vec<_> = input.lines().filter(|x| !x.is_empty()).collect();
+
+ println!(
+ "Part 1: {}",
+ full.iter()
+ .step_by(2)
+ .zip(full.iter().skip(1).step_by(2))
+ .map(|(left, right)| { compare(left, right) })
+ .enumerate()
+ .filter_map(|(i, cmp)| match cmp {
+ Ordering::Greater => None,
+ _ => Some(i + 1),
+ })
+ .sum::<usize>()
+ );
+
+ full.sort_by(|l, r| compare(l, r));
+
+ println!(
+ "Part 2: {}",
+ full.iter()
+ .enumerate()
+ .filter_map(|(i, val)| match *val {
+ "[[2]]" | "[[6]]" => Some(i + 1),
+ _ => None,
+ })
+ .product::<usize>()
+ );
+}
+
+fn compare(left: &str, right: &str) -> Ordering {
+ let mut left = Packet(left).peekable();
+ let mut right = Packet(right).peekable();
+ assert_eq!(left.next(), Some(PacketContents::StartList));
+ assert_eq!(right.next(), Some(PacketContents::StartList));
+ compare_lists(&mut left, &mut right)
+}
+
+fn compare_lists(
+ left: &mut Peekable<impl Iterator<Item = PacketContents>>,
+ right: &mut Peekable<impl Iterator<Item = PacketContents>>,
+) -> Ordering {
+ loop {
+ match (left.next().unwrap(), right.next().unwrap()) {
+ (PacketContents::EndList, PacketContents::EndList) => {
+ return Ordering::Equal;
+ }
+ (PacketContents::EndList, _) => {
+ while !matches!(right.next(), Some(PacketContents::EndList)) {}
+ return Ordering::Less;
+ }
+ (_, PacketContents::EndList) => {
+ while !matches!(left.next(), Some(PacketContents::EndList)) {}
+
+ return Ordering::Greater;
+ }
+ (PacketContents::StartList, PacketContents::StartList) => {
+ match compare_lists(left, right) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ }
+ (l @ PacketContents::Integer(_), PacketContents::StartList) => {
+ match compare_lists(
+ &mut once(l).chain(once(PacketContents::EndList)).peekable(),
+ right,
+ ) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ }
+ (PacketContents::StartList, r @ PacketContents::Integer(_)) => {
+ match compare_lists(
+ left,
+ &mut once(r).chain(once(PacketContents::EndList)).peekable(),
+ ) {
+ Ordering::Equal => (),
+ x => return x,
+ }
+ }
+ (PacketContents::Integer(l), PacketContents::Integer(r)) => match l.cmp(&r) {
+ Ordering::Equal => (),
+ x => return x,
+ },
+ };
+ }
+}
+
+#[derive(Debug, PartialEq, Eq)]
+enum PacketContents {
+ Integer(usize),
+ StartList,
+ EndList,
+}
+
+struct Packet<'a>(&'a str);
+
+impl Iterator for Packet<'_> {
+ type Item = PacketContents;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ loop {
+ if let Ok((i, _)) = tag::<_, _, (&str, nom::error::ErrorKind)>("[")(self.0) {
+ self.0 = i;
+ return Some(PacketContents::StartList);
+ } else if let Ok((i, _)) = tag::<_, _, (&str, nom::error::ErrorKind)>("]")(self.0) {
+ self.0 = i;
+ return Some(PacketContents::EndList);
+ } else if let Ok((i, x)) = u32::<_, (&str, nom::error::ErrorKind)>(self.0) {
+ self.0 = i;
+ return Some(PacketContents::Integer(x as usize));
+ } else if let Ok((i, _)) = tag::<_, _, (&str, nom::error::ErrorKind)>(",")(self.0) {
+ self.0 = i;
+ } else {
+ return None;
+ }
+ }
+ }
+}
diff --git a/2022/src/day14.html b/2022/src/day14.html
new file mode 100644
index 0000000..c441303
--- /dev/null
+++ b/2022/src/day14.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+ <link data-trunk rel="rust" data-wasm-opt="2" href="../Cargo.toml" data-bin="day14" />
+
+ <style>
+ html {
+ /* Remove touch delay: */
+ touch-action: manipulation;
+ }
+
+ html,
+ body {
+ overflow: hidden;
+ margin: 0 !important;
+ padding: 0 !important;
+ height: 100%;
+ width: 100%;
+ }
+
+ canvas {
+ margin-right: auto;
+ margin-left: auto;
+ display: block;
+ position: absolute;
+ top: 0%;
+ left: 50%;
+ transform: translate(-50%, 0%);
+ }
+ </style>
+</head>
+
+<body>
+ <canvas id="canvas"></canvas>
+</body>
+
+</html>
diff --git a/2022/src/day14.rs b/2022/src/day14.rs
new file mode 100644
index 0000000..903f919
--- /dev/null
+++ b/2022/src/day14.rs
@@ -0,0 +1,230 @@
+mod utils;
+use std::{
+ cmp::{max, min},
+ collections::HashSet,
+ ops::Add,
+ time::Duration,
+};
+
+use egui::{Color32, Rect, Sense, Stroke};
+use nom::{bytes::complete::tag, character::complete::u32, multi::separated_list0, IResult};
+
+fn main() {
+ console_error_panic_hook::set_once();
+
+ let input = include_str!("../fake_inputs/day14");
+
+ let options = eframe::WebOptions::default();
+ wasm_bindgen_futures::spawn_local(async {
+ eframe::start_web("canvas", options, Box::new(|_cc| Box::new(App::new(input))))
+ .await
+ .expect("unable to start eframe");
+ });
+}
+
+struct App {
+ structures: Vec<Structure>,
+ sand_grains: HashSet<Pos>,
+ speed: usize,
+ finished: bool,
+}
+
+impl App {
+ fn new(input: &str) -> Self {
+ let mut structures = separated_list0(tag("\n"), Structure::parse)(input)
+ .unwrap()
+ .1;
+ let floor_y = structures
+ .iter()
+ .map(|s| s.points.iter().map(|p| p.1).max().unwrap())
+ .max()
+ .unwrap()
+ + 2;
+ structures.push(Structure::new(vec![
+ Pos(isize::MIN, floor_y),
+ Pos(isize::MAX, floor_y),
+ ]));
+
+ App {
+ structures,
+ sand_grains: HashSet::new(),
+ speed: 0,
+ finished: false,
+ }
+ }
+
+ fn reset(&mut self) {
+ self.sand_grains.clear();
+ }
+
+ fn step(&mut self) {
+ let mut pos = Pos(500, 0);
+ if self.sand_grains.contains(&pos) {
+ self.finished = true;
+ return;
+ }
+ loop {
+ // TODO
+ pos = if !self.inhabited(pos + Pos(0, 1)) {
+ pos + Pos(0, 1)
+ } else if !self.inhabited(pos + Pos(-1, 1)) {
+ pos + Pos(-1, 1)
+ } else if !self.inhabited(pos + Pos(1, 1)) {
+ pos + Pos(1, 1)
+ } else {
+ self.sand_grains.insert(pos);
+ return;
+ };
+ }
+ }
+
+ fn inhabited(&self, pos: Pos) -> bool {
+ self.structures.iter().any(|s| s.contains(pos)) || self.sand_grains.contains(&pos)
+ }
+}
+
+#[derive(Debug)]
+struct Structure {
+ points: Vec<Pos>,
+ bbox_min: Pos,
+ bbox_max: Pos,
+}
+
+impl Structure {
+ fn new(points: Vec<Pos>) -> Self {
+ let bbox_min = points.iter().fold(Pos(isize::MAX, isize::MAX), |acc, pos| {
+ Pos(min(acc.0, pos.0), min(acc.1, pos.1))
+ });
+ let bbox_max = points.iter().fold(Pos(isize::MAX, isize::MAX), |acc, pos| {
+ Pos(max(acc.0, pos.0), max(acc.1, pos.1))
+ });
+
+ Structure {
+ points,
+ bbox_max,
+ bbox_min,
+ }
+ }
+ fn parse(i: &str) -> IResult<&str, Self> {
+ let (i, points) = separated_list0(tag(" -> "), Pos::parse)(i)?;
+
+ Ok((i, Structure::new(points)))
+ }
+
+ fn contains(&self, pos: Pos) -> bool {
+ if pos.0 < self.bbox_min.0
+ || pos.0 > self.bbox_max.0
+ || pos.1 < self.bbox_min.1
+ || pos.1 > self.bbox_max.1
+ {
+ return false;
+ }
+ for (a, b) in self.points.iter().zip(self.points.iter().skip(1)) {
+ if a.0 == b.0 {
+ if pos.0 == a.0 && pos.1 >= min(a.1, b.1) && pos.1 <= max(a.1, b.1) {
+ return true;
+ }
+ } else {
+ // a.1 == b.1
+ if pos.1 == a.1 && pos.0 >= min(a.0, b.0) && pos.0 <= max(a.0, b.0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+struct Pos(isize, isize);
+impl Pos {
+ fn parse(i: &str) -> IResult<&str, Self> {
+ let (i, x) = u32(i)?;
+ let (i, _) = tag(",")(i)?;
+ let (i, y) = u32(i)?;
+
+ Ok((i, Pos(x as _, y as _)))
+ }
+}
+impl From<Pos> for egui::Pos2 {
+ fn from(value: Pos) -> Self {
+ egui::Pos2 {
+ x: value.0 as _,
+ y: value.1 as _,
+ }
+ }
+}
+
+impl Add for Pos {
+ type Output = Pos;
+
+ fn add(self, rhs: Self) -> Self::Output {
+ Pos(self.0 + rhs.0, self.1 + rhs.1)
+ }
+}
+
+impl eframe::App for App {
+ fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
+ egui::SidePanel::right("instructions").show(ctx, |ui| {
+ egui::ScrollArea::vertical().show(ui, |ui| {
+ if ui.button("Step").clicked() && !self.finished {
+ self.step();
+ }
+ if ui.button("Reset").clicked() {
+ self.reset()
+ }
+ ui.label(format!(
+ "{} grains, finished: {}",
+ self.sand_grains.len(),
+ self.finished
+ ));
+ ui.add(egui::Slider::new(&mut self.speed, 0..=100).text("Speed"));
+ })
+ });
+
+ if self.speed > 0 {
+ for _ in 0..self.speed {
+ self.step();
+ }
+ ctx.request_repaint_after(Duration::from_millis(100))
+ }
+
+ egui::CentralPanel::default().show(ctx, |ui| {
+ let mut painter_size = ui.available_size_before_wrap();
+ if !painter_size.is_finite() {
+ painter_size = egui::vec2(500.0, 500.0);
+ }
+
+ const RANGE: f32 = 200.0;
+ const SHIFT: egui::Pos2 = egui::pos2(400.0, 5.0);
+ let (_, painter) = ui.allocate_painter(painter_size, Sense::hover());
+
+ let transform_point = |p: &Pos| -> egui::Pos2 {
+ egui::pos2(
+ ((p.0 as f32 - SHIFT.x) / RANGE) * painter_size.x,
+ ((p.1 as f32 + SHIFT.y) / RANGE) * painter_size.y,
+ )
+ };
+ for structure in self.structures.iter() {
+ for (a, b) in structure.points.iter().zip(structure.points.iter().skip(1)) {
+ painter.line_segment(
+ [transform_point(a), transform_point(b)],
+ Stroke::new(1.0, Color32::RED),
+ );
+ }
+ }
+
+ for grain in self.sand_grains.iter() {
+ painter.rect(
+ Rect {
+ min: transform_point(grain),
+ max: transform_point(&Pos(grain.0 + 1, grain.1 + 1)),
+ },
+ egui::Rounding::none(),
+ Color32::YELLOW,
+ Stroke::NONE,
+ )
+ }
+ });
+ }
+}
diff --git a/2022/src/utils.rs b/2022/src/utils.rs
new file mode 100644
index 0000000..8230c69
--- /dev/null
+++ b/2022/src/utils.rs
@@ -0,0 +1,59 @@
+#![allow(unused)]
+use std::{fs::File, io::Read, str::FromStr};
+
+pub fn read_input() -> String {
+ let mut args = std::env::args();
+
+ let mut file = File::open(
+ args.nth(1)
+ .expect("first argument should be input filename"),
+ )
+ .expect("could not open input");
+ let mut out = String::new();
+ file.read_to_string(&mut out)
+ .expect("could not read input file");
+
+ out
+}
+
+pub fn max_n<T: Ord>(vec: &mut Vec<T>, n: usize) -> &[T] {
+ top_n_by(vec, |a, b| a > b, n)
+}
+
+pub fn top_n_by<T, F: FnMut(&T, &T) -> bool>(vec: &mut Vec<T>, mut f: F, n: usize) -> &[T] {
+ for _ in 0..n {
+ for i in 0..vec.len() - 1 {
+ if f(&vec[i], &vec[i + 1]) {
+ vec.swap(i, i + 1);
+ }
+ }
+ }
+
+ &vec[vec.len() - n..]
+}
+
+pub fn iter_pair<T>(mut i: impl Iterator<Item = T>) -> (T, T) {
+ (i.next().unwrap(), i.next().unwrap())
+}
+
+pub fn iter_triple<T>(mut i: impl Iterator<Item = T>) -> (T, T, T) {
+ (i.next().unwrap(), i.next().unwrap(), i.next().unwrap())
+}
+
+#[inline(always)]
+pub fn parse_num<T: FromStr>(string: &str) -> (T, &str)
+where
+ <T as FromStr>::Err: std::fmt::Debug,
+{
+ let count = string
+ .chars()
+ .take_while(|x| x.is_numeric() || *x == '-')
+ .count();
+
+ (string[..count].parse().unwrap(), &string[count..])
+}
+
+#[inline(always)]
+pub fn parse_static<'a>(exp: &'static str, source: &'a str) -> &'a str {
+ &source[exp.len()..]
+}