module HeldKarp_List
(makePoint,
makeTestSet,
convertFloat,
getDistance, 
getPathDistance, 
triples, 
permShort, 
minTrip, 
minTripFib) where

import qualified Data.List as List
import Data.Function.FastMemo
import Data.Word
import Data.FloatCast

type Point = (Word32, Word32)

makePoint :: Float -> Float -> Point
makePoint x y = (floatToWord x, floatToWord y)

makeTestSet :: Int -> [Point]
makeTestSet n = [ makePoint (fromIntegral a) ((fromIntegral a) + 1) | a <- [1..n]]

convertFloat :: [Point] -> [(Float, Float)]
convertFloat pts = [(wordToFloat a, wordToFloat b) | (a, b) <- pts]

getDistance :: Point -> Point -> Word32
getDistance (x1, y1) (x2, y2) = floatToWord ((((wordToFloat x1 - wordToFloat x2) ** (2 :: Float)) + ((wordToFloat y1 - wordToFloat y2) ** (2 :: Float))) ** (0.5 :: Float))

getPathDistance :: [Point] -> Word32
getPathDistance (p1:p2:[]) = getDistance p1 p2
getPathDistance (p1:p2:xs) = floatToWord (wordToFloat (getDistance p1 p2) + wordToFloat (getPathDistance (p2:xs)))
getPathDistance _ = floatToWord 0.0

triples :: Point -> [Point] -> [(Point, Point, [Point])]
triples start_pt points = [(start, end, trav) | start <- points, end <- points, start == start_pt, start /= end, let trav = List.delete start $ List.delete end points]

permShort :: [Point] -> [[Point]]
permShort xs = [ x : [y | y <- xs, y /= x] | x <- xs ]


minTrip :: (Point, Point, [Point]) -> Word32
minTrip (start_pt, end_pt, []) = getDistance start_pt end_pt
minTrip (start_pt, end_pt, (pt1:[])) = floatToWord ( wordToFloat (getDistance start_pt pt1) + wordToFloat (getDistance pt1 end_pt))
minTrip (start_pt, end_pt, (pt1:xs)) = floatToWord ( wordToFloat (getDistance pt1 end_pt) + wordToFloat (minimum (map (minTrip) [(start_pt, pt1, ps) | ps <- pms])))
                                                where 
                                                    pms = permShort xs


minTripFib :: (Point, Point, [Point]) -> Word32
minTripFib = memoize mtf'
                where
                    mtf' (start_pt, end_pt, []) = getDistance start_pt end_pt
                    mtf' (start_pt, end_pt, (pt1:[])) = floatToWord ( wordToFloat (getDistance start_pt pt1) + wordToFloat (getDistance pt1 end_pt))
                    mtf' (start_pt, end_pt, (pt1:xs)) = floatToWord ( wordToFloat (getDistance pt1 end_pt) + wordToFloat (minimum (map (mtf') [(start_pt, pt1, ps) | ps <- pms])))
                                                                    where 
                                                                        pms = permShort xs
