Skip to content

Commit

Permalink
Extract binary search into Prelude
Browse files Browse the repository at this point in the history
  • Loading branch information
glguy committed Dec 6, 2023
1 parent a76c492 commit a089b3d
Show file tree
Hide file tree
Showing 3 changed files with 20 additions and 29 deletions.
15 changes: 15 additions & 0 deletions common/src/Advent/Prelude.hs
Original file line number Diff line number Diff line change
Expand Up @@ -275,3 +275,18 @@ multiline = QuasiQuoter {
partialSums :: Num a => [a] -> [a]
partialSums = scanl' (+) 0
{-# Inline partialSums #-}

-- | Binary search for the largest value satisfying a predicate.
-- Finds the largest value when the predicate switches from True
-- to False. There should only be one such point in the range.
binSearchLargest ::
(Int -> Bool) {- ^ predicate -} ->
Int {- ^ small enough -} ->
Int {- ^ too big -} ->
Int
binSearchLargest p lo hi
| lo + 1 == hi = lo
| p mid = binSearchLargest p mid hi
| otherwise = binSearchLargest p lo mid
where
mid = lo + (hi - lo) `div` 2
16 changes: 2 additions & 14 deletions solutions/src/2019/14.hs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Maintainer : emertens@gmail.com
-}
module Main (main) where

import Advent.Format (format)
import Advent.Format (format, binSearch)
import Data.List (foldl', sortOn)
import Data.Map (Map)
import Data.Map qualified as Map
Expand Down Expand Up @@ -81,16 +81,4 @@ expSearch p lo = go (lo+1)
where
go hi
| p hi = go (2*hi)
| otherwise = binSearch p lo hi

binSearch ::
(Int -> Bool) {- ^ predicate -} ->
Int {- ^ small enough -} ->
Int {- ^ too big -} ->
Int
binSearch p lo hi
| lo + 1 == hi = lo
| p mid = binSearch p mid hi
| otherwise = binSearch p lo mid
where
mid = lo + (hi - lo) `div` 2
| otherwise = binSearchLargest p lo hi
18 changes: 3 additions & 15 deletions solutions/src/2023/06.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ Distance: 9 40 200
-}
module Main where

import Advent (format)
import Advent (format, binSearchLargest)

-- |
--
Expand All @@ -47,17 +47,5 @@ ways (t, d)
where
valid hold = (t - hold) * hold > d
mid = t `div` 2 -- the midpoint is the best we can get
tooLo = binSearch (not . valid) 0 mid
hi = binSearch valid mid t

binSearch ::
(Int -> Bool) {- ^ predicate -} ->
Int {- ^ small enough -} ->
Int {- ^ too big -} ->
Int
binSearch p lo hi
| lo + 1 == hi = lo
| p mid = binSearch p mid hi
| otherwise = binSearch p lo mid
where
mid = lo + (hi - lo) `div` 2
tooLo = binSearchLargest (not . valid) 0 mid
hi = binSearchLargest valid mid t

0 comments on commit a089b3d

Please sign in to comment.