2013年2月11日月曜日

開発環境

Real World Haskell』(Bryan O'SullivanJohn GoerzenDon Stewart(著)、山下 伸夫伊東 勝利株式会社タイムインターメディア(翻訳)、オライリー・ジャパン、2009年、ISBN978-4-87311-423-3)の3章(型を定義し、関数を単純化する)の3.13(ガード条件節の評価)の練習問題12.を解いてみる。

12.

コード(BBEdit)

Sample.hs

-- file: Sample.hs
data Point = Point Double Double
                   deriving (Eq, Show)
data Direction = DLeft |
                 DRight |
                 DStraight
                 deriving (Eq, Show)
crossProduct :: Point -> Point -> Double
crossProduct (Point x1 y1) (Point x2 y2) = x1 * y2 - x2 * y1
getDirection :: Point -> Point -> Point -> Direction
getDirection (Point x1 y1) (Point x2 y2) (Point x3 y3)
    | cp > 0 = DLeft
    | cp == 0 = DStraight
    | cp < 0 = DRight
        where cp = crossProduct a b
              a = Point (x2 - x1) (y2 - y1)
              b = Point (x3 - x2) (y3 - y2)
getDirections :: [Point] -> [Direction]
getDirections [] = []
getDirections (x:xs) | length xs <= 1 = []
                     | otherwise = (getDirection x y z):(getDirections xs)
                         where y = head l
                               z = last l
                               l = take 2 xs
sortByY :: [Point] -> [Point]
sortByY [] = []
sortByY (x:[]) = [x]
sortByY (x:xs) = (sortByY small) ++ [x] ++ (sortByY large)
    where small = smaller x xs
          large = larger x xs
          smaller (Point x y) [] = []
          smaller (Point x1 y1) ((Point x2 y2):xs)
              | y1 > y2 = (Point x2 y2):(smaller (Point x1 y1) xs)
              | y1 == y2 && x1 > x2 = (Point x2 y2):(smaller (Point x1 y1) xs)
              | otherwise = smaller (Point x1 y1) xs
          larger (Point x y) [] = []
          larger (Point x1 y1) ((Point x2 y2):xs)
              | y1 < y2 = (Point x2 y2):(larger (Point x1 y1) xs)
              | y1 == y2 && x1 <= x2 = (Point x2 y2):(larger (Point x1 y1) xs)
              | otherwise = larger (Point x1 y1) xs
angle :: Point -> Point -> Double
angle (Point x1 y1) (Point x2 y2) = (x2 - x1) / (y2 - y1)
sortByAngleSub :: Point -> [Point] -> [Point]
sortByAngleSub p [] = []
sortByAngleSub p (x:xs) = sortByAngleSub p small ++ [x] ++ sortByAngleSub p large
    where small = smaller x xs
          large = larger x xs
          smaller a [] = []
          smaller a (b:bs)
              | angle p a <= angle p b = b:(smaller a bs)
              | otherwise = smaller a bs
          larger a [] = []
          larger a (b:bs)
              | angle p a > angle p b = b:(larger a bs)
              | otherwise = larger a bs
sortByAngle :: [Point] -> [Point]
sortByAngle [] = []
sortByAngle (x:[]) = [x]
sortByAngle (x:xs)
    | length xs == 1 = (x:xs)
    | otherwise = x:sortByAngleSub x xs
grahamScan :: [Point] -> [Point]
grahamScan [] = []
grahamScan (x:xs)
    | length xs <= 1 = (x:xs)
    | otherwise = scan as
        where bs = sortByY (x:xs)
              p = take 1 bs
              as = (sortByAngle bs) ++ p
              scan [a, b] = [a]
              scan (a:b:c:as) 
                  | getDirection a b c == DLeft = a:(scan (b:c:as))
                  | getDirection a b c == DStraight = scan (a:c:as)
                  | getDirection a b c == DRight = scan (a:c:as)

a = Point (-10) 10
b = Point 10 10
c = Point (-10) (-10)
d = Point 10 (-10)
e = Point 0 0
f = Point 1 5
g = Point (-5) 1
h = Point (-2) (-4)
i = Point 4 (-2)
j = Point 0 (-5)
pointList = [a,b,c,d,e,f,g,h,i,j]

入出力結果(Terminal)

$ ghci
GHCi, version 7.4.2: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :load Sample.hs
[1 of 1] Compiling Main             ( Sample.hs, interpreted )
Ok, modules loaded: Main.
*Main> grahamScan pointList
[Point (-10.0) (-10.0),Point 10.0 (-10.0),Point 4.0 (-2.0),Point 10.0 10.0,Point 1.0 5.0,Point (-10.0) 10.0]
*Main> :quit
Leaving GHCi.
$

出力見ると、凸集合は4点((10,10), (-10, 10), (-10,-10), (10, -10))だし、どこか間違えてるみたい。(どこかというか、間違えてるとこいっぱいありそう。。凸集合の定義自体を勘違いしてるのかも><)

0 コメント:

コメントを投稿