~rootmos/AoC

3b33e2696a7bb6fed36fca3d91cd9d6dc324c705 — Gustav Behm a month ago ac3ebbb
Add ugly solution to AoC 2023 #07a
3 files changed, 127 insertions(+), 11 deletions(-)

M 2023/07.hs
M lib/Qulude.hs
M templates/template.hs
M 2023/07.hs => 2023/07.hs +124 -9
@@ 18,10 18,26 @@ import qualified Data.Maybe as Maybe
import qualified Data.Sequence as Seq
import qualified Data.Set as Set

data Card = Ace | King | Queen | Jack | Joker | Num Int
  deriving ( Show, Eq )
data Card = Ace | King | Queen | Jack | Num Int
  deriving Eq
type Hand = [Card]

instance Show Card where
  show Ace = "A"
  show King = "K"
  show Queen = "Q"
  show Jack = "J"
  show (Num 10) = "T"
  show (Num i) = show i

instance Ord Card where
  _ <= Ace = True
  c <= King = c `notElem` [ Ace ]
  c <= Queen = c `notElem` [ Ace, King ]
  c <= Jack = c `notElem` [ Ace, King, Queen ]
  Num c0 <= Num c1 = c0 <= c1
  _ <= Num c1 = False

type Parse = [(Hand, Int)]
parser :: Parser Parse
parser = many $ do


@@ 32,20 48,119 @@ parser = many $ do
  return (hand, bid)
  where cardP = (char 'A' $> Ace)
            <|> (char 'K' $> King)
            <|> (char 'Q' $> King)
            <|> (char 'T' $> Jack)
            <|> (char 'J' $> Joker)
            <|> (char 'Q' $> Queen)
            <|> (char 'J' $> Jack)
            <|> (char 'T' $> Num 10)
            <|> (digit <&> Num . read . flip (:) [])

partA :: Parse -> Parse
partA = id
cards = [ Ace, King, Queen, Jack ] ++ [ Num i | i <- [2..10] ]

data Type = Five Card
          | Four Card
          | FullHouse Card Card
          | Three Card
          | TwoPair Card Card
          | OnePair Card
          | High Card
  deriving ( Show, Eq )

instance Ord Type where
  Five c <= Five d = c <= d
  _ <= Five _ = True

  Five _ <= Four _ = False
  Four c <= Four d = c <= d
  _ <= Four _ = True

  Five _ <= FullHouse _ _ = False
  Four _ <= FullHouse _ _ = False
  FullHouse c0 c1 <= FullHouse d0 d1 = if c0 == d0 then c1 <= d1 else c0 <= d0
  _ <= FullHouse _ _ = True

  Five _ <= Three _ = False
  Four _ <= Three _ = False
  FullHouse _ _ <= Three _ = False
  Three c <= Three d = c <= d
  _ <= Three _ = True

  Five _ <= TwoPair _ _ = False
  Four _ <= TwoPair _ _ = False
  FullHouse _ _ <= TwoPair _ _ = False
  Three _ <= TwoPair _ _ = False
  TwoPair c0 c1 <= TwoPair d0 d1 = if c0 == d0 then c1 <= d1 else c0 <= d0
  _ <= TwoPair _ _ = True

  Five _ <= OnePair _ = False
  Four _ <= OnePair _ = False
  FullHouse _ _ <= OnePair _ = False
  Three _ <= OnePair _ = False
  TwoPair _ _ <= OnePair _ = False
  OnePair c <= OnePair d = c <= d
  _ <= OnePair d = True

  High c <= High d = c <= d
  _ <= High _ = False

maxMaybe :: Ord a => [a] -> Maybe a
maxMaybe [] = Nothing
maxMaybe as = Just . last $ List.sort as

sameType :: Type -> Type -> Bool
sameType (Five _) (Five _) = True
sameType (Four _) (Four _) = True
sameType (FullHouse _ _) (FullHouse _ _) = True
sameType (Three _) (Three _) = True
sameType (TwoPair _ _) (TwoPair _ _) = True
sameType (OnePair _) (OnePair _) = True
sameType (High _) (High _) = True
sameType _ _ = False

judge :: Hand -> Maybe Type
judge h = maxMaybe $ good
  where cs = [ (c, count $ (==) c <$> h) | c <- cards ]
        fives = fmap Five $ mapMaybe (\(c, i) -> if i == 5 then Just c else Nothing) cs
        fours = fmap Four $ mapMaybe (\(c, i) -> if i == 4 then Just c else Nothing) cs
        threes = mapMaybe (\(c, i) -> if i == 3 then Just c else Nothing) cs
        pairs = reverse . List.sort $ mapMaybe (\(c, i) -> if i == 2 then Just c else Nothing) cs
        (twopairs, fullhouse) = case (threes, pairs) of
                                (t:_, p:_) -> ([], [FullHouse t p])
                                ([], p:q:_) -> ([], [TwoPair p q])
                                (_, _) -> ([], [])
        good = fives
            ++ fours
            ++ (fmap Three threes)
            ++ fullhouse
            ++ (fmap Three threes)
            ++ twopairs
            ++ (fmap OnePair pairs)

        t2c (Five c) = [c]
        t2c (Four c) = [c]
        t2c (FullHouse c d) = [c, d]
        t2c (Three c) = [c]
        t2c (TwoPair c d) = [c, d]
        t2c (OnePair c) = [c]
        t2c (High c) = [c]

        highest = fmap High $ filter (\c -> c `notElem` (concat (fmap t2c good))) h

camel :: Hand -> Hand -> Ordering
camel h0 h1 = cmp (judge h0) (judge h1)
  where cmp (Just p) (Just q) = if sameType p q then compare h0 h1 else compare p q
        cmp Nothing (Just _) = LT
        cmp (Just _) Nothing = GT
        cmp Nothing Nothing = compare h0 h1

partA :: Parse -> Int
partA hs = foldl (+) 0 $ fmap (\(r, b) -> r * b) $ zip [1..] $ fmap snd $ js
  where js = List.sortBy (\(h0, _) (h1, _) -> camel h0 h1) hs

--partB :: Parse -> Parse
--partB = id

main :: IO ()
main = with parser $ do
  run "07.example" "a example" partA
  run "07.input" "a input" partA
  run "07.example" "a example" partA -- 6440
  run "07.input" "a input" partA -- 245794640
  --run "07.example" "b example" partB
  --run "07.input" "b input" partB

M lib/Qulude.hs => lib/Qulude.hs +2 -1
@@ 48,6 48,7 @@ module Qulude ( module Prelude
              , fromMaybe
              , catMaybes
              , mapMaybe
              , listToMaybe

              , swap



@@ 68,7 69,7 @@ import Prelude hiding ( lines, cycle )

import Data.List ( (\\), foldl' )
import Data.Sequence ( (><), (<|), (|>), Seq ( (:<|), (:|>) ) )
import Data.Maybe ( fromJust, fromMaybe, catMaybes, mapMaybe )
import Data.Maybe ( fromJust, fromMaybe, catMaybes, mapMaybe, listToMaybe )
import Data.Tuple ( swap )
import Data.Function ( (&) )
import Data.Either

M templates/template.hs => templates/template.hs +1 -1
@@ 12,7 12,7 @@ import qualified Data.Array as Array
import qualified Data.Array.ST as STArray
import qualified Data.Either as Either
import qualified Data.List as List
--import Data.Array ( (!) )
--import Data.Map ( (!) )
import qualified Data.Map as Map
import qualified Data.Maybe as Maybe
import qualified Data.Sequence as Seq