13 Haskell
Part I Assignment
Haskell (GHC) is installed by
sudo apt install haskell-platform -y
.
Then the interpreter is run by ghci
.
A script test.hs
is compiled by ghc -o test test.hs
and then run as usual ./test
.
The write-compile-run is then accomplished with
ghc -o 13 13.hs && ./13
.
This is actually pretty elegant solution in my opinion.
Part I Assignment
-- we need isDigit function
import Data.Char
-- convert text into a list of lines
process_text :: String -> [String]
-- lines is built-in function
process_text text = lines text
-- read integer from a string and convert it to integer
-- return also the rest of the string
readn :: (String, String) -> (Int, String)
readn (s,[]) = (read s :: Int, [])
readn (s,(x:xs)) =
if isDigit x
then readn (s ++ [x], xs)
else (read s :: Int, x:xs)
-- extract integer from string, wrap it into [] and
-- put back into the string
wrapn :: String -> String
wrapn [] = []
wrapn x =
let (n, rest) = readn ([], x)
in "[" ++ show n ++ "]" ++ rest
-- split list of lines into pairs of strings
-- omit empty lines
parse :: [String] -> [(String,String)]
parse [] = []
parse (x:y:xs) =
if x == []
then parse (y : xs)
else [(x, y)] ++ parse xs
-- compare two strings
-- right order => 1 wrong order => 0
cmpp :: (String, String) -> Int
cmpp ([],[]) = 1
cmpp ([x],[]) = 0
cmpp ([],[y]) = 1
cmpp (x:xs,y:ys) =
if isDigit x && isDigit y -- both numbers
-- both first chars are digits, compare the numbers
then let (ln, lr) = readn ([], x:xs)
(rn, rr) = readn ([], y:ys)
in
if ln < rn
-- left number < right number
then 1
else if ln == rn
-- left number == right number
then cmpp (lr, rr)
-- left number > right number
else 0
else if x == y
-- the same symbol, continue with the suffix
then cmpp (xs, ys)
else if [x] == "]"
-- left is shorter
then 1
else if [y] == "]"
-- right is shorter
then 0
else if isDigit x && [y] == "["
-- wrap left number into brackets and continue
then cmpp (wrapn (x:xs), y:ys)
else if isDigit y && [x] == "["
-- wrap right number into brackets and continue
then cmpp (x:xs, wrapn (y:ys))
else 1
-- if the packets are in the right order
-- multiply the packet number (second argument) with the compare result
-- and increase the sum (first argument)
packet_list :: Int -> Int -> [(String,String)] -> Int
packet_list a b [] = a
packet_list a b (x:xs) = packet_list (a + b * (cmpp x)) (b + 1) xs
-- main
main :: IO ()
main = do
content <- readFile "13.input"
-- first get lines, then split into packet pairs
-- then process the list and finally print the result
print $ packet_list 0 1 (parse $ process_text content)
Part II
import Data.List
import Data.Char
import Data.Maybe
process_text :: String -> [String]
process_text text = lines text
readn :: (String, String) -> (Int, String)
readn (s,[]) = (read s :: Int, [])
readn (s,(x:xs)) =
if isDigit x
then readn (s ++ [x], xs)
else (read s :: Int, x:xs)
wrapn :: String -> String
wrapn [] = []
wrapn x =
let (n, rest) = readn ([], x)
in "[" ++ show n ++ "]" ++ rest
-- now we convert lines into a list of packets
parse :: [String] -> [String]
parse [] = []
parse (x:xs) =
if x == []
then parse xs
else [x] ++ parse xs
-- now this function returns Ordering (LT and GT)
-- so we can use it to sort array
cmpp :: String -> String -> Ordering
cmpp [] [] = LT
cmpp [x] [] = GT
cmpp [] [y] = LT
cmpp (x:xs) (y:ys) =
if isDigit x && isDigit y
then let (ln, lr) = readn ([], x:xs)
(rn, rr) = readn ([], y:ys)
in
if ln < rn
then LT
else if ln == rn
then cmpp lr rr
else GT
else if x == y
then cmpp xs ys
else if [x] == "]"
then LT
else if [y] == "]"
then GT
else if isDigit x && [y] == "["
then cmpp (wrapn (x:xs)) (y:ys)
else if isDigit y && [x] == "["
then cmpp (x:xs) (wrapn (y:ys))
else LT
-- helper function to convert Maybe Int a to a + 1
indInt :: Maybe Int -> Int
indInt x = (fromMaybe 1 x) + 1
main :: IO ()
main = do
content <- readFile "13.input"
-- parse lines into a pa
let packets = sortBy cmpp
(["[[2]]"] ++ ["[[6]]"] ++ parse (process_text content))
in
print $
(indInt (elemIndex "[[2]]" packets)) * (indInt (elemIndex "[[6]]" packets))
Materials
- Cheat sheet (PDF) (reminds me of my CS studies at university).
What I learned
- I’ve forgotten almost everything about Haskell.
- It’s very elegant language but not very convenient.
published: 2022-12-13
last modified: 2023-01-21
https://vit.baisa.cz/notes/code/advent-of-code-2022/13/
last modified: 2023-01-21
https://vit.baisa.cz/notes/code/advent-of-code-2022/13/