initial framework added
[fp1415-soccerfun.git] / src / Game / Footballer.icl
diff --git a/src/Game/Footballer.icl b/src/Game/Footballer.icl
new file mode 100644 (file)
index 0000000..ef8d800
--- /dev/null
@@ -0,0 +1,433 @@
+implementation module Footballer
+
+import StdEnvExt
+import Football, FootballerFunctions, Geometry
+
+instance == Edge                                       where == North                    North                                         = True
+                                                                             == South                    South                                         = True
+                                                                             == _                        _                                                     = False
+instance == FootballerID                       where == i1                       i2                                            = i1.clubName == i2.clubName && i1.playerNr == i2.playerNr
+instance == Half                                       where == FirstHalf                FirstHalf                                     = True
+                                                                             == SecondHalf               SecondHalf                            = True
+                                                                             == _                        _                                                     = False
+instance == Reprimand                          where == Warning                  Warning                                       = True
+                                                                             == YellowCard               YellowCard                            = True
+                                                                             == RedCard                  RedCard                                       = True
+                                                                             == _                        _                                                     = False
+instance == Skill                                      where == s1                       s2                                            = toString s1 == toString s2
+instance == Success                                    where == Success                  Success                                       = True
+                                                                             == Fail                     Fail                                          = True
+                                                                             == _                        _                                                     = False
+instance == Footballer                         where == fb1                      fb2                                           = fb1.playerID == fb2.playerID
+instance == Home                                       where == West                     West                                          = True
+                                                                             == East                     East                                          = True
+                                                                             == _                        _                                                     = False
+instance == FeintDirection                     where == FeintLeft                FeintLeft                                     = True
+                                                                             == FeintRight               FeintRight                            = True
+                                                                             == _                        _                                                     = False
+instance == FootballerAction           where == (Move     speed1 angle1) (Move     speed2 angle2)      = speed1 == speed2 && angle1 == angle2
+                                                                             == GainBall                 GainBall                                      = True
+                                                                             == (KickBall speed3D1)      (KickBall speed3D2)           = speed3D1 == speed3D2
+                                                                             == (HeadBall speed3D1)      (HeadBall speed3D2)           = speed3D1 == speed3D2
+                                                                             == (Feint    fd1)           (Feint    fd2)                        = fd1 == fd2
+                                                                             == (Tackle   tf1 v1)        (Tackle   tf2 v2)                     = tf1 == tf2 && v1 == v2
+                                                                             == CatchBall                CatchBall                                     = True
+                                                                             == _ _                                                                                            = False
+instance other    Edge                         where other North                                               = South
+                                                                             other South                                               = North
+instance other    Half                         where other FirstHalf                                   = SecondHalf
+                                                                             other SecondHalf                                  = FirstHalf
+instance other    Home                         where other West                                                = East
+                                                                             other East                                                = West
+instance toString Edge                         where toString North                                    = "North"
+                                                                             toString South                                    = "South"
+instance toString FootballerID         where toString i                                                = "{clubName=" <+++ i.clubName +++ ",playerNr=" <+++ i.playerNr +++ "}"
+instance toString Half                         where toString FirstHalf                                = "FirstHalf"
+                                                                             toString SecondHalf                               = "SecondHalf"
+instance toString Reprimand                    where toString Warning                                  = "Warning"
+                                                                             toString YellowCard                               = "YellowCard"
+                                                                             toString RedCard                                  = "RedCard"
+instance toString Skill                                where toString Running                                  = "Running"
+                                                                             toString Dribbling                                = "Dribbling"
+                                                                             toString Rotating                                 = "Rotating"
+                                                                             toString Gaining                                  = "Gaining"
+                                                                             toString Kicking                                  = "Kicking"
+                                                                             toString Heading                                  = "Heading"
+                                                                             toString Feinting                                 = "Feinting"
+                                                                             toString Jumping                                  = "Jumping"
+                                                                             toString Catching                                 = "Catching"
+                                                                             toString Tackling                                 = "Tackling"
+instance toString Success                      where toString Success                                  = "Success"
+                                                                             toString Fail                                             = "Fail"
+instance toString Home                         where toString West                                             = "West"
+                                                                             toString East                                             = "East"
+instance toString FeintDirection       where toString FeintLeft                                = "FeintLeft"
+                                                                             toString FeintRight                               = "FeintRight"
+instance toString FootballerAction     where toString (Move     speed angle)   = "(Move "     <+++ speed  <+++ " " <+++ angle <+++ ")"
+                                                                             toString  GainBall                                = "GainBall"
+                                                                             toString (KickBall speed)                 = "(KickBall " <+++ speed  <+++ ")"
+                                                                             toString (HeadBall speed)                 = "(HeadBall " <+++ speed  <+++ ")"
+                                                                             toString (Feint    fd)                    = "(Feint "    <+++ fd     <+++ ")"
+                                                                             toString (Tackle   fbID v)                = "(Tackle "   <+++ fbID.playerNr <+++ " " <+++ v <+++ ")"
+                                                                             toString  CatchBall                               = "CatchBall"
+
+::     Minutes =   Minutes !Real
+
+instance zero         Minutes          where zero                                                              = Minutes zero
+instance <            Minutes          where <  (Minutes m1) (Minutes m2)              = m1 < m2
+instance ==           Minutes          where == (Minutes m1) (Minutes m2)              = m1 == m2
+instance +            Minutes          where +  (Minutes m1) (Minutes m2)              = Minutes (m1+m2)
+instance -            Minutes          where -  (Minutes m1) (Minutes m2)              = Minutes (m1-m2)
+instance scale        Minutes       where scale         k (Minutes m)       = Minutes (k * m)
+instance toString     Minutes          where toString        (Minutes m)               = toString (s/60) <+++ ":" <+++ if (s mod 60 < 10) "0" "" <+++ (s mod 60) <+++" min"
+                                          where s                                                      = toInt (((toReal (toInt (m * 100.0)))/100.0) * 60.0)
+instance toReal       Minutes          where toReal (Minutes m)                                = m
+instance minutes      Real                     where minutes m                                                 = Minutes m
+
+instance toPosition   Footballer       where toPosition   fb                                   = fb.pos
+instance toPosition3D Footballer       where toPosition3D fb                                   = toPosition3D fb.pos
+instance nameOf       Footballer       where nameOf {name,nose}                                = name
+instance nameOf       FootballerID     where nameOf {clubName}                                 = clubName
+instance sameClub     FootballerID     where sameClub id1 id2                                  = nameOf id1 == nameOf id2
+instance sameClub     Footballer       where sameClub fb1 fb2                                  = sameClub fb1.playerID fb2.playerID
+
+defaultFootballer                                                      :: !FootballerID -> Footballer
+defaultFootballer playerID                                     = { playerID    = playerID
+                                                                                         , name                = "default"
+                                                                                         , length              = m 1.6
+                                                                                         , pos                 = zero 
+                                                                                         , speed               = zero
+                                                                                         , nose                = zero
+                                                                                         , skills              = (Running, Kicking, Dribbling)
+                                                                                         , effect              = Nothing
+                                                                                         , stamina             = max_stamina
+                                                                                         , health              = max_health
+                                                                                         , brain               = {memory=Void, ai=returnAI (Move zero zero)}
+                                                                                         }
+
+inRadiusOfFootballer                                           :: !Position !Footballer -> Bool
+inRadiusOfFootballer pos player                                = isbetween pos.px (player.pos.px - xWidthFootballer) (player.pos.px + xWidthFootballer) &&
+                                                                                         isbetween pos.py (player.pos.py - yWidthFootballer) (player.pos.py + yWidthFootballer)
+
+skillsAsList                                                           :: !Footballer -> [Skill]
+skillsAsList fb                                                                = (\(a,b,c)->[a,b,c]) fb.skills
+
+identify_player                                                                :: !FootballerID !Footballer -> Bool
+identify_player id fb                                          = id == fb.playerID
+
+player_identity                                                                :: !Footballer -> FootballerID
+player_identity fb                                                     = fb.playerID
+
+getClubName                                                                    :: !Footballer -> ClubName
+getClubName fb                                                         = nameOf fb.playerID
+
+isKeeper                                                                       :: !Footballer -> Bool
+isKeeper fb                                                                    = fb.playerID.playerNr == 1
+
+isFielder                                                                      :: !Footballer -> Bool
+isFielder fb                                                           = not (isKeeper fb)
+
+/**    Footballer attribute dependent abilities:
+*/
+maxGainReach                                                           :: !Footballer -> Metre
+maxGainReach fb                                                                = scale (if (isMember Gaining (skillsAsList fb)) 0.5 0.3) fb.length
+
+maxJumpReach                                                           :: !Footballer -> Metre
+maxJumpReach fb                                                                = scale (if (isMember Jumping (skillsAsList fb)) 0.6 0.4) fb.length
+
+maxGainVelocityDifference                                      :: !Footballer !Metre -> Velocity
+maxGainVelocityDifference fb d_player_ball     = ms (if (isMember Gaining (skillsAsList fb)) 15.0 10.0 -  distanceDifficulty)
+where
+       length                                                                  = toReal fb.length
+       distanceDifficulty                                              = max zero ((0.8 * length)^4.0 * ((toReal d_player_ball)/length))
+
+maxCatchVelocityDifference                                     :: !Footballer !Metre -> Velocity
+maxCatchVelocityDifference fb d_player_ball    = ms (if (isMember Gaining (skillsAsList fb)) 20.0 17.0 - distanceDifficulty)
+where
+       length                                                                  = toReal fb.length
+       distanceDifficulty                                              = max zero ((0.8 * length)^4.0 * ((toReal d_player_ball)/length))
+
+maxKickReach                                                           :: !Footballer -> Metre
+maxKickReach fb                                                                = scale (if (isMember Kicking (skillsAsList fb)) 0.6 0.4) fb.length
+
+maxHeadReach                                                           :: !Footballer -> Metre
+maxHeadReach fb                                                                = scale (if (isMember Heading (skillsAsList fb)) 0.4 0.2) fb.length
+
+maxCatchReach                                                          :: !Footballer -> Metre         // includes horizontal jumping
+maxCatchReach fb                                                       = scale (if (isMember Catching (skillsAsList fb)) 1.8 1.5) fb.length
+
+maxTackleReach                                                         :: !Footballer -> Metre
+maxTackleReach fb                                                      = scale (if (isMember Tackling (skillsAsList fb)) 0.33 0.25) fb.length
+
+maxVelocityBallKick                                                    :: !Footballer -> Velocity      
+maxVelocityBallKick fb                                         = ms ((if (isMember Kicking (skillsAsList fb)) 27.0 25.0 + (toReal fb.length)/2.0) * (0.2*fatHealth+0.8))
+where
+       fatHealth                                                               = getHealthStaminaFactor fb.health fb.stamina
+
+maxVelocityBallHead                                                    :: !Footballer !Velocity -> Velocity
+maxVelocityBallHead fb ballSpeed                       = scale 0.7 ballSpeed + scale (0.1*fatHealth+0.9) (ms (if (isMember Heading (skillsAsList fb)) 7.0 5.0))
+where
+       fatHealth                                                               = getHealthStaminaFactor fb.health fb.stamina
+       
+maxKickingDeviation                                                    :: !Footballer -> Angle
+maxKickingDeviation skills                                     = rad (0.5*pi) //if (isMember Kicking skills) (pi/18.0) (pi/2.0)
+
+maxHeadingDeviation                                                    :: !Footballer -> Angle
+maxHeadingDeviation skills                                     = rad (0.25*pi) //if (isMember Heading skills) (pi/16.0) (pi/5.0)
+
+maxRotateAngle                                                         :: !Footballer -> Angle
+maxRotateAngle fb=:{speed,length}
+| velocity < 1.0                                                       = rad pi
+| otherwise                                                                    = rad (pi/18.0*((5.0/velocity)*((toReal length)/2.0)))
+where
+       velocity                                                                = abs (toReal speed.velocity)
+
+maxFeintStep                                                           :: !Footballer -> Metre
+maxFeintStep fb                                                                = m (if (isMember Feinting (skillsAsList fb)) 0.75 0.5)
+
+::     HealthStaminaFactor                                             :== Real                // combination of stamina and health
+
+getHealthStaminaFactor                                         :: !Health !Stamina -> HealthStaminaFactor
+getHealthStaminaFactor health stamina
+| stamina <= health                                                    = stamina
+| otherwise                                                                    = avg [stamina,health]
+
+isMove                                                                         :: !FootballerAction -> Bool
+isMove (Move _ _)                                                      = True
+isMove _                                                                       = False
+
+isGainBall                                                                     :: !FootballerAction -> Bool
+isGainBall GainBall                                                    = True
+isGainBall _                                                           = False
+
+isKickBall                                                                     :: !FootballerAction -> Bool
+isKickBall (KickBall _)                                                = True
+isKickBall _                                                           = False
+
+isHeadBall                                                                     :: !FootballerAction -> Bool
+isHeadBall (HeadBall _)                                                = True
+isHeadBall _                                                           = False
+
+isFeint                                                                                :: !FootballerAction -> Bool
+isFeint (Feint _)                                                      = True
+isFeint _                                                                      = False
+
+isFootballerTackle                                                     :: !FootballerAction -> Bool
+isFootballerTackle (Tackle _ _)                                = True
+isFootballerTackle _                                           = False
+
+isCatchBall                                                                    :: !FootballerAction -> Bool
+isCatchBall CatchBall                                          = True
+isCatchBall _                                                          = False
+
+isActionOnBall                                                         :: !FootballerAction -> Bool
+isActionOnBall GainBall                                                = True
+isActionOnBall CatchBall                                       = True
+isActionOnBall (KickBall _)                                    = True
+isActionOnBall (HeadBall _)                                    = True
+isActionOnBall _                                                       = False
+
+getDefaultField                                                                :: FootballField
+getDefaultField                                                                = { fwidth = m 75.0, flength = m 110.0 }
+
+inPenaltyArea                                                          :: !FootballField !Home !Position -> Bool
+inPenaltyArea field home pos                           = isbetween pos.py south_edge north_edge && if (home == West) (pos.px <= west_edge) (pos.px >= east_edge)
+where
+       north_edge                                                              = northPole + radius_penalty_area
+       south_edge                                                              = southPole - radius_penalty_area
+       (northPole,southPole)                                   = goal_poles field
+       half_length                                                             = scale 0.5 field.flength
+       west_edge                                                               = penalty_area_depth - half_length
+       east_edge                                                               = half_length - penalty_area_depth
+
+goal_poles                                                                     :: !FootballField -> (!Metre,!Metre)
+goal_poles field                                                       = (half_goal_width,~half_goal_width)
+where
+       half_goal_width                                                 = scale 0.5 goal_width
+
+isMoved                                                                                :: !FootballerEffect -> Bool
+isMoved (Moved _ _)                                                    = True
+isMoved _                                                                      = False
+
+isGainedBall                                                           :: !FootballerEffect -> Bool
+isGainedBall (GainedBall _)                                    = True
+isGainedBall _                                                         = False
+
+isKickedBall                                                           :: !FootballerEffect -> Bool
+isKickedBall (KickedBall _)                                    = True
+isKickedBall _                                                         = False
+
+isHeadedBall                                                           :: !FootballerEffect -> Bool
+isHeadedBall (HeadedBall _)                                    = True
+isHeadedBall _                                                         = False
+
+isFeinted                                                                      :: !FootballerEffect -> Bool
+isFeinted (Feinted _)                                          = True
+isFeinted _                                                                    = False
+
+isTackled                                                                      :: !FootballerEffect -> Bool
+isTackled (Tackled _ _ _)                                      = True
+isTackled _                                                                    = False
+
+isCaughtBall                                                           :: !FootballerEffect -> Bool
+isCaughtBall (CaughtBall _)                                    = True
+isCaughtBall _                                                         = False
+
+isOnTheGround                                                          :: !FootballerEffect -> Bool
+isOnTheGround (OnTheGround _)                          = True
+isOnTheGround _                                                                = False
+
+failFootballerAction                                           :: !FootballerAction -> FootballerEffect
+failFootballerAction (Move   s a)                      = Moved    s a
+failFootballerAction GainBall                          = GainedBall Fail
+failFootballerAction CatchBall                         = CaughtBall Fail
+failFootballerAction (KickBall v)                      = KickedBall Nothing
+failFootballerAction (HeadBall v)                      = HeadedBall Nothing
+failFootballerAction (Feint    d)                      = Feinted d
+failFootballerAction (Tackle p v)                      = Tackled p v Fail
+failFootballerAction _                                         = abort "failFootballerAction: unknown action failed"
+
+displacements                                                          :: !Team -> Displacements
+displacements team                                                     = [(playerID,pos) \\ {playerID,pos} <- team]
+
+showSuccintRefereeAction                                       :: !RefereeAction -> String
+showSuccintRefereeAction refAction
+       = case refAction of
+               (ReprimandPlayer  id r)                         = player id                     <+++ " receives " <+++ r
+               (Hands            id)                           = "Hands by "                   <+++ player id
+               (TackleDetected   id)                           = "Tackle by "                  <+++ player id
+               (DangerousPlay    id)                           = "Dangerous play by "          <+++ player id
+               GameOver                                                        = "Game ended"
+               (GameCancelled    mt)                           = "Game cancelled"              <+++ if (isJust mt) (" winner is " <+++ fromJust mt) ""
+               PauseGame                                                       = "Game paused"
+               (AddTime  t)                                            = "Extra time added: "          <+++ t
+               EndHalf                                                         = "First half ended"
+               (Goal     t)                                            = "Goal for "                   <+++ t
+               (Offside        id)                                     = "Offside by "                 <+++ player id
+               (DirectFreeKick t p)                            = "Direct free kick for "       <+++ t
+               (GoalKick t)                                            = "Goal kick for "              <+++ t
+               (Corner   t e)                                          = "Corner for "                 <+++ t
+               (ThrowIn  t p)                                          = "Throw in for "               <+++ t
+               (Penalty    t)                                          = "Penalty for "                <+++ t
+               (CenterKick t)                                          = "Center kick for "            <+++ t
+               (Advantage t)                                           = "Advantage for "              <+++ t
+               (OwnBallIllegally id)                           = "Illegal ball possession by " <+++ player id
+               (DisplacePlayers _)                                     = "Players displaced"
+               ContinueGame                                            = "Game continued"
+               (TellMessage txt)                                       = txt
+where
+       player {clubName,playerNr}                              = clubName <+++"[" <+++ playerNr <+++ "]"
+
+isReprimandPlayer                                                      :: !RefereeAction -> Bool
+isReprimandPlayer (ReprimandPlayer _ _)                = True
+isReprimandPlayer _                                                    = False
+
+isHands                                                                                :: !RefereeAction -> Bool
+isHands (Hands _)                                                      = True
+isHands _                                                                      = False
+
+isTackleDetected                                                       :: !RefereeAction -> Bool
+isTackleDetected (TackleDetected _)                    = True
+isTackleDetected _                                                     = False
+
+isDangerousPlay                                                                :: !RefereeAction -> Bool
+isDangerousPlay (DangerousPlay _)                      = True
+isDangerousPlay _                                                      = False
+
+isGameOver                                                                     :: !RefereeAction -> Bool
+isGameOver GameOver                                                    = True
+isGameOver _                                                           = False
+
+isGameCancelled                                                                :: !RefereeAction -> Bool
+isGameCancelled (GameCancelled _)                      = True
+isGameCancelled _                                                      = False
+
+isPauseGame                                                                    :: !RefereeAction -> Bool
+isPauseGame PauseGame                                          = True
+isPauseGame _                                                          = False
+
+isAddTime                                                                      :: !RefereeAction -> Bool
+isAddTime (AddTime _)                                          = True
+isAddTime _                                                                    = False
+
+isEndHalf                                                                      :: !RefereeAction -> Bool
+isEndHalf EndHalf                                                      = True
+isEndHalf _                                                                    = False
+
+isGoal                                                                         :: !RefereeAction -> Bool
+isGoal (Goal _)                                                                = True
+isGoal _                                                                       = False
+
+isOffside                                                                      :: !RefereeAction -> Bool
+isOffside (Offside _)                                          = True
+isOffside _                                                                    = False
+
+isDirectFreeKick                                                       :: !RefereeAction -> Bool
+isDirectFreeKick (DirectFreeKick _ _ )         = True
+isDirectFreeKick _                                                     = False
+
+isGoalKick                                                                     :: !RefereeAction -> Bool
+isGoalKick (GoalKick _)                                                = True
+isGoalKick _                                                           = False
+
+isCorner                                                                       :: !RefereeAction -> Bool
+isCorner (Corner _ _)                                          = True
+isCorner _                                                                     = False
+
+isThrowIn                                                                      :: !RefereeAction -> Bool
+isThrowIn (ThrowIn _ _)                                                = True
+isThrowIn _                                                                    = False
+
+isPenalty                                                                      :: !RefereeAction -> Bool
+isPenalty (Penalty _)                                          = True
+isPenalty _                                                                    = False
+
+isCenterKick                                                           :: !RefereeAction -> Bool
+isCenterKick (CenterKick _)                                    = True
+isCenterKick _                                                         = False
+
+isAdvantage                                                                    :: !RefereeAction -> Bool
+isAdvantage (Advantage _)                                      = True
+isAdvantage _                                                          = False
+
+isOwnBallIllegally                                                     :: !RefereeAction -> Bool
+isOwnBallIllegally (OwnBallIllegally _)                = True
+isOwnBallIllegally _                                           = False
+
+isDisplacePlayers                                                      :: !RefereeAction -> Bool
+isDisplacePlayers (DisplacePlayers _)          = True
+isDisplacePlayers _                                                    = False
+
+isContinueGame                                                         :: !RefereeAction -> Bool
+isContinueGame ContinueGame                                    = True
+isContinueGame _                                                       = False
+
+isTellMessage                                                          :: !RefereeAction -> Bool
+isTellMessage (TellMessage _)                          = True
+isTellMessage _                                                                = False
+
+getKickPos                                                                     :: !FootballField !Half !RefereeAction -> Maybe Position
+getKickPos field half (GoalKick home)          = Just { zero & px = if (home == West) (penalty_area_depth - half_length) (half_length - penalty_area_depth) }
+where
+       half_length                                                             = scale 0.5 field.flength
+getKickPos field half (Corner home edge)       = Just { px = if (home == West && half == SecondHalf || home == East && half == FirstHalf)
+                                                                                                        (half_radius_corner_kick_area - half_length)
+                                                                                                        (half_length - half_radius_corner_kick_area)
+                                                                                              , py = if (edge == North)
+                                                                                                        (half_radius_corner_kick_area - half_width)
+                                                                                                        (half_width - half_radius_corner_kick_area)
+                                                                                              }                
+where
+       half_width                                                              = scale 0.5 field.fwidth
+       half_length                                                             = scale 0.5 field.flength
+       half_radius_corner_kick_area                    = scale 0.5 radius_corner_kick_area
+getKickPos field half (Penalty home)           = Just { zero & px = if (home == West && half == SecondHalf || home == East && half == FirstHalf)
+                                                                                                               (penalty_spot_depth - half_length)
+                                                                                                               (half_length - penalty_spot_depth)
+                                                                                              }
+where
+       half_length                                                             = scale 0.5 field.flength
+getKickPos field _ (CenterKick _)                      = Just zero
+getKickPos _ _ (DirectFreeKick _ pos)          = Just pos
+getKickPos _ _ (ThrowIn _ pos)                         = Just pos
+getKickPos _ _ _                                                       = Nothing