aboutsummaryrefslogtreecommitdiff
path: root/2020/14a.hs
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 /2020/14a.hs
initial commit
Diffstat (limited to '2020/14a.hs')
-rw-r--r--2020/14a.hs89
1 files changed, 89 insertions, 0 deletions
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 ();