SoccerFun-0.3.1: template/Child.hs
{-# LANGUAGE UnicodeSyntax #-}
-- | A very simple minded player, that always chases after the ball and kicks the ball towards the opponent's goal.
module Child where
import SoccerFun.Player
import SoccerFun.Types
import SoccerFun.Geometry
import Control.Monad.State
import SoccerFun.Field
import SoccerFun.Ball
import SoccerFun.RefereeAction
-- Generate a child.
child ∷ ClubName → Home → Field → Position → PlayersNumber → Player
child club home field position no = Player
{playerID = PlayerID {clubName = club, playerNo = no},
name = "child." ++ show no,
height = minHeight,
pos = position,
nose = 0,
speed = 0,
skills = (Running, Kicking, Rotating),
effect = Nothing,
stamina = maxStamina,
health = maxHealth,
-- The only thing the child remembers is on which side it belongs to
brain = Brain {m = Memory {myHome = home}, ai = minibrain field}}
-- The child remembers nothing but which side it is playing on.
data Memory = Memory {myHome ∷ Home}
-- A stateful computation, with the memory serving as a state.
type Think = State Memory
-- | Based on the perceived surroundings (BrainInput) and the memories, make a decision (BrainOutput) and update the memory.
minibrain ∷ Field → PlayerAI Memory
-- = Field → BrainInput → Think PlayerAction
minibrain field BrainInput {referee=refereeActions, me=me, ball=ballState, others=others} = do
mem ← get
let home = myHome mem
when (any isEndHalf refereeActions) (put mem {myHome = other home})
if ballIsClose
then let goal = centerOfGoal (other home) field in kick goal
else trackBall $ maxKickReach me
where
ball = getBall ballState (me : others) ∷ Ball
ballXY = pxy $ ballPos ball ∷ Position
ballIsClose = dist (pos me) ballXY < maxKickReach me
move ∷ Speed → Angle → Think PlayerAction
move speed angle = return $ Move speed angle
centerOfGoal ∷ Home → Field → Position
centerOfGoal home field = Position
{py = let (n,s) = goalPoles field in (n+s)/2,
px = if home == West then 0 else flength field}
kick ∷ Position → Think PlayerAction
kick point = let
angle = angleWithObject (pos me) point
v = 2.0*dist (pos me) point
in if (dist (pos me) (ballPos ball) <= maxKickReach me)
then return $ KickBall Speed3D {vxy = Speed {direction=angle,velocity=v},vz=1.0}
else halt
trackBall ∷ Metre → Think PlayerAction
trackBall eps = fix ballXY eps
halt ∷ Think PlayerAction
halt = move 0 0
-- run towards a position
fix ∷ Position → Metre → Think PlayerAction
fix point eps = let
distance = dist (pos me) point
angle = angleWithObject (pos me) point
v = max 6.0 distance
in if (distance <= eps)
then halt
else move Speed {direction=angle,velocity=v} (angle - (nose me))