Skip to content

Commit 9badc5c

Browse files
authored
Merge pull request #46 from coproduto/main
Added Haskell solution for day 14
2 parents 66d4235 + 2179404 commit 9badc5c

File tree

3 files changed

+99
-1
lines changed

3 files changed

+99
-1
lines changed

2020/coproduto/haskell/app/Main.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import qualified Day10
1313
import qualified Day11
1414
import qualified Day12
1515
import qualified Day13
16+
import qualified Day14
1617

1718
main :: IO ()
1819
main = do
@@ -106,3 +107,10 @@ main = do
106107
putStr "Day 13 Part 2 - Result: "
107108
Day13.part2
108109
putStr "\n"
110+
111+
putStrLn "-- Day 14 --"
112+
putStr "Day 14 Part 1 - Result: "
113+
Day14.part1
114+
putStr "Day 14 Part 2 - Result: "
115+
Day14.part2
116+
putStr "\n"

2020/coproduto/haskell/src/Common.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ sum' = foldl' (+) 0
1818
product' :: (Num a, Foldable f) => f a -> a
1919
product' = foldl' (*) 1
2020

21-
textToInt :: Text -> Int
21+
textToInt :: Integral a => Text -> a
2222
textToInt txt = let Right (x, _) = Read.decimal txt in x
2323

2424
textToInteger :: Text -> Integer

2020/coproduto/haskell/src/Day14.hs

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
{-# LANGUAGE OverloadedStrings #-}
2+
module Day14
3+
( part1
4+
, part2
5+
) where
6+
7+
import Data.Int (Int64)
8+
import Data.Bits ((.&.), (.|.), testBit, clearBit, setBit, complement, zeroBits)
9+
import Data.List (foldl')
10+
import Data.Text (Text)
11+
import qualified Data.Text as Text
12+
import Data.Map (Map, (!))
13+
import qualified Data.Map as Map
14+
import Control.Monad.State
15+
import Common (textToInt, readFileUtf8, sum')
16+
17+
data Inst = SetMask (Int64, Int64, Int64) | SetMem (Int, Int64) deriving Show
18+
type ProgramState = (Map Int Int64, (Int64, Int64, Int64))
19+
20+
run :: (ProgramState -> Inst -> ProgramState) -> IO ()
21+
run execInst = do
22+
input <- fmap parseLine . Text.lines <$> (readFileUtf8 "input/day_14.txt")
23+
let (finalMem, _) = foldl' execInst (Map.empty, (0, 0, 0)) input
24+
print (sum' $ Map.elems finalMem)
25+
26+
part1 :: IO ()
27+
part1 = run runInst
28+
29+
part2 :: IO ()
30+
part2 = run runInstWithFloat
31+
32+
runInst :: ProgramState -> Inst -> ProgramState
33+
runInst (mem, mask) (SetMask newMask) = (mem, newMask)
34+
runInst (mem, mask) (SetMem (addr, val)) = (Map.insert addr maskedVal mem, mask)
35+
where maskedVal = applyMask mask val
36+
37+
runInstWithFloat :: ProgramState -> Inst -> ProgramState
38+
runInstWithFloat (mem, mask) (SetMask newMask) = (mem, newMask)
39+
runInstWithFloat (mem, mask) (SetMem (addr, val)) =
40+
(foldl' (\mem' addr -> Map.insert addr val mem') mem (fromIntegral <$> maskedAddrs), mask)
41+
where maskedAddrs = applyMaskWithFloat mask (fromIntegral addr)
42+
43+
binTextToInt64 :: Text -> Int64
44+
binTextToInt64 txt = binTextToInt64' 0 (Text.unpack txt)
45+
where binTextToInt64' acc [] = acc
46+
binTextToInt64' acc ('0':cs) = binTextToInt64' (2*acc) cs
47+
binTextToInt64' acc ('1':cs) = binTextToInt64' (2*acc + 1) cs
48+
49+
parseMask :: Text -> (Int64 ,Int64, Int64)
50+
parseMask mask = (floatMask, andMask, orMask)
51+
where andMask = binTextToInt64 (Text.replace "X" "1" mask)
52+
orMask = binTextToInt64 (Text.replace "X" "0" mask)
53+
floatMask =
54+
binTextToInt64 (Text.replace "X" "1" (Text.replace "1" "0" mask))
55+
56+
parseSet :: Text -> (Int, Int64)
57+
parseSet text = (addr, arg)
58+
where (_, rest) = Text.break (=='[') text
59+
(addrText, rest') = Text.break (==']') rest
60+
arg = textToInt (last (Text.words rest'))
61+
addr = textToInt (Text.drop 1 addrText)
62+
63+
applyMask :: (Int64, Int64, Int64) -> Int64 -> Int64
64+
applyMask (_, andMask, orMask) n = andMask .&. (orMask .|. n)
65+
66+
applyMask' :: (Int64, Int64, Int64) -> Int64 -> Int64
67+
applyMask' (_, andMask, orMask) n = orMask .|. (andMask .&. n)
68+
69+
makeFloatMasks :: Int64 -> [(Int64, Int64, Int64)]
70+
makeFloatMasks mask =
71+
let bits = filter (testBit mask) [0..35]
72+
subMasks = powerset bits
73+
setBits = foldl' setBit 0
74+
unsetAll = foldl' clearBit (complement zeroBits) bits
75+
in (\mask -> (0, unsetAll, setBits mask)) <$> subMasks
76+
77+
powerset :: [a] -> [[a]]
78+
powerset [] = [[]]
79+
powerset (x:xs) = [x:ps | ps <- powerset xs] ++ powerset xs
80+
81+
applyMaskWithFloat :: (Int64, Int64, Int64) -> Int64 -> [Int64]
82+
applyMaskWithFloat mask n =
83+
let (floatMask, _, orMask) = mask
84+
floatMasks = makeFloatMasks floatMask
85+
in zipWith applyMask' floatMasks (repeat $ orMask .|. n)
86+
87+
parseLine :: Text -> Inst
88+
parseLine line
89+
| "mask" `Text.isPrefixOf` line = SetMask $ parseMask (last $ Text.words line)
90+
| otherwise = SetMem $ parseSet line

0 commit comments

Comments
 (0)