packages feed

Rasenschach-0.1.2: BallFSM.hs

module BallFSM (freeBallSF, controlledBallSF, outOfPlayBallSF)

where

import FRP.Yampa
import FRP.Yampa.Geometry

import Data.List
import Data.Maybe

import Data.FSM
import Message
import Physics
import Object
import States
import Helper
import BasicTypes
import Global

type BallPerception = (BallMsgParam, [VisibleState])

s1 :: State BallState BallTransition p [a]
s1 = addTransition BTCollisionB 3 $
     addTransition BTOutOfPlay 4 $
     state 1 BSFree (const []) (const []) (const [])
s2 :: Param -> State BallState BallTransition (BallMsgParam, (BallMsgParam, [VisibleState])) [Message]
s2 param = addTransition BTCollisionB 3 $
     addTransition BTOutOfPlay 4 $
     addTransition BTLost 1 $
     state 2 BSControlled (const []) (checkForOffsite param) (const [])
s3 :: Param -> State BallState BallTransition (BallStateParam, BallPerception) [Message]
s3 param = addTransition BTGained 2 $
     addTransition BTGainedOOP 5 $
     addTransition BTGainedGoalie 6 $
     addTransition BTLostOOP 4 $
     addTransition BTLost 1 $
     state 3 BSChallenged (const []) (takeMe param) (const [])
s4 :: State BallState BallTransition p [a]
s4 = addTransition BTCollisionB 3 $
     state 4 BSOutOfPlay (const []) (const []) (const [])
s5 :: State BallState BallTransition p [a]
s5 = addTransition BTLost 1 $
     state 5 BSControlledOOP (const []) (const []) (const [])
s6 :: Param -> State BallState BallTransition (BallMsgParam, (BallMsgParam, [VisibleState])) [Message]
s6 param = addTransition BTLost 1 $
     state 6 BSControlledGoalie (const []) (checkForOffsite param) (const [])
fsm :: Param -> Either [Problem BallTransition] (FSM BallState BallTransition (BallMsgParam, (BallMsgParam, [VisibleState])) [Message])
fsm param = fromList [s1, s2 param, s3 param, s4, s5, s6 param]

takeMe :: Param -> (BallStateParam, BallPerception) -> [Message]
takeMe _ (BPWho playerIdTouching t, (BPWho me _,vss)) =
 let (ballState, ballParam) = vsBallState . fetchBallVS $ vss
     gameVS = fetchGameVS vss
     game = vsObjId gameVS
     attacker = vsAttacker gameVS
     playerVS = fetchVS vss playerIdTouching
     teamTouching = vsTeam playerVS
 in
     if ballState == BSOutOfPlay then
         if teamTouching == attacker then
          -- if colliding player is on the right team, send him a kickoff/throw-in/kick-corner message,
          -- otherwise ignore him
             [(playerIdTouching, PlayerMessage (PhysicalPlayerMessage (PPTPrepareThrowIn, BSPWhoAndWhen me t)))]
         else
             [(me, BallMessage (BTLostOOP, ballParam))]
     else -- ball was in play
--            -- if goalie has the ball, then don't take it from him
        if ballState == BSControlledGoalie then
            [(me, BallMessage (BTLost, ballParam))]
        else
            [(playerIdTouching, PlayerMessage (PhysicalPlayerMessage (PPTTakeMe, BSPWhoAndWhen me t))),
             (game, GameMessage (GTTakePossession, GPTeamPosition teamTouching (-1) [] (Point2 0 0) (-1) False InPlay))] ++
             (map (\vs -> (vsObjId vs, PlayerMessage (PhysicalPlayerMessage (PPTLoseMe, BSPRelease 0 RTNothing)))) $ filter hasBall vss)

checkForOffsite :: Param -> (BallMsgParam, (BallMsgParam, [VisibleState])) -> [Message]
checkForOffsite param (BPWho playerIdTouching t, (BPWho _ _,vss)) =
 let gameVS = fetchGameVS vss
     playerVS = fetchVS vss playerIdTouching
     teamTouching = vsTeam playerVS
     posTouching = vsPos $ playerVS
 in snd $ checkOffsite' param t (fst (vsGameState gameVS))
                        playerIdTouching teamTouching posTouching
                        ((snd $ vsGameState gameVS), vss)

checkOffsite' :: Param -> Time -> GameState -> ObjId -> Team -> Position3 -> (GameStateParam, [VisibleState]) -> (Bool, [Message])
checkOffsite' param t gs playerIdTouching teamTouching _
             (GPTeamPosition teamPassing playerIdPassing oposs posPassing _ _ _, vss) =

  if gs /= GSOffsitePending then (False, [])
  else if teamTouching /= teamPassing then (False, noOffsiteMsg)
  else if playerIdTouching == playerIdPassing then (False, noOffsiteMsg)
  else if noOffsite teamTouching (point2Y posPassing) (posYTouchingT0 playerIdTouching) then (False, noOffsiteMsg)
  else (True, offsiteMsg)

   where
     me = vsObjId (fetchGameVS vss)
     noOffsite team posPassing' posTouchingT0 =
         False ||
         (team == Home && posTouchingT0 > halfLine) ||
         (team == Away && posTouchingT0 < halfLine) ||
         (team == Home && posTouchingT0 >= posPassing') ||
         (team == Away && posTouchingT0 <= posPassing') ||
         (twoBehind team posTouchingT0 oposs)

     noOffsiteMsg = [(me, GameMessage (GTNoOffsite,
                                       GPTeamPosition teamTouching (-1) [] (Point2 0 50) t False InPlay))]
     offsiteMsg = [(me, GameMessage (GTOffsite,
                                     GPTeamPosition (otherTeam teamTouching) (-1) [] (Point2 0 50) t False OOPOffsite))]
     halfLine = pPitchLength param / 2

     posYTouchingT0 oid = thrd3 $ fromJust $ find (\(_, oid', _) -> oid == oid') oposs

twoBehind :: Ord a => Team -> a -> [(Team, t, a)] -> Bool
twoBehind team p0 oposs =
    length (filter (\(t, _, p) ->
                        t == otherTeam team &&
                        if team == Home then p < p0 else p > p0) oposs) > 1

freeBallSF :: Param -> BallStateParam ->
          SF (BallPerception, Event [(BallTransition, BallStateParam)])
             ((State BallState BallTransition (BallStateParam, BallPerception) [Message], BallStateParam), [Message])
freeBallSF param me = reactMachineMult (fromRight $ fsm param) s1 me
controlledBallSF :: Param -> Bool -> BallMsgParam -> 
                      SF ((BallMsgParam, [VisibleState]), Event [(BallTransition, BallMsgParam)]) 
                           ((State BallState BallTransition (BallMsgParam, (BallMsgParam, [VisibleState])) [Message], BallMsgParam), [Message])
controlledBallSF param goalie me = reactMachineMult (fromRight $ fsm param) (if goalie then (s6 param) else s2 param) me
outOfPlayBallSF :: Param -> BallMsgParam -> SF ((BallMsgParam, [VisibleState]), Event [(BallTransition, BallMsgParam)]) ((State BallState BallTransition (BallMsgParam, (BallMsgParam, [VisibleState])) [Message], BallMsgParam), [Message])
outOfPlayBallSF param me = reactMachineMult (fromRight $ fsm param) s4 me