-
Notifications
You must be signed in to change notification settings - Fork 0
/
4_1.hs
64 lines (50 loc) · 2.01 KB
/
4_1.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import Data.List(transpose)
import Data.Maybe
main = do
contents <- readFile "4.txt"
let rawLines = lines contents :: [String]
rawLinesNoEmpty = filter (/= "") rawLines
calledNumbers = map (\x -> read x :: Int) $ split (head rawLinesNoEmpty) ','
rawCards = tail rawLinesNoEmpty
bingoCards = createBingoCards rawCards
(winningNumber, summedRest) = play bingoCards calledNumbers
print (winningNumber, summedRest)
print $ winningNumber * summedRest
return ()
createBingoCards :: [String] -> [[[(Int, Bool)]]]
createBingoCards [] = []
createBingoCards cards = createBingoCard (take 5 cards) : createBingoCards (drop 5 cards)
createBingoCard :: [String] -> [[(Int, Bool)]]
createBingoCard = map (createBingoCardRow . words)
createBingoCardRow :: [String] -> [(Int, Bool)]
createBingoCardRow = map (\x -> (read x :: Int, False))
play :: [[[(Int, Bool)]]] -> [Int] -> (Int, Int)
play _ [] = (0, 0)
play boards (number:rest) =
let newBoards = map (\board -> applyBoard board number) boards
winner = first checkBoard newBoards
in if isJust winner then (number, sumBoard $ fromJust winner) else play newBoards rest
sumBoard :: [[(Int, Bool)]] -> Int
sumBoard board =
let fields = concat board
relevant = filter (not . snd) fields
numbers = map fst relevant
in sum numbers
first :: (a -> Bool) -> [a] -> Maybe a
first _ [] = Nothing
first f (head:tail) = if f head then Just head else first f tail
checkBoard :: [[(Int, Bool)]] -> Bool
checkBoard board =
let rows = board
columns = transpose board
slices = rows ++ columns
in any validateSlice slices
validateSlice :: [(Int, Bool)] -> Bool
validateSlice = all snd
applyBoard :: [[(Int, Bool)]] -> Int -> [[(Int, Bool)]]
applyBoard board number = map (map (\(field, called) -> (field, called || number == field))) board
split :: String -> Char -> [String]
split [] _ = []
split str sep =
let (word, rest) = break (== sep) str
in word : split (dropWhile (== sep) rest) sep