-- -- | -- Module : RobberHeuristic -- Authors : Sean Seefried (http://www.cse.unsw.edu.au/~sseefried) -- Copyright : (c) 2005 -- License : GPL version 2 or later -- Created : 26 Jun 2005 -- module RobberHeuristic where import Graph import KnowledgeBase import Logging import CR import Pretty onFootSmellDist :: Int onFootSmellDist = 2 byCarSmellDist :: Int byCarSmellDist = 1 -- -- Finds the path length from one location to another via a specific means -- of transport (foot or car) -- -- pathLengthTo :: (Graph, Graph, GNode, SPMap, SPMap) -> GNode -> GNode -> CopType -- Either ByFoot or ByCar. Could be used on cop tho. -> Int pathLengthTo (graphFoot, graphCar, hqNode, footsp, carsp) from to onFoot | from == to = 0 | otherwise = if len >= 1 -- if there is a path via current means (foot or car) then pathLen else lenToHQ + lenFromHQOnFoot -- must be in car where len = length (fastShortestPath from to sp) pathLen = len - 1 lenToHQ = let len = length (fastShortestPath from hqNode carsp) in if from == hqNode then 0 else len - 1 lenFromHQOnFoot = length (fastShortestPath hqNode to footsp) - 1 sp = case onFoot of ByFoot -> footsp _ -> carsp -- -- The goodness of the map at the point after -- larceny, evidence, -- -- goodness kb -- knowledgeBase yourNode copThreshDist nearMoneyCoeff haveMoneyCoeff smelledCoeff copCoeff caughtCoeff = let graphFoot = kb_footMap kb graphCar = kb_carMap kb fsp = kb_footSPs kb csp = kb_carSPs kb yourMoney = kb_robberLoot kb banks = kb_banks kb cops = kb_cops kb worldTime = kb_worldCount kb hqNode = kb_hq kb bonuses = [ nearMoneyVal, haveMoneyVal ] penalties = [ smelledVal, copVal, caughtVal ] nearMoneyVal = nearMoneyCoeff * nearMoneyBonus graphTriple yourNode banks haveMoneyVal = haveMoneyCoeff * fromIntegral yourMoney smelledVal = smelledCoeff * smelledPenalty graphTriple yourNode cops copVal = copCoeff * copPenalty graphTriple yourNode cops copThreshDist caughtVal = caughtCoeff * caughtPenalty yourNode cops graphTriple = (graphFoot, graphCar, hqNode, fsp, csp ) copDistance cop = ( showPpr (cop_name cop) , pathLengthTo graphTriple (cop_node cop) yourNode (cop_type cop) , show (cop_type cop) , showPpr (locOfNode (cop_node cop)) ) copsAndDistances = map copDistance cops in {- dtrace ("For location " ++ showPpr (locOfNode yourNode) ++ "\n bonuses and penalties are:" ++ "\nnearMoneyBonus = " ++ show nearMoneyVal ++ "\nhaveMoneyBonus = " ++ show haveMoneyVal ++ "\nsmelledPenalty = " ++ show smelledVal ++ "\ncopPenalty = " ++ show copVal ++ "\ncaughtPenalty = " ++ show caughtVal ++ "\nCop locations and distances:\n" ++ show copsAndDistances) $ -} ((sum bonuses) - (sum penalties)) :: Float type GraphTriple = ( Graph -- foot map , Graph -- car map , GNode -- hq node , SPMap -- foot sp map , SPMap -- car sp map ) -- -- The penalty for being smelled. Returns a value in range [1,10] -- depending on how many cops smell you. A cop that smells you at -- range 1 is worth 2 penalty points. A cop that smells you at range 2 -- is worth 1 penalty. -- -- Returns 0 if the cop is on the same node as you. -- smelledPenalty :: GraphTriple -> GNode -- your location -> [Cop] -- locations the cops are on -> Float smelledPenalty graphTriple yourNode cops = sum $ map beingSmelled cops where beingSmelled :: Cop -> Float beingSmelled cop | cop_node cop == yourNode = 0 | cop_type cop == ByFoot = if pathLengthTo graphTriple (cop_node cop) yourNode ByFoot <= onFootSmellDist then 1 else 0 | otherwise = let len = pathLengthTo graphTriple (cop_node cop) yourNode ByCar in if len <= byCarSmellDist then fromIntegral $ byCarSmellDist - len + 1 else 0 -- -- Proximity to money bonus. Sums over all the banks. Always non-negative. -- Only given if you are *near* a bank, not if you're on it. -- Returns a value in range (0,1000] -- nearMoneyBonus :: GraphTriple -> GNode -> [Bank] -> Float nearMoneyBonus graphTriple yourNode banks = sum $ map nearBankBonus banks where nearBankBonus bank = let p = pathLengthTo graphTriple yourNode (bank_node bank) ByFoot in if p > 0 then fromIntegral (bank_money bank) / (fromIntegral p) else 0 -- -- The penalty for cops being too close to you. Calculated based on the -- length of the paths *they* would have to take to get to you. -- The closer they are, the worse the penalty. The penalty is only applied -- if they are *not* on the same square. -- -- threshDist: Beyond this distance the cops are considered too far -- away to be scary. -- -- Returns in range [0,5] -- -- copPenalty :: GraphTriple -> GNode -> [Cop] -> Int -> Float copPenalty graphTriple yourNode cops treshDist = sum (map penalise proximities) where penalise d = 1 / (fromIntegral d) proximities = filter isTooClose (map distToYou cops) distToYou cop = pathLengthTo graphTriple (cop_node cop) yourNode (cop_type cop) -- Returns False for cops at distance zero. isTooClose d = d >= 1 && d <= treshDist -- -- Returns 1 if you have been caught, 0 otherwise -- caughtPenalty :: GNode -> [Cop] -> Float caughtPenalty yourNode cops | any onCop cops = 1 | otherwise = 0 where onCop cop = yourNode == cop_node cop