Skip to content

Commit 780ece9

Browse files
committed
Use a partial sort for the partial ordering
1 parent c9a7757 commit 780ece9

File tree

2 files changed

+38
-34
lines changed

2 files changed

+38
-34
lines changed

hs/aoc2024.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ library
3535
containers ^>=0.7,
3636
megaparsec ^>=9.7.0,
3737
text ^>=2.1.2,
38+
vector ^>=0.13.2.0,
3839

3940
ghc-options: -Wall
4041
default-language: GHC2024

hs/src/Day5.hs

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,56 +3,59 @@
33
-- Description: <https://adventofcode.com/2024/day/5 Day 5: Print Queue>
44
module Day5 (part1, part2) where
55

6-
import Control.Arrow (second)
7-
import Data.IntMap qualified as IntMap (findWithDefault, fromList, (!?))
8-
import Data.IntMap.Strict qualified as IntMap (fromListWith)
9-
import Data.IntSet qualified as IntSet (empty, member, singleton, toList, union)
10-
import Data.List (sortBy)
11-
import Data.Maybe (fromJust, fromMaybe)
6+
import Data.List (tails)
7+
import Data.Set (Set)
8+
import Data.Set qualified as Set (fromList, notMember)
129
import Data.String (IsString)
1310
import Data.Text (Text)
11+
import Data.Vector.Generic (Vector)
12+
import Data.Vector.Generic qualified as V (fromList, length, modify, (!))
13+
import Data.Vector.Generic.Mutable qualified as MV (length, read, write)
14+
import Data.Vector.Unboxed qualified as UV (Vector)
1415
import Data.Void (Void)
1516
import Text.Megaparsec (MonadParsec, ParseErrorBundle, Stream (Token, Tokens), parse, sepEndBy, sepEndBy1, skipMany)
1617
import Text.Megaparsec.Char (char, newline)
1718
import Text.Megaparsec.Char.Lexer (decimal)
1819

19-
parser :: (MonadParsec e s m, IsString (Tokens s), Token s ~ Char, Num a) => m ([(a, a)], [[a]])
20+
parser :: (MonadParsec e s m, IsString (Tokens s), Token s ~ Char, Num a, Ord a) => m (Set (a, a), [[a]])
2021
parser =
21-
(,)
22+
(,) . Set.fromList
2223
<$> ((,) <$> decimal <* char '|' <*> decimal) `sepEndBy` newline
2324
<* skipMany newline
2425
<*> (decimal `sepEndBy1` char ',') `sepEndBy` newline
2526

2627
part1 :: Text -> Either (ParseErrorBundle Text Void) Int
2728
part1 input = do
2829
(deps, updates) <- parse parser "" input
29-
pure $
30-
sum
31-
[ update !! (length update `div` 2)
32-
| update <- updates,
33-
let order = IntMap.fromList @Int $ zip update [0 ..],
34-
and
35-
[ fromMaybe True $ (<) <$> order IntMap.!? a <*> order IntMap.!? b
36-
| (a, b) <- deps
37-
]
38-
]
30+
pure . sum $
31+
[ update !! (length update `div` 2)
32+
| update <- updates,
33+
and [(b, a) `Set.notMember` deps | a : rest <- tails update, b <- rest]
34+
]
3935

4036
part2 :: Text -> Either (ParseErrorBundle Text Void) Int
4137
part2 input = do
4238
(deps, updates) <- parse parser "" input
43-
let deps' = IntMap.fromListWith IntSet.union $ second IntSet.singleton <$> deps
44-
tryCompare a b
45-
| a == b = Just EQ
46-
| b `IntSet.member` (IntMap.findWithDefault IntSet.empty a deps') = Just LT
47-
| a `IntSet.member` (IntMap.findWithDefault IntSet.empty b deps') = Just GT
48-
| otherwise =
49-
mconcat (tryCompare a <$> maybe [] IntSet.toList (deps' IntMap.!? b))
50-
<> fmap (compare EQ) (mconcat (tryCompare b <$> maybe [] IntSet.toList (deps' IntMap.!? a)))
51-
compare' a b = fromJust $ tryCompare a b
52-
pure $
53-
sum
54-
[ update' !! (length update `div` 2)
55-
| update <- updates,
56-
let update' = sortBy compare' update,
57-
update /= update'
58-
]
39+
let ok a b = (b, a) `Set.notMember` deps
40+
pure . sum $
41+
[ pages V.! (V.length pages `div` 2)
42+
| update <- V.fromList @UV.Vector @Int <$> updates,
43+
let pages = sort' ok update,
44+
update /= pages
45+
]
46+
47+
sort' :: (Vector v a) => (a -> a -> Bool) -> v a -> v a
48+
sort' ok = V.modify $ \v ->
49+
let go i j
50+
| j < MV.length v = do
51+
x <- MV.read v i
52+
y <- MV.read v j
53+
if ok x y
54+
then go i (j + 1)
55+
else do
56+
MV.write v i y
57+
MV.write v j x
58+
go i (i + 1)
59+
| i < MV.length v = go (i + 1) (i + 2)
60+
| otherwise = pure ()
61+
in go 0 1

0 commit comments

Comments
 (0)