-
Notifications
You must be signed in to change notification settings - Fork 1
/
circ.hs
71 lines (54 loc) · 2.17 KB
/
circ.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
65
import Data.Ord
import Data.List (sortBy)
-- x,y
type Point = (Float, Float)
-- center (x,y) and radius.
type Circle = (Point, Float)
-- 0.68543744 0.5940232
-- 0.35073838
makeCircle :: Point -> Point -> Point -> Circle
makeCircle (x1, y1) (x2, y2) (x3, y3) = ((x, y), r) where
k = 2 * (x1 * (y2 - y3) - y1 * (x2 - x3) + x2 * y3 - x3 * y2)
x = ((x1^2 + y1^2) * (y2 - y3) + (x2^2 + y2^2) * (y3 - y1) + (x3^2 + y3^2) * (y1 - y2)) / k
y = ((x1^2 + y1^2) * (x3 - x2) + (x2^2 + y2^2) * (x1 - x3) + (x3^2 + y3^2) * (x2 - x1)) / k
r = sqrt ((x - x1)^2 + (y - y1)^2)
makeCircle' :: Point -> Point -> Circle
makeCircle' (x1, y1) (x2, y2) = ( (x, y) , r) where
x = (x1+x2)/2
y = (y1+y2)/2
r = sqrt ((x - x1)^2 + (y - y1)^2)
isInCircle :: Point -> Circle -> Bool
isInCircle (x, y) ((cx, cy), r) =
(x - cx)^2 + (y - cy)^2 - r^2 < 0.000000001
allCircles :: [Point] -> [Circle]
allCircles ps = [makeCircle p1 p2 p3 | p1 <- ps, p2 <- ps, p3 <- ps, p1 /= p2 && p1 /= p3 && p2 /= p3] ++ [makeCircle p1 p1 p2 | p1 <- ps, p2 <- ps, p1 /= p2 && p2 /= p1]
countPointsIn :: [Point] -> Circle -> Int
countPointsIn [] _ = 0
countPointsIn (p:ps) c
| isInCircle p c = 1 + countPointsIn ps c
| otherwise = countPointsIn ps c
isMinCircle :: [Point] -> Circle -> Bool
isMinCircle ps c = countPointsIn ps c == min where min = div (length ps) 2
getMinCircle :: [Point] -> Maybe Circle
getMinCircle ps = result where
circs = sortBy (comparing snd) . allCircles $ ps
maybeList = dropWhile (\x -> not $ isMinCircle ps x ) circs
result = f maybeList where
f [] = Nothing
f ls = Just (head ls)
toPoint :: [String] -> Point
toPoint (x:y:[]) = (read x :: Float, read y :: Float)
showResult :: Maybe Circle -> String
showResult c =
case c of
Nothing -> "Nothing"
Just ((x, y), d ) -> show x ++ " " ++ show y ++ " " ++ show d
-- "0.57601506 0.34845096 0.3578915"
-- [Finished in 26.8s]
main :: IO ()
main = do
input <- readFile "points.txt"
let points = map toPoint . map words . lines $ input
print $ showResult . getMinCircle $ points
-- "0.57601506 0.34845096 0.3578915"
-- [Finished in 25.4s]