From: Mart Lubbers Date: Tue, 2 Jun 2015 11:30:38 +0000 (+0200) Subject: initial framework added X-Git-Url: https://git.martlubbers.net/?a=commitdiff_plain;h=5d2f06991116c1828e8aebd60a2120004eb9b742;p=fp1415-soccerfun.git initial framework added --- diff --git a/doc/Installing SoccerFun on Windows.txt b/doc/Installing SoccerFun on Windows.txt new file mode 100644 index 0000000..2eab777 --- /dev/null +++ b/doc/Installing SoccerFun on Windows.txt @@ -0,0 +1,72 @@ +To install SoccerFun on a Windows machine: + +(1) You need a Clean 2.3 distribution. You can download this for + free at: + + http://wiki.clean.cs.ru.nl/Clean + +(2) Unpack the Clean 2.3 distribution. + +(3) In the Clean 2.3 distribution you find the CleanIDE.exe and a number + of directories: Config, Examples, Help, Libraries, Temp, and Tools. + + Move the unpacked SoccerFun distribution to Examples. + + After this action the Examples folder of your Clean distribution should + contain a SoccerFun folder with the following content: + + Examples\ + ... + SoccerFun\ + doc\ + quickstart_SoccerFun\ + quickstart_SoccerFun.pdf + Installing SoccerFun on Windows.txt // the document you're reading right now + src\ + afbeeldingen\ + Game\ + Gui\ + sound\ + StdLibExt\ + StdReferee\ + StdTeam\ + SoccerFun.env // see step 5 below + SoccerFun64.env // see step 5 below + SoccerFun.icl + SoccerFun.prj // see step 6 below + + +(4) Run the CleanIDE. If it is the first time that you run it, it will ask you + if it can integrate itself in the Windows system. + Choose "Yes" if you want this, "No" if you want to defer. + Note: choose "Never" only if you are very certain about this, + because it means truely never. + +(5) In the CleanIDE choose the command "Environment:Import...". + On a 32bit Windows machine, direct the file selector dialog to + SoccerFun\src\SoccerFun.env + and import the environment. + On a 64bit Windows machine, direct the file selector dialog to + SoccerFun\src\SoccerFun64.env + and import the environment. + + This will set the default paths for the compiler. + + You need to do this only once for your Clean distribution. + + This step was successful if the CleanIDE has added "SoccerFun" to its list of + environments (command "Environment"). + +(6) Now you can open (command "File:Open...") the project file at + Examples\SoccerFun\src\SoccerFun.prj. + +(7) Make sure the Environment of the CleanIDE is set to "SoccerFun". + Do this with the command "Environment:SoccerFun". + +(8) Bring the project up to date with "Project:Bring Up To Date". + Now all modules are compiled and an executable is created. + The executable can be launched with "Project:Run". + + Note that "Project:Update and Run" combines the latter commands. + +(9) If all went well, Soccer-Fun should have started. Have fun! diff --git a/doc/Over SoccerFun.pptx b/doc/Over SoccerFun.pptx new file mode 100644 index 0000000..fbf7f75 Binary files /dev/null and b/doc/Over SoccerFun.pptx differ diff --git a/doc/images/appel_en_peer.jpg b/doc/images/appel_en_peer.jpg new file mode 100644 index 0000000..e265a01 Binary files /dev/null and b/doc/images/appel_en_peer.jpg differ diff --git a/doc/images/appel_en_peer_2.jpg b/doc/images/appel_en_peer_2.jpg new file mode 100644 index 0000000..f7d32e0 Binary files /dev/null and b/doc/images/appel_en_peer_2.jpg differ diff --git a/doc/images/fixed_camera.bmp b/doc/images/fixed_camera.bmp new file mode 100644 index 0000000..a00894e Binary files /dev/null and b/doc/images/fixed_camera.bmp differ diff --git a/doc/images/flatland.bmp b/doc/images/flatland.bmp new file mode 100644 index 0000000..7908b66 Binary files /dev/null and b/doc/images/flatland.bmp differ diff --git a/doc/images/player_and_ball.bmp b/doc/images/player_and_ball.bmp new file mode 100644 index 0000000..01de090 Binary files /dev/null and b/doc/images/player_and_ball.bmp differ diff --git a/doc/quickstart_SoccerFun.pdf b/doc/quickstart_SoccerFun.pdf new file mode 100644 index 0000000..c844efc Binary files /dev/null and b/doc/quickstart_SoccerFun.pdf differ diff --git a/src/Game/Football.dcl b/src/Game/Football.dcl new file mode 100644 index 0000000..d4b89e1 --- /dev/null +++ b/src/Game/Football.dcl @@ -0,0 +1,41 @@ +definition module Football + +/** The Football data type and a number of access functions. +*/ + +import Footballer, randomstream + +:: FootballState = Free !Football + | GainedBy !FootballerID +:: Football = { ballPos :: !Position3D + , ballSpeed :: !Speed3D + } +:: BounceDirection = Down | Up | Forward | Back + +instance zero Football +instance toPosition Football +instance toPosition3D Football + +/* mkFootball returns a football with 3D dimensions. +*/ +mkFootball :: !Position !Speed -> Football + +/* ballIsFree yields True iff argument is (Free ...). +*/ +ballIsFree :: !FootballState -> Bool + +/* ballIsGainedBy yields True iff the ball is in possession by the given player. +*/ +ballIsGainedBy :: !FootballerID !FootballState -> Bool + +/* getFootball returns the football (containing its position and speed-information) + that is either free or gained by a footballer. + For this reason, the list of footballers must contain all footballers, otherwise + this function may fail. +*/ +getFootball :: !FootballState !.[Footballer] -> Football + +radius_football :== m 0.113 // radius of football +surface_resistance :== 0.85 // maximum speed of ball when moving over surface +air_resistance :== 0.95 // maximum speed of ball when moving through air (should depend on velocity) +accelleration_sec :== ms 9.81 // acceleration difference per square second diff --git a/src/Game/Football.icl b/src/Game/Football.icl new file mode 100644 index 0000000..528091c --- /dev/null +++ b/src/Game/Football.icl @@ -0,0 +1,25 @@ +implementation module Football + +import Footballer, randomstream + +instance zero Football where zero = {ballPos=zero, ballSpeed=zero} +instance toPosition Football where toPosition {ballPos} = ballPos.pxy +instance toPosition3D Football where toPosition3D {ballPos} = ballPos + +mkFootball :: !Position !Speed -> Football +mkFootball pos2D speed2D = {ballPos = toPosition3D pos2D, ballSpeed = toSpeed3D speed2D} + +ballIsFree :: !FootballState -> Bool +ballIsFree (Free _) = True +ballIsFree _ = False + +ballIsGainedBy :: !FootballerID !FootballState -> Bool +ballIsGainedBy id (GainedBy id`) = id == id` +ballIsGainedBy _ _ = False + +getFootball :: !FootballState !.[Footballer] -> Football +getFootball (Free ball) _ = ball +getFootball (GainedBy playerID) allPlayers + = case filter (identify_player playerID) allPlayers of + [] = abort "getFootball: no player found with requested identifier." + [{pos,speed}:_] = mkFootball pos speed diff --git a/src/Game/Footballer.dcl b/src/Game/Footballer.dcl new file mode 100644 index 0000000..5cba703 --- /dev/null +++ b/src/Game/Footballer.dcl @@ -0,0 +1,277 @@ +definition module Footballer + +/** This module defines the part of the SoccerFun API that is concerned with the footballer data types. +*/ +import StdMaybe, StdEnvExt +from StdIOCommon import :: Void(..) +import Football, Geometry, Team + +:: Footballer = E. memory: // The memory of a footballer is a black box + { playerID :: !FootballerID // The identification of a player: this must be unique + , name :: !String // The name of a player: this need not be unique + , length :: !Length // The length of a player: should be in range [min_length..max_length] + , pos :: !Position // The position of a player: should be on the football field + , speed :: !Speed // The speed of a player: absolute direction and velocity with which player is moving + , nose :: !Angle // The bearing of a player: absolute direction in which player is looking + , skills :: !MajorSkills // The major skills of a player: these improve performance of affected actions + , effect :: !Maybe FootballerEffect // The effect(s) of the previous action + , stamina :: !Stamina // The current stamina of a player: 1.0 is optimal, 0.0 is worst + , health :: !Health // The current health of a player: 1.0 is optimal, 0.0 is worst + , brain :: !Brain (FootballerAI memory) memory // The precious asset: use and update the memory and compute an action + } +:: FootballerID = { clubName :: !ClubName // Club name of team + , playerNr :: !PlayersNumber // Number of player (1 for keeper, other for fielders) + } +instance == FootballerID +instance toString FootballerID +instance nameOf FootballerID + +class sameClub a :: !a !a -> Bool // belong to same club +instance sameClub FootballerID +instance sameClub Footballer + +:: ClubName :== String +:: Length :== Metre +:: MajorSkills :== (!Skill,!Skill,!Skill) +:: Skill = Running // Faster running without ball in possession + | Dribbling // Faster running with ball in possession + | Rotating // Wider range of rotation + | Gaining // Better ball gaining ability + | Kicking // More accurate and wider ball kicking + | Heading // More accurate and wider ball heading + | Feinting // Wider range of feint manouvre + | Jumping // Further jumping + | Catching // Better catching + | Tackling // More effective tackling +instance == Skill +instance toString Skill +:: PlayersNumber :== Int + +instance == Footballer // two players are equal if their playerID's are equal +instance toPosition Footballer +instance toPosition3D Footballer + +defaultFootballer :: !FootballerID -> Footballer + +inRadiusOfFootballer :: !Position !Footballer -> Bool // True iff position touches/hits footballer +skillsAsList :: !Footballer -> [Skill] // Skills of the footballer as a list + +:: FootballerAI memory :== (BrainInput,memory) -> (BrainOutput,memory) +:: FootballerAI` :== BrainInput -> BrainOutput +:: BrainInput = { referee :: [RefereeAction] // the referee actions + , football :: FootballState // the state of the football + , others :: [Footballer] // all other football players + , me :: Footballer // the player himself + } +:: BrainOutput :== FootballerAction // the footballer action + +:: Half = FirstHalf | SecondHalf +instance == Half +instance toString Half +instance other Half + +:: Home = West | East +instance == Home +instance toString Home +instance other Home + +xWidthFootballer :== m (0.7/2.0) // chest size of footballer +yWidthFootballer :== m (0.4/2.0) // stomach size of footballer + +identify_player :: !FootballerID !Footballer -> Bool +player_identity :: !Footballer -> FootballerID + +class nameOf a :: !a -> String +instance nameOf Footballer + +getClubName :: !Footballer -> ClubName +isKeeper :: !Footballer -> Bool +isFielder :: !Footballer -> Bool + + +:: Brain ai m = { ai :: !ai + , memory:: !m + } +:: Stamina :== Real +:: Health :== Real + +min_length :== m 1.6 // minimum length of a person. Advantages: better gainball; better stamina at sprinting; better dribbling; less health damage when fall, better rotating. +max_length :== m 2.1 // maximum length of a person. Advantages: wider gainball; better stamina at running; higher headball; improved catching; harder kicking. +max_stamina :== 1.0 +max_health :== 1.0 + +/** Footballer attribute dependent abilities: + use these functions to make your player correctly dependent of abilities. +*/ +maxGainReach :: !Footballer -> Metre +maxJumpReach :: !Footballer -> Metre // vertical jumping +maxGainVelocityDifference :: !Footballer !Metre -> Velocity +maxCatchVelocityDifference :: !Footballer !Metre -> Velocity +maxKickReach :: !Footballer -> Metre +maxHeadReach :: !Footballer -> Metre +maxCatchReach :: !Footballer -> Metre // includes horizontal jumping +maxTackleReach :: !Footballer -> Metre +maxVelocityBallKick :: !Footballer -> Velocity +maxVelocityBallHead :: !Footballer !Velocity -> Velocity +maxKickingDeviation :: !Footballer -> Angle +maxHeadingDeviation :: !Footballer -> Angle +maxRotateAngle :: !Footballer -> Angle // maximum angle with which footballer can rotate +maxFeintStep :: !Footballer -> Metre // maximum side step of footballer for feint manouvre + +:: HealthStaminaFactor :== Real // combination of stamina and health +getHealthStaminaFactor :: !Health !Stamina -> HealthStaminaFactor + + +:: FootballField = { fwidth :: !FieldWidth // width of football field (64m <=width <=75m) + , flength :: !FieldLength // length of football field (100m<=length<=110m) + } +:: FieldWidth :== Metre +:: FieldLength :== Metre + +getDefaultField :: FootballField +inPenaltyArea :: !FootballField !Home !Position -> Bool + +/** Official metrics of a football field: +*/ +radius_centre_circle :== m 9.15 +radius_centre_spot :== m 0.3 // not official, taken for rendering +goal_width :== m 7.32 // interior +goal_height :== m 2.44 // interior +goal_area_depth :== m 5.50 +penalty_area_depth :== m 16.50 +penalty_spot_depth :== m 11.00 +radius_penalty_spot :== m 0.3 // not official, taken for rendering +radius_penalty_area :== m 9.15 +radius_corner_kick_area :== m 0.90 +goal_pole_width :== m 0.2 // not official + +/** goal_poles yields the py coordinates of the interiors of (north pole, south pole) of the goal (note that north > 0 > south) +*/ +goal_poles :: !FootballField -> (!Metre,!Metre) + +repell_distance :== m 9.15 // minimum distance of opponents from ball at (in)direct free kick + +:: FootballerAction // actions a player can intend to perform + = Move !Speed !Angle // wish to rotate over given angle, and then move with given speed + | Feint !FeintDirection // wish to make feint manouvre + | KickBall !Speed3D // wish to kick ball with given speed + | HeadBall !Speed3D // wish to head ball with given speed + | GainBall // wish to gain possession of the ball + | CatchBall // wish to catch the ball with his hands + | Tackle !FootballerID !Velocity // wish to tackle identified player, higher velocity is higher chance of succes AND injury + +isMove :: !FootballerAction -> Bool +isGainBall :: !FootballerAction -> Bool +isCatchBall :: !FootballerAction -> Bool +isKickBall :: !FootballerAction -> Bool +isHeadBall :: !FootballerAction -> Bool +isFeint :: !FootballerAction -> Bool +isFootballerTackle :: !FootballerAction -> Bool +isActionOnBall :: !FootballerAction -> Bool + +instance == FootballerAction +instance toString FootballerAction + +:: FeintDirection = FeintLeft | FeintRight +instance == FeintDirection +instance toString FeintDirection + +:: FootballerEffect = Moved !Speed !Angle // player has rotated with given angle, and then ran with given speed + | Feinted !FeintDirection // player had feinted + | KickedBall !(Maybe Speed3D) // player kicked ball (Just v) with velocity, or didn't (Nothing) + | HeadedBall !(Maybe Speed3D) // player headed ball (Just v) with velocity, or didn't (Nothing) + | GainedBall !Success // player attempt to gain ball from other player + | CaughtBall !Success // player caught the ball with his hands + | Tackled !FootballerID !Velocity !Success // player attempt to tackle an opponent + | OnTheGround !FramesToGo // tackled by someone else; FramesToGo is the amount of frames that you will be on the ground +:: Reprimand = Warning | YellowCard | RedCard // If the referee gives a second yellow he should add red to it himself +instance toString Reprimand +instance == Reprimand +:: Success = Success | Fail +instance toString Success +instance == Success +:: FramesToGo :== Int // number of frames to go before event ends + +isMoved :: !FootballerEffect -> Bool +isGainedBall :: !FootballerEffect -> Bool +isKickedBall :: !FootballerEffect -> Bool +isHeadedBall :: !FootballerEffect -> Bool +isFeinted :: !FootballerEffect -> Bool +isTackled :: !FootballerEffect -> Bool +isCaughtBall :: !FootballerEffect -> Bool +isOnTheGround :: !FootballerEffect -> Bool + +failFootballerAction :: !FootballerAction -> FootballerEffect + +:: RefereeAction = ReprimandPlayer !FootballerID !Reprimand // player with given name receives reprimand + | Hands !FootballerID // person is seen for doing hands + | TackleDetected !FootballerID // person is seen for doing tackle + | DangerousPlay !FootballerID // person is seen for doing dangerous actions + | GameOver // end of game + | GameCancelled !(Maybe Home) // game is cancelled, (Just home) wins + | PauseGame // game is paused + | AddTime !ExtraTime // extra time is added to the game + | EndHalf // first half is over, teams go for a second half + | Goal !Home // team playing at home has scored + | Offside !FootballerID // player is offside + | DirectFreeKick !Home !Position // a direct free kick is granted for team home at given position + | GoalKick !Home // a goal kick is granted for team home + | Corner !Home !Edge // a corner kick is granted for team home + | ThrowIn !Home !Position // a throw in ball is granted for team home at given position + | Penalty !Home // penalty at homeside + | CenterKick !Home // team playing at home may start from the center + | Advantage !Home // referee gives advantages to home-team + | OwnBallIllegally !FootballerID // ball was for the other team + | DisplacePlayers !Displacements // displaces all footballers at the provided position (used with free kicks) + | ContinueGame + | TellMessage !String // no effect on match, message is displayed by referee +showSuccintRefereeAction :: !RefereeAction -> String // yield a concise string representation of the referee decision + +:: Edge = North | South +instance == Edge +instance toString Edge +instance other Edge + +:: Displacements :== AssocList FootballerID Displacement // players that need to be displaced +:: Displacement :== Position // new position + +displacements :: !Team -> Displacements + +:: ExtraTime :== Minutes +:: Minutes +instance zero Minutes +instance < Minutes +instance == Minutes +instance + Minutes +instance - Minutes +instance scale Minutes +instance toString Minutes +instance toReal Minutes + +class minutes a :: !a -> Minutes +instance minutes Real // (minutes m) interprets m as number of minutes + +isReprimandPlayer :: !RefereeAction -> Bool +isHands :: !RefereeAction -> Bool +isTackleDetected :: !RefereeAction -> Bool +isDangerousPlay :: !RefereeAction -> Bool +isGameOver :: !RefereeAction -> Bool +isGameCancelled :: !RefereeAction -> Bool +isPauseGame :: !RefereeAction -> Bool +isAddTime :: !RefereeAction -> Bool +isEndHalf :: !RefereeAction -> Bool +isGoal :: !RefereeAction -> Bool +isOffside :: !RefereeAction -> Bool +isDirectFreeKick :: !RefereeAction -> Bool +isGoalKick :: !RefereeAction -> Bool +isCorner :: !RefereeAction -> Bool +isThrowIn :: !RefereeAction -> Bool +isPenalty :: !RefereeAction -> Bool +isCenterKick :: !RefereeAction -> Bool +isAdvantage :: !RefereeAction -> Bool +isOwnBallIllegally :: !RefereeAction -> Bool +isDisplacePlayers :: !RefereeAction -> Bool +isContinueGame :: !RefereeAction -> Bool +isTellMessage :: !RefereeAction -> Bool + +getKickPos :: !FootballField !Half !RefereeAction -> Maybe Position diff --git a/src/Game/Footballer.icl b/src/Game/Footballer.icl new file mode 100644 index 0000000..ef8d800 --- /dev/null +++ b/src/Game/Footballer.icl @@ -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 diff --git a/src/Game/FootballerFunctions.dcl b/src/Game/FootballerFunctions.dcl new file mode 100644 index 0000000..4f1e8f9 --- /dev/null +++ b/src/Game/FootballerFunctions.dcl @@ -0,0 +1,32 @@ +definition module FootballerFunctions + +/** Functions for creating miniscule brains: +*/ + +import Footballer + +// The core functions that do not require a memory: +returnAI` :: !FootballerAction -> FootballerAI` // just return the action +halt` :: FootballerAI` // halt lets the footballer stand quite still +rotate` :: !Angle -> FootballerAI` // rotate over given angle +ahead` :: !Velocity -> FootballerAI` // follow your nose with given velocity/ +fix` :: !Position !Metre -> FootballerAI` // fix p d lets the footballer run to p, with a precision of d +kick` :: !Position -> FootballerAI` // kick p lets the footballer kick the ball to position p, if in kicking range +track_ball` :: !Metre -> FootballerAI` // track_ball` d lets the footballer move to the ball, with a precision of d + +amnesia :: FootballerAI` -> FootballerAI m + +// The derived functions that do not care about their memory (the amnesia versions of the above functions): +returnAI :: (FootballerAction -> FootballerAI m) +halt :: ( FootballerAI m) +rotate :: (Angle -> FootballerAI m) +ahead :: (Velocity -> FootballerAI m) +fix :: (Position Metre -> FootballerAI m) +kick :: (Position -> FootballerAI m) +track_ball :: (Metre -> FootballerAI m) + +centerOfGoal :: !Home !FootballField -> Position +(team) infix 9 :: !Footballer ![Footballer] -> [Footballer] +(opponents) infix 9 :: !Footballer ![Footballer] -> [Footballer] + +getBall :: !BrainInput -> Football diff --git a/src/Game/FootballerFunctions.icl b/src/Game/FootballerFunctions.icl new file mode 100644 index 0000000..2bcd55a --- /dev/null +++ b/src/Game/FootballerFunctions.icl @@ -0,0 +1,95 @@ +implementation module FootballerFunctions + +import Footballer + +returnAI` :: !FootballerAction -> FootballerAI` +returnAI` action = const action + +move` :: !Speed !Angle -> FootballerAI` +move` speed angle = returnAI` (Move speed angle) + +halt` :: FootballerAI` +halt` = move` zero zero + +rotate` :: !Angle -> FootballerAI` +rotate` angle = move` zero angle + +ahead` :: !Velocity -> FootballerAI` +ahead` v = \input=:{me} -> move` {direction=me.nose,velocity=v} zero input + +fix` :: !Position !Metre -> FootballerAI` +fix` point eps = \input=:{me} -> + let distance = dist me point + angle = bearing zero me point + rotate = bearing me.nose me point + v = ms (max 6.0 (toReal distance)) + in if (distance <= eps) + (halt` input) + (move` {direction=angle,velocity=v} rotate input) + +kick` :: !Position -> FootballerAI` +kick` point = \input=:{me} -> + let ball = getBall input + angle = bearing zero me point + v = ms (2.0 * (toReal (dist me point))) + in if (dist me ball <= maxKickReach me) + (KickBall {vxy = {direction=angle,velocity=v},vz=ms 1.0}) + (halt` input) + +track_ball` :: !Metre -> FootballerAI` +track_ball` eps = \input -> fix` (getBall input).ballPos.pxy eps input + +amnesia :: FootballerAI` -> FootballerAI m +amnesia f = \(input,m) -> (f input,m) + +returnAI :: (FootballerAction -> FootballerAI m) +returnAI = amnesia o returnAI` + +move :: (Speed Angle -> FootballerAI m) +move = \speed angle -> amnesia (move` speed angle) + +halt :: (FootballerAI m) +halt = amnesia halt` + +rotate :: (Angle -> FootballerAI m) +rotate = amnesia o rotate` + +ahead :: (Velocity -> FootballerAI m) +ahead = amnesia o ahead` + +fix :: (Position Metre -> FootballerAI m) +fix = \point eps -> amnesia (fix` point eps) + +kick :: (Position -> FootballerAI m) +kick = amnesia o kick` + +track_ball :: (Metre -> FootballerAI m) +track_ball = \eps -> amnesia (track_ball` eps) + +centerOfGoal :: !Home !FootballField -> Position +centerOfGoal home field = {zero & px = if (home==West) (~half_length) half_length} +where + half_length = scale 0.5 field.flength + +(team) infix 9 :: !Footballer ![Footballer] -> [Footballer] +(team) player players = filter (sameClub player) players + +(opponents) infix 9 :: !Footballer ![Footballer] -> [Footballer] +(opponents) player players = filter (not o (sameClub player)) players + +getBall :: !BrainInput -> Football +getBall {football,me,others}= getFootball football [me : others] + +:: HomeM m = { home :: !Home, mem :: !m } + +educate` :: (Home -> FootballerAI`) -> FootballerAI (HomeM m) +educate` home_ai = \(input=:{referee},memory) -> + let new_home = if (any isEndHalf referee) other id memory.home + action = home_ai new_home input + in (action, {memory & home = new_home}) + +educate :: (Home -> FootballerAI m) -> FootballerAI (HomeM m) +educate home_ai = \(input=:{referee},memory) -> + let new_home = if (any isEndHalf referee) other id memory.home + (action,new_memory) = home_ai new_home (input,memory.mem) + in (action, {memory & home = new_home, mem = new_memory}) diff --git a/src/Game/GamePicture.dcl b/src/Game/GamePicture.dcl new file mode 100644 index 0000000..e08511d --- /dev/null +++ b/src/Game/GamePicture.dcl @@ -0,0 +1,13 @@ +definition module GamePicture + +/** Type definitions for handling bitmaps for referees (and footballers in the future). +*/ + +import StdBitmap + +:: Path :== String +:: GamePicture = { img :: !Bitmap + , path :: !Path + } +:: ActionPics = { refereePics :: ![GamePicture] + } diff --git a/src/Game/GamePicture.icl b/src/Game/GamePicture.icl new file mode 100644 index 0000000..a68bddf --- /dev/null +++ b/src/Game/GamePicture.icl @@ -0,0 +1,3 @@ +implementation module GamePicture + +import StdBitmap diff --git a/src/Game/Geometry.dcl b/src/Game/Geometry.dcl new file mode 100644 index 0000000..ac456ad --- /dev/null +++ b/src/Game/Geometry.dcl @@ -0,0 +1,205 @@ +definition module Geometry + +/** This module defines the part of the SoccerFun API that is concerned with the footballer dimensions. +*/ +import StdEnvExt + + +class scale a :: !Real !a -> a + + +:: Metre +m :: !Real -> Metre // (m metre) is a distance in metres + +instance zero Metre +instance + Metre +instance - Metre +instance abs Metre +instance sign Metre +instance ~ Metre +instance == Metre +instance < Metre +instance toReal Metre +instance toString Metre +instance scale Metre + + +:: Position + = { px :: !Metre // x-coordinate in plane + , py :: !Metre // y-coordinate in plane + } +:: Position3D + = { pxy :: !Position // position on plane + , pz :: !Metre // height above plane + } + +instance zero Position +instance zero Position3D +instance == Position +instance == Position3D +instance toString Position +instance toString Position3D + +class toPosition a :: !a -> Position +class fromPosition a :: !Position -> a +class toPosition3D a :: !a -> Position3D +class fromPosition3D a :: !Position3D -> a +instance toPosition (!Metre,!Metre) +instance toPosition Position +instance toPosition Position3D +instance fromPosition (!Metre,!Metre) +instance fromPosition Position +instance fromPosition Position3D +instance toPosition3D (!Metre,!Metre,!Metre) +instance toPosition3D Position +instance toPosition3D Position3D +instance fromPosition3D (!Metre,!Metre,!Metre) +instance fromPosition3D Position +instance fromPosition3D Position3D + +dist :: !a !b -> Metre | toPosition3D a & toPosition3D b + + +:: Angle + +pi :== 3.1415926535897932384 // (rad pi) is equivalant with (degree 180) + +rad :: !Real -> Angle // (rad x) is an angle of x radians (counter-clockwise) +degree :: !Int -> Angle // (degree x) is an angle of x degrees (counter-clockwise) + +instance zero Angle +instance + Angle +instance - Angle +instance abs Angle +instance sign Angle +instance ~ Angle +instance == Angle +instance < Angle +instance toReal Angle +instance toInt Angle +instance toString Angle +instance scale Angle +instance sinus Angle +instance cosinus Angle +instance tangens Angle +instance arcsinus Angle +instance arccosinus Angle +instance arctangens Angle + +/** orthogonal a + returns the left- and right- orthogonal angles to a +*/ +orthogonal :: !Angle -> (!Angle,!Angle) + +/** bearing nose base target: + returns the smallest rotation angle needed for a player at @base having current direction @nose + to face @target. + The result is a value between ~pi and pi. +*/ +bearing :: !Angle !base !target -> Angle | toPosition base & toPosition target + + +:: RVector + = { dx :: !Metre // difference in px-coordinate + , dy :: !Metre // difference in py-coordinate + } +:: RVector3D + = { dxy :: !RVector + , dz :: !Metre + } + +class toRVector a :: !a -> RVector +instance toRVector Angle +instance toRVector Position + +/** size_vector {dx, dy} = sqrt ( dx^2 + dy^2) + size_vector3D {dxy,dz} = sqrt (dxy.dx^2 + dxy.dy^2 + dz^2) +*/ +size_vector :: !RVector -> Metre +size_vector3D :: !RVector3D -> Metre + +instance + RVector +instance + RVector3D +instance - RVector +instance - RVector3D +instance zero RVector +instance zero RVector3D +instance one RVector +instance one RVector3D +instance ~ RVector +instance ~ RVector3D +instance scale RVector +instance scale RVector3D + + +/** move_point v p: + moves point p over vector v. + move_point3D v p: + moves point p over vector v. +*/ +move_point :: !RVector !Position -> Position +move_point3D :: !RVector3D !Position3D -> Position3D + +/** repell minimum_distance base pos: + if @pos is too close to @base, compute a new position that is at least @minimum_distance metres away from @base. + attract maximum_distance base pos: + if @pos is too far away from @base, compute a new position that is at most @maximum_distance metres away from @base. +*/ +repell :: !Metre !Position !Position -> Position +attract :: !Metre !Position !Position -> Position + +/** point_to_rectangle (a,b) c + returns c if (point_in_rectangle (a,b) c) and the projected point c` of c that is exactly on the closest edge of + rectangle (a,b). +*/ +point_to_rectangle :: !(!Position,!Position) !Position -> Position + +/** point_in_rectangle (a,b) c + returns True iff point c is inside the rectangle determined by + the diagonal corner points a and b. +*/ +point_in_rectangle :: !(!Position,!Position) !Position -> Bool + + +:: Velocity + +ms :: !Real -> Velocity // (ms metre-per-second) is a velocity + +instance zero Velocity +instance + Velocity +instance - Velocity +instance abs Velocity +instance sign Velocity +instance ~ Velocity +instance == Velocity +instance < Velocity +instance toReal Velocity +instance toString Velocity +instance scale Velocity + + +:: Speed // speed of an object + = { direction :: !Angle // direction of object + , velocity :: !Velocity // velocity of object + } +:: Speed3D // speed of an object in space + = { vxy :: !Speed // surface speed of object + , vz :: !Velocity // velocity in z-axis (positive: goes up; negative: goes down; zero: horizontally) + } + +instance zero Speed +instance zero Speed3D +instance == Speed +instance == Speed3D +instance toString Speed +instance toString Speed3D + +class toSpeed a :: !a -> Speed +class fromSpeed a :: !Speed -> a +class toSpeed3D a :: !a -> Speed3D +class fromSpeed3D a :: !Speed3D -> a + +instance toSpeed Speed3D +instance fromSpeed Speed3D +instance toSpeed3D Speed +instance fromSpeed3D Speed diff --git a/src/Game/Geometry.icl b/src/Game/Geometry.icl new file mode 100644 index 0000000..e9b29da --- /dev/null +++ b/src/Game/Geometry.icl @@ -0,0 +1,223 @@ +implementation module Geometry + +import StdEnvExt + +:: Metre = Metre !Real + +m :: !Real -> Metre // distance in metre +m metre = Metre metre + +instance zero Metre where zero = Metre zero +instance + Metre where + (Metre m1) (Metre m2) = Metre (m1 + m2) +instance - Metre where - (Metre m1) (Metre m2) = Metre (m1 - m2) +instance scale Metre where scale k (Metre m) = Metre (k * m) +instance abs Metre where abs (Metre m) = Metre (abs m) +instance sign Metre where sign (Metre m) = sign m +instance ~ Metre where ~ (Metre m) = Metre (~m) +instance == Metre where == (Metre m1) (Metre m2) = m1 == m2 +instance < Metre where < (Metre m1) (Metre m2) = m1 < m2 +instance toReal Metre where toReal (Metre m) = m +instance toString Metre where toString (Metre m) = m +++> " m." + + + +:: Velocity = MetrePerSecond !Real // velocity in metre/second + +ms :: !Real -> Velocity +ms v = MetrePerSecond v + +instance zero Velocity where zero = MetrePerSecond zero +instance + Velocity where + (MetrePerSecond v1) (MetrePerSecond v2) = MetrePerSecond (v1 + v2) +instance - Velocity where - (MetrePerSecond v1) (MetrePerSecond v2) = MetrePerSecond (v1 - v2) +instance scale Velocity where scale k (MetrePerSecond v) = MetrePerSecond (k * v) +instance abs Velocity where abs (MetrePerSecond v) = MetrePerSecond (abs v) +instance sign Velocity where sign (MetrePerSecond v) = sign v +instance ~ Velocity where ~ (MetrePerSecond v) = MetrePerSecond (~v) +instance == Velocity where == (MetrePerSecond v1) (MetrePerSecond v2) = v1 == v2 +instance < Velocity where < (MetrePerSecond v1) (MetrePerSecond v2) = v1 < v2 +instance toReal Velocity where toReal (MetrePerSecond v) = v +instance toString Velocity where toString (MetrePerSecond v) = v +++> "m/s" + +instance zero RVector where zero = {dx = zero, dy = zero} +instance + RVector where + v1 v2 = {dx = v1.dx + v2.dx, dy = v1.dy + v2.dy} +instance - RVector where - v1 v2 = {dx = v1.dx - v2.dx, dy = v1.dy - v2.dy} +instance one RVector where one = {dx = m 1.0, dy = m 1.0} +instance scale RVector where scale k {dx, dy} = {dx = scale k dx, dy = scale k dy} +instance ~ RVector where ~ v = zero - v +instance coords RVector where coords {dx,dy} = [dx,dy] +instance zero RVector3D where zero = {dxy = zero, dz = zero} +instance + RVector3D where + v1 v2 = {dxy = v1.dxy + v2.dxy, dz = v1.dz + v2.dz} +instance - RVector3D where - v1 v2 = {dxy = v1.dxy - v2.dxy, dz = v1.dz - v2.dz} +instance one RVector3D where one = {dxy = one, dz = m 1.0} +instance scale RVector3D where scale k {dxy,dz} = {dxy = scale k dxy, dz = scale k dz} +instance ~ RVector3D where ~ v = zero - v +instance coords RVector3D where coords {dxy={dx,dy},dz} = [dx,dy,dz] + + +:: Angle = Radian !Real + +pi :== 3.1415926535897932384 + +rad :: !Real -> Angle +rad x = Radian (normalize_radian x) + +degree :: !Int -> Angle +degree x = rad (toReal x * pi / 180.0) + +normalize_radian :: !Real -> Real +normalize_radian r +| r < (~cycle) = normalize_radian (r + cycle) +| r > cycle = normalize_radian (r - cycle) +| otherwise = r +where + cycle = 2.0 * pi + +instance zero Angle where zero = Radian zero +instance + Angle where + (Radian r1) (Radian r2) = Radian (normalize_radian (r1 + r2)) +instance - Angle where - (Radian r1) (Radian r2) = Radian (normalize_radian (r1 - r2)) +instance scale Angle where scale k (Radian r) = Radian (normalize_radian (k*r)) +instance abs Angle where abs (Radian r) = Radian (abs r) +instance sign Angle where sign (Radian r) = sign r +instance ~ Angle where ~ (Radian r) = Radian (~r) +instance == Angle where == (Radian r1) (Radian r2) = r1 == r2 +instance < Angle where < (Radian r1) (Radian r2) = r1 < r2 +instance toReal Angle where toReal (Radian r) = r +instance toInt Angle where toInt (Radian r) = toInt (r * 180.0 / pi) +instance toString Angle where toString (Radian r) = r +++> " rad" +instance toRVector Angle where toRVector (Radian r) = {dx = Metre (cos r), dy = Metre (sin r)} +instance sinus Angle where sinus (Radian r) = sin r +instance cosinus Angle where cosinus (Radian r) = cos r +instance tangens Angle where tangens (Radian r) = tan r +instance arcsinus Angle where arcsinus x = Radian (asin x) +instance arccosinus Angle where arccosinus x = Radian (acos x) +instance arctangens Angle where arctangens x = Radian (atan x) + +instance zero Position where zero = {px = zero, py = zero} +instance == Position where == p1 p2 = p1.px == p2.px && p1.py == p2.py +instance coords Position where coords {px,py} = [px,py] +instance toString Position where toString {px, py} = "{px=" +++ toString px +++ ",py=" +++ toString py +++ "}" +instance toRVector Position where toRVector p = {dx = p.px, dy = p.py} +instance zero Position3D where zero = {pxy = zero, pz = zero} +instance == Position3D where == p1 p2 = p1.pxy == p2.pxy && p1.pz == p2.pz +instance coords Position3D where coords {pxy={px,py},pz} = [px,py,pz] +instance toString Position3D where toString {pxy,pz} = "{pxy=" +++ toString pxy +++ ",pz=" +++ toString pz +++ "}" + +instance toPosition (!Metre,!Metre) where toPosition (x,y) = {px=x,py=y} +instance toPosition Position where toPosition p2D = p2D +instance toPosition Position3D where toPosition p3D = p3D.pxy +instance fromPosition (!Metre,!Metre) where fromPosition p2D = (p2D.px,p2D.py) +instance fromPosition Position where fromPosition p2D = p2D +instance fromPosition Position3D where fromPosition p2D = {zero & pxy=p2D} +instance toPosition3D (!Metre,!Metre,!Metre) where toPosition3D (x,y,z) = {pxy=toPosition (x,y),pz=z} +instance toPosition3D Position where toPosition3D p2D = {zero & pxy=p2D} +instance toPosition3D Position3D where toPosition3D p3D = p3D +instance fromPosition3D (!Metre,!Metre,!Metre) where fromPosition3D p3D = (p3D.pxy.px,p3D.pxy.py,p3D.pz) +instance fromPosition3D Position where fromPosition3D p3D = p3D.pxy +instance fromPosition3D Position3D where fromPosition3D p3D = p3D + +instance zero Speed where zero = {direction=zero,velocity=zero} +instance == Speed where == sp1 sp2 = sp1.direction == sp2.direction && sp1.velocity == sp2.velocity +instance toString Speed where toString {direction,velocity} = "{direction=" +++ toString direction +++ ",velocity=" +++ toString velocity +++ "}" +instance toSpeed3D Speed where toSpeed3D s = {zero & vxy=s} +instance zero Speed3D where zero = {vxy=zero,vz=zero} +instance == Speed3D where == sp1 sp2 = sp1.vxy == sp2.vxy && sp1.vz == sp2.vz +instance toString Speed3D where toString {vxy,vz} = "{vxy=" +++ toString vxy +++ ",vz=" +++ toString vz +++ "}" +instance toSpeed Speed3D where toSpeed s = s.vxy +instance fromSpeed Speed3D where fromSpeed s = {zero & vxy=s} +instance fromSpeed3D Speed where fromSpeed3D s = s.vxy + +class coords a :: !a -> [Metre] + +move_point :: !RVector !Position -> Position +move_point {dx,dy} {px,py} = {px=px+dx,py=py+dy} + +move_point3D :: !RVector3D !Position3D -> Position3D +move_point3D {dxy,dz} {pxy,pz} = {pxy=move_point dxy pxy,pz=pz+dz} + +repell :: !Metre !Position !Position -> Position +repell minimum_distance base pos +| d == zero = move_point {zero & dx=minimum_distance} pos +| d < minimum_distance = move_point v` base //move_point (v` - v) pos +| otherwise = pos +where + d = dist base pos + v = {dx = pos.px - base.px, dy = pos.py - base.py} + v` = scale ((toReal minimum_distance) / (toReal d)) v + +attract :: !Metre !Position !Position -> Position +attract maximum_distance base pos +| d > maximum_distance = move_point v` base +| otherwise = pos +where + d = dist base pos + v = {dx = pos.px - base.px, dy = pos.py - base.py} + v` = scale ((toReal maximum_distance) / (toReal d)) v + +between_points :: !(!Position,!Position) !Position -> Bool +between_points (a,b) c = point_in_rectangle (a,b) c && (toReal dcx) / (toReal dcy) == (toReal dx) / (toReal dy) +where + [min_x,max_x:_] = sort [a.px,b.px] + [min_y,max_y:_] = sort [a.py,b.py] + (dx, dy) = (a.px - b.px, a.py - b.py) + (dcx,dcy) = (a.px - c.px, a.py - c.py) + +point_in_rectangle :: !(!Position,!Position) !Position -> Bool +point_in_rectangle (a,b) c = isbetween c.px min_x max_x && isbetween c.py min_y max_y +where + (min_x,max_x) = minmax (a.px,b.px) + (min_y,max_y) = minmax (a.py,b.py) + +point_to_rectangle :: !(!Position,!Position) !Position -> Position +point_to_rectangle (a,b) c +| point_in_rectangle (a,b) c = c +| otherwise = toPosition c` +where + (min_x,max_x) = minmax (a.px,b.px) + (min_y,max_y) = minmax (a.py,b.py) + left = c.px <= min_x + right = c.px >= max_x + above = c.py >= max_y + below = c.py <= min_y + + c` | left && above = (min_x,max_y) + | right && above = (max_x,max_y) + | left && below = (min_x,min_y) + | right && below = (max_x,min_y) + | above = (c.px, max_y) + | below = (c.px, min_y) + | left = (min_x,c.py ) + | right = (max_x,c.py ) + | otherwise = abort ("unsuspected error; please rotate with angles between pi and -pi\n") + +size_vector :: !RVector -> Metre +size_vector v = Metre (dist` v z) +where z :: RVector; z = zero + +size_vector3D :: !RVector3D -> Metre +size_vector3D v = Metre (dist` v z) +where z :: RVector3D; z = zero + +dist :: !a !b -> Metre | toPosition3D a & toPosition3D b +dist a b = Metre (dist` (toPosition3D a) (toPosition3D b)) + +dist` :: !a !b -> Real | coords a & coords b +dist` cs1 cs2 = sqrt (sum [ (toReal c1 - toReal c2)^2.0 \\ c1 <- coords cs1 & c2 <- coords cs2 ]) + +orthogonal :: !Angle -> (!Angle,!Angle) +orthogonal a = (a + rad (0.25*pi), a - rad (0.25*pi)) + +px_bearing :: !base !target -> Angle | toPosition base & toPosition target +px_bearing base target +| v.dx >= zero && v.dy >= zero = Radian base_angle // 1st quadrant +| v.dx <= zero && v.dy >= zero = Radian (pi-base_angle) // 2nd quadrant +| v.dx <= zero && v.dy <= zero = Radian (base_angle-pi) // 3rd quadrant +| v.dx >= zero && v.dy <= zero = Radian (~base_angle) // 4th quadrant +where + pbase = toPosition base + ptarget = toPosition target + v = {dx = ptarget.px - pbase.px, dy = ptarget.py - pbase.py} + d = toReal (dist pbase ptarget) + base_angle = acos ((toReal (abs v.dx)) / d) + +bearing :: !Angle !base !target -> Angle | toPosition base & toPosition target +bearing angle base target = px_bearing base target - angle diff --git a/src/Game/Referee.dcl b/src/Game/Referee.dcl new file mode 100644 index 0000000..fd965bf --- /dev/null +++ b/src/Game/Referee.dcl @@ -0,0 +1,36 @@ +definition module Referee + +/** The referee data type, and all available referees within Soccer-Fun. +*/ +import Footballer, GamePicture, matchGame + +:: Referee = E.memory: + { name :: !String + , brain :: !Brain (RefereeAI RefereeOutput (memory,RandomSeed)) memory + , refActionPics :: ![Path] + } +:: RefereeAI msg memory :== (RefereeInput,memory) -> (msg,memory) +:: RefereeAI` msg :== RefereeInput -> msg +:: RefereeInput = { playingTime :: !PlayingTime // the duration of an entire match + , unittime :: !TimeUnit // the time unit of a single simulation step + , theBall :: !FootballState // the whereabouts of the football + , playingHalf :: !Half // first or second half; team1 is team that starts game on West; team2 is other team + , team1 :: !Team // team1 + , team2 :: !Team // team2 + , lastContact :: !Maybe FootballerID // last player who has played the ball + } +:: RefereeOutput :== [RefereeAction] + +instance nameOf Referee + +defaultReferee :: Referee + +allAvailableReferees:: [FootballField -> Referee] +defaultImage :: !Match !RefereeAction !*env -> (!Bitmap,!*env) | FileSystem env +defaultSoundFile :: !RefereeAction -> Maybe String + +/** Wrapper functions for simpler referee brains: +*/ +randomlessRefereeAI :: (RefereeAI msg memory) -> RefereeAI msg (memory,RandomSeed) +amnesiaRefereeAI :: (RefereeAI msg RandomSeed) -> RefereeAI msg (memory,RandomSeed) +witlessRefereeAI :: (RefereeAI` msg) -> RefereeAI msg (memory,RandomSeed) diff --git a/src/Game/Referee.icl b/src/Game/Referee.icl new file mode 100644 index 0000000..2f88d83 --- /dev/null +++ b/src/Game/Referee.icl @@ -0,0 +1,82 @@ +implementation module Referee + +import StdEnvExt +import matchGame +import Umpire +// When coding for all referees, include following modules: +import RefereeCoach_Rounds_Assignment +import RefereeCoach_Slalom_Assignment +import RefereeCoach_Passing_Assignment +import RefereeCoach_DeepPass_Assignment +import RefereeCoach_Keeper_Assignment + +allAvailableReferees :: [FootballField -> Referee] +allAvailableReferees = [ umpire ] +// When coding for all referees, use following list: + ++ + [ RefereeCoach_Rounds + , RefereeCoach_Slalom + , RefereeCoach_Passing + , RefereeCoach_DeepPass + , RefereeCoach_Keeper + ] + +instance nameOf Referee where nameOf {Referee | name} = name + +defaultReferee :: Referee +defaultReferee = { name = "Default" + , brain = {memory = Void,ai = \(_,st) -> ([ContinueGame],st)} + , refActionPics = [] + } + +defaultImage :: !Match !RefereeAction !*env -> (!Bitmap,!*env) | FileSystem env +defaultImage match action env +# bitmapf = case action of + (ReprimandPlayer _ r) = "ivanov_" +++ reprimandf r +++ ".bmp" + (Hands _) = "hands.bmp" + (OwnBallIllegally _) = "ivanov_badluck.bmp" + (TellMessage _) = "ivanov_look.bmp" + (DirectFreeKick _ p) = ivanovf (p.px < zero) + (GoalKick h) = ivanovf (h == West) + (Corner h _) = ivanovf (h == West) + (ThrowIn h _) = ivanovf (h == West) + (Penalty h) = ivanovf (h == West) + (Advantage _) = "ivanov_badluck.bmp" + _ = "ivanov_fluit.bmp" += case openBitmap ("afbeeldingen\\" +++ bitmapf) env of + (Just bm,env) = (bm,env) + nothing = abort "defaultImage: unable to load default picture.\n" +where + reprimandf r = case r of + Warning = "warning" + YellowCard = "yellow" + RedCard = "red" + ivanovf left = "ivanov_wijst_" +++ if left "links" "rechts" +++ ".bmp" + +defaultSoundFile :: !RefereeAction -> Maybe String +defaultSoundFile action = if (soundfilename == "") Nothing (Just ("sound\\"+++soundfilename)) +where + soundfilename = defaultSoundFileName action + + defaultSoundFileName (Hands _) = "stopBecauseOfFoul.wav" + defaultSoundFileName (TackleDetected _) = "tackles_ed.wav" + defaultSoundFileName (DangerousPlay _) = "tackles_ed.wav" + defaultSoundFileName GameOver = "endGameOrHalf.wav" + defaultSoundFileName (GameCancelled _) = "endGameOrHalf.wav" + defaultSoundFileName EndHalf = "endGameOrHalf.wav" + defaultSoundFileName (Offside _) = "offside.wav" + defaultSoundFileName (GoalKick _) = "ballOut.wav" + defaultSoundFileName (Corner _ _) = "ballOut.wav" + defaultSoundFileName (ThrowIn _ _) = "ballOut.wav" + defaultSoundFileName (Goal _) = "CenterKick.wav" + defaultSoundFileName (OwnBallIllegally _) = "wrongPosition2restartFrom.wav" + defaultSoundFileName _ = "" + +randomlessRefereeAI :: (RefereeAI msg memory) -> RefereeAI msg (memory,RandomSeed) +randomlessRefereeAI f = \(input,(memory,seed)) = let (decisions,memory`) = f (input,memory) in (decisions,(memory`,seed)) + +amnesiaRefereeAI :: (RefereeAI msg RandomSeed) -> RefereeAI msg (memory,RandomSeed) +amnesiaRefereeAI f = \(input,(memory,seed)) = let (decisions,seed`) = f (input,seed) in (decisions,(memory,seed`)) + +witlessRefereeAI :: (RefereeAI` msg) -> RefereeAI msg (memory,RandomSeed) +witlessRefereeAI f = \(input,state) = (f input,state) diff --git a/src/Game/Team.dcl b/src/Game/Team.dcl new file mode 100644 index 0000000..5d9158d --- /dev/null +++ b/src/Game/Team.dcl @@ -0,0 +1,25 @@ +definition module Team + +/** This module defines the Soccer-Fun API that is concerned with teams. + All available teams are collected in this module (allAvailableTeams). +*/ +import Footballer + +allAvailableTeams :: [Home FootballField -> Team] + +:: Team :== [Footballer] // the fielders are supposed to have different numbers, and all not equal to 1 + +instance nameOf Team + +validateTeam :: !Team -> Team +isValidTeam :: !Team -> Bool +allPlayersAtHome :: !FootballField !Home !Team -> Bool +replaceInTeam :: ![Footballer] !Team -> Team +getTeam :: !ClubName ![Team] -> Team + +class mirror a :: !FootballField !a -> a +instance mirror [a] | mirror a +instance mirror Footballer +instance mirror Position +instance mirror Speed +instance mirror Angle diff --git a/src/Game/Team.icl b/src/Game/Team.icl new file mode 100644 index 0000000..3b5dcb7 --- /dev/null +++ b/src/Game/Team.icl @@ -0,0 +1,85 @@ +implementation module Team + +import StdEnvExt +import Footballer +/* Import all standard teams: */ +import TeamMiniEffie +import Team_Opponent_Slalom_Assignment +import Team_Opponent_Passing_Assignment +import Team_Opponent_DeepPass_Assignment +import Team_Opponent_Keeper_Assignment +import Team_Student_Rounds_Assignment +import Team_Student_Slalom_Assignment +import Team_Student_Passing_Assignment +import Team_Student_DeepPass_Assignment +import Team_Student_Keeper_Assignment + +allAvailableTeams :: [Home FootballField -> Team] +allAvailableTeams = [ Team_MiniEffies + , Team_Student_Rounds + , Team_Student_Slalom + , Team_Student_Passing + , Team_Student_DeepPass + , Team_Student_Keeper + , Team_Opponent_Slalom + , Team_Opponent_Passing + , Team_Opponent_DeepPass + , Team_Opponent_Keeper + ] + +instance nameOf Team where nameOf players + = case players of + [fb:_] = nameOf fb.playerID + none = abort "nameOf[Team]: applied to empty team.\n" + +validateTeam :: !Team -> Team +validateTeam team = map validateFootballer team +where + validateFootballer :: !Footballer -> Footballer + validateFootballer fb=:{length} = {fb & length = setbetween length min_length max_length + , stamina = max_stamina + , health = max_health + } + +isValidTeam :: !Team -> Bool +isValidTeam team = length clubNames == 1 + && + (isEmpty keepers || isValidKeeper (hd keepers)) + && + all isValidPlayer players + && + sort (map nrOf players) == sort (removeDup (map nrOf players)) + && + not (isMember 1 (map nrOf fielders)) +where + (keepers,fielders) = spanfilter isKeeper team + clubNames = removeDup (map clubOf players) + clubName = hd clubNames + players = keepers ++ fielders + clubOf fb = fb.playerID.clubName + nrOf fb = fb.playerID.playerNr + isValidKeeper fb = fb.playerID == {clubName=clubName,playerNr=1} + isValidPlayer fb = clubOf fb == clubName + +allPlayersAtHome :: !FootballField !Home !Team -> Bool +allPlayersAtHome field home team = all atHome team +where + atHome = if (home == West) (\player -> player.Footballer.pos.px <= zero) + (\player -> player.Footballer.pos.px >= zero) + +replaceInTeam :: ![Footballer] !Team -> Team +replaceInTeam fbs team = removeMembers team fbs ++ fbs + +getTeam :: !ClubName ![Team] -> Team +getTeam cn teams = case [team \\ team<-teams | nameOf team==cn] of + [team:_] = team + _ = abort ("Team " <+++ cn <+++ " does not seem to exist.\n") + +instance mirror [a] | mirror a where mirror field as = map (mirror field) as +instance mirror Footballer where mirror field fb = {fb & pos = mirror field fb.pos + , nose = mirror field fb.nose + , speed = mirror field fb.speed + } +instance mirror Position where mirror field pos = {pos & px = ~pos.px} +instance mirror Speed where mirror field speed = {speed & direction = mirror field speed.direction} +instance mirror Angle where mirror field angle = rad pi - angle diff --git a/src/Game/matchControl.dcl b/src/Game/matchControl.dcl new file mode 100644 index 0000000..7688634 --- /dev/null +++ b/src/Game/matchControl.dcl @@ -0,0 +1,41 @@ +definition module matchControl + +/** This module defines the logical behavior of Soccer-Fun. + The core function is stepMatch, which computes a single, complete transition of a match. +*/ +import Referee + +:: Match = { team1 :: !Team // team1 + , team2 :: !Team // team2 + , theBall :: !FootballState // the whereabouts of the football + , theField :: !FootballField // the football field + , theReferee :: !Referee // the referee + , playingHalf :: !Half // first half or second half team1 plays West at first half and East at second half + , playingTime :: !PlayingTime // todo: add a boolean gameOver, playingtime will not walk back to zero and its up to the referee at which time he is to end the game + , score :: !Score // the score + , nextRandomP :: !St RandomSeed P // generate pseudo random value + , seed :: !RandomSeed // random seed for generating pseudo random values + , unittime :: !TimeUnit // the time unit of a single simulation step + , lastContact :: !Maybe FootballerID // the player who has the ball the last time (ball can have bounced against this player) + } +:: PlayingTime :== Minutes +:: Score :== (!NrOfGoals,!NrOfGoals) // (goals by Team1, goals by Team2) +:: NrOfGoals :== Int // zero <= nr of goals + +:: TimeUnit :== Seconds // time unit in sec. +:: Seconds + +s :: !Real -> Seconds // (s x) represents x seconds of time +instance zero Seconds +instance == Seconds +instance < Seconds +instance + Seconds +instance - Seconds +instance minutes Seconds +instance toReal Seconds +instance scale Seconds +instance toString Seconds + +doSoccerFun :: !*World -> *World +setMatchStart :: !Team !Team !FootballField !Referee !PlayingTime !RandomSeed -> Match +stepMatch :: !Match -> (!(![RefereeAction],!AssocList FootballerID FootballerAction),!Match) diff --git a/src/Game/matchControl.icl b/src/Game/matchControl.icl new file mode 100644 index 0000000..e0505c0 --- /dev/null +++ b/src/Game/matchControl.icl @@ -0,0 +1,557 @@ +implementation module matchControl + +import StdEnvExt +import Gui2D // we choose the 2D GUI version of SoccerFun +import Referee + +:: Seconds = Seconds !Real + +s :: !Real -> Seconds // (s x) represents x seconds of time +s x = Seconds x + +instance zero Seconds where zero = Seconds zero +instance == Seconds where == (Seconds s1) (Seconds s2)= s1 == s2 +instance < Seconds where < (Seconds s1) (Seconds s2)= s1 < s2 +instance + Seconds where + (Seconds s1) (Seconds s2)= Seconds (s1 + s2) +instance - Seconds where - (Seconds s1) (Seconds s2)= Seconds (s1 - s2) +instance minutes Seconds where minutes (Seconds s) = minutes (s/60.0) +instance toReal Seconds where toReal (Seconds s) = s +instance scale Seconds where scale k (Seconds s) = Seconds (k * s) +instance toString Seconds where toString (Seconds s) = s +++> " sec." + +doSoccerFun :: !*World -> *World +doSoccerFun world = SoccerFunGUI2D world + +setMatchStart :: !Team !Team !FootballField !Referee !PlayingTime !RandomSeed -> Match +setMatchStart fstTeam sndTeam field referee time rs + = { team1 = validateTeam fstTeam + , team2 = validateTeam sndTeam + , theBall = Free zero + , theField = field + , theReferee = referee + , playingHalf = FirstHalf + , playingTime = time + , unittime = s 0.05 + , score = (0,0) + , nextRandomP = nextRandomP + , seed = rs + , lastContact = Nothing + } + +stepMatch :: !Match -> (!(![RefereeAction],!AssocList FootballerID FootballerAction),!Match) +stepMatch match +# (refereeActions, match) = refereeTurn match +# match = performRefereeActions refereeActions match +# (intendedActions, match) = playersThink refereeActions match +# (okActions, match) = successfulActions intendedActions match +# match = doFootballerActions intendedActions okActions match +# match = moveFootball match +# match = advanceTime match += ((refereeActions,okActions),match) +where +/* refereeTurn match + determines whether the rules of soccer are adhered to and yields a list of referee actions. +*/ refereeTurn :: !Match -> (![RefereeAction],!Match) + refereeTurn match=:{theReferee=referee=:{Referee | brain=brain=:{ai,memory}},theBall,playingHalf,team1,team2,playingTime,unittime,seed,lastContact} + = (refereeActions,{match & theReferee=new_referee,seed=new_seed}) + where + (refereeActions,(memory`,new_seed)) = ai ({RefereeInput | playingTime = playingTime + , unittime = unittime + , theBall = theBall + , playingHalf = playingHalf + , team1 = team1 + , team2 = team2 + , lastContact = lastContact + } + ,(memory,seed) + ) + new_referee = {Referee | referee & brain={Brain | brain & memory=memory`}} + +/* performRefereeActions refereeActions match + performs for each football player in match his succeededAction, informs them about the referee actions, and moves the ball. +*/ performRefereeActions :: ![RefereeAction] !Match -> Match + performRefereeActions refActions match = foldl doRefereeEvent match refActions + where + doRefereeEvent :: !Match !RefereeAction -> Match + doRefereeEvent theMatch=:{Match | playingHalf,theField,team1,team2} refereeAction + | isAlterMatchBallAndTeams = {Match | theMatch & theBall=Free (mkFootball pos zero),lastContact=Nothing} + | isProgressEvent = gameProgress theMatch + | isDisplaceTeamsEvent = {Match | theMatch & team1=map (displacePlayer ds) team1,team2=map (displacePlayer ds) team2} + | isReprimandEvent = let (team1`,team2`) = reprimandPlayer rep (team1,team2) in {Match | theMatch & team1=team1`,team2=team2`} + | otherwise = theMatch + where + (isAlterMatchBallAndTeams,pos) = case refereeAction of + DirectFreeKick _ pos = (True,pos) + ThrowIn _ pos = (True,pos) + Corner _ _ = (True,fromJust (getKickPos theField playingHalf refereeAction)) + GoalKick _ = (True,fromJust (getKickPos theField playingHalf refereeAction)) + Penalty _ = (True,fromJust (getKickPos theField playingHalf refereeAction)) + CenterKick _ = (True,fromJust (getKickPos theField playingHalf refereeAction)) + otherwise = (False,undef) + (isProgressEvent,gameProgress) = case refereeAction of + GameOver = (True,\m -> {Match | m & playingTime=zero}) + GameCancelled mt = (True,\m -> {Match | m & playingTime=zero,score=case mt of + Nothing = (0,0) + Just West = if (playingHalf==FirstHalf) (1,0) (0,1) + just_east = if (playingHalf==FirstHalf) (0,1) (1,0) + }) + AddTime t = (True,\m -> {Match | m & playingTime=m.Match.playingTime+t}) + EndHalf = (True,\m -> {Match | m & playingHalf=SecondHalf}) + Goal h = (True,\m=:{score=(w,e)} -> {Match | m & score=if (h==West && playingHalf==FirstHalf || h==East && playingHalf==SecondHalf) (w+1,e) (w,e+1)}) + otherwise = (False,undef) + (isDisplaceTeamsEvent,ds) = case refereeAction of + DisplacePlayers ds = (True, ds) + otherwise = (False,undef) + (isReprimandEvent,rep) = case refereeAction of + ReprimandPlayer p r = (True, (p,r)) + otherwise = (False,undef) + + displacePlayer :: !Displacements !Footballer -> Footballer + displacePlayer displacements fb = case lookup fb.playerID displacements of + Just pos = {fb & pos=pos} + nothing = fb + + reprimandPlayer :: !(!FootballerID,!Reprimand) !(![Footballer],![Footballer]) -> (![Footballer],![Footballer]) + reprimandPlayer (playerID,RedCard) (team1,team2) + = splitAt (nr_players_1 - if (playerID.clubName == club1) 1 0) (uneq1++uneq2) + where + club1 = nameOf team1 + (uneq1,_,uneq2) = break1 (identify_player playerID) (team1++team2) + nr_players_1 = length team1 + reprimandPlayer _ teams = teams + +/* playersThink match + lets every footballer player conjure an initiative. +*/ playersThink :: ![RefereeAction] !Match -> (!AssocList FootballerID FootballerAction,!Match) + playersThink refereeActions match=:{Match | theBall,team1,team2} + = (intendedActions,new_match) + where + actionsOfTeam1 = map (think refereeActions theBall team2) (singleOutElems team1) + actionsOfTeam2 = map (think refereeActions theBall team1) (singleOutElems team2) + new_match = {Match | match & team1 = map snd actionsOfTeam1,team2 = map snd actionsOfTeam2} + intendedActions = [(playerID,action) \\ (action,{playerID}) <- actionsOfTeam1 ++ actionsOfTeam2] + + think :: ![RefereeAction] !FootballState ![Footballer] !(!Footballer,![Footballer]) -> (!FootballerAction,!Footballer) + think refereeActions ballstate opponents (me=:{Footballer | brain=brain=:{ai,memory}},ownTeam) + # (action,memory) = ai ({referee=refereeActions,football=ballstate,others=ownTeam ++ opponents,me=me},memory) + # me = {Footballer | me & brain = {Brain | brain & memory=memory}} + = (action,me) + +/* successfulActions intendedActions match + removes all failing intended actions, and returns the list of remaining succeeding actions. + Players who are successfully tackled fail their action. + Players who are (still) lying on the ground fail their action. + At most one action of {GainBall, KickBall, HeadBall, CatchBall} succeeds. + If another player has successfully played the ball then his/her playerID is registered in Match. +*/ successfulActions :: !(AssocList FootballerID FootballerAction) !Match -> (!AssocList FootballerID FootballerAction,!Match) + successfulActions intendedActions match=:{seed,lastContact,nextRandomP,team1,team2,theBall} + # otherActions = filter (\(playerID,_) -> not (isMember playerID groundVictims)) intendedActions + # (tackleActions,otherActions) = spanfilter (isFootballerTackle o snd) intendedActions + # (okTackleActions,seed) = selectTackleActions tackleActions seed + # tackleVictims = [victim \\ (_,Tackle victim _) <- okTackleActions] + # otherActions = filter (\(playerID,action) -> not (isMember playerID tackleVictims)) otherActions + # (ballActions,otherActions) = spanfilter (isActionOnBall o snd) otherActions + # (okBallAction,seed) = selectBallAction ballActions seed + # (okActions,newContact) = case okBallAction of + Just (player,action) = ([(player,action):okTackleActions ++ otherActions],Just player) + nope = ( okTackleActions ++ otherActions ,lastContact) + = (okActions,{match & seed=seed, lastContact=newContact}) + where + all_players = team1 ++ team2 + ball = getFootball theBall all_players + groundVictims = [playerID \\ {playerID,effect=Just (OnTheGround frames)} <- all_players | frames >= 0] + + /* selectBallAction picks at most one action of {GainBall, KickBall, HeadBall, CatchBall} intentions. + The association list is assumed to contain only these actions. + */ selectBallAction :: !(AssocList FootballerID FootballerAction) !RandomSeed -> (!Maybe (FootballerID,FootballerAction),!RandomSeed) + selectBallAction intendedActions seed + # (ps,seed) = iterateStn (length intendedActions) nextRandomP seed + = selectMostProbableAction [ (successOfAction action (if (p==one) p (makeRandomRealistic p)),action) \\ action <- intendedActions & p <- ps ] seed + where + successOfAction :: !(!FootballerID,!FootballerAction) !P -> P + successOfAction (who,action) p = me.stamina * me.health * p * success_of_action + where + success_of_action = if (isGainBall action && ballGainable && ballAtGainSpeed) success_gaining + (if (isCatchBall action && ballCatchable && ballAtCatchSpeed) success_catching + (if (isKickBall action && ballKickable) success_kicking + (if (isHeadBall action && ballHeadable) success_heading + zero + ))) + me = find1 (identify_player who) all_players + mySkills = skillsAsList me + length = me.length + iGainWell = isMember Gaining mySkills + iKickWell = isMember Kicking mySkills + iHeadWell = isMember Heading mySkills + iCatchWell = isMember Catching mySkills + ballGainable = d_player_ball <= maxGainReach me && ball_height <= scale 0.8 length + scale (if iGainWell 0.2 0.0) length + ballKickable = d_player_ball <= maxKickReach me && ball_height <= scale 0.4 length + scale (if iKickWell 0.6 0.0) length + ballCatchable = d_player_ball <= maxCatchReach me && ball_height <= length + scale (if iCatchWell 1.0 0.5) length + ballHeadable = d_player_ball <= maxHeadReach me && ball_height <= length + scale (if iHeadWell 0.5 0.0) length && ball_height >= scale 0.8 length + ballAtGainSpeed = d_velocity <= maxGainVelocityDifference me d_player_ball + ballAtCatchSpeed = d_velocity <= maxCatchVelocityDifference me d_player_ball + d_speed = {zero & dxy = scale (toReal me.speed.velocity) (toRVector me.speed.direction)} + - + {dxy = scale (toReal ball.ballSpeed.vxy.velocity) (toRVector ball.ballSpeed.vxy.direction),dz = m (toReal ball.ballSpeed.vz)} + d_velocity = ms (toReal (size_vector3D d_speed)) + ball_height = ball.ballPos.pz + d_player_ball = dist me ball + others_with_ball = case theBall of + GainedBy playerID = if (playerID <> who) (filter (identify_player playerID) all_players) [] + free = [] + other_has_ball = not (isEmpty others_with_ball) + otherDribblesWell = isMember Dribbling (skillsAsList (hd others_with_ball)) + success_gaining = if (ballIsFree theBall) (if iGainWell 0.95 0.8) + (if other_has_ball (if iGainWell 0.75 0.3 * if otherDribblesWell 0.6 1.0) + 1.0) + success_kicking = if (ballIsFree theBall) (if iKickWell 0.95 0.85) + (if other_has_ball (if iKickWell 0.80 0.70 * if otherDribblesWell 0.7 1.0) + 1.0) + success_heading = if iHeadWell 0.95 0.90 + success_catching = if iCatchWell 1.00 0.95 + + /** selectTackleActions removes impossible tackle actions and, by chance, ignores some of the possible tackle actions. + */ selectTackleActions :: !(AssocList FootballerID FootballerAction) !RandomSeed -> (!AssocList FootballerID FootballerAction,!RandomSeed) + selectTackleActions performedActions seed + = filterSt isPossibleTackle [action \\ action <- performedActions | isFootballerTackle (snd action)] seed + where + isPossibleTackle :: !(!FootballerID,!FootballerAction) !RandomSeed -> (!Bool,!RandomSeed) + isPossibleTackle (playerID,Tackle victimID _) seed + | d_me_victim > maxTackleReach offender // victim is out of reach + = (False,seed) + # (p,seed) = nextRandomP seed + | otherwise = (avg [p,chanceOfSuccess] > 0.5,seed) // victim is within reach, but tackle may fail + where + offender = find1 (identify_player playerID) all_players + victim = find1 (identify_player victimID) all_players + d_me_victim = dist offender victim + chanceOfSuccess = avg [1.0 - toReal d_me_victim, if (isMember Tackling (skillsAsList offender)) 0.9 0.7] + +/* doFootballerActions intendedActions okActions match + performs for each football player in match his succeededAction. +*/ doFootballerActions :: !(AssocList FootballerID FootballerAction) !(AssocList FootballerID FootballerAction) !Match -> Match + doFootballerActions intendedActions okActions match=:{theField,theBall,team1,team2,seed,nextRandomP} + # (seed,ball,new_players1,new_players2) = foldl (flip doAction) (seed,theBall,team1,team2) intendedActions + = { match & team1 = new_players1, team2 = new_players2, theBall = ball, seed = seed } + where + dt = toReal match.Match.unittime // duration, in seconds, of one step + {fwidth,flength} = theField + + doAction :: !(!FootballerID,!FootballerAction) !(!RandomSeed,!FootballState,![Footballer],![Footballer]) + -> (!RandomSeed,!FootballState,![Footballer],![Footballer]) + doAction intendedAction (seed,ball,allPlayers1,allPlayers2) + | isMember intendedAction okActions = act intendedAction (seed,ball,allPlayers1,allPlayers2) + | otherwise = (seed,ball,map (failThisPlayerAction intendedAction) allPlayers1,map (failThisPlayerAction intendedAction) allPlayers2) + where + failThisPlayerAction :: !(!FootballerID,!FootballerAction) !Footballer -> Footballer + failThisPlayerAction (id,idea) fb=:{playerID,effect} + | id <> playerID = fb + | otherwise = {fb & effect = new_effect} + where + new_effect = case effect of + Just (OnTheGround nr_of_frames) = if (nr_of_frames < 0) Nothing (Just (OnTheGround (nr_of_frames-1))) + _ = Just (failFootballerAction idea) + + act :: !(!FootballerID,!FootballerAction) !(!RandomSeed,!FootballState,![Footballer],![Footballer]) + -> (!RandomSeed,!FootballState,![Footballer],![Footballer]) + + /** Rules for moving: + */ act (playerID,Move speed angle) (seed,ball,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed,ball,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + feasible_angle = scale (fromInt (sign angle)) (setbetween (abs angle) zero (maxRotateAngle fb)) + new_nose = fb.nose + feasible_angle + angleDifficulty = angleHowFarFromPi (speed.direction-new_nose) + angleDifference = angleHowFarFromAngle speed.direction new_nose + new_stamina = alter_stamina ball fb angleDifficulty angleDifference + new_vel = scale (1.4 * fb.health * new_stamina) (setbetween speed.velocity zero (maxVelocity (skillsAsList fb) angleDifficulty angleDifference)) + new_speed = {speed & velocity=new_vel} + new_position` = move_point (scale (dt * (toReal new_vel)) (toRVector new_speed.direction)) fb.pos + new_position = point_to_rectangle ({px=scale -0.5 flength, py=scale -0.5 fwidth},{px=scale 0.5 flength,py=scale 0.5 fwidth}) new_position` + new_fb = {fb & stamina = new_stamina + , speed = new_speed + , pos = new_position + , nose = new_nose + , effect = Just (Moved new_speed feasible_angle) + } + + /** Rules for gaining ball: + (1) ball obtains position and surface speed of obtaining player + */ act (playerID,GainBall) (seed,ball,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed,GainedBy playerID,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + new_fb = {fb & effect = Just (GainedBall Success)} + + /** Rules for kicking ball: + (1) kicking decreases stamina + (2) kicking is more effective towards your direction, and least effective in opposite direction + (3) being taller, you can kick harder + (4) a low stamina/health lower your max kickspeed + (5) todo: kicking a ball held/gained by a keeper, may damage the keeper + */ act (playerID,KickBall {vxy={velocity=v,direction=d},vz}) (seed,ball,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed1,Free new_ball,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + new_fb = {fb & stamina=new_stamina,effect=Just (KickedBall (Just new_speed))} + theBall = getFootball ball (team1 ++ team2) + skills = skillsAsList fb + max_v = maxVelocityBallKick fb + new_v = scale speed_factor (setbetween v zero max_v) + new_vz = scale speed_factor (setbetween vz zero max_v) + new_speed = {vxy={velocity=new_v,direction=new_d},vz=new_vz} + new_stamina = kickingPenalty fb new_v * fb.stamina + speed_factor = oppositeKickPenalty fb d + new_ball = {theBall & ballSpeed=new_speed} + (new_d,seed1) = new_ball_direction Kicking fb d seed + + /** Rules for heading ball: + (1) heading decreases stamina, but less than kicking + (2) kicking is more effective towards your direction, and least effective in opposite direction + (3) a low stamina/health lower your max headspeed, but less than kicking + (4) heading is less harder than kicking, but is not effected by your length + (5) todo: heading a ball held/gained by a keeper, may damage the keeper (less than with kicking) + */ act (playerID,HeadBall {vxy={velocity=v,direction=d},vz}) (seed,ballstate,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed1,Free new_ball,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + skills = skillsAsList fb + ball = getFootball ballstate (team1 ++ team2) + ball_speed = ball.ballSpeed.vxy.velocity + max_v = maxVelocityBallHead fb ball_speed + new_v = setbetween v zero max_v + new_vz = scale 0.25 (setbetween vz zero max_v) + new_speed = {vxy={velocity=new_v,direction=new_d},vz=new_vz} + new_stamina = headingPenalty fb new_v ball_speed * fb.stamina + new_fb = {fb & stamina=new_stamina,effect=Just (HeadedBall (Just new_speed))} + new_ball = {ball & ballSpeed=new_speed} + (new_d,seed1) = new_ball_direction Heading fb d seed + + /** Rules for feinting: + (1) you must have velocity in order to feint manouvre. + (2) a feint manouvre changes your position, and decreases your velocity (depends on Feinting skill) + */ act (playerID,Feint d) (seed,ball,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed,ball,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + new_stamina = (maxFatigueLossAtFeint fb) * fb.stamina + new_velocity = scale (fb.health * fb.stamina * (maxVelocityLossAtFeint fb)) fb.speed.velocity + new_speed = {fb.speed & velocity=new_velocity} + (leftv,rightv) = orthogonal fb.speed.direction + sidestep = case d of FeintLeft -> leftv; _ -> rightv + new_position` = move_point ((scale (toReal (maxFeintStep fb)) (toRVector sidestep)) + + + (scale (dt * toReal new_velocity) (toRVector fb.speed.direction)) + ) fb.pos + new_position = point_to_rectangle ({px=scale -0.5 flength,py=scale -0.5 fwidth},{px=scale 0.5 flength,py=scale 0.5 fwidth}) new_position` + new_fb = {fb & pos=new_position,speed=new_speed,stamina=new_stamina,effect=Just (Feinted d)} + + /** Rules for Tackling + (1) tackling may lower the health of the victim but increases his stamina (last is because he lies on the ground the next rounds) + (2) tackling costs stamina + */ act (playerID,Tackle victimID ve) (seed,ball,team1,team2) + = (seed1,new_ball,team1T,team2T) + where + nrPlayersTeam1 = length team1 + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + (team1N,team2N) = splitAt nrPlayersTeam1 (unbreak1 (uneq1,new_fb,uneq2)) + (uneq1T,fbT,uneq2T) = break1 (identify_player victimID) (team1N ++ team2N) + (team1T,team2T) = splitAt nrPlayersTeam1 (unbreak1 (uneq1T,new_target,uneq2T)) + new_stamina_self = maxFatigueLossAtTackle fb * fb.stamina + new_fb = {fb & stamina = new_stamina_self, effect = Just (Tackled victimID ve Success)} + target_has_ball = ballIsGainedBy victimID ball + (p,seed1) = nextRandomP seed + new_v` = min max_tackle_velocity ve + max_tackle_velocity = ms 10.0 + max_ground_time = s 30.0 + ground_frames = toInt ((((toReal new_v`) / (toReal max_tackle_velocity)) * (toReal max_ground_time)) / dt) + new_v = scale 0.1 new_v` + healthDamageTarget = (toReal new_v) * fb.health * fb.stamina * (0.5*p + 0.1) + (toReal (fbT.length-min_length))/2.0 + new_health_target = max zero (fbT.health - healthDamageTarget) + new_target = {fbT & health = new_health_target, effect = Just (OnTheGround ground_frames) } + new_ball = if target_has_ball (Free (mkFootball fbT.pos fbT.speed)) ball + + /** Rules for catching + (1) ball optains speed and distance of player + */ act (playerID,CatchBall) (seed,ball,team1,team2) + # (team1,team2) = splitAt (length team1) (unbreak1 (uneq1,new_fb,uneq2)) + = (seed,GainedBy playerID,team1,team2) + where + (uneq1,fb,uneq2) = break1 (identify_player playerID) (team1 ++ team2) + new_fb = {fb & effect=Just (CaughtBall Success)} + + new_ball_direction :: !Skill !Footballer !Angle !RandomSeed -> (!Angle,!RandomSeed) + new_ball_direction skill fb d seed + # (p1,seed) = nextRandomP seed + # (p2,seed) = nextRandomP seed + | p2 == one = (d,seed) + # failure = one - if (isMember skill (skillsAsList fb)) makeRandomRealisticSkilled makeRandomRealistic p2 + # diff = scale failure (maxHeadingDeviation fb) + | p1 <= 0.5 = (d - diff, seed) + | otherwise = (d + diff, seed) + +/** moveFootball match + makes the free ball move (a gained ball moves along with its player). +*/ moveFootball :: !Match -> Match + moveFootball match=:{Match | theBall=Free football=:{ballSpeed={vxy={velocity=v,direction=d},vz},ballPos},theField,team1,team2,seed,lastContact,unittime} + = { match & theBall = Free {football & ballSpeed=new_speed,ballPos=new_ballpos}, seed = seed1, lastContact = if (isJust hit_player) hit_player lastContact } + where + old_height = ballPos.pz + in_the_air = old_height > zero + resistance = if in_the_air air_resistance surface_resistance + dt = toReal unittime + surface_movement = scale (dt * (toReal v)) (toRVector d) + new_speed2D = let new_v = scale resistance v in {direction = d, velocity = if (new_v <= ms 0.05) zero new_v} + new_vz` = if in_the_air (vz - scale dt accelleration_sec) zero + new_height` = ballPos.pz + m (toReal vz) + (new_height,new_vz) = if (in_the_air && new_height` <= zero) // the ball bounces on the field + (scale 0.5 (abs new_height`),let new_vz`` = scale 0.33 (abs new_vz`) in if (new_vz`` <= ms 0.8) zero new_vz``) + (new_height`, new_vz`) + new_speed` = {vxy=new_speed2D, vz=new_vz} + new_ballpos = {pxy=move_point surface_movement ballPos.pxy,pz=new_height} + all_players = team1 ++ team2 + (hit_player,new_speed,seed1) = ballBounces new_ballpos new_speed` seed + + // the direction of the ball changes after a bounce and its velocity may reduce in case of bouncing against a player + ballBounces :: !Position3D !Speed3D !RandomSeed -> (!Maybe FootballerID,!Speed3D,!RandomSeed) + ballBounces new_ballpos new_speed=:{vxy={velocity=v,direction=d},vz=s3d} seed + | hit_west_goal = (Nothing,{new_speed & vxy = {new_speed.vxy & direction = if (d <= rad pi) (d - rad (0.5*pi)) (d + rad (0.5*pi)), velocity = v}},seed) + | hit_east_goal = (Nothing,{new_speed & vxy = {new_speed.vxy & direction = if (d <= rad pi) (d + rad (0.5*pi)) (d - rad (0.5*pi)), velocity = v}},seed) + | isEmpty hit_players = (Nothing, new_speed, seed) + # (p1,seed) = nextRandomP seed + # (p2,seed) = nextRandomP seed + # (p3,seed) = nextRandomP seed + | otherwise = (Just (hd hit_players),{vxy = {direction = rad (p2*2.0*pi), velocity = scale p3 v}, vz=scale p1 s3d},seed) + where + half_length = scale 0.5 theField.flength + goal_pole_r = scale 0.5 goal_pole_width + (northPole,southPole) = goal_poles theField + hit_west_goal = againstGoalWestNorthPole || againstGoalWestSouthPole || againstGoalWestPoleUpper + hit_east_goal = againstGoalEastNorthPole || againstGoalEastSouthPole || againstGoalEastPoleUpper + hit_players = [playerID \\ fb=:{length,playerID} <- all_players | inRadiusOfFootballer new_ballpos.pxy fb && length >= new_ballpos.pz] + againstGoalWestNorthPole = inCircleRadiusOfPosition new_ballpos goal_pole_r goal_height {px = ~half_length, py = northPole + goal_pole_r} + againstGoalWestSouthPole = inCircleRadiusOfPosition new_ballpos goal_pole_r goal_height {px = ~half_length, py = southPole - goal_pole_r} + againstGoalEastNorthPole = inCircleRadiusOfPosition new_ballpos goal_pole_r goal_height {px = half_length, py = northPole + goal_pole_r} + againstGoalEastSouthPole = inCircleRadiusOfPosition new_ballpos goal_pole_r goal_height {px = half_length, py = southPole - goal_pole_r} + againstGoalWestPoleUpper = (isbetween new_ballpos.pxy.py (southPole - goal_pole_r) (northPole + goal_pole_r)) + && + (isbetween new_ballpos.pz goal_height (goal_height+goal_pole_width)) + && + (new_ballpos.pxy.px <= ~half_length) + againstGoalEastPoleUpper = (isbetween new_ballpos.pxy.py (southPole - goal_pole_r) (northPole + goal_pole_r)) + && + (isbetween new_ballpos.pz goal_height (goal_height+goal_pole_width)) + && + (new_ballpos.pxy.px >= half_length) + inCircleRadiusOfPosition {pxy,pz} r zr pos + = dist pxy pos <= r && pz <= zr + + moveFootball match + = match + +/** advanceTime match + decreases the time to play with unittime. +*/ advanceTime :: !Match -> Match + advanceTime match=:{Match | playingTime, unittime} + = {Match | match & playingTime = max zero (playingTime - minutes unittime)} + +/* Attribute altering functions depending on angles: + params: + Angle :: between zero and pi, how much the player is running backwards (pi is backwards). + Angle :: between zero and pi, the difference between the desired angle and the angle the player previously ran to. +*/ +alter_stamina :: !FootballState !Footballer !Angle !Angle -> Stamina +alter_stamina ballState fb angleDifficulty angleDifference +| velocity <= rfv // increase stamina + | stamina < MinimumFatigue = MinimumFatigue + | otherwise = stamina^0.8 +| otherwise = fatigue * factor +where + velocity = fb.speed.velocity + length = fb.length + stamina = fb.stamina + rfv = restore_stamina_velocity (ballIsGainedBy fb.playerID ballState) (skillsAsList fb) angleDifficulty angleDifference + diff = velocity - rfv + fv = if (diff >= ms 6.0) (stamina^(stamina^(1.6 + 0.02 * toReal length))) + (if (diff >= ms 4.0) (stamina^( 1.5 + 0.01 * toReal length)) + (if (diff >= ms 2.0) (stamina^( 1.4 - 0.01 * toReal length)) + (stamina^( 1.3 - 0.02 * toReal length)))) + factor = one - (toReal angleDifficulty)/(4.0*pi) + fatigue = if (stamina > MaximumFatigue) MaximumFatigue fv + +restore_stamina_velocity :: !Bool ![Skill] !Angle !Angle -> Velocity +restore_stamina_velocity gained_ball skills angleDifficulty angleDifference +| gained_ball = scale ( one / if (isMember Running skills) 1.6 2.6) max_v +| isMember Running skills = scale ((one / if (isMember Dribbling skills) 2.0 3.0) * 1.22) max_v +| otherwise = scale ( one / if (isMember Dribbling skills) 2.0 3.0) max_v +where + max_v = maxVelocity skills angleDifficulty angleDifference + +maxVelocity :: ![Skill] !Angle !Angle -> Velocity +maxVelocity skills angleDifficulty angleDifference + = scale (dribblingPenalty * runningPenalty) base_velocity +where + base_velocity = ms 10.0 + dribblingPenalty = if (isMember Dribbling skills) 0.95 0.85 + runningPenalty = if (isMember Running skills) 1.0 0.85 + +MinimumFatigue :== 0.05 +MaximumFatigue :== 0.985 + + +/** The functions below defines the penalty factor: values between 0.0 and 1.0 that define the loss of an attribute of an action. +*/ +:: PenaltyFactor :== Real // a value between 0.0 and 1.0 + +kickingPenalty :: !Footballer !Velocity -> PenaltyFactor +kickingPenalty fb new_v = 1.0 - (if (isMember Kicking (skillsAsList fb)) 0.3 0.6) * ((toReal new_v)/(toReal max_v))^2.0 +where + max_v = maxVelocityBallKick fb + +headingPenalty :: !Footballer !Velocity !Velocity -> PenaltyFactor +headingPenalty fb new_v ball_v = 1.0 - (if (isMember Heading (skillsAsList fb)) 0.08 0.13) * ((toReal new_v)/(toReal max_v))^2.0 +where + max_v = maxVelocityBallHead fb ball_v + +maxFatigueLossAtTackle :: !Footballer -> PenaltyFactor +maxFatigueLossAtTackle fb = if (isMember Tackling (skillsAsList fb)) 0.99 0.9 + +maxFatigueLossAtFeint :: !Footballer -> PenaltyFactor +maxFatigueLossAtFeint fb = if (isMember Feinting (skillsAsList fb)) 0.92 0.77 + +maxVelocityLossAtFeint :: !Footballer -> PenaltyFactor +maxVelocityLossAtFeint fb = if (isMember Feinting (skillsAsList fb)) 0.99 0.75 + +oppositeKickPenalty :: !Footballer !Angle -> PenaltyFactor +oppositeKickPenalty fb kick_to = 1.0 - toReal (scale (skillPenaltyFactor/pi) (angleHowFarFromPi angle)) +where + angle = abs (fb.nose - kick_to) + skills = skillsAsList fb + skillPenaltyFactor = if (isAllMember [Rotating,Kicking] skills) 0.3 + (if (isAnyMember [Rotating,Kicking] skills) 0.5 + 0.9) + +angleHowFarFromPi :: !Angle -> Angle +angleHowFarFromPi a +| a` > rad pi = rad (2.0*pi) - a` +| otherwise = a` +where + a` = abs a + +angleHowFarFromAngle :: !Angle !Angle -> Angle +angleHowFarFromAngle a b +| a` > b` + | a` - b` > rad pi = b` - a` + rad (2.0*pi) + | otherwise = a` - b` +| otherwise + | b` - a` > rad pi = a` - b` + rad (2.0*pi) + | otherwise = b` - a` +where + a` = abs a + b` = abs b diff --git a/src/Game/matchGame.dcl b/src/Game/matchGame.dcl new file mode 100644 index 0000000..6660874 --- /dev/null +++ b/src/Game/matchGame.dcl @@ -0,0 +1,108 @@ +definition module matchGame + +/** This module defines the match and tournament data structures. +*/ +import matchLog, guiInterface, render + +:: FootballGame + = { match :: !Match // the football match to be played + , actionPics :: !ActionPics // the action-images + , history :: !History // recent history of game + , frames :: !Int // nr of frames so far (reset to zero every second) + , options :: !Options // options of football game + , logging :: !WhatToLog // logging options + } + +:: Options + = { closeReferee :: !Bool // automatically close referee dialog after one second (True - default) or by user (False) + , showSplash :: !Bool // show splash screen at opening (False - default) or do (True) + , displaySpeed :: !DisplaySpeed // slow, normal or fast-play (Normal - default) + , showReferee :: !Bool // show referee-intermezzo (True - default) or not (False) + , playingTime :: !PlayingTime // default playingtime (defaultPlayingTime) + , renderStyle :: !RenderStyle // the chosen render style (flatland style is default) + } +instance toString Options +instance fromString Options +instance == Options + +:: History + = { time :: !Seconds // time in seconds of length history + , past :: ![Match] // the recent history + } + +/** incFrames game increases the frames count of game. +*/ +incFrames :: !FootballGame -> FootballGame + +/* defaultPlayingTime returns recommended playing time +*/ +defaultPlayingTime :: PlayingTime + +/** defaultOptions returns default options. +*/ +defaultOptions :: Options + +/* timeLeft is True if the game has not finished +*/ +timeLeft :: !FootballGame -> Bool + +/** getOptions env reads the options file (if present) and returns its content. + If no options file was found, it is created and filled with default values. + setOptions options stores the options in the options file. +*/ +getOptions :: !*env -> (!Options,!*env) | FileSystem env +setOptions :: !Options !*env -> *env | FileSystem env + +:: Competition = { results :: ![[Maybe Score]] // teams x teams matrix of match results (note: team x team -> Nothing) + , west :: ![ClubName] // names of participating teams (west side) + , east :: ![ClubName] // names of participating teams (east side) + , usedRandomSeed:: !RandomSeed // the seed that is used for computing the matches + } +:: Ranking :== AssocList ClubName Rank +:: Rank = { matchpoints :: !Int // number of matchpoints (>= 0) + , goals_scored :: !Int // number of scored goals (>= 0) + , goals_against :: !Int // number of goals against (>= 0) + } +instance zero Rank +instance == Rank +instance < Rank +instance + Rank + +/** competition teams field referee time rs + computes an entire competition between all teams in teams. + Each match uses the same referee and same initial random seed value rs. +*/ +competition :: ![Home FootballField -> Team] !FootballField !Referee !PlayingTime !RandomSeed -> Competition + +/** computeMatch match + computes an entire match between the currently selected team1 and team2. +*/ +computeMatch :: !Match -> Score + +/** ranking competition + computes the ranking of all teams that have participated in competition. +*/ +//ranking :: !Competition -> Ranking +ranking :: ![ClubName] ![Maybe Score] -> Ranking + +/** checkCompetitionFile west_team_names rs env + checks whether there is a competition backup file present for the current set + of teams (assuming they start on the West home side) and initial random seed value rs + for computing matches. + If not, then such a file is created, and the same random seed value and empty list of scores is returned. + If so, then the currently stored random seed value and list of scores is returned. +*/ +checkCompetitionFile :: ![ClubName] !RandomSeed !*env -> (!(!RandomSeed,![Maybe Score]),!*env) | FileSystem env + +/** appendMatchToCompetitionFile west east env + appends an empty entry of a match between west versus east in the competition backup file. + It also returns the file pointer to allow a correct update in updateMatchToCompetitionFile. +*/ +appendMatchToCompetitionFile:: !ClubName !ClubName !*env -> (!Int,!*env) | FileSystem env + + +/** updateMatchToCompetitionFile west east score filepointer env + updates the line that starts at filepointer in the competition backup file with the result + of the match between west versus east. +*/ +updateMatchToCompetitionFile:: !ClubName !ClubName !(Maybe Score) !Int !*env -> *env | FileSystem env diff --git a/src/Game/matchGame.icl b/src/Game/matchGame.icl new file mode 100644 index 0000000..ae6b0c1 --- /dev/null +++ b/src/Game/matchGame.icl @@ -0,0 +1,214 @@ +implementation module matchGame + +import StdEnvExt, fileIO +import guiInterface, matchControl, render +from Parsers import parse, :: Parser, :: Result(..), :: SugPosition, :: Rose(..), :: RoseNode(..), :: SymbolTypes(..), + :: SymbolType(..), + fail, yield, token, symbol, <&>, &>, , , , number, digit + +timeLeft :: !FootballGame -> Bool +timeLeft game = game.match.Match.playingTime > zero + +defaultPlayingTime :: PlayingTime +defaultPlayingTime = minutes 1.0 + +incFrames :: !FootballGame -> FootballGame +incFrames game=:{frames} = {game & frames=frames+1} + + +instance zero Rank where + zero = { matchpoints = zero, goals_scored = zero, goals_against = zero } +instance == Rank where + (==) r1 r2 = (r1.matchpoints,r1.goals_scored,r1.goals_against) == (r2.matchpoints,r2.goals_scored,r2.goals_against) +instance < Rank where + (<) r1 r2 = r1.matchpoints < r2.matchpoints || + r1.matchpoints == r2.matchpoints && r1.goals_scored < r2.goals_scored || + r1.matchpoints == r2.matchpoints && r1.goals_scored == r2.goals_scored && r1.goals_against > r2.goals_against +instance + Rank where + (+) r1 r2 = { matchpoints = r1.matchpoints + r2.matchpoints + , goals_scored = r1.goals_scored + r2.goals_scored + , goals_against = r1.goals_against + r2.goals_against + } + +competition :: ![Home FootballField -> Team] !FootballField !Referee !PlayingTime !RandomSeed -> Competition +competition teams field referee playingtime rs + = { results = [ [ if (nr_west == nr_east) + Nothing + (Just (computeMatch (setMatchStart (team_west West field) (team_east East field) field referee playingtime rs))) + \\ (nr_east,team_east) <- zip2 [1..] teams + ] + \\ (nr_west,team_west) <- zip2 [1..] teams + ] + , west = map (\f -> nameOf (f West field)) teams + , east = map (\f -> nameOf (f East field)) teams + , usedRandomSeed = rs + } + +computeMatch :: !Match -> Score +computeMatch match +| match.Match.playingTime > zero + = computeMatch (snd (stepMatch match)) +| otherwise = match.score + +ranking :: ![ClubName] ![Maybe Score] -> Ranking +ranking names scores = foldl upd [(t,zero) \\ t <- names] (zip2 [(tw,te) \\ tw <- names, te <- names] scores) +where + upd ranking (_,Nothing) + = ranking + upd ranking ((west,east),Just (goals_west,goals_east)) + = updkeyvalue west ((+) rank_west) (updkeyvalue east ((+) rank_east) ranking) + where + (mps_west, mps_east) = if (goals_west > goals_east) (3,0) (if (goals_west < goals_east) (0,3) (1,1)) + (rank_west,rank_east) = ({matchpoints=mps_west,goals_scored=goals_west,goals_against=goals_east} + ,{matchpoints=mps_east,goals_scored=goals_east,goals_against=goals_west} + ) + +instance toString Options where + toString {closeReferee,showSplash,displaySpeed,showReferee,playingTime,renderStyle} + = "{closeReferee=" <+++ closeReferee <+++ + ",showSplash=" <+++ showSplash <+++ + ",displaySpeed=" <+++ displaySpeed <+++ + ",showReferee=" <+++ showReferee <+++ + ",playingTime=" <+++ playingTime <+++ + ",renderStyle=" <+++ nameOf renderStyle <+++ + "}" +instance fromString Options where + fromString str + = case parse optionsP (fromString str) optionsFile "char" of + Succ [opt:_] = opt + _ = defaultOptions + where + optionsP :: Parser Char Options Options + optionsP = token ['{closeReferee='] &> + boolP <&> \closeReferee -> + token [',showSplash='] &> + boolP <&> \showSplash -> + token [',displaySpeed='] &> + displaySpeedP <&> \displaySpeed -> + token [',showReferee='] &> + boolP <&> \showReferee -> + token [',playingTime='] &> + timeP <&> \playingTime -> + token [',renderStyle='] &> + renderP <&> \renderStyle -> + symbol '}' &> + yield { closeReferee = closeReferee + , showSplash = showSplash + , displaySpeed = displaySpeed + , showReferee = showReferee + , playingTime = playingTime + , renderStyle = renderStyle + } + boolP = (token ['True'] &> yield True) (token ['False'] &> yield False) + renderP = firstP [token (fromString (nameOf style)) &> yield style \\ style <- allRenderStyles] yield (hd allRenderStyles) + firstP [] = fail + firstP [p:ps] = p firstP ps + timeP = digit <&> \mts -> + (symbol ':') <&> \colon -> + digit <&> \secs -> + (token [' min']) <&> \_ -> + yield (minutes ((toReal (toInt (toString mts))) + (toReal (toInt (toString secs)))/60.0)) + displaySpeedP = (token ['Slowest'] &> yield Slowest) + (token ['Slower'] &> yield Slower) + (token ['Normal'] &> yield Normal) + (token ['Faster'] &> yield Faster) + (token ['Fastest'] &> yield Fastest) + +instance == Options where + (==) o1 o2 = o1.closeReferee == o2.closeReferee && + o1.showSplash == o2.showSplash && + o1.displaySpeed == o2.displaySpeed && + o1.showReferee == o2.showReferee && + o1.Options.playingTime == o2.Options.playingTime && + o1.renderStyle.RenderStyle.name == o2.renderStyle.RenderStyle.name + +getOptions :: !*env -> (!Options,!*env) | FileSystem env +getOptions env + = case readFile optionsFile env of + (Just options,env) = (fromString options,env) + (nothing, env) = (defaultOptions, env) + +setOptions :: !Options !*env -> *env | FileSystem env +setOptions options env = writeFile False optionsFile (toString options) env + +optionsFile :== "SoccerFun_options.txt" + +defaultOptions :: Options +defaultOptions + = { closeReferee = True + , showSplash = False + , displaySpeed = Normal + , showReferee = True + , playingTime = defaultPlayingTime + , renderStyle = hd allRenderStyles + } + +checkCompetitionFile :: ![ClubName] !RandomSeed !*env -> (!(!RandomSeed,![Maybe Score]),!*env) | FileSystem env +checkCompetitionFile west rs env +# (ok,cf,env) = fopen competitionFile FReadText env +| not ok = ((rs,[]), createCompetitionFile west rs env) // competition file does not exist: create it +# (ok,frs,fwest,cf) = header cf +| not ok || fwest <> teams_line west + = ((rs,[]), createCompetitionFile west rs (snd (fclose cf env))) // competition file ill-formatted or different set of teams: create it +# (scores,cf) = readScores cf // competition file exists, and for this competition +# (ok,env) = fclose cf env +| not ok = abort ("Could not close competition file after reading scores.\n" <+++ length scores) +| otherwise = ((frs,scores),env) +where + readScores :: !*File -> (![Maybe Score],!*File) + readScores cf + # (end,cf) = fend cf + | end = ([],cf) + # (line,cf) = freadline cf + # score = if (line.[0] == 'x') Nothing + (let (i1,l1) = span ((<>) ' ') [c \\ c<-:line] + (i2,l2) = span ((<>) ' ') (tl l1) + in Just (toInt (toString i1),toInt (toString i2)) + ) + # (scores,cf) = readScores cf + = ([score:scores],cf) + +appendMatchToCompetitionFile:: !ClubName !ClubName !*env -> (!Int,!*env) | FileSystem env +appendMatchToCompetitionFile west east env +# (ok,cf,env) = fopen competitionFile FAppendText env +| not ok = abort "Could not open competition file for appending data.\n" +# (pos,cf) = fposition cf +# (ok,env) = fclose (cf <<< "x " <<< west <<< " vs " <<< east <<< '\n') env +| not ok = abort "Could not close competition file after appending data.\n" +| otherwise = (pos,env) + +updateMatchToCompetitionFile:: !ClubName !ClubName !(Maybe Score) !Int !*env -> *env | FileSystem env +updateMatchToCompetitionFile west east score pos env +# (ok,cf,env) = fopen competitionFile FAppendText env +| not ok = abort "Could not open competition file for appending data.\n" +# (ok,cf) = fseek cf pos FSeekSet +| not ok = abort "Could not seek in competition file for updating data.\n" +# (ok,env) = fclose (cf <<< result <<< ' ' <<< west <<< " vs " <<< east <<< '\n') env +| not ok = abort "Could not close competition file after appending data.\n" +| otherwise = env +where + result = case score of + Nothing = "x" + Just (gw,ge) = gw +++> (" " <+++ ge) + +createCompetitionFile :: ![ClubName] !RandomSeed !*env -> *env | FileSystem env +createCompetitionFile west rs env +# (ok,cf,env) = fopen competitionFile FWriteText env +| not ok = abort "Could not create competition file.\n" +# (ok,env) = fclose (cf <<< seed_line rs <<< '\n' <<< teams_line west <<< '\n') env +| not ok = abort "Could not close competition file.\n" +| otherwise = env + +header :: !*File -> (!Bool,!RandomSeed,!String,!*File) +header file +# (rs_line, file) = freadline file +# (teams_line,file) = freadline file += (size rs_line > 1 && size teams_line > 1, fromString (rs_line%(0,size rs_line-2)), teams_line%(0,size teams_line-2),file) + +seed_line :: !RandomSeed -> String +seed_line rs = toString rs + +teams_line :: ![ClubName] -> String +teams_line west = foldl (\t ts -> t +++ "," +++ ts) "" west + +competitionFile :== "competition.txt" diff --git a/src/Game/matchLog.dcl b/src/Game/matchLog.dcl new file mode 100644 index 0000000..1b179bc --- /dev/null +++ b/src/Game/matchLog.dcl @@ -0,0 +1,23 @@ +definition module matchLog + +/** This module defines the logging facilities of Soccer-Fun. +*/ +import matchControl + +/** Logging a match. +*/ +:: WhatToLog = { footballerActions :: !Bool + , fbPositions :: !Bool + , refEvents :: !Bool + , ballPosition :: !Bool + } +instance toString WhatToLog + +getWhatToLog :: !*env -> (!WhatToLog,!*env) | FileSystem env + +logFile :: String + +/* logMatch options match refereeActions succeededActions env + writes the indicated log fields to logFile. +*/ +logMatch :: !WhatToLog !Match ![RefereeAction] !(AssocList FootballerID FootballerAction) !*env -> *env | FileSystem env diff --git a/src/Game/matchLog.icl b/src/Game/matchLog.icl new file mode 100644 index 0000000..744f25b --- /dev/null +++ b/src/Game/matchLog.icl @@ -0,0 +1,125 @@ +implementation module matchLog + +import StdEnvExt, fileIO +import matchControl + +logFile :: String +logFile = "SoccerFun.log" + +getWhatToLog :: !*env -> (!WhatToLog,!*env) | FileSystem env +getWhatToLog env + = case readFile fileStr env of + (Just line,env) = (fromString line,env) + (nothing, env) = (defaultLogging, env) +where + fileStr = "logMatch.conf" + +instance toString WhatToLog where + toString l = "{footballerActions=" <+++ l.footballerActions +++ + ",fbPositions=" <+++ l.fbPositions +++ + ",refEvents=" <+++ l.refEvents +++ + ",ballPosition=" <+++ l.ballPosition +++ + "}" +instance fromString WhatToLog where + fromString str + # (okActions, actions, str) = isBool (literal "{footballerActions=" str) + # (okPositions,positions,str) = isBool (literal ",fbPositions=" str) + # (okRefEvents,events, str) = isBool (literal ",refEvents=" str) + # (okPositions,pos, str) = isBool (literal ",ballPosition=" str) + | okActions && okPositions && okRefEvents && okPositions && str=="}" + = { footballerActions = actions + , fbPositions = positions + , refEvents = events + , ballPosition = pos + } + | otherwise + = defaultLogging + where + literal literal str + | stringStarts str literal = str%(size literal,size str-1) + | otherwise = str + isBool str + | stringStarts str "True" = (True,True, str%(4,size str-1)) + | stringStarts str "False" = (True,False,str%(5,size str-1)) + | otherwise = (False,undef,str) + +defaultLogging = { footballerActions = False + , fbPositions = False + , refEvents = False + , ballPosition = False + } + + +/* logMatch logging match refereeActions succeededActions env + writes the log fields indicated in logging from the match and actions to disk. +*/ +logMatch :: !WhatToLog !Match ![RefereeAction] !(AssocList FootballerID FootballerAction) !*env -> *env | FileSystem env +logMatch logging match_to_log=:{Match | team1,team2,playingTime,theBall} refereeActions succeededActions env + | logging.footballerActions || logging.fbPositions || logging.refEvents || logging.ballPosition + # env = writeFile True logFile ("BEGIN STEP "<+++playingTime<+++"\n") env + # env = if (logging.footballerActions) (writeFile True logFile (logActions allPlayers succeededActions) env) env + # env = if (logging.fbPositions) (writeFile True logFile (logPositions allPlayers) env) env + # env = if (logging.refEvents) (writeFile True logFile (logRefereeActions refereeActions) env) env + # env = if (logging.ballPosition) (writeFile True logFile ("BallPos: " <+++ ball.ballPos +++ "\n") env) env + # env = writeFile True logFile ("END STEP " <+++ playingTime <+++ "\n") env + = env + | otherwise + = env +where + allPlayers = team1 ++ team2 + ball = getFootball theBall allPlayers + + logActions :: ![Footballer] !(AssocList FootballerID FootballerAction) -> String + logActions _ [] = "" + logActions allPlayers [(playerID=:{clubName,playerNr},action) : mfals] + = "FootballerWithAction\n\tTeam: " <+++ + clubName <+++ + "\n\tNumber: " <+++ + playerNr <+++ + "\n\tName: " <+++ + nameOf self <+++ + "\n\tAction: " <+++ + improveString (toString action) <+++ + "\n" <+++ logActions allPlayers mfals + where + self = find1 (identify_player playerID) allPlayers + + improveString = (replaceInString "}\"" "}") o (replaceInString "\"{" "{") o (replaceInString "\\\"" "\"") + + logPositions :: ![Footballer] -> String + logPositions fbs = "POSITIONS:\n" <+++ foldl printFootballer "" fbs + where + printFootballer str {playerID={clubName,playerNr},name,pos} + = str <+++ "\t(" <+++ clubName <+++ ",(" <+++ playerNr <+++"," <+++ name <+++")):\t" <+++ pos <+++ "\n" + + logRefereeActions :: ![RefereeAction] -> String + logRefereeActions [] = "" + logRefereeActions refls = "REFEREE_ACTIONS:" <+++ logRefereeActions` refls <+++ "\n" + where + logRefereeActions` :: ![RefereeAction] -> String + logRefereeActions` [] = "" + logRefereeActions` [ref:refls] = "\n\t" <+++ logRefereeAction ref <+++ logRefereeActions` refls + + logRefereeAction :: !RefereeAction -> String + logRefereeAction (ReprimandPlayer tfp r) = "(ReprimandPlayer " <+++ tfp.playerNr <+++ " " <+++ r <+++ ")" + logRefereeAction (Hands tfp) = "(Hands " <+++ tfp.playerNr <+++ ")" + logRefereeAction (TackleDetected tfp) = "(TackleDetected " <+++ tfp.playerNr <+++ ")" + logRefereeAction (DangerousPlay tfp) = "(DangerousPlay " <+++ tfp.playerNr <+++ ")" + logRefereeAction GameOver = "GameOver" + logRefereeAction (GameCancelled mt) = "(GameCancelled " <+++ mt <+++ ")" + logRefereeAction PauseGame = "PauseGame" + logRefereeAction (AddTime t) = "(AddTime " <+++ t <+++ ")" + logRefereeAction EndHalf = "EndHalf" + logRefereeAction (Goal t) = "(Goal " <+++ t <+++ ")" + logRefereeAction (Offside tfp) = "(Offside " <+++ tfp.playerNr <+++ ")" + logRefereeAction (DirectFreeKick t p) = "(DirectFreeKick " <+++ t <+++ " " <+++ p <+++ ")" + logRefereeAction (GoalKick t) = "(GoalKick " <+++ t <+++ ")" + logRefereeAction (Corner t e) = "(Corner " <+++ t <+++ " " <+++ e <+++ ")" + logRefereeAction (ThrowIn t p) = "(ThrowIn " <+++ t <+++ " " <+++ p <+++ ")" + logRefereeAction (Penalty t) = "(Penalty " <+++ t <+++ ")" + logRefereeAction (CenterKick t) = "(CenterKick " <+++ t <+++ ")" + logRefereeAction (Advantage t) = "(Advantage " <+++ t <+++ ")" + logRefereeAction (OwnBallIllegally tfp) = "(OwnBallIllegally" <+++ tfp.playerNr <+++ ")" + logRefereeAction (DisplacePlayers ds) = "DisplacePlayers" + logRefereeAction ContinueGame = "ContinueGame" + logRefereeAction (TellMessage txt) = "(TellMessage " <+++ txt <+++ ")" diff --git a/src/Game/randomstream.dcl b/src/Game/randomstream.dcl new file mode 100644 index 0000000..55c6a05 --- /dev/null +++ b/src/Game/randomstream.dcl @@ -0,0 +1,49 @@ +definition module randomstream + +/** This module implements a number of infinite random streams. + For predictable games, the onesStream can be used. +*/ +import StdClass +import StdMaybe +import RandomExt + +:: Stream a :== [a] // an infinite list of random values +:: P :== Real // 0<=x<=1.0 + +/** intRandomStream + creates a stream of random (positive and negative) Integer values. + realRandomStream + creates a stream of random (positive and negative) Real values. + boolRandomStream + creates a stream of random Bool values. + probabilityRandomStream + creates a stream of random P values. + onesStream + creates a stream of one values. +*/ +intRandomStream :: !RandomSeed -> Stream Int +realRandomStream :: !RandomSeed -> Stream Real +boolRandomStream :: !RandomSeed -> Stream Bool +probabilityRandomStream :: !RandomSeed -> Stream P +onesStream :: Stream P + +/** nextRandom creates a next pseudo random value of given type. +*/ +nextRandomInt :: !RandomSeed -> .(!Int, !RandomSeed) +nextRandomReal :: !RandomSeed -> .(!Real,!RandomSeed) +nextRandomBool :: !RandomSeed -> .(!Bool,!RandomSeed) +nextRandomP :: !RandomSeed -> .(!P, !RandomSeed) +next1 :: !RandomSeed -> .(!P, !RandomSeed) + +/** make the random realistic, as in, small errors occur more often: + \r -> 1.0-r^4 (zero <= r <= 1.0) +*/ +makeRandomRealistic :: !P -> P +// \r -> 1-r^10 +makeRandomRealisticSkilled :: !P -> P + +/** selectMostProbableAction randomly selects one of the elements of the list that have the same + highest probability. + If all probabilities are equal to zero, then Nothing is returned. +*/ +selectMostProbableAction :: ![(P,a)] !RandomSeed -> (!Maybe a,!RandomSeed) diff --git a/src/Game/randomstream.icl b/src/Game/randomstream.icl new file mode 100644 index 0000000..f5a907e --- /dev/null +++ b/src/Game/randomstream.icl @@ -0,0 +1,101 @@ +implementation module randomstream + +import StdEnv, StdEnvExt +import RandomExt + +:: Stream a :== [a] + +randomStream :: !Int !([Int] -> a) !RandomSeed -> Stream a +randomStream nrInts transform seed + # (ints,seed) = randoms nrInts seed + = [transform ints : randomStream nrInts transform seed] +where + randoms :: !Int !RandomSeed -> (![Int],!RandomSeed) + randoms 0 seed = ([],seed) + randoms n seed + # (r, seed) = random seed + # (rs,seed) = randoms (n-1) seed + = ([r:rs],seed) + +intRandomStream :: !RandomSeed -> Stream Int +intRandomStream seed = randomStream 2 createInt seed +where + createInt :: ![Int] -> Int + createInt [a,b] = if (isOdd a) -1 1 * (abs b) + createInt _ = abort "Fatal error: intRandomStream applied to unexpected number of integers.\n" + +realRandomStream :: !RandomSeed -> Stream Real +realRandomStream seed = randomStream 4 createReal seed +where + createReal :: ![Int] -> Real + createReal [s,a,b,c] = toReal (if (isOdd s) "-" "" <+++ abs a <+++ "." <+++ abs b <+++ "E" <+++ (c rem 100)) + createReal _ = abort "Fatal error: realRandomStream applied to unexpected number of integers.\n" + +boolRandomStream :: !RandomSeed -> Stream Bool +boolRandomStream seed = randomStream 1 createBool seed +where + createBool :: ![Int] -> Bool + createBool [i] = isEven i + createBool _ = abort "Fatal error: boolRandomStream applied to unexpected number of integers.\n" + +probabilityRandomStream :: !RandomSeed -> Stream P +probabilityRandomStream seed = randomStream 2 createProbability seed +where + createProbability :: ![Int] -> P + createProbability [a,b] + | b==0 = 1.0 + | otherwise = (toReal a`) / (toReal b`) + where + [a`,b`:_] = sort [abs a,abs b] + createProbability _ = abort "Fatal error: probabilityRandomStream applied to unexpected number of integers.\n" + +onesStream :: Stream P +onesStream = [one,one..] + +nextRandomInt :: !RandomSeed -> .(!Int, !RandomSeed) +nextRandomInt seed + # (r1,seed) = random seed + # (r2,seed) = random seed + = (if (isOdd r1) -1 1 * (abs r2),seed) + +nextRandomReal :: !RandomSeed -> .(!Real,!RandomSeed) +nextRandomReal seed + # (r1,seed) = random seed + # (r2,seed) = random seed + # (r3,seed) = random seed + # (r4,seed) = random seed + = (toReal (if (isOdd r1) "-" "" <+++ abs r2 <+++ "." <+++ abs r3 <+++ "E" <+++ (r4 rem 100)),seed) + +nextRandomBool :: !RandomSeed -> .(!Bool,!RandomSeed) +nextRandomBool seed + # (r1,seed) = random seed + = (isEven r1,seed) + +nextRandomP :: !RandomSeed -> .(!P, !RandomSeed) +nextRandomP seed + # (r1,seed) = random seed + # (r2,seed) = random seed + # (a,b) = minmax (abs r1,abs r2) + = (if (r2==0) 1.0 ((toReal a)/(toReal b)),seed) + +next1 :: !RandomSeed -> .(!P, !RandomSeed) +next1 seed = (1.0,seed) + +/** make the random realistic, as in, small errors occur more often: + \r -> 1.0-r^4 + zero <= r <= 1.0 +*/ +makeRandomRealistic :: !P -> P +makeRandomRealistic r = 1.0-r^4.0 + +makeRandomRealisticSkilled :: !P -> P +makeRandomRealisticSkilled r = 1.0-r^10.0 + +selectMostProbableAction :: ![(P,a)] !RandomSeed -> (!Maybe a,!RandomSeed) +selectMostProbableAction odds seed + = case sortBy (\(p1,_) (p2,_) -> p1 > p2) (filter (\(p,_) -> p > zero) odds) of + [] = (Nothing,seed) + odds=:[(p,_):_] = let mostProbable = takeWhile ((==) p o fst) odds + nr = length mostProbable + (p1,seed1) = nextRandomP seed + in (Just (snd (odds !! (entier (p1 * toReal nr)))),seed1) diff --git a/src/Gui/Gui2D.dcl b/src/Gui/Gui2D.dcl new file mode 100644 index 0000000..9e8bb8d --- /dev/null +++ b/src/Gui/Gui2D.dcl @@ -0,0 +1,6 @@ +definition module Gui2D + +/** This module implements a simple SDI GUI for Soccer-Fun. +*/ + +SoccerFunGUI2D :: !*World -> *World diff --git a/src/Gui/Gui2D.icl b/src/Gui/Gui2D.icl new file mode 100644 index 0000000..53902a3 --- /dev/null +++ b/src/Gui/Gui2D.icl @@ -0,0 +1,571 @@ +implementation module Gui2D + +import StdEnvExt, StdIOExt +import fileIO +import digitdisplay, textdisplay, render, matchGame, RangeSlider +import StdDebug + +SoccerFunGUI2D :: !*World -> *World +SoccerFunGUI2D world +# (theGame, world) = getBeginMatch world +# (ids, world) = openIds 4 world +# (displIds,world) = sseqList (repeatn 2 openDigitDisplayId) world +# (teamdIds,world) = sseqList (repeatn 5 openTextDisplayId) world +# (frameId, world) = openTextDisplayId world += startIO SDI theGame (initGUI (ids,displIds,teamdIds,frameId)) [ProcessClose closeProcess] world +where + getBeginMatch :: !*env -> (!FootballGame,!*env) | TimeEnv, FileSystem env + getBeginMatch env + | isEmpty teams = abort "There are no teams.\nPlease add teams to \"allAvailableTeams\" in the \"Team\"-module\n" + | isEmpty referees = abort "There are no referees.\nPlease add referees to \"allAvailableReferees\" in the \"Referee\"-module\n" + # (whatToLog,env) = getWhatToLog env + # (options, env) = getOptions env + # (seed, env) = getNewRandomSeed env + # match = setMatchStart (hd teams West field) (hd teams East field) field (hd referees field) options.Options.playingTime seed + = ( { match = match + , actionPics = {refereePics=[]} + , history = {time=s 2.0,past=[]} + , frames = 0 + , options = options + , logging = whatToLog + } + , env + ) + where + teams = allAvailableTeams + referees = allAvailableReferees + field = getDefaultField + + initGUI :: !(![Id],![DigitDisplayId],![TextDisplayId],!TextDisplayId) !(PSt FootballGame) -> (PSt FootballGame) + initGUI ([timerId,fieldId,windowId,splashId],[westId,eastId],[team1Id,team2Id,halfId,timeId,refId],framesId) pSt=:{ls=ls=:{match=matchAtStart,options}} + # (penAtts, pSt) = accPIO renderAttributes pSt + # (penFont, pSt) = accPIO (accScreenPicture (openFont {fName="Courier New",fSize=32,fStyles=[BoldStyle]})) pSt + # (frameFont,pSt) = accPIO (accScreenPicture (openFont {fName="Courier New",fSize=16,fStyles=[BoldStyle]})) pSt + # (underFont,pSt) = accPIO (accScreenPicture (openFont {fName="Courier New",fSize=12,fStyles=[BoldStyle]})) pSt + # refsName = nameOf matchAtStart.Match.theReferee + # wDef = Window "SoccerFun: Van Gaal's Electronic Notebook" + ( LayoutControl + ( teamName team1Id (nameOf matchAtStart.Match.team1) (snd penFont) WestColour + :+: DigitDisplay westId (IntegerFormat 2) digitDisplaySize WestColour [] + :+: DigitDisplay eastId (IntegerFormat 2) digitDisplaySize EastColour [] + :+: teamName team2Id (nameOf matchAtStart.Match.team2) (snd penFont) EastColour + ) [ ControlPos (Center,zero) ] + :+: fpsDisplay framesId frameRatePrefix (snd frameFont) Green + :+: CustomControl footballFieldDisplaySize (options.renderStyle.look ls.match) + [ ControlId fieldId + , ControlPen penAtts + , ControlPos (Center,zero) + , ControlResize (\_ _ wViewSize=:{h} -> {wViewSize & h=h-digitDisplaySize.h-60}) + ] + :+: TextDisplay halfId (showHalf matchAtStart.Match.playingHalf) {w=80,h=15} + [ ControlPen [PenColour White,PenBack Black,PenFont (snd underFont)] + //, ControlResize (\_ _ size -> {size & h=size.h-digitDisplaySize.h}) + , ControlPos (LeftBottom,OffsetVector {vx=10,vy=(~7)}) + ] + :+: TextDisplay timeId (toString matchAtStart.Match.playingTime) {w=100,h=15} + [ ControlPen [PenColour White,PenBack Black,PenFont (snd underFont)] + , ControlPos (Center,OffsetVector {vx=zero,vy=zero}) + ] + :+: TextDisplay refId refsName {w=80+(12*(size refsName)),h=15} + [ ControlPen [PenColour White,PenBack Black,PenFont (snd underFont)] + , ControlPos (RightBottom,OffsetVector {vx=zero,vy=(~7)})//(3*(size "test")) + ] + ) + [ WindowViewSize {w=footballFieldDisplaySize.w-1, h=footballFieldDisplaySize.h+digitDisplaySize.h} + , WindowLook False stdUnfillNewFrameLook + , WindowPen [PenBack Black] + , WindowId windowId + ] + # (error,pSt) = openWindow undef wDef pSt + # pSt = setDigitDisplayValue westId (fst ls.match.score) pSt + # pSt = setDigitDisplayValue eastId (snd ls.match.score) pSt + | error<>NoError = abort "Could not create window.\n" + # speed = intervalFactor ls.options.displaySpeed + # tDef = Timer (toInt ((toReal ticksPerSecond)*(toReal matchAtStart.Match.unittime)*speed)) NilLS + [ TimerFunction (noLS1 (const (nextstep timerId fieldId westId eastId))) + , TimerId timerId + , TimerSelectState Unable + ] + # (error,pSt) = openTimer undef tDef pSt + | error<>NoError = abort "Could not create step timer.\n" + # tDef = Timer ticksPerSecond NilLS [TimerFunction (noLS1 (const (frameRatef timeId halfId framesId)))] + # (error,pSt) = openTimer undef tDef pSt + | error<>NoError = abort "Could not open frame rate timer.\n" + # mDef = Menu "&File" + ( MenuItem "E&xit" [MenuShortKey 'q',MenuFunction (noLS quitf)] + ) [] + # (error,pSt) = openMenu undef mDef pSt + | error<>NoError = abort "Could not create File menu.\n" + # mDef2 = Menu "&Game" + ( MenuItem "&Match" [MenuShortKey 'm',MenuFunction (noLS (matchDialogf westId eastId fieldId timerId refId team1Id team2Id))] + :+: MenuItem "Competition" [MenuShortKey 'u',MenuFunction (noLS (competitionDialogf timerId refId))] + :+: MenuSeparator [] + :+: MenuItem "&Run" [MenuShortKey 'r',MenuFunction (noLS (continuef timerId))] + :+: MenuItem "&Step" [MenuShortKey 's',MenuFunction (noLS (stepf timerId fieldId westId eastId))] + :+: MenuItem "&Halt" [MenuShortKey 'h',MenuFunction (noLS (haltf timerId))] + :+: MenuSeparator [] + :+: SubMenu "&Mode" ( RadioMenu [ ("&Realistic", Nothing,Nothing,noLS realisticf) + , ("&Predictable",Nothing,Nothing,noLS predictablef) + ] 0 [] + ) [] + :+: SubMenu "Sp&eed" ( RadioMenu [ ("&Slowest",Nothing, Just '1', noLS (changeSpeedf timerId Slowest)) + , ("S&lower", Nothing, Just '2', noLS (changeSpeedf timerId Slower)) + , ("N&ormal", Nothing, Just '3', noLS (changeSpeedf timerId Normal)) + , ("&Faster", Nothing, Just '4', noLS (changeSpeedf timerId Faster)) + , ("Fas&test",Nothing, Just '5', noLS (changeSpeedf timerId Fastest)) + ] ([Slowest,Slower,Normal,Faster,Fastest]??options.displaySpeed+1) [] + ) [] + :+: SubMenu "Re&feree" ( RadioMenu [ ("&Show", Nothing, Just '+', noLS (showReff True)) + , ("&NoShow", Nothing, Just '-', noLS (showReff False)) + ] ([True,False]??options.showReferee+1) [] + ) [] + :+: SubMenu "R&ender" ( RadioMenu [ (nameOf style, Nothing, Nothing, noLS (setfieldlook fieldId style)) + \\ style <- allRenderStyles + ] ((map nameOf allRenderStyles)??(nameOf options.renderStyle)+1) [] + ) [] + :+: MenuItem "&Playing Time..." [MenuFunction (noLS (playtimef westId eastId fieldId timeId)), MenuShortKey 't'] + :+: MenuItem "Splash screen" [MenuFunction (noLS (setSplashScreenf splashId)),MenuMarkState (if options.showSplash Mark NoMark),MenuId splashId] + ) [] + # (error,pSt) = openMenu undef mDef2 pSt + | error<>NoError = abort "Could not create Game menu.\n" + # pSt = appPIO (setWindowViewSize windowId {w=640,h=550}) pSt + # pSt = showSplashScreen pSt + = pSt + + showSplashScreen :: !(PSt FootballGame) -> PSt FootballGame + showSplashScreen pSt=:{ls=game} + | not game.options.showSplash = pSt + # (spls,pSt) = getSplashImageForGui pSt + # splashDef = Dialog "The Footballer's Mind" + ( CompoundControl + ( ButtonControl "&Close" [ControlFunction (noLS closeActiveWindow)] + ) + [ ControlLook True (const2 (drawAt zero spls.img)) + , ControlViewSize (getBitmapSize spls.img) + ] + ) [] + # ((error,_),pSt) = openModalDialog undef splashDef pSt + | error<>NoError = abort "Could not open splash screen.\n" + | otherwise = pSt + + +// Constants for the GUI: +digitDisplaySize = { w=24, h=36 } +footballFieldDisplaySize = { w=640,h=400} +frameRatePrefix :== "Rounds/sec: " + +// GUI elements: + +/** teamName id name font colour + describes a TextDisplay that is identified by id, has text content name, uses the given font in the given colour. +*/ +teamName :: TextDisplayId String Font Colour -> TextDisplay .ls .pst +teamName id name penFont colour = TextDisplay id name (teamSize footballFieldDisplaySize) + [ ControlPen [PenColour colour,PenBack Black,PenFont penFont] + , ControlResize (const2 teamSize) + ] +where teamSize {w} = {digitDisplaySize & w=(w-digitDisplaySize.w*4)/2} + +/** fpsDisplay id name font colour + describes a TextDisplay that is used to display the frame rate of a match. +*/ +fpsDisplay :: TextDisplayId String Font Colour -> TextDisplay .ls .pst +fpsDisplay id name penFont colour = TextDisplay id name {digitDisplaySize & w=300} + [ ControlPen [PenColour colour, PenBack Black, PenFont penFont] + , ControlPos (Center,zero) + ] + + +// The callback functions of the GUI: + +/** setSplashScreenf splashId pSt + sets the check mark of the menu item that controls the splash screen option, and updates the Options record in the state accordingly. +*/ +setSplashScreenf :: !Id !(PSt FootballGame) -> PSt FootballGame +setSplashScreenf splashId pSt=:{ls=game} +| game.options.showSplash = appPIO (unmarkMenuItems [splashId]) {pSt & ls={game & options={game.options & showSplash = False}}} +| otherwise = appPIO (markMenuItems [splashId]) {pSt & ls={game & options={game.options & showSplash = True}}} + +/** quitf pSt + stores the current options to disk and terminates the parent interactive process. +*/ +quitf :: !(PSt FootballGame) -> PSt FootballGame +quitf pSt=:{ls=game} + # pSt = setOptions game.options pSt + # pSt = closeProcess pSt + = pSt + +/** continuef timerId pSt + continues the simulation of the current match. +*/ +continuef :: !Id !(PSt FootballGame) -> PSt FootballGame +continuef timerId pSt = appPIO (enableTimer timerId) pSt + +/** haltf timerId pSt + stops the simulation of the current match. +*/ +haltf :: !Id !(PSt FootballGame) -> PSt FootballGame +haltf timerId pSt = appPIO (disableTimer timerId) pSt + +/** stepf timerId fieldId westId eastId pSt + stops the simulation of the current match, and computes a single step of the current match. +*/ +stepf :: !Id !Id !DigitDisplayId !DigitDisplayId -> IdFun (PSt FootballGame) +stepf timerId fieldId westId eastId = nextstep timerId fieldId westId eastId o haltf timerId + +/** nextstep timerId fieldId westId eastId pSt + computes a single step for the current match, renders the new state of the match, and displays the referee dialog if required. +*/ +nextstep :: !Id !Id !DigitDisplayId !DigitDisplayId !(PSt FootballGame) -> PSt FootballGame +nextstep timerId fieldId westId eastId pSt=:{ls=game,io} + # (refEvents,game,io) = stepMatchForGui game io + # pSt = {pSt & io = setControlLook fieldId True (False,game.options.renderStyle.look game.match) io + , ls = incFrames game + } + = analyseRefEvents refEvents pSt +where + analyseRefEvents :: ![RefereeAction] !(PSt FootballGame) -> PSt FootballGame + analyseRefEvents refEvents pSt = foldl analyseRefEvent pSt refEvents + where + analyseRefEvent :: !(PSt FootballGame) !RefereeAction -> PSt FootballGame + analyseRefEvent pSt=:{ls=ls=:{FootballGame | match={score,playingHalf}}} rev + | or (apply rev [isContinueGame,isDisplacePlayers,isDirectFreeKick,isCenterKick,isPauseGame,isAddTime]) + = pSt + # pSt = refereeDialog rev pSt + # pSt = if (isGameOver rev) (appPIO (disableTimer timerId) pSt) pSt + = case rev of + Goal h = if (h == West && playingHalf == FirstHalf || h == East && playingHalf == SecondHalf) + (setDigitDisplayValue westId (fst score) pSt) + (setDigitDisplayValue eastId (snd score) pSt) + no_goal = pSt + + refereeDialog :: !RefereeAction !(PSt FootballGame) -> PSt FootballGame + refereeDialog rev pSt=:{ls=ls=:{match=match=:{theReferee=referee=:{Referee | name}}}} + | not pSt.ls.options.showReferee + = pSt + # pSt = case defaultSoundFile rev of + Just sound = appPIO (makeSound sound) pSt + nothing = pSt + # pSt = haltf timerId pSt + # (image,pSt) = accPIO (defaultImage match rev) pSt + # (closeId, pSt) = openId pSt + # (dialogId,pSt) = openId pSt + # tDef = Timer (3*ticksPerSecond) NilLS [ TimerFunction (noLS1 (const ((continuef timerId) o (closeWindow dialogId) o (appPIO (closeTimer closeId))))) + , TimerId closeId + ] + # (error, pSt) = openTimer undef tDef pSt + | error<>NoError = abort "Could not open referee dialog timer.\n" + # refereeDef = Dialog ("Referee " <+++ name) + ( TextControl (showSuccintRefereeAction rev) [] + :+: CustomControl (getBitmapSize image) (const2 (drawAt zero image)) [] + ) [WindowId dialogId] + # ((error,_),pSt) = openModalDialog undef refereeDef pSt + | error<>NoError = abort "Could not open referee dialog.\n" + | otherwise = pSt + +/** showReff show pSt + sets the option to show the referee during simulation. +*/ +showReff :: !Bool !(PSt FootballGame) -> PSt FootballGame +showReff show pSt = {pSt & ls = {pSt.ls & options = {pSt.ls.options & showReferee = show}}} + +/** playtimef westId eastId fieldId timeId pSt + opens the dialog to alter the play time of a match. +*/ +playtimef :: !DigitDisplayId !DigitDisplayId !Id !TextDisplayId !(PSt FootballGame) -> PSt FootballGame +playtimef westId eastId fieldId timeId pSt=:{ls=game=:{options={Options | playingTime}}} + # (dialogId,pSt) = openId pSt + # (textId, pSt) = openId pSt + # (sliderId,pSt) = openRangeSliderId pSt + # playingtimeDef = Dialog "Playing Time" + ( TextControl (toString playingTime) [ControlId textId, ControlPos (Center,zero),ControlWidth (ContentWidth (toString (maxList times)))] + :+: RangeSlider sliderId Horizontal (PixelWidth 16) {values=times,index=times??playingTime} (noLS1 (setPlayingTime westId eastId textId)) [] + :+: ButtonControl "Close" [ControlFunction (noLS (closeWindow dialogId)),ControlPos (Right,zero)] + ) + [ WindowClose (noLS (closeWindow dialogId)) + , WindowId dialogId + ] + # ((error,_),pSt) = openModalDialog undef playingtimeDef pSt + | error <> NoError = abort "Could not open Playing Time dialog.\n" + | otherwise = pSt +where + times = map minutes [0.5, 1.0 .. 10.0] + + setPlayingTime westId eastId textId newtime pSt=:{ls=game} + # pSt = setTextDisplayText timeId display_time pSt + # pSt = appPIO (setControlText textId display_time) pSt + # pSt = {pSt & ls = {game & options = {Options | game.options & playingTime=newtime} + , match = {Match | game.match & playingTime=newtime} + } } + # pSt = restartf westId eastId fieldId pSt + = pSt + where + display_time = toString newtime + +/** changeteamf fieldId team1Id team2Id home team pSt + replaces the current team at home with the given team. The display name of the team is adapted, and the match is to the beginning of the first half. +*/ +changeteamf :: !DigitDisplayId !DigitDisplayId !Id !TextDisplayId !TextDisplayId !Home !Team !(PSt FootballGame) -> PSt FootballGame +changeteamf westId eastId fieldId team1Id team2Id home team pSt=:{ls=game=:{match,options},io} + # match = {Match | match & team1 = if (home == West) team match.Match.team1, team2 = if (home == East) team match.Match.team2} + # pSt = {pSt & ls = {game & match=match}} + # pSt = setTextDisplayText (if (home == West) team1Id team2Id) (nameOf team) pSt + # pSt = restartf westId eastId fieldId pSt + = pSt + +/** changereff timerId refId referee pSt + replaces the current referee with the given referee and adapts the display name of the new referee. +*/ +changereff :: !Id !TextDisplayId !Referee !(PSt FootballGame) -> PSt FootballGame +changereff timerId refId ref=:{Referee | name} pSt + # pSt = setTextDisplayText refId name pSt //todo: de positionering moet aangepast worden + = appPIO (disableTimer timerId) {pSt & ls={pSt.ls & match = {pSt.ls.match & theReferee = ref}}} + +/** restartf fieldId pSt + makes sure that the current match is reinitialized to the initial teams, referee, and ball position.s +*/ +restartf :: !DigitDisplayId !DigitDisplayId !Id !(PSt FootballGame) -> PSt FootballGame +restartf westId eastId fieldId pSt=:{ls=game=:{match,options},io} + # match = {match & theBall = Free zero + , playingHalf = FirstHalf + , playingTime = options.Options.playingTime + , score = (0,0) + , theReferee = getRefereeFresh match.Match.theField (nameOf match.Match.theReferee) + , team1 = getTeamFresh West match.Match.theField (nameOf match.Match.team1) + , team2 = getTeamFresh East match.Match.theField (nameOf match.Match.team2) + } + # pSt = setDigitDisplayValue westId 0 pSt + # pSt = setDigitDisplayValue eastId 0 pSt + = {pSt & ls = {game & match=match} + , io = setControlLook fieldId True (False,options.renderStyle.look match) io + } +where + getRefereeFresh :: !FootballField !String -> Referee + getRefereeFresh field name = hd [r field \\ r <- allAvailableReferees | nameOf (r field) == name] + + getTeamFresh :: !Home !FootballField !String -> Team + getTeamFresh home field name = hd [t \\ t <- getAllTeamsOfHome home field | nameOf t == name] + +/** setfieldlook fieldId style pSt + sets a new rendering style for the football field +*/ +setfieldlook :: !Id !RenderStyle !(PSt FootballGame) -> PSt FootballGame +setfieldlook fieldId style=:{look} pSt=:{ls=game=:{match,options},io} + = {pSt & ls = {game & options = {options & renderStyle = style}} + , io = setControlLook fieldId True (False,look match) io + } + + +/** changeSpeedf timerId speed pSt + modifies the current simulation speed of a match. +*/ +changeSpeedf :: !Id !DisplaySpeed !(PSt FootballGame) -> PSt FootballGame +changeSpeedf timerId speed pSt=:{ls} + # timerInterval = toInt ((toReal ticksPerSecond)*(toReal ls.match.Match.unittime)*(intervalFactor speed)) + # pSt = {pSt & ls = {FootballGame | ls & options = {Options | ls.options & displaySpeed = speed}}} + = appPIO (setTimerInterval timerId timerInterval) pSt + +/** realisticf pSt + sets a true pseudo-random generating function. +*/ +realisticf :: !(PSt FootballGame) -> PSt FootballGame +realisticf pSt=:{ls=ls=:{match}} = {pSt & ls={FootballGame | ls & match={match & nextRandomP=nextRandomP}}} + +/** predictablef pSt + sets a 'random-generating' function that always yields 1.0. +*/ +predictablef :: !(PSt FootballGame) -> PSt FootballGame +predictablef pSt=:{ls=ls=:{match}} = {pSt & ls={FootballGame | ls & match={match & nextRandomP=next1}}} + +/** frameRatef timeId halfId framesId pSt + updates the current playing time and playing half information, as well as the frame rate counter, which is reset every second. +*/ +frameRatef :: !TextDisplayId !TextDisplayId !TextDisplayId !(PSt FootballGame) -> PSt FootballGame +frameRatef timeId halfId framesId pSt=:{ls=ls=:{frames,match={Match | playingTime,playingHalf}}} + # pSt = setTextDisplayText timeId (toString playingTime) pSt + # pSt = setTextDisplayText halfId (showHalf playingHalf) pSt + = setTextDisplayText framesId (frameRatePrefix <+++ frames) {pSt & ls={ls & frames=0}} + +/** matchDialogf westId eastId fieldId timerId refId team1Id team2Id pSt + opens a dialog in which the user can select two teams that play a match, and a referee to control the match. +*/ +matchDialogf :: DigitDisplayId DigitDisplayId Id Id TextDisplayId TextDisplayId TextDisplayId (PSt FootballGame) -> PSt FootballGame +matchDialogf westId eastId fieldId timerId refId team1Id team2Id pSt=:{ls=game} + # (dialogId,pSt) = openId pSt + # dialog = Dialog "Choose Match" + ( LayoutControl + ( TextControl "Choose Team West" [ControlPos (Center,zero)] + :+: LayoutControl + ( RadioControl [ (nameOf t,Nothing,noLS (changeteamf westId eastId fieldId team1Id team2Id West t)) + \\ t <- teams West + ] (Columns 1) ((map nameOf (teams West)) ?? (nameOf game.match.Match.team1)+1) [] + ) [ControlPos (Center,zero)] + ) [ControlPos (Left,zero)] + :+: LayoutControl + ( TextControl "Choose Team East" [ControlPos (Center,zero)] + :+: LayoutControl + ( RadioControl [ (nameOf t,Nothing,noLS (changeteamf westId eastId fieldId team1Id team2Id East t)) + \\ t <- teams East + ] (Columns 1) ((map nameOf (teams East)) ?? (nameOf game.match.Match.team2)+1) [] + ) [ControlPos (Center,zero)] + ) [ControlPos (RightToPrev,zero)] + :+: LayoutControl + ( TextControl "Choose Referee" [ControlPos (Center,zero)] + :+: LayoutControl + ( RadioControl [ (nameOf r,Nothing,noLS (changereff timerId refId r)) + \\ r <- apply field allAvailableReferees + ] (Columns 1) ((map nameOf (apply field allAvailableReferees)) ?? (nameOf game.match.theReferee)+1) [] + ) [ControlPos (Center,zero)] + ) [ControlPos (RightToPrev,zero)] + :+: ButtonControl "Ok" [ControlFunction (closef dialogId),ControlPos (Right,zero)] + ) + [ WindowClose (closef dialogId) + , WindowId dialogId + ] + # ((error,_),pSt) = openModalDialog undef dialog pSt + | error <> NoError = abort "Could not open match dialog.\n" + | otherwise = pSt +where + teams home = getAllTeamsOfHome home field + field = game.match.theField + closef dialogId = noLS (restartf westId eastId fieldId o closeWindow dialogId) + +/** competitionDialogf timerId refId pSt + opens a dialog in which the user can select the teams that participate in a full competition; i.e. each team plays against each other at either home side of + the football field. Once the teams and referee are selected, all matches are computed, and the final ranking is displayed. +*/ +competitionDialogf :: Id TextDisplayId (PSt FootballGame) -> PSt FootballGame +competitionDialogf timerId refId pSt=:{ls=game} + # (dialogId,pSt) = openId pSt + # (teamsId, pSt) = openId pSt + # dialog = Dialog "Competition" + ( LayoutControl + ( TextControl "Choose Teams West" [ControlPos (Center,zero)] + :+: LayoutControl + ( CheckControl [(nameOf t,Nothing,Mark,id) \\ t <- teams_west] (Columns 1) [ControlId teamsId] + ) [ControlPos (Center,zero)] + :+: ButtonControl "Select &All" + [ControlFunction (noLS (selectTeams teamsId (index_all_teams,index_no_teams))),ControlPos (Left,zero)] + :+: ButtonControl "Cl&ear All" + [ControlFunction (noLS (selectTeams teamsId (index_no_teams,index_all_teams))),ControlPos (RightToPrev,zero)] + ) [ControlPos (Left,zero)] + :+: LayoutControl + ( TextControl "Choose Referee" [ControlPos (Center,zero)] + :+: LayoutControl + ( RadioControl [(nameOf r,Nothing,noLS (changereff timerId refId r)) \\ r <- apply field allAvailableReferees] (Columns 1) 1 [] + ) [ControlPos (Center,zero)] + ) [ControlPos (RightToPrev,zero)] + :+: ButtonControl "Ok" [ControlFunction (noLS (startCompetition teamsId dialogId)),ControlPos (Right,zero)] + ) + [ WindowClose (noLS (closeWindow dialogId)) + , WindowId dialogId + , WindowPos (Center,OffsetVector {zero & vy=100}) + ] + # ((error,_),pSt) = openModalDialog undef dialog pSt + | error <> NoError = abort "Could not open competition dialog.\n" + | otherwise = pSt +where + teams home = getAllTeamsOfHome home field + teams_west = teams West + index_all_teams = [1 .. length teams_west] + index_no_teams = [] + field = game.match.theField + + selectTeams checkId (set,clear) = appPIO (markCheckControlItems checkId set o unmarkCheckControlItems checkId clear) + + startCompetition checkId dialogId pSt=:{ls=game} + = case accPIO (getWindow dialogId) pSt of + (Nothing, pSt) = abort "Fatal error: could not retrieve competition dialog data.\n" // should be impossible, because the dialog has not been closed yet + (Just wSt,pSt=:{ls=game}) + = case getCheckControlSelection checkId wSt of + (_,Nothing) = closeWindow dialogId pSt + (_,Just idxs) + # (teams,names) = unzip [(t,nameOf (t West game.match.theField)) \\ t <- allAvailableTeams & i <- [1..] | isMember i idxs] + # ((rs,scores),pSt) = checkCompetitionFile names game.match.seed pSt + # compete = competition teams game.match.theField game.match.theReferee game.match.Match.playingTime rs + = showMatches dialogId compete scores {pSt & ls={game & match = {game.match & seed=rs}}} + + showMatches dialogId compete=:{west,east} scores pSt + # pSt = appPIO (closeAllControls dialogId) pSt + # (textId, pSt) = openId pSt + # (progressId,pSt) = openId pSt + # (matchId, pSt) = openId pSt + # (error, pSt) = openControls dialogId undef + ( TextControl "" [ ControlWidth (ContentWidth (result (longest west) (longest east) (Just (99,99)))) + , ControlId textId + , ControlPos (Center,OffsetVector {zero & vy=100}) + ] + :+: TextControl "" [ ControlWidth (ContentWidth (progress nr_of_matches nr_of_matches)) + , ControlId progressId + , ControlPos (BelowPrev,zero) + ] + ) pSt + # (error, pSt) = openTimer ([(i,j) \\ i <- [0..length compete.west-1], j <- [0 .. length compete.east-1]],scores) + (Timer 0 NilLS [TimerFunction (showNextMatch textId progressId matchId compete),TimerId matchId]) pSt + | error <> NoError = abort "Could not open timer to display matches.\n" + | otherwise = pSt + where + longest texts = hd (sortBy (\t1 t2 -> size t1 > size t2) texts) + nr_of_matches = length west * length east + + result teamw teame score = teamw +++ "-" +++ teame +++": " <+++ if (isNothing score) "no result" (toString (fromJust score)) + progress i total = i +++> (" out of "<+++ total) + + showNextMatch textId progressId matchId compete dt (([_:ms],[_:cs]),pSt) // match has already been computed: skip it + = showNextMatch textId progressId matchId compete dt ((ms,cs),pSt) + showNextMatch textId progressId matchId compete=:{results,west,east} dt (([(tw,te):ms],cs),pSt) // match has not yet been computed: compute and backup + # (pos,pSt) = appendMatchToCompetitionFile westt eastt pSt // create an empty entry in the competition backup file + # pSt = updateMatchToCompetitionFile westt eastt score pos pSt // after computing match, store in the competition backup file + # pSt = appPIO (setControlText textId (result westt eastt score) o // show user which match was successfully computed + setControlText progressId (progress (tw*length west + te) nr_of_matches)) pSt + = ((ms,cs),pSt) + where + (westt,eastt,score) = ( west!!tw, east!!te, results!!tw!!te ) + showNextMatch textId progressId matchId compete _ (ls,pSt) + # pSt = appPIO (closeTimer matchId) pSt + # ((_,scores),pSt) = checkCompetitionFile compete.west compete.usedRandomSeed pSt + = (ls,showRanking dialogId (ranking compete.west scores) pSt) + + showRanking dialogId ranking pSt + # pSt = rankingToFile pSt + # pSt = appPIO (closeAllControls dialogId) pSt + # (error,pSt) = openControls dialogId undef resultlist pSt + | error <> NoError = abort "Could not refill dialog with result list.\n" + | otherwise = pSt + where + sorted_ranking = sortBy (\(_,r1) (_,r2) -> r1 > r2) ranking // sort ranked list in descending order + resultlist = LayoutControl + ( ListLS [TextControl (toString i) [ControlPos (Left,zero)] \\ i <- [1..length sorted_ranking]] + ) [ControlPos (LeftTop,zero),ControlItemSpace 4 0] + :+: LayoutControl + ( ListLS [TextControl club [ControlPos (Left,zero)] \\ (club,_) <- sorted_ranking] + ) [ControlPos (RightToPrev,zero),ControlItemSpace 4 0] + :+: LayoutControl + ( ListLS [TextControl (toString r.matchpoints) [ControlPos (Left,zero)] \\ (_,r) <- sorted_ranking] + ) [ControlPos (RightToPrev,zero),ControlItemSpace 4 0] + :+: LayoutControl + ( ListLS [TextControl (toString r.goals_scored) [ControlPos (Left,zero)] \\ (_,r) <- sorted_ranking] + ) [ControlPos (RightToPrev,zero),ControlItemSpace 4 0] + :+: LayoutControl + ( ListLS [TextControl (toString r.goals_against) [ControlPos (Left,zero)] \\ (_,r) <- sorted_ranking] + ) [ControlPos (RightToPrev,zero),ControlItemSpace 4 0] + :+: ButtonControl "Ok" [ControlFunction (noLS (closeWindow dialogId)),ControlPos (Right,zero)] + + rankingToFile env + # (ok,file,env) = fopen "ranking.txt" FWriteText env + | not ok = trace_n "Could not output ranking to ranking.txt" env + # file = foldl (\file (club,{matchpoints,goals_scored,goals_against}) -> fwrites (club <+++ "\t" <+++ matchpoints <+++ "\t" <+++ goals_scored <+++ "\t" <+++ goals_against <+++ "\n") file) file sorted_ranking + # (ok,env) = fclose file env + | not ok = trace_n "Could not close ranking.txt" env + | otherwise = env + +// Utility functions: +showHalf :: !Half -> String +showHalf FirstHalf = "1st half" +showHalf SecondHalf = "2nd half" + +/** getAllTeamsOfHome home field + yields all teams that start playing at given home and given football field dimensions. +*/ +getAllTeamsOfHome :: !Home !FootballField -> [Team] +getAllTeamsOfHome home field = apply field (apply home allAvailableTeams) diff --git a/src/Gui/digitdisplay.dcl b/src/Gui/digitdisplay.dcl new file mode 100644 index 0000000..b891767 --- /dev/null +++ b/src/Gui/digitdisplay.dcl @@ -0,0 +1,27 @@ +definition module digitdisplay + +import StdControl, StdId + +/* A DigitDisplay displayId format size colour atts + is a Controls instance that displays a positive integral number of maximal format digits + in the given colour. Each digit has a given size. + The following ControlAttribute-s are inherited: + ControlPos: the layout position of the digit display control + ControlTip: the tool tip text that must be displayed + All other attributes are ignored. +*/ + +:: DigitDisplay ls pst + = DigitDisplay DigitDisplayId DigitFormat DigitSize Colour [ControlAttribute *(ls,pst)] +:: DigitDisplayId // The identification value of the digit display +:: DigitFormat + = IntegerFormat !Int // The number of digits +:: DigitSize // The size of one digit + :== Size + +openDigitDisplayId :: !*env -> (!DigitDisplayId,!*env) | Ids env + +instance Controls DigitDisplay + +getDigitDisplayValue :: !DigitDisplayId !(PSt .ps) -> (!Int,!PSt .ps) +setDigitDisplayValue :: !DigitDisplayId !Int !(PSt .ps) -> PSt .ps diff --git a/src/Gui/digitdisplay.icl b/src/Gui/digitdisplay.icl new file mode 100644 index 0000000..a1d548c --- /dev/null +++ b/src/Gui/digitdisplay.icl @@ -0,0 +1,205 @@ +implementation module digitdisplay + +import StdArray, StdClass, StdEnum, StdInt, StdList, StdMisc, StdReal, StdString +import StdEnvExt +import StdControl, StdControlAttribute, StdControlReceiver, StdId, StdPicture, StdPSt, StdReceiver + +/* A DigitDisplay displayId format size atts + is a Controls instance that displays a positive integral number of maximal format digits + in a given colour. Each digit has a given size. + The following ControlAttribute-s are inherited: + ControlPos: the layout position of the digit display control + ControlTip: the tool tip text that must be displayed + All other attributes are ignored. +*/ + +:: DigitDisplay ls pst + = DigitDisplay DigitDisplayId DigitFormat DigitSize Colour [ControlAttribute *(ls,pst)] +:: DigitDisplayId + = { customId :: !Id + , receiverId :: !R2Id DigitDisplayMsgIn DigitDisplayMsgOut + } +:: DigitDisplayMsgIn = SetDigitValueIn Int | GetDigitValueIn +:: DigitDisplayMsgOut = SetDigitValueOut | GetDigitValueOut Int +:: DigitFormat + = IntegerFormat !Int // The number of digits +:: DigitSize // The size of one digit + :== Size + +openDigitDisplayId :: !*env -> (!DigitDisplayId,!*env) | Ids env +openDigitDisplayId env + # (id, env) = openId env + # (r2id,env) = openR2Id env + = ({customId=id,receiverId=r2id},env) + +:: DigitDisplaySt + = { value :: !Int // The current value that is displayed + } +:: DigitShapeTT + = { horDigitBars:: ![RPoint2] // The positions of the horizontal digitbars + , verDigitBars:: ![RPoint2] // The positions of the vertical digitbars + } +:: DigitBarTT + = { horDigitBar :: !PolygonShapeTT // The horizontal `true type' polygon shape + , verDigitBar :: !PolygonShapeTT // The vertical `true type' polygon shape + } +:: RPoint2 = {rx ::!Real,ry ::!Real} +:: RVector2 = {rvx::!Real,rvy::!Real} +:: PolygonShapeTT :== [RVector2] + + +instance Controls DigitDisplay where + controlToHandles (DigitDisplay {customId,receiverId} digitFormat digitSize colour atts) pst + = controlToHandles digitdisplay pst + where + okDigitFormat = validateDigitFormat digitFormat + okDigitSize = validateDigitSize digitSize + nrOfDigits = getNrOfDigits digitFormat + customControlSize = { okDigitSize & w = okDigitSize.w*nrOfDigits } + initDisplaySt = { value = 0 } + digitdisplay = { newLS = initDisplaySt + , newDef = CustomControl customControlSize (displaylook (format okDigitFormat 0)) + [ ControlId customId + , ControlPen [PenBack Black,PenColour colour] + : flatten [posAtt,tipAtt] + ] + :+: + Receiver2 receiverId receiverfun [] + } + + posAtt = case [att \\ att<-atts | isControlPos att] of + [ ControlPos pos : _] -> [ControlPos pos] + _ -> [] + tipAtt = case [att \\ att<-atts | isControlTip att] of + [ ControlTip text : _] -> [ControlTip text] + _ -> [] + digitbars = { horDigitBar = [ {rvx = dx, rvy = ~dy} + , {rvx = 1.0-lx,rvy = 0.0} + , {rvx = dx, rvy = dy} + , {rvx = ~dx, rvy = dy} + , {rvx = lx-1.0,rvy = 0.0} + , {rvx = ~dx, rvy = ~dy} + ] + , verDigitBar = [ {rvx = dx, rvy = dy} + , {rvx = 0.0, rvy = 0.5-ly} + , {rvx = ~dx, rvy = dy} + , {rvx = ~dx, rvy = ~dy} + , {rvx = 0.0, rvy = ly-0.5} + , {rvx = dx, rvy = ~dy} + ] + } + (hmargin,vmargin) = (0.12,0.12) + (dx,dy) = (0.06,0.06) + (lx,ly) = (2.0*(hmargin+dx),vmargin+dy) + digitshapes :: {!DigitShapeTT} + digitshapes = {shape0,shape1,shape2,shape3,shape4,shape5,shape6,shape7,shape8,shape9} + shape0 = { horDigitBars = [a,c], verDigitBars = [a,b,d,e] } + shape1 = { horDigitBars = [], verDigitBars = [d,e] } + shape2 = { horDigitBars = [a,b,c], verDigitBars = [b,d] } + shape3 = { horDigitBars = [a,b,c], verDigitBars = [d,e] } + shape4 = { horDigitBars = [b], verDigitBars = [a,d,e] } + shape5 = { horDigitBars = [a,b,c], verDigitBars = [a,e] } + shape6 = { horDigitBars = [a,b,c], verDigitBars = [a,b,e] } + shape7 = { horDigitBars = [a], verDigitBars = [d,e] } + shape8 = { horDigitBars = [a,b,c], verDigitBars = [a,b,d,e] } + shape9 = { horDigitBars = [a,b,c], verDigitBars = [a,d,e] } + [a,b,c,d,e:_] = [ {rx=hmargin, ry=vmargin} + , {rx=hmargin, ry=0.5} + , {rx=hmargin, ry=1.0-vmargin} + , {rx=1.0-hmargin,ry=vmargin} + , {rx=1.0-hmargin,ry=0.5} + ] + + receiverfun :: !DigitDisplayMsgIn !*(DigitDisplaySt,PSt .ps) -> (DigitDisplayMsgOut,(DigitDisplaySt,PSt .ps)) + receiverfun (SetDigitValueIn newValue) (ddst,pst=:{io}) + # ddst = {ddst & value = okValue} + # io = setControlLook customId True (True,displaylook (format okDigitFormat okValue)) io + = (SetDigitValueOut,(ddst,{pst & io=io})) + where + okValue = validateDigitValue okDigitFormat newValue + receiverfun GetDigitValueIn (ddst=:{value},pst) + = (GetDigitValueOut value,(ddst,pst)) + + displaylook :: ![Digit] !SelectState !UpdateState !*Picture -> *Picture + displaylook digits _ _ picture + # picture = unfill {zero & corner2={x=customControlSize.w,y=customControlSize.h}} picture + # picture = sseq [fillPolygons {x=i*okDigitSize.w,y=0} digitshapes.[digit] \\ digit <- digits & i <- [0..]] picture + = picture + where + fillPolygons base {horDigitBars,verDigitBars} picture + = sseq + ( [fillAt (base + scaleRPoint2 okDigitSize posTT) {polygon_shape=map (scaleRVector2 okDigitSize) digitbars.horDigitBar} \\ posTT <- horDigitBars] + ++ + [fillAt (base + scaleRPoint2 okDigitSize posTT) {polygon_shape=map (scaleRVector2 okDigitSize) digitbars.verDigitBar} \\ posTT <- verDigitBars] + ) picture + + getControlType _ = "DigitDisplay" + +getDigitDisplayValue :: !DigitDisplayId !(PSt .ps) -> (!Int,!PSt .ps) +getDigitDisplayValue {receiverId} pst + = case syncSend2 receiverId GetDigitValueIn pst of + ((SendOk,Just (GetDigitValueOut x)),pst) -> (x,pst) + other -> sendError "getDigitDisplayValue" + +setDigitDisplayValue :: !DigitDisplayId !Int !(PSt .ps) -> PSt .ps +setDigitDisplayValue {receiverId} newValue pst + = case syncSend2 receiverId (SetDigitValueIn newValue) pst of + ((SendOk,Just SetDigitValueOut),pst) -> pst + other -> sendError "setDigitDisplayValue" + +sendError fName + = abort (fName +++ ": wrong reply from DigitDisplay.\n") + + +// Validate format: +validateDigitFormat :: !DigitFormat -> DigitFormat +validateDigitFormat (IntegerFormat nrDigits) + = IntegerFormat (setbetween nrDigits 1 maxNrDigits) +where + maxInt = 0x7FFFFFFF + maxNrDigits = toInt (log10 (toReal maxInt))-1 + + +// getNrOfDigits returns the number of digits to display: +getNrOfDigits :: !DigitFormat -> Int +getNrOfDigits (IntegerFormat nrDigits) = nrDigits + +// Validate digit size: +validateDigitSize :: !DigitSize -> Size +validateDigitSize {w,h} + = {w=max 1 w,h=max 1 h} + +// Validate value according to valid format: +validateDigitValue :: !DigitFormat !Int -> Int +validateDigitValue (IntegerFormat nrDigits) x + = setbetween x 0 (10^nrDigits-1) + +// Format integer values: +:: Digit :== Int // A digit is an int in [0..9] + +class format a :: !DigitFormat !a -> [Digit] + +instance format Int where + format (IntegerFormat nrDigits) x + = getdigits nrDigits (abs x) [] + where + getdigits :: !Int !Int ![Digit] -> [Digit] + getdigits 0 _ digits + = digits + getdigits n x digits + = getdigits (n-1) (x / 10) [x rem 10 : digits] + +digitsToString :: ![Digit] -> String +digitsToString digits + = {toChar (toInt '0'+d) \\ d<-digits} + + +instance toString DigitFormat where + toString (IntegerFormat nrDigits) = "(IntegerFormat " <+++ nrDigits <+++")" + + +scaleRVector2 :: !Size !RVector2 -> Vector2 +scaleRVector2 {w,h} {rvx,rvy} = {vx=toInt ((toReal w)*rvx), vy=toInt ((toReal h)*rvy)} + +scaleRPoint2 :: !Size !RPoint2 -> Point2 +scaleRPoint2 {w,h} {rx,ry} = {x=toInt ((toReal w)*rx), y=toInt ((toReal h)*ry)} diff --git a/src/Gui/guiInterface.dcl b/src/Gui/guiInterface.dcl new file mode 100644 index 0000000..e7e5db4 --- /dev/null +++ b/src/Gui/guiInterface.dcl @@ -0,0 +1,21 @@ +definition module guiInterface + +import matchGame + +/** getSplashImageForGui loads the splash image for Soccer-Fun. +*/ +getSplashImageForGui :: !*env -> (!GamePicture,!*env) | FileSystem env + +// todo: +getActionPicsForGui :: !Match !*env -> (!ActionPics,!*env) | FileSystem env + +/* Steps the game one step, returns the game and the referee events +*/ +stepMatchForGui :: !FootballGame !*env -> (![RefereeAction], !FootballGame, !*env) | FileSystem env + +:: DisplaySpeed = Slowest | Slower | Normal | Faster | Fastest +instance toString DisplaySpeed +instance fromString DisplaySpeed +instance == DisplaySpeed + +intervalFactor :: !DisplaySpeed -> Real diff --git a/src/Gui/guiInterface.icl b/src/Gui/guiInterface.icl new file mode 100644 index 0000000..e6a7dff --- /dev/null +++ b/src/Gui/guiInterface.icl @@ -0,0 +1,55 @@ +implementation module guiInterface + +import fileIO +import matchGame + +inDir img :== "afbeeldingen\\"+++img+++".bmp" + +getSplashImageForGui :: !*env -> (!GamePicture,!*env) | FileSystem env +getSplashImageForGui env +# pathToSplash = inDir "AmsterdamArenA" +# (splashImg, env) = getImage pathToSplash env += ({img = splashImg, path = pathToSplash},env) + +stepMatchForGui :: !FootballGame !*env -> (![RefereeAction], !FootballGame, !*env) | FileSystem env +stepMatchForGui game env +| timeLeft game + # ((refEvents,actions),match) = stepMatch game.match + # env = logMatch game.logging match refEvents actions env + = (refEvents,{game & match=match},env) +| otherwise + = ([GameOver],game,env) + +getActionPicsForGui :: !Match !*env -> (!ActionPics,!*env) | FileSystem env +getActionPicsForGui match env +# (refereePics,env) = sseqList (map fillWithPics` match.theReferee.refActionPics) env += ({refereePics=refereePics},env) +where + fillWithPics` :: !Path !*env -> (!GamePicture,!*env) | FileSystem env + fillWithPics` path env + # (img,env) = getImage path env + = ({img=img, path=path},env) + +instance toString DisplaySpeed where toString Slowest = "Slowest" + toString Slower = "Slower" + toString Normal = "Normal" + toString Faster = "Faster" + toString Fastest = "Fastest" +instance fromString DisplaySpeed where fromString "Slowest" = Slowest + fromString "Slower" = Slower + fromString "Normal" = Normal + fromString "Faster" = Faster + fromString "Fastest" = Fastest +instance == DisplaySpeed where == Slowest Slowest = True + == Slower Slower = True + == Normal Normal = True + == Faster Faster = True + == Fastest Fastest = True + == _ _ = False + +intervalFactor :: !DisplaySpeed -> Real +intervalFactor Slowest = 1.0 / 0.2 // five times slower +intervalFactor Slower = 1.0 / 0.5 // two times slower +intervalFactor Normal = 1.0 // two times faster +intervalFactor Faster = 1.0 / 5.0 // five times faster +intervalFactor Fastest = zero // no timer delay diff --git a/src/Gui/render.dcl b/src/Gui/render.dcl new file mode 100644 index 0000000..ae62319 --- /dev/null +++ b/src/Gui/render.dcl @@ -0,0 +1,23 @@ +definition module render + +import StdIOCommon, StdPicture, StdPSt +import matchControl + +:: RenderStyle = { name :: !String + , look :: !Match -> Look + } + +instance nameOf RenderStyle + +/** allRenderStyles: + enumerates all present rendering styles. +*/ +allRenderStyles :: [RenderStyle] + +/** renderAttributes + yields the attributes required by the rendering functions to accurately draw a match. +*/ +renderAttributes :: !*env -> (![PenAttribute],!*env) | accScreenPicture env + +WestColour :: Colour +EastColour :: Colour diff --git a/src/Gui/render.icl b/src/Gui/render.icl new file mode 100644 index 0000000..f523d9d --- /dev/null +++ b/src/Gui/render.icl @@ -0,0 +1,31 @@ +implementation module render + +import StdIOCommon, StdPicture, StdPSt +import matchControl +import renderGameFlatlandish // the default rendering style +import renderGameFixCamera // 2.5D rendering with fixed camera and angles at south-east + +instance nameOf RenderStyle where nameOf style = style.RenderStyle.name + +allRenderStyles :: [RenderStyle] +allRenderStyles = [ renderFlatland + , renderFixCamera + ] + +green :== RGB {r=30,g=140,b=40} // dark green works better on a beamer +home_colour :== RGB {r=255,g=255,b=70} // yellow works well on dark green background +away_colour :== RGB {r=102,g=255,b=255} + +WestColour :: Colour +WestColour = home_colour + +EastColour :: Colour +EastColour = away_colour + +renderAttributes :: !*env -> (![PenAttribute],!*env) | accScreenPicture env +renderAttributes env = accScreenPicture attributes env +where + attributes :: !*Picture -> (![PenAttribute],!*Picture) + attributes picture + # ((_,font),picture)= openFont SmallFontDef picture + = ([PenBack green,PenFont font],picture) diff --git a/src/Gui/renderGameFixCamera.dcl b/src/Gui/renderGameFixCamera.dcl new file mode 100644 index 0000000..8582719 --- /dev/null +++ b/src/Gui/renderGameFixCamera.dcl @@ -0,0 +1,14 @@ +definition module renderGameFixCamera + +/** This module implements a camera at the south-east corner of the football field. + The field is displayed in an isometric style. + Because a 'pure' isometric projection gives the illusion that the west-edge of the football field + is too wide, a visual correction is added to decrease this effect. +*/ +import render + +/** renderFixCamera + renders a match using an elevated camera at the south-east corner of the football field + and fixed angles. +*/ +renderFixCamera :: RenderStyle diff --git a/src/Gui/renderGameFixCamera.icl b/src/Gui/renderGameFixCamera.icl new file mode 100644 index 0000000..5acc609 --- /dev/null +++ b/src/Gui/renderGameFixCamera.icl @@ -0,0 +1,255 @@ +implementation module renderGameFixCamera + +import Geometry +import render + +renderFixCamera :: RenderStyle +renderFixCamera = { name = "Fixed camera" + , look = fixcamera + } + +fixcamera :: !Match !SelectState !UpdateState !*Picture -> *Picture +fixcamera match=:{theField,theBall,team1,team2} _ updSt=:{newFrame} picture +# picture = setPenColour Black picture +# picture = fill newFrame picture // erase entire background +# picture = setPenColour green picture +# picture = drawField picture // draw the field and outer lines +# picture = drawMiddleArea picture // middle line, circle and spot +# picture = drawGoalAreas picture // goal areas +# picture = drawPenaltyAreas picture // penalty areas +# picture = drawCornerAreas picture // corner areas +# picture = drawGoals picture // goals +# picture = foldr drawPlayer picture sorted_players // players +# picture = drawBall (getFootball theBall (team1 ++ team2)) picture // football += picture +where + {w,h} = rectangleSize newFrame + {fwidth,flength} = theField + ratio = min ((toReal w) / (toReal flength)) ((toReal h) / (toReal fwidth)) + pix x = toInt (ratio * toReal x) // convert metres to pixels + ppix {px,py} = {x = pix px, y = pix py} // convert Position to pixels + (northPole,southPole) = goal_poles theField + fieldfit = min (toReal w / (ratio * (convertToIsoXNormal (toReal flength) 0.0 - convertToIsoXNormal 0.0 (toReal fwidth)))) + (toReal h / (ratio * (convertToIsoYNormal (toReal flength) (toReal fwidth) - convertToIsoYNormal 0.0 0.0))) + north_west = ppix (convertToIso {px = zero, py = zero }) + north_east = ppix (convertToIso {px = flength, py = zero }) + south_east = ppix (convertToIso {px = flength, py = fwidth}) + south_west = ppix (convertToIso {px = zero, py = fwidth}) + sorted_players = let se = {px=scale 0.5 flength, py=scale -0.5 fwidth} + in sortBy (\(_,fb1) (_,fb2) -> dist fb1 se < dist fb2 se) ([(WestColour,fb) \\ fb <- team1] ++ [(EastColour,fb) \\ fb <- team2]) + + drawPlayer :: !(!Colour, !Footballer) !*Picture -> *Picture + drawPlayer (colour, fb=:{playerID ,name,nose=nose_dir,effect,pos=pos`}) picture + # picture = drawName name picture + | perhaps isOnTheGround effect = drawGroundPlayer fb picture + | otherwise = drawStandingPlayer fb picture + where + pos = move_point {dx=scale 0.5 flength, dy=scale 0.5 fwidth} {pos` & py = ~pos`.py} + player_width = m 0.5 + body_circle = circle (pix player_width) + bearing_circle = circle (pix (m 0.3)) + nose_dir_point k = move_point (scale k (convertToIsoVector {dx = m (cosinus nose_dir), dy = m (~(sinus nose_dir))})) (convertToIso pos) + + drawName name picture + # picture = setPenColour White picture + # picture = drawAt (ppix (move_point one (convertToIso pos))) name picture + = picture + + drawGroundPlayer fb=:{length} picture + # (w,picture) = getPenSize picture + # picture = setPenSize (pix player_width + 2) picture + # picture = setPenColour Black picture + # picture = draw (body_line offset) picture + # picture = setPenSize (pix player_width) picture + # picture = setPenColour colour picture + # picture = draw (body_line zero) picture + # picture = setPenSize w picture + # picture = fillAt (ppix (nose_dir_point (toReal length + 0.2))) bearing_circle picture + # picture = setPenColour Black picture + # picture = drawAt (ppix (nose_dir_point (toReal length + 0.2))) bearing_circle picture + = picture + where + offset = {vx = -1, vy = -1} + body_line v = { line_end1 = movePoint v (ppix (convertToIso pos)) + , line_end2 = movePoint v (ppix (nose_dir_point (toReal length))) + } + + drawStandingPlayer fb=:{length} picture + # picture = setPenColour colour picture + # picture = fillAt (ppix (nose_dir_point 1.0)) bearing_circle picture // nose direction + # picture = foldr (uncurry fillAt) picture playerCorpus + # picture = setPenColour Black picture + # picture = drawAt (ppix (nose_dir_point 1.0)) bearing_circle picture // surrounding circle + # picture = foldr (uncurry drawAt) picture playerCorpus + = picture + where + player_width` = toReal player_width + length` = pix length + (up,down) = ({vx = 0, vy = ~length`}, {vx = 0,vy = length`}) + playerCorpus = [(ptl,{polygon_shape = [up,{vx = ptr.x-ptl.x, vy = ptr.y-ptl.y},down]}) + ,(pbl,{polygon_shape = [up,{vx = pbr.x-pbl.x, vy = pbr.y-pbl.y},down]}) + ,(pbr,{polygon_shape = [up,{vx = ptr.x-pbr.x, vy = ptr.y-pbr.y},down]}) + ,(pbl,{polygon_shape = [up,{vx = ptl.x-pbl.x, vy = ptl.y-pbl.y},down]}) + ] + playerRadius = m (sqrt (player_width` * player_width` + player_width` * player_width`)) + add_angle a = let c = cosinus (a + nose_dir) + s = sinus (a + nose_dir) + in ppix (convertToIso (move_point {dx = scale c playerRadius, dy = scale s playerRadius} pos)) + ptr = add_angle (rad (0.25*pi)) + ptl = add_angle (rad (0.75*pi)) + pbl = add_angle (rad (1.25*pi)) + pbr = add_angle (rad (1.75*pi)) + + drawMiddleArea :: !*Picture -> *Picture + drawMiddleArea picture + # picture = drawLine {x = (north_west.x+north_east.x)/2, y = (north_west.y+north_east.y)/2} + {x = (south_west.x+south_east.x)/2, y = (south_west.y+south_east.y)/2} picture // middle line + # picture = drawAt center (circle (pix (scale fieldfit radius_centre_spot))) picture // centre spot + # picture = drawAt centerRadius {polygon_shape = circle_vs} picture // centre circle + = picture + where + center = {x = sum [north_west.x,north_east.x,south_west.x,south_east.x] / 4 + ,y = sum [north_west.y,north_east.y,south_west.y,south_east.y] / 4 + } + centerRadius = ppix (convertToIso {px = scale 0.5 flength, py = scale 0.5 fwidth - radius_centre_circle}) // centre circle starting location for drawing + start = {px=radius_centre_circle, py=zero} // starting location for generating circle points + circle_vs = circle_shape radius_centre_circle (rad (0.025*pi)) (rad (2.0*pi)) start zero [] + + drawGoals :: !*Picture -> *Picture + drawGoals picture + # picture = drawLine (ppix ne) (ppix (addGoalHeight ne)) picture // east north pole + # picture = drawLine (ppix se) (ppix (addGoalHeight se)) picture // east south pole + # picture = drawLine (ppix (addGoalHeight ne)) (ppix (addGoalHeight se)) picture // east pole connect + # picture = drawLine (ppix nw) (ppix (addGoalHeight nw)) picture // west north pole + # picture = drawLine (ppix sw) (ppix (addGoalHeight sw)) picture // west south pole + # picture = drawLine (ppix (addGoalHeight nw)) (ppix (addGoalHeight sw)) picture // west pole connect + = picture + where + addGoalHeight p = move_point {zero & dy = ~goal_height} p + nw = convertToIso {px = zero, py = northPole + scale 0.5 fwidth} + sw = convertToIso {px = zero, py = southPole + scale 0.5 fwidth} + ne = convertToIso {px = flength, py = northPole + scale 0.5 fwidth} + se = convertToIso {px = flength, py = southPole + scale 0.5 fwidth} + + drawField :: !*Picture -> *Picture + drawField picture + # picture = fillAt north_west field_shape picture //field + # picture = setPenColour White picture + # picture = drawAt north_west field_shape picture //outline + = picture + where + field_shape = {polygon_shape = [{vx = north_east.x-north_west.x, vy = north_east.y-north_west.y} + ,{vx = south_east.x-north_east.x, vy = south_east.y-north_east.y} + ,{vx = south_west.x-south_east.x, vy = south_west.y-south_east.y} + ] + } + + drawBall :: !Football !*Picture -> *Picture + drawBall football picture + # picture = setPenColour ball_colour picture + # picture = drawAt (ppix ballPosition) ball picture // ball shadow + # picture = fillAt (ppix elevation) ball picture // ball + # picture = setPenColour White picture + # picture = drawAt (ppix elevation) ball picture // ball-line + = picture + where + groundPos` = football.ballPos.pxy + groundPos = {groundPos` & py = ~groundPos`.py} + ballPosition = convertToIso (move_point {dx=scale 0.5 flength,dy=scale 0.5 fwidth} groundPos) + elevation = move_point {zero & dy=scale (~fieldfit) football.ballPos.pz} ballPosition + ball = circle (pix (scale 2.8 radius_football)) + + drawGoalAreas :: !*Picture -> *Picture + drawGoalAreas picture + # picture = drawLine (ppix (convertToIso {px = flength,py = y_north})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east north edge + # picture = drawLine (ppix (convertToIso {px = flength,py = y_south})) (ppix (convertToIso {px = x_east, py = y_south})) picture // east south edge + # picture = drawLine (ppix (convertToIso {px = x_east, py = y_south})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east edge + # picture = drawLine (ppix (convertToIso {px = zero, py = y_north})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west north edge + # picture = drawLine (ppix (convertToIso {px = zero, py = y_south})) (ppix (convertToIso {px = x_west, py = y_south})) picture // west south edge + # picture = drawLine (ppix (convertToIso {px = x_west, py = y_south})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west edge + = picture + where + (y_north,y_south) = (scale 0.5 fwidth + goal_area_depth + northPole, scale 0.5 fwidth + southPole - goal_area_depth) + (x_west, x_east) = (goal_area_depth, flength - goal_area_depth) + + drawPenaltyAreas :: !*Picture -> *Picture + drawPenaltyAreas picture + # picture = drawLine (ppix (convertToIso {px = flength,py = y_north})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east north edge + # picture = drawLine (ppix (convertToIso {px = flength,py = y_south})) (ppix (convertToIso {px = x_east, py = y_south})) picture // east south edge + # picture = drawLine (ppix (convertToIso {px = x_east, py = y_south})) (ppix (convertToIso {px = x_east, py = y_north})) picture // east edge + # picture = drawLine (ppix (convertToIso {px = zero, py = y_north})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west north edge + # picture = drawLine (ppix (convertToIso {px = zero, py = y_south})) (ppix (convertToIso {px = x_west, py = y_south})) picture // west south edge + # picture = drawLine (ppix (convertToIso {px = x_west, py = y_south})) (ppix (convertToIso {px = x_west, py = y_north})) picture // west edge + # picture = drawAt (ppix east_spotIso) (circle (pix (scale fieldfit radius_penalty_spot))) picture // east penalty spot + # picture = drawAt (ppix (move_point (convertToIsoVector {dx=m (~h_dist),dy=m dyStart}) east_spotIso)) east_curve picture // east curve + # picture = drawAt (ppix west_spotIso) (circle (pix (scale fieldfit radius_penalty_spot))) picture // west penalty spot + # picture = drawAt (ppix (move_point (convertToIsoVector {dx=m h_dist,dy=m (~dyStart)}) west_spotIso)) west_curve picture // west curve + = picture + where + (y_north,y_south) = (northPole + penalty_area_depth + scale 0.5 fwidth, southPole - penalty_area_depth + scale 0.5 fwidth) + (x_west, x_east) = (penalty_area_depth, flength - penalty_area_depth) + angle = arccosinus (h_dist / (toReal radius_penalty_area * fieldfit)) + h_dist = (toReal penalty_area_depth - toReal penalty_spot_depth) * fieldfit + east_spotIso = convertToIso {px = flength - penalty_spot_depth, py = scale 0.5 fwidth} + west_spotIso = convertToIso {px = penalty_spot_depth, py = scale 0.5 fwidth} + circleStartWest = {px = scale (cosinus (angle - rad (0.5*pi))) radius_penalty_area, py = scale (sinus (angle - rad (0.5*pi))) radius_penalty_area} + circleStartEast = {px = scale (cosinus (angle + rad (0.5*pi))) radius_penalty_area, py = scale (sinus (angle + rad (0.5*pi))) radius_penalty_area} + dyStart = sqrt (rpaff * rpaff - h_dist * h_dist) + rpaff = toReal radius_penalty_area * fieldfit + east_curve = {polygon_shape = circle_shape radius_penalty_area (rad (pi/180.0)) (rad (0.5*pi) + angle) circleStartEast (rad (0.5*pi) - angle) []} + west_curve = {polygon_shape = circle_shape radius_penalty_area (rad (pi/180.0)) (angle - rad (0.5*pi)) circleStartWest (~(angle + rad (0.5*pi))) []} + + drawCornerAreas :: !*Picture -> *Picture + drawCornerAreas picture + # picture = drawAt (ppix (convertToIso {px = flength - radius_corner_kick_area, py = fwidth})) (corner (rad (1.0*pi) - a1) (rad (0.0*pi) + a1) True ) picture // east south corner + # picture = drawAt (ppix (convertToIso {px = radius_corner_kick_area, py = zero })) (corner (rad (2.0*pi) - a1) (rad (1.0*pi) + a1) True ) picture // west north corner + # picture = drawAt (ppix (convertToIso {px = radius_corner_kick_area, py = fwidth})) (corner (rad (1.5*pi) + a2) (rad (0.5*pi) - a2) False) picture // west south corner + # picture = drawAt (ppix (convertToIso {px = flength - radius_corner_kick_area, py = zero })) (corner (rad (0.5*pi) + a2) (rad (1.5*pi) - a2) False) picture // east north corner + = picture + where + corner f t c = { curve_oval = circle (pix (scale fieldfit radius_corner_kick_area)) + , curve_from = toReal f + , curve_to = toReal t + , curve_clockwise = c + } + (a1,a2) = (arctangens 0.5, arctangens 2.0) + + circle_shape :: !Metre !Angle !Angle !Position !Angle ![Vector2] -> [Vector2] + circle_shape r i angle base end vs + | angle <= end = reverse vs + | otherwise = circle_shape r i (angle-i) this end [{vx = thisIso.x - baseIso.x, vy = baseIso.y - thisIso.y} : vs] + where + this = {px = scale (cosinus angle) r, py = scale (sinus angle) r} + thisIso = ppix (convertToIsoNormal this) + baseIso = ppix (convertToIsoNormal base) + + convertToIsoNormal {px,py} = {px = scale fieldfit (px - py + fwidth), py = scale (0.5*fieldfit) (px + py)} + + convertToIso :: !Position -> Position + convertToIso pos = { px = scale fieldfit (pos.px - yScaled pos + fwidth) + , py = scale (0.5*fieldfit) (pos.px + yScaled pos) + } + + yScaled :: !Position -> Metre + yScaled pos=:{px, py} + | py <= scale 0.5 fwidth = py + scale yscale d + | otherwise = py - scale yscale d + where + yscale = (1.0 - (toReal px)/(toReal flength)) / factor + d = abs (py - scale 0.5 fwidth) + factor = 8.0 + + convertToIsoVector :: !RVector -> RVector + convertToIsoVector {dx,dy} = {dx = dx - dy, dy = scale 0.5 (dx+dy)} + + convertToIsoXNormal :: !Real !Real -> Real + convertToIsoXNormal x y = x - y + + convertToIsoYNormal :: !Real !Real -> Real + convertToIsoYNormal x y = (x + y) / 2.0 + +green :== RGB {r=30,g=140,b=40} // dark green works better on a beamer +black :== Black // black +ball_colour :== Black + +circle r :== {oval_rx=r,oval_ry=r} diff --git a/src/Gui/renderGameFlatlandish.dcl b/src/Gui/renderGameFlatlandish.dcl new file mode 100644 index 0000000..46afd27 --- /dev/null +++ b/src/Gui/renderGameFlatlandish.dcl @@ -0,0 +1,13 @@ +definition module renderGameFlatlandish + +/** Render a football match in Flatland-style: + the camera hovers above the center of the football field and everything is displayed in a + deliberately simplistic manner. +*/ +import StdIOCommon, StdPSt +import matchControl, render + +/** renderFlatland + renders a complete match in Flatland style. +*/ +renderFlatland :: RenderStyle diff --git a/src/Gui/renderGameFlatlandish.icl b/src/Gui/renderGameFlatlandish.icl new file mode 100644 index 0000000..6f9e6e2 --- /dev/null +++ b/src/Gui/renderGameFlatlandish.icl @@ -0,0 +1,168 @@ +implementation module renderGameFlatlandish + +import matchControl, render +import StdIOCommon, StdPSt + +renderFlatland :: RenderStyle +renderFlatland = { name = "Flatland" + , look = flatland + } + +/** flatland match updSt + renders a complete match, given the current dimensions of the drawing environment (updSt). +*/ +flatland :: !Match !SelectState !UpdateState !*Picture -> *Picture +flatland match=:{theField,theBall,team1,team2} _ updSt=:{newFrame} picture +# picture = setPenColour Black picture +# picture = fill {corner1={x=pixl,y=zero},corner2={x=w,y=pixw}} picture // exterior right +# picture = fill {corner1={x=zero,y=pixw},corner2={x=w,y=h}} picture // exterior bottom +# picture = unfill field_rectangle picture // football field +# picture = setPenColour White picture +# picture = draw field_rectangle picture // field outline +# picture = drawMiddleArea picture // middle line, circle and spot +# picture = drawGoals picture // goals +# picture = drawGoalAreas picture // goal areas +# picture = drawPenaltyAreas picture // penalty areas +# picture = drawCornerAreas picture // corner areas +# picture = foldr (drawPlayer WestColour) picture team1 // team1 players +# picture = foldr (drawPlayer EastColour) picture team2 // team2 players +# picture = drawBall (getFootball theBall (team1 ++ team2)) picture // football += picture +where + {w,h} = rectangleSize newFrame + {fwidth,flength} = theField + field_rectangle = {corner1=ppix {px=scale -0.5 flength,py=scale 0.5 fwidth}, corner2=ppix {px=scale 0.5 flength,py=scale -0.5 fwidth}} + ratio = min ((toReal w) / (toReal flength)) ((toReal h) / (toReal fwidth)) + pixw = pix fwidth + pixl = pix flength + pix x = toInt (ratio * toReal x) + pixx x = pixl / 2 + pix x // convert metres to pixels + pixy y = pixw / 2 - pix y + ppix {px,py} = {x = pixx px, y = pixy py} // convert Position to pixels + vpix {dx,dy} = {vx = pix dx, vy = pix dy} // convert RVector to pixels + (northPole,southPole) = goal_poles theField + + drawPlayer :: !Colour !Footballer !*Picture -> *Picture + drawPlayer colour fb=:{name,nose=nose_dir,effect,pos} picture + # picture = drawName name picture + | perhaps isOnTheGround effect + = drawLyingPlayer fb picture + | otherwise = drawStandingPlayer fb picture + where + player_width = m 0.5 + body_circle = circle (pix player_width) + bearing_circle = circle (pix (m 0.3)) + nose_dir_vector = {dx = m (cosinus nose_dir), dy = m (sinus nose_dir) } + offset = {vx = -1, vy = -1} + nose_dir_point k = move_point (scale k nose_dir_vector) pos + + drawName name picture + # picture = setPenColour White picture + # picture = drawAt (ppix (move_point one pos)) name picture + = picture + + drawLyingPlayer fb=:{length} picture + # (w,picture) = getPenSize picture + # picture = setPenSize (pix player_width+2) picture + # picture = setPenColour Black picture + # picture = draw (body_line offset) picture + # picture = setPenSize (pix player_width) picture + # picture = setPenColour colour picture + # picture = draw (body_line zero) picture + # picture = setPenSize w picture + # picture = fillAt (ppix (nose_dir_point (toReal length+0.2))) bearing_circle picture + # picture = setPenColour Black picture + # picture = drawAt (ppix (nose_dir_point (toReal length+0.2))) bearing_circle picture + = picture + where + body_line v = { line_end1 = movePoint v (ppix pos) + , line_end2 = movePoint v (ppix (nose_dir_point (toReal length))) + } + + drawStandingPlayer fb picture + # picture = setPenColour colour picture + # picture = fillAt (ppix pos) body_circle picture // body + # picture = fillAt (ppix (nose_dir_point 1.0)) bearing_circle picture // nose direction + # picture = setPenColour Black picture // surrounding circle + # picture = drawAt (ppix pos) body_circle picture + # picture = drawAt (ppix (nose_dir_point 1.0)) bearing_circle picture // nose direction + = picture + + drawMiddleArea :: !*Picture -> *Picture + drawMiddleArea picture + # picture = drawLine (ppix {zero & py = scale 0.5 fwidth}) (ppix {zero & py = scale -0.5 fwidth}) picture + # picture = drawAt (ppix zero) (circle (pix radius_centre_circle)) picture // middle area + # picture = drawAt (ppix zero) (circle (pix radius_centre_spot)) picture // center spot + = picture + + drawGoals :: !*Picture -> *Picture + drawGoals picture + # picture = drawAt (ppix {px=scale 0.5 flength-goal_indent,py=northPole}) h_vector picture // east north pole + # picture = drawAt (ppix {px=scale 0.5 flength-goal_indent,py=southPole}) h_vector picture // east south pole + # picture = drawAt (ppix {px=scale -0.5 flength, py=northPole}) h_vector picture // west north pole + # picture = drawAt (ppix {px=scale -0.5 flength, py=southPole}) h_vector picture // west south pole + = picture + where + goal_indent = m 1.0 + h_vector = vpix {zero & dx=goal_indent} + + drawGoalAreas :: !*Picture -> *Picture + drawGoalAreas picture + # picture = drawAt (ppix {px=scale 0.5 flength-goal_area_depth, py=northPole+goal_area_depth}) h_vector picture // east north edge + # picture = drawAt (ppix {px=scale 0.5 flength-goal_area_depth, py=southPole-goal_area_depth}) h_vector picture // east south edge + # picture = drawAt (ppix {px=scale 0.5 flength-goal_area_depth, py=northPole+goal_area_depth}) v_vector picture // east edge + # picture = drawAt (ppix {px=scale -0.5 flength, py=northPole+goal_area_depth}) h_vector picture // west north edge + # picture = drawAt (ppix {px=scale -0.5 flength, py=southPole-goal_area_depth}) h_vector picture // west south edge + # picture = drawAt (ppix {px=scale -0.5 flength + goal_area_depth,py=northPole+goal_area_depth}) v_vector picture // west edge + = picture + where + h_vector = vpix {zero & dx=goal_area_depth} + v_vector = vpix {zero & dy=scale 2.0 goal_area_depth + goal_width} + + drawPenaltyAreas :: !*Picture -> *Picture + drawPenaltyAreas picture + # picture = drawAt (ppix {px=scale 0.5 flength-penalty_area_depth,py=northPole+penalty_area_depth}) h_vector picture // east north edge + # picture = drawAt (ppix {px=scale 0.5 flength-penalty_area_depth,py=southPole-penalty_area_depth}) h_vector picture // east south edge + # picture = drawAt (ppix {px=scale 0.5 flength-penalty_area_depth,py=northPole+penalty_area_depth}) v_vector picture // east edge + # picture = drawAt (ppix east_spot) (circle (pix radius_penalty_spot)) picture // east penalty spot + # picture = drawAt (ppix (move_point {dx= ~h_dist,dy= scale (~(sinus angle)) radius_penalty_area} east_spot)) // east curve + {curve_oval = circle (pix radius_penalty_area) + ,curve_from = pi + angle + ,curve_to = pi - angle + ,curve_clockwise = True } picture + # picture = drawAt (ppix {px=scale -0.5 flength, py=northPole+penalty_area_depth}) h_vector picture // west north edge + # picture = drawAt (ppix {px=scale -0.5 flength, py=southPole-penalty_area_depth}) h_vector picture // west south edge + # picture = drawAt (ppix {px=scale -0.5 flength + penalty_area_depth,py=northPole+penalty_area_depth}) v_vector picture // west edge + # picture = drawAt (ppix west_spot) (circle (pix radius_penalty_spot)) picture // west penalty spot + # picture = drawAt (ppix (move_point {dx=h_dist,dy= scale (~(sinus angle)) radius_penalty_area} west_spot)) // west curve + {curve_oval = circle (pix radius_penalty_area) + ,curve_from = ~angle + ,curve_to = angle + ,curve_clockwise = False } picture + = picture + where + h_vector = vpix {zero & dx=penalty_area_depth} + v_vector = vpix {zero & dy=scale 2.0 penalty_area_depth + goal_width} + angle = arccosinus ((toReal h_dist)/(toReal radius_penalty_area)) + h_dist = penalty_area_depth - penalty_spot_depth + east_spot = {zero & px=scale 0.5 flength - penalty_spot_depth} + west_spot = {zero & px=scale -0.5 flength + penalty_spot_depth} + + drawCornerAreas :: !*Picture -> *Picture + drawCornerAreas picture + # picture = drawAt (ppix {px=scale -0.5 flength + radius_corner_kick_area,py=scale 0.5 fwidth}) (corner 0.0 (1.5*pi) True ) picture // west north corner + # picture = drawAt (ppix {px=scale -0.5 flength + radius_corner_kick_area,py=scale -0.5 fwidth}) (corner 0.0 (0.5*pi) False) picture // west south corner + # picture = drawAt (ppix {px=scale 0.5 flength - radius_corner_kick_area,py=scale 0.5 fwidth}) (corner pi (1.5*pi) False) picture // east north corner + # picture = drawAt (ppix {px=scale 0.5 flength - radius_corner_kick_area,py=scale -0.5 fwidth}) (corner pi (0.5*pi) True ) picture // east south corner + = picture + where + corner f t c = {curve_oval=circle (pix radius_corner_kick_area),curve_from=f,curve_to=t,curve_clockwise=c} + + drawBall :: !Football !*Picture -> *Picture + drawBall ball picture + # picture = setPenColour ball_colour picture + # picture = fillAt (ppix ball.ballPos.pxy) (circle (pix (scale (2.8*toReal radius_football) (m 1.0 + scale 0.2 ball.ballPos.pz)))) picture + = picture + +ball_colour :== Black +circle r :== {oval_rx=r,oval_ry=r} diff --git a/src/Gui/textdisplay.dcl b/src/Gui/textdisplay.dcl new file mode 100644 index 0000000..d30b876 --- /dev/null +++ b/src/Gui/textdisplay.dcl @@ -0,0 +1,31 @@ +definition module textdisplay + +import StdControl, StdId + +/** A TextDisplay is similar to a TextControl. A TextControl displays text using + system settings. A TextDisplay uses the ControlPen attribute to display text. + In addition, the ControlSize can be set by the programmer. + The following ControlAttribute-s are inherited: + ControlMinimumSize: the minimum size of the control in case of resizing + ControlPen: the pen settings used to display the text + ControlPos: the layout position of the text display control + ControlResize: resizing the control + ControlTip: the tool tip text that must be displayed +*/ +:: TextDisplay ls pst + = TextDisplay TextDisplayId String TextSize [ControlAttribute *(ls,pst)] +:: TextDisplayId + = { customId :: !Id + , receiverId :: !R2Id TextDisplayMsgIn TextDisplayMsgOut + } +:: TextDisplayMsgIn = SetTextIn String | GetTextIn +:: TextDisplayMsgOut = SetTextOut | GetTextOut String + +:: TextSize :== Size // The size of the text display + +openTextDisplayId :: !*env -> (!TextDisplayId,!*env) | Ids env + +instance Controls TextDisplay + +getTextDisplayText :: !TextDisplayId !(PSt .ps) -> (!String,!PSt .ps) +setTextDisplayText :: !TextDisplayId !String !(PSt .ps) -> PSt .ps diff --git a/src/Gui/textdisplay.icl b/src/Gui/textdisplay.icl new file mode 100644 index 0000000..494092f --- /dev/null +++ b/src/Gui/textdisplay.icl @@ -0,0 +1,107 @@ +implementation module textdisplay + +import StdInt, StdList, StdMisc +import StdControl, StdControlAttribute, StdControlReceiver, StdId, StdPSt, StdReceiver + +/** A TextDisplay is similar to a TextControl. A TextControl displays text using + system settings. A TextDisplay uses the ControlPen attribute to display text. + In addition, the ControlSize can be set by the programmer. + The following ControlAttribute-s are inherited: + ControlMinimumSize: the minimum size of the control in case of resizing + ControlPen: the pen settings used to display the text + ControlPos: the layout position of the text display control + ControlResize: resizing the control + ControlTip: the tool tip text that must be displayed +*/ +:: TextDisplay ls pst + = TextDisplay TextDisplayId String TextSize [ControlAttribute *(ls,pst)] +:: TextDisplayId + = { customId :: !Id + , receiverId :: !R2Id TextDisplayMsgIn TextDisplayMsgOut + } +:: TextSize :== Size // The size of the text display +:: TextDisplayMsgIn = SetTextIn String | GetTextIn +:: TextDisplayMsgOut = SetTextOut | GetTextOut String + +openTextDisplayId :: !*env -> (!TextDisplayId,!*env) | Ids env +openTextDisplayId env + # (id, env) = openId env + # (r2id,env) = openR2Id env + = ({customId=id,receiverId=r2id},env) + +:: TextDisplaySt + = { text :: !String // The text to be displayed + } + +instance Controls TextDisplay where + controlToHandles (TextDisplay {customId,receiverId} text size atts) pst + = controlToHandles textdisplay pst + where + customControlSize = validateTextDisplaySize minSize size + initDisplaySt = { text = text + } + textdisplay = { newLS = initDisplaySt + , newDef = CustomControl customControlSize (displaylook text) [ ControlId customId : okAtts ] + :+: + Receiver2 receiverId receiverfun [] + } + okAtts = map toTextDisplayAttribute (filter isTextDisplayAttribute atts) + minSize = case filter isControlMinimumSize okAtts of + [ControlMinimumSize s : _] -> s + _ -> zero + + receiverfun :: !TextDisplayMsgIn !*(TextDisplaySt,PSt .ps) -> (TextDisplayMsgOut,(TextDisplaySt,PSt .ps)) + receiverfun (SetTextIn str) (tdst,pst=:{io}) + # tdst = {tdst & text = str} + # io = setControlLook customId True (True,displaylook str) io + = (SetTextOut,(tdst,{pst & io=io})) + receiverfun GetTextIn (tdst=:{text},pst) + = (GetTextOut text,(tdst,pst)) + + displaylook :: !String !SelectState !UpdateState !*Picture -> *Picture + displaylook text _ {newFrame} picture + # picture = unfill newFrame picture + # (metrics,picture) = getPenFontMetrics picture + # base = metrics.fAscent + metrics.fLeading + # height = fontLineHeight metrics + # (width,picture) = getPenFontStringWidth text picture + # picture = drawAt {x=max 0 ((w-width)/2),y=(h-height)/2+base} text picture + = picture + where + {w,h} = rectangleSize newFrame + + getControlType _ = "TextDisplay" + +isTextDisplayAttribute :: !(ControlAttribute .ps) -> Bool +isTextDisplayAttribute (ControlMinimumSize _) = True +isTextDisplayAttribute (ControlPen _) = True +isTextDisplayAttribute (ControlPos _) = True +isTextDisplayAttribute (ControlResize _) = True +isTextDisplayAttribute (ControlTip _) = True +isTextDisplayAttribute _ = False + +toTextDisplayAttribute :: !(ControlAttribute *(.ls,.pst)) -> ControlAttribute *(TextDisplaySt,.pst) +toTextDisplayAttribute (ControlMinimumSize s) = ControlMinimumSize s +toTextDisplayAttribute (ControlPen p) = ControlPen p +toTextDisplayAttribute (ControlPos p) = ControlPos p +toTextDisplayAttribute (ControlResize f) = ControlResize f +toTextDisplayAttribute (ControlTip t) = ControlTip t + + +validateTextDisplaySize :: !Size !Size -> Size +validateTextDisplaySize minSize {w,h} = {w=max w (min 0 minSize.w),h=max h (min 0 minSize.h)} + +getTextDisplayText :: !TextDisplayId !(PSt .ps) -> (!String,!PSt .ps) +getTextDisplayText {receiverId} pst + = case syncSend2 receiverId GetTextIn pst of + ((SendOk,Just (GetTextOut x)),pst) -> (x,pst) + other -> sendError "getTextDisplayText" + +setTextDisplayText :: !TextDisplayId !String !(PSt .ps) -> PSt .ps +setTextDisplayText {receiverId} newTxt pst + = case syncSend2 receiverId (SetTextIn newTxt) pst of + ((SendOk,Just SetTextOut),pst) -> pst + other -> sendError "setTextDisplayText" + +sendError fName + = abort (fName +++ ": wrong reply from TextDisplay.\n") diff --git a/src/SoccerFun.env b/src/SoccerFun.env new file mode 100644 index 0000000..ca5338e --- /dev/null +++ b/src/SoccerFun.env @@ -0,0 +1,27 @@ +Version: 1.0 +Environments + Environment + EnvironmentName: SoccerFun + EnvironmentPaths + Path: {Application}\Libraries\StdEnv + Path: {Application}\Libraries\StdLib + Path: {Application}\Libraries\ObjectIO + Path: {Application}\Libraries\ObjectIO\OS Windows + Path: {Application}\Libraries\Parsers + Path: {Application}\Libraries\Parsers\LanguageDependent + Path: {Application}\Libraries\Parsers\LanguageDependent\English + Path: {Application}\Examples\ObjectIO Examples\gui utilities + Path: {Application}\Examples\SoccerFun\src\Game + Path: {Application}\Examples\SoccerFun\src\Gui + Path: {Application}\Examples\SoccerFun\src\StdLibExt + Path: {Application}\Examples\SoccerFun\src\StdReferee + Path: {Application}\Examples\SoccerFun\src\StdTeam + EnvironmentCompiler: Tools\Clean System\CleanCompiler.exe + EnvironmentCodeGen: Tools\Clean System\CodeGenerator.exe + EnvironmentLinker: Tools\Clean System\StaticLinker.exe: -h 40M + EnvironmentDynLink: Tools\Dynamics\DynamicLinker.exe + EnvironmentVersion: 920 + EnvironmentRedirect: False + EnvironmentCompileMethod: Pers + EnvironmentProcessor: I386 + Environment64BitProcessor: False diff --git a/src/SoccerFun.icl b/src/SoccerFun.icl new file mode 100644 index 0000000..85de8fa --- /dev/null +++ b/src/SoccerFun.icl @@ -0,0 +1,10 @@ +module SoccerFun + +/** The main module for Soccer-Fun. +*/ +import matchControl + +/** Function to start SoccerFun. +*/ +Start :: *World -> *World +Start world = doSoccerFun world diff --git a/src/SoccerFun.prj b/src/SoccerFun.prj new file mode 100644 index 0000000..464dc9e --- /dev/null +++ b/src/SoccerFun.prj @@ -0,0 +1,3027 @@ +Version: 1.4 +Global + ProjectRoot: . + Built: True + Target: SoccerFun64 + Exec: {Project}\SoccerFun.exe + CodeGen + CheckStacks: False + CheckIndexes: True + Application + HeapSize: 2097152 + StackSize: 512000 + ExtraMemory: 81920 + IntialHeapSize: 204800 + HeapSizeMultiplier: 4096 + ShowExecutionTime: False + ShowGC: False + ShowStackSize: False + MarkingCollector: False + StandardRuntimeEnv: True + Profile + Memory: False + MemoryMinimumHeapSize: 0 + Time: False + Stack: False + Output + Output: ShowConstructors + Font: Courier + FontSize: 9 + WriteStdErr: False + Link + LinkMethod: Static + GenerateRelocations: False + GenerateLinkMap: False + LinkResources: False + ResourceSource: + GenerateDLL: False + ExportedNames: + Paths + Path: {Project} + Path: {Project}\Achten Peter + Precompile: + Postlink: +MainModule + Name: SoccerFun + Dir: {Project} + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False +OtherModules + Module + Name: StdBitmap + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdClipboard + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdControl + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdControlAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdControlClass + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdControlDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdControlReceiver + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdFileSelect + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdIO + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdIOBasic + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdIOCommon + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdId + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdKey + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenu + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenuAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenuDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenuElement + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenuElementClass + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMenuReceiver + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPSt + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPStClass + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPicture + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPictureDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPrint + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdPrintText + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdProcess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdProcessAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdProcessDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdReceiver + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdReceiverAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdReceiverDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdSystem + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTime + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTimer + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTimerAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTimerDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTimerElementClass + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTimerReceiver + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdWindow + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdWindowAttribute + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdWindowDef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: cast + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: commondef + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlcreate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controldraw + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlinternal + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controllayout + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlpos + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlrelayout + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlresize + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: controlvalidate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: device + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: deviceevents + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: devicefunctions + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: devicesystemstate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: id + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: iostate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: keyfocus + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: layout + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menucreate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menudefaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menudevice + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuhandle + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuinternal + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuitems + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: mstate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: processdevice + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: processhandle + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: processstack + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiveraccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiverdefaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiverdevice + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiverhandle + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiverid + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receivermessage + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receivertable + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: relayout + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: roundrobin + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: scheduler + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: sdisize + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: semidynamic + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: systemid + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timeraccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timerdefaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timerdevice + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timerhandle + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timertable + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: toolbar + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowclipstate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowcontrols + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowcreate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowdevice + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowdispose + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowdraw + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowhandle + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowupdate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowvalidate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: world + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: wstate + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: wstateaccess + Dir: {Application}\Libraries\ObjectIO + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: clCCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: util_121. + ObjectFile: cpicture_121. + ObjectFile: cdebug_121. + ObjectFile: cCrossCall_121. + ObjectFile: cCrossCallWindows_121. + ObjectFile: cCCallWindows_121. + ObjectFile: cCCallSystem_121. + Module + Name: clCrossCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallWindows_121. + ObjectFile: cCrossCallProcedureTable_121. + ObjectFile: cCrossCallCursor_121. + ObjectFile: cCrossCall_121. + ObjectFile: cCCallSystem_121. + ObjectFile: cCCallWindows_121. + ObjectFile: cAcceleratorTable_121. + NeededLibraries + Library: userExt_library + Library: gdiExt_library + Library: kernelExt_library + Library: winspool_library + Library: winmm_library + Library: shell32_library + Library: ole32_library + Library: kernel32_library + Library: comctl32_library + Library: advapi32_library + Module + Name: clipboardCrossCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallClipboard_121. + Module + Name: menuCCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallMenus_121. + Module + Name: menuCrossCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: menuwindowmenu + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osactivaterequests + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osbeep + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osbitmap + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osclipboard + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osdocumentinterface + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallxDI_121. + Module + Name: osevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osfileselect + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallFileSelectors_121. + Module + Name: osfont + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osguishare + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: oskey + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osmenu + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osmouse + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ospicture + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: osprint + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cprinter_121. + ObjectFile: cCrossCallPrinter_121. + Module + Name: osrgn + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ossystem + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ostick + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ostime + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ostoolbar + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ostoolbox + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cCrossCallFont_121. + Module + Name: ostooltip + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ostypes + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: oswindow + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: pictCCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: processevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: receiverevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: rgnCCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: timerevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowCCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + NeededObjFiles + ObjectFile: cpicture_121. + ObjectFile: cCCallWindows_121. + Module + Name: windowCrossCall_12 + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: windowevent + Dir: {Application}\Libraries\ObjectIO\OS Windows + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Parsers + Dir: {Application}\Libraries\Parsers + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ParsersAccessories + Dir: {Application}\Libraries\Parsers + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ParsersDerived + Dir: {Application}\Libraries\Parsers + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ParsersKernel + Dir: {Application}\Libraries\Parsers + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: ParserLanguage + Dir: {Application}\Libraries\Parsers\LanguageDependent\Nederlands + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdArray + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdBool + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdChar + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdCharList + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdClass + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdDebug + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdEnum + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdEnv + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdFile + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdFunc + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdInt + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdList + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMisc + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdOrdList + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdOverloaded + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdReal + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdString + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdTuple + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: _SystemArray + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: _SystemEnum + Dir: {Application}\Libraries\StdEnv + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdLibMisc + Dir: {Application}\Libraries\StdLib + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdMaybe + Dir: {Application}\Libraries\StdLib + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Football + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Footballer + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: FootballerFunctions + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: GamePicture + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Geometry + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Referee + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: matchControl + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: matchGame + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: matchLog + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: randomstream + Dir: {Project}\Game + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Gui2D + Dir: {Project}\Gui + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: digitdisplay + Dir: {Project}\Gui + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: guiInterface + Dir: {Project}\Gui + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: renderGame + Dir: {Project}\Gui + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: textdisplay + Dir: {Project}\Gui + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RandomExt + Dir: {Project}\StdLibExt + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RangeSlider + Dir: {Project}\StdLibExt + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdEnvExt + Dir: {Project}\StdLibExt + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: StdIOExt + Dir: {Project}\StdLibExt + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: fileIO + Dir: {Project}\StdLibExt + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Ivanov + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeCoach_DeepPass_Assignment + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeCoach_Keeper_Assignment + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeCoach_Passing_Assignment + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeCoach_Rounds_Assignment + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeCoach_Slalom_Assignment + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: RefereeFunctions + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Umpire + Dir: {Project}\StdReferee + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Buffer + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: KeeperChallenger + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: TeamMiniEffie + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Opponent_DeepPass_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Opponent_Keeper_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Opponent_Passing_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Opponent_Slalom_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Student_DeepPass_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Student_Keeper_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Student_Passing_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Student_Rounds_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False + Module + Name: Team_Student_Slalom_Assignment + Dir: {Project}\StdTeam + Compiler + NeverMemoryProfile: False + NeverTimeProfile: False + StrictnessAnalysis: True + ListTypes: StrictExportTypes + ListAttributes: True + Warnings: True + Verbose: True + ReadableABC: False + ReuseUniqueNodes: True + Fusion: False diff --git a/src/SoccerFun64.env b/src/SoccerFun64.env new file mode 100644 index 0000000..4fdbb12 --- /dev/null +++ b/src/SoccerFun64.env @@ -0,0 +1,27 @@ +Version: 1.0 +Environments + Environment + EnvironmentName: SoccerFun64 + EnvironmentPaths + Path: {Application}\Libraries\StdEnv + Path: {Application}\Libraries\StdLib + Path: {Application}\Libraries\ObjectIO + Path: {Application}\Libraries\ObjectIO\OS Windows + Path: {Application}\Libraries\Parsers + Path: {Application}\Libraries\Parsers\LanguageDependent + Path: {Application}\Libraries\Parsers\LanguageDependent\English + Path: {Application}\Examples\ObjectIO Examples\gui utilities + Path: {Application}\Examples\SoccerFun\src\Game + Path: {Application}\Examples\SoccerFun\src\Gui + Path: {Application}\Examples\SoccerFun\src\StdLibExt + Path: {Application}\Examples\SoccerFun\src\StdReferee + Path: {Application}\Examples\SoccerFun\src\StdTeam + EnvironmentCompiler: Tools\Clean System 64\CleanCompiler64.exe + EnvironmentCodeGen: Tools\Clean System 64\CodeGenerator.exe + EnvironmentLinker: Tools\Clean System 64\StaticLinker.exe: -h 40M + EnvironmentDynLink: Tools\Dynamics\DynamicLinker.exe + EnvironmentVersion: 920 + EnvironmentRedirect: False + EnvironmentCompileMethod: Pers + EnvironmentProcessor: I386 + Environment64BitProcessor: True diff --git a/src/SoccerFun_options.txt b/src/SoccerFun_options.txt new file mode 100644 index 0000000..787224a --- /dev/null +++ b/src/SoccerFun_options.txt @@ -0,0 +1 @@ +{closeReferee=True,showSplash=False,displaySpeed=Normal,showReferee=True,playingTime=4:00 min,renderStyle=Fixed camera} \ No newline at end of file diff --git a/src/StdLibExt/RandomExt.dcl b/src/StdLibExt/RandomExt.dcl new file mode 100644 index 0000000..5b19fac --- /dev/null +++ b/src/StdLibExt/RandomExt.dcl @@ -0,0 +1,28 @@ +definition module RandomExt + +// ************************************************************************************************** +// +// General utility for random number generation. +// +// This module is actually an extension of the Random module in the 'Object IO Examples:gui utilities' +// folder. That module lacked instances of the usual overloaded functions. +// +// ************************************************************************************************** + +import StdTime +import StdClass + +:: RandomSeed + +nullRandomSeed :: RandomSeed +// nullRandomSeed generates a useless RandomSeed (random nullRandomSeed = (0,nullRandomSeed)). + +getNewRandomSeed:: !*env -> (!RandomSeed, !*env) | TimeEnv env +// GetNewRandomSeed generates a useful RandomSeed, using the current time. + +random :: !RandomSeed -> (!Int, !RandomSeed) +// Given a RandomSeed, Random generates a random number and a new RandomSeed. + +instance toString RandomSeed +instance fromString RandomSeed +instance == RandomSeed diff --git a/src/StdLibExt/RandomExt.icl b/src/StdLibExt/RandomExt.icl new file mode 100644 index 0000000..1ed4f58 --- /dev/null +++ b/src/StdLibExt/RandomExt.icl @@ -0,0 +1,30 @@ +implementation module RandomExt + +import StdEnvExt +import StdClass, StdInt, StdString +import StdTime + + +:: RandomSeed = RS !Int + + +nullRandomSeed :: RandomSeed +nullRandomSeed += RS 0 + +getNewRandomSeed :: !*env -> (!RandomSeed, !*env) | TimeEnv env +getNewRandomSeed env +# ({hours,minutes,seconds}, env) = getCurrentTime env += (RS (1+(hours+minutes+seconds) bitand 65535), env) + +random :: !RandomSeed -> (!Int,!RandomSeed) +random (RS seed) += (newSeed,RS newSeed) +where + newSeed = if (nextSeed>=0) nextSeed (nextSeed+65537) + nextSeed = (seed75 bitand 65535)-(seed75>>16) + seed75 = seed*75 + +instance toString RandomSeed where toString (RS r) = toString r +instance fromString RandomSeed where fromString str = RS (fromString str) +instance == RandomSeed where == (RS r1) (RS r2) = r1 == r2 diff --git a/src/StdLibExt/RangeSlider.dcl b/src/StdLibExt/RangeSlider.dcl new file mode 100644 index 0000000..5c4c987 --- /dev/null +++ b/src/StdLibExt/RangeSlider.dcl @@ -0,0 +1,53 @@ +definition module RangeSlider + +import StdEnv, StdIO + +/** A (RangeSlider id dir width range action atts) value describes a control that allows users to select values from the + given range. The parameters have the following meaning: + id: the identification value of the range slider; + dir: the direction of the range slider (Horizontal or Vertical); + width: the length of the range slider; + range: the range {values=[v_0, ..., v_n],index=i}; here i is the 0-based index of the currently selected value, v_i. + When the user selects another value, then index will have the corresponding value; + action: the function that is applied to the current local and process state of the control whenever the user has used + the range slider; + atts: the standard set of control attributes. + + Author: Peter Achten + E-mail: P.Achten@cs.ru.nl + Date: january 2008 + Uses: Clean 2.2, Object I/O +*/ +:: RangeSliderId a +:: RangeSlider a ls pst + = RangeSlider (RangeSliderId a) Direction ControlWidth (Range a) (RangeAction a *(ls,pst)) [ControlAttribute *(ls,pst)] +:: Range a + = { values :: ![a] + , index :: !RangeIndex + } +:: RangeIndex + :== Int +:: RangeAction a st + :== a -> st -> st + +openRangeSliderId :: !*env -> (!RangeSliderId a,!*env) | Ids env + +instance Controls (RangeSlider a) + +/** getRangeSliderIndex id pSt + yields (Just index) of the selected value of the indicated range slider if it exists, and Nothing otherwise. + getRangeSliderValue id pSt + yields (Maybe (values!!index)) of the indicated range slider if it exists, and Nothing otherwise. + setRangeSliderIndex id i pSt + sets the current index value of the indicated range slider to i, and applies the action function to that value + and the current local and process state. + If the indicated range slider does not exist, nothing happens. + setRangeSliderValue id v pSt + updates the value at the current index of the indicated range slider to v, and applies the action function to + that value and the current local and process state. + If the indicated range slider does not exist, nothing happens. +*/ +getRangeSliderIndex :: !(RangeSliderId a) !(PSt .ps) -> (!Maybe RangeIndex,!PSt .ps) +getRangeSliderValue :: !(RangeSliderId a) !(PSt .ps) -> (!Maybe a, !PSt .ps) +setRangeSliderIndex :: !(RangeSliderId a) !Index !(PSt .ps) -> PSt .ps +setRangeSliderValue :: !(RangeSliderId a) !a !(PSt .ps) -> PSt .ps diff --git a/src/StdLibExt/RangeSlider.icl b/src/StdLibExt/RangeSlider.icl new file mode 100644 index 0000000..7ae5ffa --- /dev/null +++ b/src/StdLibExt/RangeSlider.icl @@ -0,0 +1,119 @@ +implementation module RangeSlider + +import StdEnv, StdIO + +:: RangeSliderId a + = { sliderId :: Id + , recId :: R2Id (RangeSliderMsgIn a) (RangeSliderMsgOut a) + } +:: RangeSliderMsgIn a + = RSIn_GetIndex + | RSIn_GetValue + | RSIn_SetIndex RangeIndex + | RSIn_SetValue a +:: RangeSliderMsgOut a + = RSOut_GetIndex RangeIndex + | RSOut_GetValue a + | RSOut_SetIndex + | RSOut_SetValue +:: RangeSliderSt a + :== Range a + +openRangeSliderId :: !*env -> (!RangeSliderId a,!*env) | Ids env +openRangeSliderId env + # (sliderId,env) = openId env + # (recId, env) = openR2Id env + = ({sliderId=sliderId,recId=recId},env) + +instance Controls (RangeSlider a) where + controlToHandles (RangeSlider {sliderId,recId} dir width range=:{values,index} f atts) pSt + = controlToHandles impl pSt + where + f` = liftF2 f + impl = { addLS = range + , addDef = SliderControl dir width state (action f`) [ControlId sliderId:map toLS atts] + :+: + Receiver2 recId (recF f`) [] + } + state = { sliderMin = 0 + , sliderMax = length values - 1 + , sliderThumb = index + } + + action f move ((range=:{values,index},ls),pSt) + = f (values!!i) (({range & index=i},ls),appPIO (setSliderThumb sliderId i) pSt) + where + i = case move of + SliderIncSmall = min (index+1) (length values-1) + SliderDecSmall = max (index-1) 0 + SliderIncLarge = min (index+(max 1 (length values)/10)) (length values-1) + SliderDecLarge = max (index-(max 1 (length values)/10)) 0 + SliderThumb new = new + + recF f RSIn_GetIndex ((range=:{index},ls),pSt) + = (RSOut_GetIndex index,((range,ls),pSt)) + recF f RSIn_GetValue ((range=:{values,index},ls),pSt) + = (RSOut_GetValue (values!!index),((range,ls),pSt)) + recF f (RSIn_SetIndex i) ((range=:{values},ls),pSt) + = (RSOut_SetIndex,f (values!!i`) (({range & index=i`},ls),pSt)) + where + i` = min (max i 0) (length values-1) + recF f (RSIn_SetValue v) ((range=:{values,index},ls),pSt) + = (RSOut_SetValue,f v (({range & values=updateAt index v values},ls),pSt)) + + toLS (ControlActivate f) = ControlActivate (liftF f) + toLS (ControlDeactivate f) = ControlDeactivate (liftF f) + toLS (ControlFunction f) = ControlFunction (liftF f) + toLS ControlHide = ControlHide + toLS (ControlId id) = ControlId id + toLS (ControlKeyboard kF s f) = ControlKeyboard kF s (liftF2 f) + toLS (ControlMinimumSize s) = ControlMinimumSize s + toLS (ControlModsFunction f) = ControlModsFunction (liftF2 f) + toLS (ControlMouse mF s f) = ControlMouse mF s (liftF2 f) + toLS (ControlPen p) = ControlPen p + toLS (ControlPos p) = ControlPos p + toLS (ControlResize f) = ControlResize f + toLS (ControlSelectState s) = ControlSelectState s + toLS (ControlTip t) = ControlTip t + toLS (ControlWidth w) = ControlWidth w + toLS (ControlHMargin l r) = ControlHMargin l r + toLS (ControlHScroll f) = ControlHScroll f + toLS (ControlItemSpace x y) = ControlItemSpace x y + toLS (ControlLook b f) = ControlLook b f + toLS (ControlOrigin o) = ControlOrigin o + toLS (ControlOuterSize s) = ControlOuterSize s + toLS (ControlViewDomain d) = ControlViewDomain d + toLS (ControlViewSize s) = ControlViewSize s + toLS (ControlVMargin t b) = ControlVMargin t b + toLS (ControlVScroll f) = ControlVScroll f + + liftF f ((add,ls),pSt) + # (ls,pSt) = f (ls,pSt) + = ((add,ls),pSt) + + liftF2 f a ((add,ls),pSt) + # (ls,pSt) = f a (ls,pSt) + = ((add,ls),pSt) + + getControlType _ + = "RangeSlider" + +getRangeSliderIndex :: !(RangeSliderId a) !(PSt .ps) -> (!Maybe RangeIndex,!PSt .ps) +getRangeSliderIndex {recId} pSt + = case syncSend2 recId RSIn_GetIndex pSt of + ((SendOk,Just (RSOut_GetIndex i)),pSt) = (Just i, pSt) + (_,pSt) = (Nothing,pSt) + +getRangeSliderValue :: !(RangeSliderId a) !(PSt .ps) -> (!Maybe a,!PSt .ps) +getRangeSliderValue {recId} pSt + = case syncSend2 recId RSIn_GetValue pSt of + ((SendOk,Just (RSOut_GetValue v)),pSt) = (Just v, pSt) + (_,pSt) = (Nothing,pSt) + +setRangeSliderIndex :: !(RangeSliderId a) !Index !(PSt .ps) -> PSt .ps +setRangeSliderIndex {recId} i pSt + = snd (syncSend2 recId (RSIn_SetIndex i) pSt) + +setRangeSliderValue :: !(RangeSliderId a) !a !(PSt .ps) -> PSt .ps +setRangeSliderValue {recId} v pSt + = snd (syncSend2 recId (RSIn_SetValue v) pSt) diff --git a/src/StdLibExt/StdEnvExt.dcl b/src/StdLibExt/StdEnvExt.dcl new file mode 100644 index 0000000..47e0788 --- /dev/null +++ b/src/StdLibExt/StdEnvExt.dcl @@ -0,0 +1,263 @@ +definition module StdEnvExt + +/** Collection of generally useful functions that are not related to SoccerFun. +*/ +import StdEnv +import StdMaybe + +/** const2 a _ _ = a + is a frequently occurring version of the const function. +*/ +const2 :: !.a .b .c -> .a + +/** iterateSt f x + is the state based version of iterate (StdList): + iterateSt f x_0 + [y_1,y_2,y_3,y_4...] + where + (y_i,x_i) = f x_i +*/ +iterateSt :: !(s -> (a,s)) !s -> [a] + +/** iterateStn n f x + is the finite version of iterateSt. +*/ +iterateStn :: !Int !(s -> (a,s)) !s -> (![a],!s) + +/** State strict versions of seq and seqList: +*/ +sseq :: ![.(.s -> .s)] !.s -> .s +sseqList:: ![St .s .a] !.s -> (![.a],!.s) + +/** apply x [f_0 ... f_n] = [f_0 x, ..., f_n x] +*/ +apply :: a ![a->.b] -> [.b] + +/** State passing version of map: +*/ +mapSt :: !(.(.a,.s) -> .(.b,.s)) !(![.a],.s) -> (![.b],.s) + +/** Strict state passing version of map: +*/ +smapSt :: !(.(.a,.s) -> .(.b,.s)) !(![.a],!.s) -> (![.b],!.s) + +/** singleOutElems [a_1..a_n] = [(a_1,[a_2..a_n]),(a_2,[a_1,a_3..a_n])..(a_n,[a_1..a_(n-1)])] +*/ +singleOutElems :: ![a] -> [(a,[a])] + +/** hdtl [a:as] = (a,as) +*/ +hdtl :: ![a] -> (a,[a]) + +/** isSingleton [_] = True; + isSingleton _ = False. +*/ +isSingleton :: ![a] -> Bool + +/** filterSt cond xs st + filters all elements from xs using a state parameter st that is threaded along. +*/ +filterSt :: (a .s -> (Bool,.s)) !.[a] !.s -> (.[a],.s) + +/** spanfilter cond xs = (filter cond xs, filter (not o cond) xs) + spanfilterSt cond xs st + same, but with state parameter st that is threaded along. +*/ +spanfilter :: (a -> Bool) !.[a] -> (.[a],.[a]) +spanfilterSt :: (a .s -> (Bool,.s)) !.[a] .s -> (.(.[a],.[a]),.s) + +/** find1 cond (A ++ [a] ++ B) = a + where for each x in A: not (cond x) /\ cond a +*/ +find1 :: !(a -> Bool) ![a] -> a + +/** break cond (A ++ B ++ C) = (A,B,C) + where for each x in A: not (cond x) /\ + for each x in B: (cond x) /\ + if C=[x:_]: not (cond x) +*/ +break :: !(a -> Bool) ![a] -> (![a],![a],![a]) + +/** break1 cond (A ++ [B] ++ C) = (A,B,C) + where for each x in A: not (cond x) /\ + (cond B) /\ + if C=[x:_]: not (cond x) +*/ +break1 :: !(a -> Bool) ![a] -> (![a],!a,![a]) + +/** unbreak (a,b,c) = a ++ b ++ c +*/ +unbreak :: !(![a],![a],![a]) -> [a] + +/** unbreak1 (a,b,c) = a ++ [b] ++ c +*/ +unbreak1 :: !(![a],!a,![a]) -> [a] + +/** [a_1..x..a_n] ?? x = i + where + a_j <> x for all j Int | == a +(???)infixl 9 :: ![a] !(a -> Bool) -> Int + +/** weave [a_1..a_n] [b_1..b_m] + = [a_1,b_1, a_2,b_2, ... ] +*/ +weave :: ![a] [a] -> [a] + +/** unweave [a_1,a_2..a_n] + = ([a_1,a_3..],[a_2,a_4..]) +*/ +unweave :: ![a] -> ([a],[a]) + +/** unweave_n n [a_1..a_n, a_{n+1}..a_{2n} ..] + = [[a_1,a_{n+1}..],[a_2,a_{n+2}..] ..] +*/ +unweave_n :: !Int [a] -> [[a]] + +/** Immediate instances of toString for (,), (,,) and Maybe +*/ +instance toString (a,b) | toString a & toString b +instance toString (a,b,c) | toString a & toString b & toString c +instance toString (Maybe a) | toString a + +/** Useful string concatenation function +*/ +(<+++) infixl :: !String !a -> String | toString a +(+++>) infixr :: !a !String -> String | toString a + +/** showList inf [x_0 ... x_n] = "..." + showListF inf f [x_0 ... x_n] = "..." +*/ +showList :: !String !.[a] -> String | toString a +showListF :: !String !(a -> String) !.[a] -> String + +/** Association lists a la Haskell. +*/ +:: AssocList k v :== [ (!k,v)] + +/** lookup k [...(k,v)...] = Just v + lookup k _ = Nothing +*/ +lookup :: !k !(AssocList k v) -> Maybe v | Eq k + +/** lookup _ k [...(k,v)...] = v + lookup v k _ = v +*/ +lookupd :: v !k !(AssocList k v) -> v | Eq k + +/** keymember k [...(k,v)...] = True + keymember _ _ = False +*/ +keymember :: !k !(AssocList k v) -> Bool | Eq k + +/** addkeyvalue (k,v) [...(k,_)...] = [...(k,v)...] + addkeyvalue _ assocl = assocl ++ [(k,v)] +*/ +addkeyvalue :: !(!k,v) !(AssocList k v) -> AssocList k v | Eq k + +/** updkeyvalue k f [...(k,v)...] = [...(k,f v)...] + updkeyvalue _ _ assocl = assocl +*/ +updkeyvalue :: !k !(v -> v) !(AssocList k v) -> AssocList k v | Eq k + +/** deletekeyvalue k [...(k,v)...] = [... ...] + deletekeyvalue _ assocl = assocl +*/ +deletekeyvalue :: !k !(AssocList k v) -> AssocList k v | Eq k + +/** isAllMember xs ys is true iff all elements of xs are member of ys. +*/ +isAllMember :: ![a] [a] -> Bool | Eq a + +/** zipWith f as bs = [f a_0 b_0, f a_1 b_1, ..., f a_n b_n] +*/ +zipWith :: (a b -> c) ![a] ![b] -> [c] + +/** setbetween x low up + returns x iff low <= x <= up + returns low iff low > x + returns up iff x > up +*/ +setbetween :: !a !a !a -> a | Ord a + +/** isbetween x low up + returns True iff low <= x <= up +*/ +isbetween :: !a !a !a -> Bool | Ord a + +/** minmax (a,b) = (a,b) if a<=b; (b,a) otherwise +*/ +minmax :: !(!a,!a) -> (!a,!a) | Ord a + +/** swap (a,b) = (b,a) +*/ +swap :: !(.a,.b) -> (.b,.a) + +/** modulo Int +*/ +instance mod Int + +/** foldl1 f xs folds f to the left over non-empty list xs. +*/ +foldl1 :: !(a -> a -> a) ![a] -> a + +/** foldr1 f xs folds f to the right over non-empty list xs. +*/ +foldr1 :: !(a -> a -> a) ![a] -> a + +/* removeQuotes str removes all quotes and slashes from str. +*/ +removeQuotes :: !{#Char} -> String + +/** stringStarts str prefix yields true iff str = prefix +++ s for some s. +*/ +stringStarts :: !String !String -> Bool + +/** removePrefix str prefix yields (Just s) iff str = prefix +++ s, and Nothing otherwise. +*/ +removePrefix :: !String !String -> Maybe String + +replaceInString :: !String !String !String -> String + +/** other a yields the only other value of a domain that consists of two values. +*/ +class other a :: !a -> a + +/** isSorted [x_0..x_n] holds iff x_i <= x_{i+1} for each x_i in [x_0..x_{n-1}]. +*/ +isSorted :: ![a] -> Bool | Ord a + +/** perhaps p Nothing = False, and perhaps p (Just a) = p a +*/ +perhaps :: !(a -> Bool) !(Maybe a) -> Bool + +/** instance ~ Bool = not +*/ +instance ~ Bool + +/** instance fromString Int = toInt +*/ +instance fromString Int + +/** better class definitions of the trigonometry functions: +*/ +class sinus a :: !a -> Real +class cosinus a :: !a -> Real +class tangens a :: !a -> Real +class arcsinus a :: !Real -> a +class arccosinus a :: !Real -> a +class arctangens a :: !Real -> a + +instance sinus Real +instance cosinus Real +instance tangens Real +instance arcsinus Real +instance arccosinus Real +instance arctangens Real diff --git a/src/StdLibExt/StdEnvExt.icl b/src/StdLibExt/StdEnvExt.icl new file mode 100644 index 0000000..140a6ef --- /dev/null +++ b/src/StdLibExt/StdEnvExt.icl @@ -0,0 +1,451 @@ +implementation module StdEnvExt + +/** Collection of functions of more general purpose. +*/ +import StdEnv +import StdMaybe + +/** const2 a _ _ = a + is a frequently occurring version of the const function. +*/ +const2 :: !.a .b .c -> .a +const2 a _ _ = a + +/** iterateSt f x + is the state based version of iterate (StdList): + iterateSt f x_0 + [y_1,y_2,y_3,y_4...] + where + (y_i,x_i) = f x_{i-1} +*/ +iterateSt :: !(s -> (a,s)) !s -> [a] +iterateSt f s = let (a,s1) = f s in [a:iterateSt f s1] + +/** iterateStn n f x + is the finite version of iterateSt. +*/ +iterateStn :: !Int !(s -> (a,s)) !s -> (![a],!s) +iterateStn 0 _ s = ([],s) +iterateStn n f s + # (a, s) = f s + # (as,s) = iterateStn (n-1) f s + = ([a:as],s) + +/** State strict version of seq: +*/ +sseq :: ![.(.s -> .s)] !.s -> .s +sseq [f:fs] s = sseq fs (f s) +sseq [] s = s + + +/** State strict version of seqList: +*/ +sseqList:: ![St .s .a] !.s -> (![.a],!.s) +sseqList [f:fs] s + #! (x, s) = f s + #! (xs,s) = sseqList fs s + = ([x:xs],s) +sseqList _ s + = ([],s) + +/** apply x [f_0 ... f_n] = [f_0 x, ..., f_n x] +*/ +apply :: a ![a->.b] -> [.b] +apply x fs = [f x \\ f<-fs] + +/** State passing version of map: +*/ +mapSt :: !(.(.a,.s) -> .(.b,.s)) !(![.a],.s) -> (![.b],.s) +mapSt f ([],s) + = ([],s) +mapSt f ([a:as],s) + # (b, s) = f (a,s) + # (bs,s) = mapSt f (as,s) + = ([b:bs],s) + +/** Strict state passing version of map: +*/ +smapSt :: !(.(.a,.s) -> .(.b,.s)) !(![.a],!.s) -> (![.b],!.s) +smapSt f ([],s) + = ([],s) +smapSt f ([a:as],s) + #! (b, s) = f (a,s) + #! (bs,s) = smapSt f (as,s) + = ([b:bs],s) + +/** singleOutElems [a_1..a_n] = [(a_1,[a_2..a_n]),(a_2,[a_1,a_3..a_n])..(a_n,[a_1..a_{n-1}])] +*/ +singleOutElems :: ![a] -> [(a,[a])] +singleOutElems as + = singleOut [] as +where + singleOut :: [a] [a] -> [(a,[a])] + singleOut _ [] = [] + singleOut prefix [a:as] + = [(a,prefix++as) : singleOut (prefix++[a]) as] + +/** hdtl [a:as] = (a,as) +*/ +hdtl :: ![a] -> (a,[a]) +hdtl [a:as] = (a,as) + +/** isSingleton [_] = True; + isSingleton _ = False. +*/ +isSingleton :: ![a] -> Bool +isSingleton [_] = True +isSingleton _ = False + + +/** filterSt cond xs st + filters all elements from xs using a state parameter st that is threaded along. +*/ +filterSt :: (a .s -> (Bool,.s)) !.[a] !.s -> (.[a],.s) +filterSt cond [] s + = ([],s) +filterSt cond [x:xs] s +# (b, s) = cond x s +# (yes,s) = filterSt cond xs s +| b = ([x:yes],s) +| otherwise = ( yes, s) + +/** spanfilter cond xs = (filter cond xs, filter (not o cond) xs) +*/ +spanfilter :: (a -> Bool) !.[a] -> (.[a],.[a]) +spanfilter cond [] + = ([],[]) +spanfilter cond [x:xs] + | cond x = ([x:yes],no) + | otherwise = (yes,[x:no]) +where + (yes,no) = spanfilter cond xs + +spanfilterSt :: (a .s -> (Bool,.s)) !.[a] .s -> (.(.[a],.[a]),.s) +spanfilterSt cond [] s + = (([],[]),s) +spanfilterSt cond [x:xs] s + # (ok,s) = cond x s + # ((yes,no),s) = spanfilterSt cond xs s + | ok = (([x:yes],no),s) + | otherwise = ((yes,[x:no]),s) + +/** find1 cond (A ++ [a] ++ B) = a + where for each x in A: not (cond x) /\ cond a +*/ +find1 :: !(a -> Bool) ![a] -> a +find1 c as = case filter c as of + [a:_] = a + none = abort "find1: no elements found.\n" + +/** break cond (A ++ B ++ C) = (A,B,C) + where for each x in A: not cond x /\ + for each x in B: cond x /\ + if C=[x:_]: not cond x +*/ +break :: !(a -> Bool) ![a] -> (![a],![a],![a]) +break c xs + # (no,yes) = span (not o c) xs + # (yes,no`) = span c yes + = (no,yes,no`) + +/** break1 cond (A ++ [B] ++ C) = (A,B,C) + where for each x in A: not cond x /\ + cond B /\ + if C=[x:_]: not cond x +*/ +break1 :: !(a -> Bool) ![a] -> (![a],!a,![a]) +break1 c xs + = case break c xs of + (a,[b],c) = (a,b,c) + (a,b,c) = abort ("break1: [B] is of length: " <+++ length b <+++ "\n") + +/** unbreak (a,b,c) = a ++ b ++ c +*/ +unbreak :: !(![a],![a],![a]) -> [a] +unbreak (a,b,c) = a ++ b ++ c + + +/** unbreak1 (a,b,c) = a ++ [b] ++ c +*/ +unbreak1 :: !(![a],!a,![a]) -> [a] +unbreak1 (a,b,c) = a ++ [b] ++ c + +/** [a_1..x..a_n] x = i + where + a_j <> x for all j Int | == a +(??) ys x = search ((==) x) ys 0 + +(???) infixl 9 :: ![a] !(a -> Bool) -> Int +(???) ys c = search c ys 0 + +search :: !(a -> Bool) ![a] !Int -> Int +search _ [] _ = -1 +search c [y:ys] i + | c y = i + | otherwise = search c ys (i+1) + +/** weave [a_1..a_n] [b_1..b_m] + = [a_1,b_1, a_2,b_2, ... a_k,b_k] with k = min(m,n) +*/ +weave :: ![a] [a] -> [a] +weave [a:as] [b:bs] = [a,b:weave as bs] +weave _ _ = [] + +/** unweave [a_1,a_2..a_n] + = ([a_1,a_3..],[a_2,a_4..]) +*/ +unweave :: ![a] -> ([a],[a]) +unweave [x,y:zs] = ([x:xs],[y:ys]) +where + (xs,ys) = unweave zs +unweave [x] = ([x],[]) +unweave [] = ([],[]) + +/** unweave_n n [a_1..a_n, a_{n+1}..a_{2n} ..] + = [[a_1,a_{n+1}..],[a_2,a_{n+2}..] ..] +*/ +unweave_n :: !Int [a] -> [[a]] +unweave_n nrLists zs + | length first_n < nrLists + = repeatn nrLists [] + | otherwise + = glue first_n (unweave_n nrLists after_n) +where + (first_n,after_n) = splitAt nrLists zs + + glue :: ![a] [[a]] -> [[a]] // must be non-strict in its second argument in order to work for streams + glue [] _ = [] + glue [a:as] xss = [[a:hd xss]:glue as (tl xss)] + + +/** Immediate instances of toString for (,) and (,,) +*/ +instance toString (a,b) | toString a & toString b where toString (a,b) = "(" <+++ a <+++ "," <+++ b <+++ ")" +instance toString (a,b,c) | toString a & toString b & toString c where toString (a,b,c) = "(" <+++ a <+++ "," <+++ b <+++ "," <+++ c <+++ ")" +instance toString (Maybe a) | toString a where toString (Just a) = "(Just " <+++ a <+++ ")" + toString nothing = "Nothing" + +/** Useful string concatenation function +*/ +(<+++) infixl :: !String !a -> String | toString a +(<+++) str x = str +++ toString x + +(+++>) infixr :: !a !String -> String | toString a +(+++>) x str = toString x +++ str + + +/** showList inf [x_0 ... x_n] = "..." + showListF inf f [x_0 ... x_n] = "..." +*/ +showList :: !String !.[a] -> String | toString a +showList inf [] = "" +showList inf [x] = toString x +showList inf [x:xs] = x +++> inf +++> showList inf xs + +showListF :: !String !(a -> String) !.[a] -> String +showListF inf f [] = "" +showListF inf f [x] = f x +showListF inf f [x:xs] = f x +++> inf +++> showListF inf f xs + + +/** lookup k [...(k,v)...] = Just v + lookup k _ = Nothing +*/ +lookup :: !k !(AssocList k v) -> Maybe v | Eq k +lookup k assocl + = case [v \\ (k`,v)<-assocl | k==k`] of + [v:_] = Just v + _ = Nothing + +/** lookup _ k [...(k,v)...] = v + lookup v k _ = v +*/ +lookupd :: v !k !(AssocList k v) -> v | Eq k +lookupd v k assocl + = case [v` \\ (k`,v`)<-assocl | k==k`] of + [v`:_] = v` + _ = v + +/** keymember k [...(k,v)...] = True + keymember _ _ = False +*/ +keymember :: !k !(AssocList k v) -> Bool | Eq k +keymember k assocl + = isJust (lookup k assocl) + +/** addkeyvalue (k,v) [...(k,_)...] = [...(k,v)...] + addkeyvalue _ assocl = assocl ++ [(k,v)] +*/ +addkeyvalue :: !(!k,v) !(AssocList k v) -> AssocList k v | Eq k +addkeyvalue (k,v) assocl + = case span (\(k`,_) -> k<>k`) assocl of + (before,[_:after]) = before ++ [(k,v):after] + (before,empty) = before ++ [(k,v)] + +/** updkeyvalue k f [...(k,v)...] = [...(k,f v)...] + updkeyvalue _ _ assocl = assocl +*/ +updkeyvalue :: !k !(v -> v) !(AssocList k v) -> AssocList k v | Eq k +updkeyvalue k f assocl + = case span (\(k`,_) -> k<>k`) assocl of + (before,[(k,v):after]) = before ++ [(k,f v):after] + (before,empty) = before + +/** deletekeyvalue k [...(k,v)...] = [... ...] + deletekeyvalue _ assocl = assocl +*/ +deletekeyvalue :: !k !(AssocList k v) -> AssocList k v | Eq k +deletekeyvalue k assocl + = case span (\(k`,_) -> k<>k`) assocl of + (before,[_:after]) = before ++ after + (before,empty) = before + +/** isAllMember xs ys is true iff all elements of xs are member of ys. +*/ +isAllMember :: ![a] [a] -> Bool | Eq a +isAllMember xs ys = and (map (\x -> isMember x ys) xs) + +/** zipWith f as bs = [f a_0 b_0, f a_1 b_1, ..., f a_n b_n] +*/ +zipWith :: (a b -> c) ![a] ![b] -> [c] +zipWith f as bs = [f a b \\ a<-as & b<-bs] + +/** setbetween x low up + returns x iff low <= x <= up + returns low iff low > x + returns up iff x > up +*/ +setbetween :: !a !a !a -> a | Ord a +setbetween x low up + | low > x = low + | x > up = up + | otherwise = x + +/** isbetween x low up + returns True iff low <= x <= up +*/ +isbetween :: !a !a !a -> Bool | Ord a +isbetween x low up + = low <= x && x <= up + +/** minmax (a,b) = (a,b) if a<=b; (b,a) otherwise +*/ +minmax :: !(!a,!a) -> (!a,!a) | Ord a +minmax (a,b) + | a<=b = (a,b) + | otherwise = (b,a) + + +/** swap (a,b) = (b,a) +*/ +swap :: !(.a,.b) -> (.b,.a) +swap (a,b) = (b,a) + +/** modulo int +*/ +instance mod Int where + (mod) a b = a - b * (a/b) + +/** foldl1 f xs folds f to the left over non-empty list xs. +*/ +foldl1 :: !(a -> a -> a) ![a] -> a +foldl1 f [x : xs] = foldl f x xs + +/** foldr1 f xs folds f to the right over non-empty list xs. +*/ +foldr1 :: !(a -> a -> a) ![a] -> a +foldr1 f [x] = x +foldr1 f [x:xs] = f x (foldr1 f xs) + +removeQuotes :: !{#Char} -> String +removeQuotes "" = "" +removeQuotes s = removeQuotes` s 0 +where + removeQuotes` :: !{#Char} Int -> String + removeQuotes` s i + | i == size s + = "" + | otherwise + # c = select s i + | c == '\"' || c == '\\' + = removeQuotes` s (inc i) + | otherwise + = toString c +++ removeQuotes` s (inc i) + +replaceInString :: !String !String !String -> String +replaceInString toReplace replacement s + # result = replaceInString` (fromString toReplace) (fromString replacement) (fromString s) + = charlist2string "" result +where + replaceInString` :: ![Char] ![Char] ![Char] -> [Char] + replaceInString` toReplace replacement [] = [] + replaceInString` toReplace replacement s=:[x:xs] + | length toReplace > length s = s + # firstPart = take (length toReplace) s + # lastPart = drop (length toReplace) s + | firstPart == toReplace = replacement ++ replaceInString` toReplace replacement lastPart + | otherwise = [x:replaceInString` toReplace replacement xs] + + charlist2string :: !String ![Char] -> String + charlist2string str [] = str + charlist2string str [x:xs] = charlist2string (str+++toString x) xs + +/** stringStarts s1 prefix yields true iff s1 = prefix +++ s for some s. +*/ +stringStarts :: !String !String -> Bool +stringStarts s1 prefix = size s1 >= size prefix && s1%(0,size prefix-1) == prefix + +/** removePrefix str prefix yields (Just s) iff str = prefix +++ s, and Nothing otherwise. +*/ +removePrefix :: !String !String -> Maybe String +removePrefix s1 prefix = if (stringStarts s1 prefix) (Just (s1%(size prefix,size s1-1))) Nothing + +/** isSorted [x_0..x_n] holds iff x_i <= x_{i+1} for each x_i in [x_0..x_{n-1}]. +*/ +isSorted :: ![a] -> Bool | Ord a +isSorted [] = True +isSorted xs = and [x <= y \\ x <- xs & y <- tl xs] + +/** perhaps p Nothing = False, and perhaps p (Just a) = p a +*/ +perhaps :: !(a -> Bool) !(Maybe a) -> Bool +perhaps _ Nothing = False +perhaps p (Just a) = p a + +/** instance ~ Bool is not +*/ +instance ~ Bool where (~) b = not b + +/** instance fromString Int = toInt +*/ +instance fromString Int where fromString str = toInt str + +/** test and access functions for choice values: +*/ +:: ThisOrThat a b = This a | That b + +isThis :: !(ThisOrThat a b) -> Bool +isThis (This _) = True +isThis _ = False + +isThat :: !(ThisOrThat a b) -> Bool +isThat (That _) = True +isThat _ = False + +this :: !(ThisOrThat a b) -> a +this (This a) = a +this _ = abort "this [StdEnvExt]: applied to That pattern instead of This pattern." + +that :: !(ThisOrThat a b) -> b +that (That b) = b +that _ = abort "that [StdEnvExt]: applied to This pattern instead of That pattern." + +instance sinus Real where sinus x = sin x +instance cosinus Real where cosinus x = cos x +instance tangens Real where tangens x = tan x +instance arcsinus Real where arcsinus a = asin a +instance arccosinus Real where arccosinus a = acos a +instance arctangens Real where arctangens a = atan a diff --git a/src/StdLibExt/StdIOExt.dcl b/src/StdLibExt/StdIOExt.dcl new file mode 100644 index 0000000..18c3964 --- /dev/null +++ b/src/StdLibExt/StdIOExt.dcl @@ -0,0 +1,12 @@ +definition module StdIOExt + +/** Collection of functions that extend functionality of StdIO. +*/ + +import StdIO + +/** makeSound path ioSt + plays a sound file, located at path. If no such file is found, the function + aborts. +*/ +makeSound :: !String -> (IOSt .ps) -> IOSt .ps diff --git a/src/StdLibExt/StdIOExt.icl b/src/StdLibExt/StdIOExt.icl new file mode 100644 index 0000000..a02ff5b --- /dev/null +++ b/src/StdLibExt/StdIOExt.icl @@ -0,0 +1,21 @@ +implementation module StdIOExt + +/** Collection of functions that extend functionality of StdIO. +*/ +import StdEnv +import StdIO +import clCCall_12 +from iostate import appIOToolbox + +/** makeSound path ioSt + plays a sound file, located at path. If no such file is found, the function + aborts. +*/ +makeSound :: !String -> (IOSt .l) -> IOSt .l +makeSound file = appIOToolbox (osSound file) +where + osSound :: !String !*OSToolbox -> *OSToolbox + osSound file tb + # (ok,tb) = winPlaySound file tb + | ok = tb + | otherwise = abort ("makeSound: unable to play sound file" +++ file +++ ".\n") diff --git a/src/StdLibExt/fileIO.dcl b/src/StdLibExt/fileIO.dcl new file mode 100644 index 0000000..8080102 --- /dev/null +++ b/src/StdLibExt/fileIO.dcl @@ -0,0 +1,26 @@ +definition module fileIO + +/** Collection of functions that extend functionality of StdFile. +*/ + +import StdBitmap + +/** getImage path env + expects a bitmap file at path. If this is not the case, the function + aborts. Otherwise, it returns the bitmap. +*/ +getImage :: !String !*env -> (!Bitmap,!*env) | FileSystem env + +/** writeFile appendData path content env + writes content to a currently closed file, located at path, and closes it again. + It appends content to current content in case of appendData, and replaces content otherwise. + The function aborts in case of incorrect path and failing to close the file. +*/ +writeFile :: !Bool !String !String !*env -> *env | FileSystem env + +/** readFile path env + reads the current content of the file located at path as a text file and closes it. + The function yields Nothing in case of incorrect path and failing to close the file + and (Just content) otherwise. +*/ +readFile :: !String !*env -> (!Maybe String,*env) | FileSystem env diff --git a/src/StdLibExt/fileIO.icl b/src/StdLibExt/fileIO.icl new file mode 100644 index 0000000..ec80297 --- /dev/null +++ b/src/StdLibExt/fileIO.icl @@ -0,0 +1,32 @@ +implementation module fileIO + +import StdEnvExt +import StdBitmap + +getImage :: !String !*env -> (!Bitmap,!*env) | FileSystem env +getImage path env + = case openBitmap path env of + (Nothing,_) = abort ("getImage: unable to get Image " <+++ path <+++".\n") + (Just bm,env) = (bm,env) + +writeFile :: !Bool !String !String !*env -> *env | FileSystem env +writeFile append path text env +# (open,outputFile,env) = fopen path (if append FAppendText FWriteText) env +| not open = abort ("writeFile: could not open " <+++ path <+++ ".\n") +# (close, env) = fclose (outputFile <<< text) env +| not close = abort ("writeFile: could not close " <+++ path <+++".\n") +| otherwise = env + +readFile :: !String !*env -> (!Maybe String,*env) | FileSystem env +readFile path env +# (open,inputFile,env) = fopen path FReadText env +| not open = (Nothing,snd (fclose inputFile env)) +# (ok,inputFile) = fseek inputFile 0 FSeekEnd +| not ok = (Nothing,snd (fclose inputFile env)) +# (pos,inputFile) = fposition inputFile +# (ok,inputFile) = fseek inputFile 0 FSeekSet +| not ok = (Nothing,snd (fclose inputFile env)) +# (str,inputFile) = freads inputFile pos +# (ok,env) = fclose inputFile env +| not ok = (Nothing, env) +| otherwise = (Just str,env) diff --git a/src/StdReferee/RefereeCoach_DeepPass_Assignment.dcl b/src/StdReferee/RefereeCoach_DeepPass_Assignment.dcl new file mode 100644 index 0000000..ac0f508 --- /dev/null +++ b/src/StdReferee/RefereeCoach_DeepPass_Assignment.dcl @@ -0,0 +1,16 @@ +definition module RefereeCoach_DeepPass_Assignment + +/** This module implements a referee coach for a ball passing assignment. + Two footballers from the student team are separated by a group of opponents who are crossing + the field in north-south direction. The player at one side is in possession of the ball. + He needs to pass the ball to the other player in such a way that it can not be gained by + an opponent. + + The opponent team should be Team_Opponent_DeepPass_Assignment. + + Developed by Wanja Krah. +*/ + +import Referee + +RefereeCoach_DeepPass :: !FootballField -> Referee diff --git a/src/StdReferee/RefereeCoach_DeepPass_Assignment.icl b/src/StdReferee/RefereeCoach_DeepPass_Assignment.icl new file mode 100644 index 0000000..4fcf839 --- /dev/null +++ b/src/StdReferee/RefereeCoach_DeepPass_Assignment.icl @@ -0,0 +1,87 @@ +implementation module RefereeCoach_DeepPass_Assignment + +import StdEnvExt +import Referee +import Team_Opponent_DeepPass_Assignment + +RefereeCoach_DeepPass :: !FootballField -> Referee +RefereeCoach_DeepPass field = { name = "RefereeCoach DeepPass" + , brain = { memory = initMem + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Memory = { first :: !Bool + , practiceFailed :: !Bool + , gameOver :: !Bool + , ballKicked :: !Bool + , ballGained :: !Bool + , positions :: !(!Position,!Position) + } + +initMem :: Memory +initMem = { first = True + , practiceFailed = False + , gameOver = False + , ballKicked = False + , ballGained = False + , positions = (zero,zero) + } + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) +brain field ({RefereeInput | theBall=ballState,team1,team2},memory) +| memory.gameOver // game over because of succes or failure + = ([GameOver],memory) +| memory.practiceFailed // assignment has failed + = ([TellMessage "Assignment failed, correct your team and try again."],stop memory) +| length (filter isFielder studentTeam) <> 2 // check if there are indeed two fielders in the students team + = ([TellMessage "There should be two fielders in student team."],stop memory) +# (refActions,memory) = if memory.first // when first, alter ball pos and remember all positions + ([DirectFreeKick studentHome ballKickoff],{updateAllPos memory & first = False}) + ([],memory) +# playersMovedToFar = getPlayersThatMovedTooFar memory +| not (isEmpty playersMovedToFar) // check if players did not move more than 10 meters from their starting positions + = (refActions ++ getMessagesForTooFarPlayers playersMovedToFar,fail memory) +| ballGainedByComputer + = (refActions ++ [TellMessage ("Computer gained the ball")],fail memory) +| not memory.ballKicked + | perhaps isKickedBall kickerAction = (refActions,kick memory) + | perhaps isTackled kickerAction = (refActions ++ [TackleDetected kickerID, ReprimandPlayer kickerID RedCard],fail memory) + | perhaps isTackled gainerAction = (refActions ++ [TackleDetected gainerID, ReprimandPlayer gainerID RedCard],fail memory) + | otherwise = (refActions,memory) +| not memory.ballGained + | perhaps isTackled kickerAction = (refActions ++ [TackleDetected kickerID, ReprimandPlayer kickerID RedCard],fail memory) + | perhaps isTackled gainerAction = (refActions ++ [TackleDetected gainerID, ReprimandPlayer gainerID RedCard],fail memory) + | perhaps isGainedBall gainerAction = (refActions ++ [TellMessage "Well Done! Move on to the next assignment!"], stop memory) + | otherwise = (refActions,memory) +| otherwise + = (refActions,memory) +where + (compTeam,studentTeam,studentHome) = if (stringStarts (nameOf team1) base_TeamName_Opponent_DeepPass) (team1,team2,East) (team2,team1,West) + (kicker, gainer) = let fielders = filter isFielder studentTeam in (fielders!!0,fielders!!1) + (kickerID,gainerID) = (kicker.playerID,gainer.playerID) + kickerAction = getAction kickerID + gainerAction = getAction gainerID + ballKickoff = if (studentHome == West) + {py=scale -0.05 field.fwidth, px=scale 0.06 field.flength} + {py=scale 0.05 field.fwidth, px=scale -0.06 field.flength} + ballGainedByComputer = any (\fb -> ballIsGainedBy fb.playerID ballState) compTeam + + fail memory = {memory & practiceFailed = True} + stop memory = {memory & gameOver = True} + kick memory = {memory & ballKicked = True} + + getAction :: !FootballerID -> Maybe FootballerEffect + getAction playerID = case [fb.effect \\ fb <- team1 ++ team2 | identify_player playerID fb] of + [effect:_] = effect + _ = Nothing + + updateAllPos :: !Memory -> Memory + updateAllPos memory = {memory & positions = (kicker.pos,gainer.pos)} + + getPlayersThatMovedTooFar :: !Memory -> [Footballer] + getPlayersThatMovedTooFar {positions=(kicker_pos,gainer_pos)} + = [fb \\ (fb,pos) <- [(kicker,kicker_pos),(gainer,gainer_pos)] | dist fb pos > m 10.0] + + getMessagesForTooFarPlayers = map (\fb -> TellMessage ("Your player with number " <+++ fb.playerID.playerNr <+++ " moved further than 10 meters")) diff --git a/src/StdReferee/RefereeCoach_Keeper_Assignment.dcl b/src/StdReferee/RefereeCoach_Keeper_Assignment.dcl new file mode 100644 index 0000000..91572ba --- /dev/null +++ b/src/StdReferee/RefereeCoach_Keeper_Assignment.dcl @@ -0,0 +1,13 @@ +definition module RefereeCoach_Keeper_Assignment + +/** This module implements a referee coach for a keeper assignment. + The student team consists of a single keeper. He is challenged by TeamOpponent_Keeper_Assignment + which consists of a number of footballers who are passing the ball to each other in an attempt + to have the keeper not cover the center of the goal. + + Developed by Wanja Krah. +*/ + +import Referee + +RefereeCoach_Keeper :: !FootballField -> Referee diff --git a/src/StdReferee/RefereeCoach_Keeper_Assignment.icl b/src/StdReferee/RefereeCoach_Keeper_Assignment.icl new file mode 100644 index 0000000..f1e5e77 --- /dev/null +++ b/src/StdReferee/RefereeCoach_Keeper_Assignment.icl @@ -0,0 +1,122 @@ +implementation module RefereeCoach_Keeper_Assignment + +import StdEnvExt +import Referee +import Team_Opponent_Keeper_Assignment +import Team_Student_Keeper_Assignment + +RefereeCoach_Keeper :: !FootballField -> Referee +RefereeCoach_Keeper field = { name = "RefereeCoach Keeper" + , brain = { memory = initMem + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Memory = { first :: !Bool + , practiceFailed :: !Bool + , gameOver :: !Bool + , showHowExit :: !Maybe Exit + , timesGainedBy5 :: !Int + , practiceSucceed :: !Bool + } +:: Exit = { student :: !Team + , computer :: !Team + , ball :: !Position + , exit :: !Position + } + +initMem :: Memory +initMem = { first = True + , practiceFailed = False + , gameOver = False + , showHowExit = Nothing + , timesGainedBy5 = 0 + , practiceSucceed = False + } + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) +brain field ({RefereeInput | playingTime=time,theBall=ballState,team1,team2},memory) +| memory.gameOver // game over because of succes or failure + = ([GameOver],memory) +| memory.practiceFailed && memory.practiceSucceed // assignment failed but you had already succeeded + = ([TellMessage "Failed, but you had already passed the test", DirectFreeKick studentHome ballKickoff],{memory & practiceFailed = False, showHowExit = Nothing}) +| memory.practiceFailed // assignment failed + = ([TellMessage "Assignment failed, correct your team and try again"],{memory & gameOver = True}) +| isEmpty (filter isKeeper studentTeam) // check if there is a keeper + = ([TellMessage ("No keeper in student team, please choose " <+++ base_TeamName_Student_Keeper)],{memory & gameOver = True}) +# (refActions,memory) = if (time <= minutes 0.5 && not memory.practiceSucceed) + ([TellMessage "Well Done! (but let's see how much longer you can gain control...)"], {memory & practiceSucceed=True}) + ([],memory) +# (refActions,memory) = if memory.first // when this is the first round, reposition the ball + (refActions ++ [DirectFreeKick studentHome ballKickoff],{memory & first = False}) + (refActions,memory) +| isJust memory.showHowExit // The ball could pass, show how the ball could pass the keeper + # exitInfo = fromJust memory.showHowExit + # directionToExit = bearing zero exitInfo.ball exitInfo.exit // move the ball towards exit + # nextBallPos = move_point {dx = m (cosinus directionToExit), dy = m (sinus directionToExit)} exitInfo.ball + | studentHome == West && nextBallPos.px < scale -0.5 field.flength || studentHome == East && nextBallPos.px > scale 0.5 field.flength + = ([],{memory & practiceFailed = True}) + | otherwise = ([DirectFreeKick West nextBallPos],{memory & showHowExit = Just {exitInfo & ball=nextBallPos}}) +| not memory.first && topExit.py >= scale 0.5 goal_width - spaceAllowed + # sideStr = if (studentHome == West) "left" "right" + = ( [TellMessage ("Keeper left the " <+++ sideStr <+++ " side of the goal open. Exit ypos could be: " <+++ topExit.py)] + , {memory & showHowExit = Just {student=studentTeam,computer=compTeam,ball=theBall.ballPos.pxy,exit=topExit}} + ) +| not memory.first && bottomExit.py <= scale -0.5 goal_width + spaceAllowed + # sideStr = if (studentHome == West) "right" "left" + = ( [TellMessage ("keeper left the " <+++ sideStr <+++ " side of the goal open. Exit ypos could be: " <+++ bottomExit.py)] + , {memory & showHowExit = Just {student=studentTeam,computer=compTeam,ball=theBall.ballPos.pxy,exit=bottomExit}} + ) +| otherwise = (refActions,memory) +where + (compTeam,studentTeam,studentHome) + = if (stringStarts (nameOf team1) base_TeamName_Opponent_Keeper) (team1,team2,East) (team2,team1,West) + ballKickoff = if (studentHome == West) + {zero & px = scale -0.5 field.flength + penalty_area_depth} + {zero & px = scale 0.5 field.flength - penalty_area_depth} + +/* The keeper has to cover the entire width of the goal minus spaceAllowed at both sides in order to be succesfull enough for this assignment. +*/ spaceAllowed = scale (1.0/6.0) goal_width + theBall = getFootball ballState (team1 ++ team2) + keeper = hd (filter isKeeper studentTeam) + keeperPos = keeper.pos + ballDirection2keeper = bearing zero theBall keeper + (topReachKeeper,bottomReachKeeper) + = getMaximumCatchPositions ballDirection2keeper + +/* Draws a line from football to keeper + determines the two directions the keeper can jump to cover max area behind him + gets the maximum distance the keeper can catch/jump + returns the two positions past which the ball can pass the keeper +*/ getMaximumCatchPositions :: !Angle -> (!Position,!Position) + getMaximumCatchPositions ballDirection2keeper + # ballDirection2keeper = if (ballDirection2keeper < rad (1.5*pi)) (ballDirection2keeper + rad (1.5*pi)) (ballDirection2keeper - rad (0.5*pi)) + # catchCorner1 = if (ballDirection2keeper < rad (1.5*pi)) (ballDirection2keeper + rad (1.5*pi)) (ballDirection2keeper - rad (0.5*pi)) + # catchCorner2 = if (ballDirection2keeper > rad (0.5*pi)) (ballDirection2keeper - rad (1.5*pi)) (ballDirection2keeper + rad (0.5*pi)) + # maxCatchDistance = maxCatchReach keeper + # maxPoint1 = {px=keeperPos.px + scale (sinus catchCorner1) maxCatchDistance, py=keeperPos.py + scale (~(cosinus catchCorner1)) maxCatchDistance } + # maxPoint2 = {px=keeperPos.px + scale (sinus catchCorner2) maxCatchDistance, py=keeperPos.py + scale (~(cosinus catchCorner2)) maxCatchDistance } + | maxPoint1.py < maxPoint2.py = (maxPoint2,maxPoint1) + | otherwise = (maxPoint1,maxPoint2) + +// What if the keeper is passed could be the lowest position to let the ball exit the field + direction2topReach = bearing zero theBall topReachKeeper + topExit = getExitPos topReachKeeper theBall.ballPos.pxy direction2topReach +// What if the keeper is passed could be the lowest position to let the ball exit the field + direction2bottomReach = bearing zero theBall bottomReachKeeper + bottomExit = getExitPos bottomReachKeeper theBall.ballPos.pxy direction2bottomReach + + getExitPos :: !Position !Position !Angle -> Position + getExitPos reachPos ballPos direction + = while aintOut (move_point {dx=m (cosinus dir),dy=m (sinus dir)}) target + where + (dir,target) = if (reachPos.px >= zero) (direction,reachPos) (oppositeDirection direction,ballPos) + aintOut = point_in_rectangle ({px = scale -0.5 field.flength, py = scale -0.5 field.fwidth} + ,{px = scale 0.5 field.flength, py = scale 0.5 field.fwidth} + ) + +oppositeDirection :: !Angle -> Angle +oppositeDirection d +| d > rad pi = d - rad pi +| otherwise = d + rad pi diff --git a/src/StdReferee/RefereeCoach_Passing_Assignment.dcl b/src/StdReferee/RefereeCoach_Passing_Assignment.dcl new file mode 100644 index 0000000..915ffe1 --- /dev/null +++ b/src/StdReferee/RefereeCoach_Passing_Assignment.dcl @@ -0,0 +1,15 @@ +definition module RefereeCoach_Passing_Assignment + +/** This module implements a referee coach for a ball passing assignment. + The student footballer team should pass the ball from one end of the field to the other + end of the field. Accepting players should not move further away than 10 metres from + their starting point. The last player should kick the ball in the goal to end the assignment. + + The opponent team should be Team_Opponent_Passing_Assignment. + + Developed by Wanja Krah. +*/ + +import Referee + +RefereeCoach_Passing :: !FootballField -> Referee diff --git a/src/StdReferee/RefereeCoach_Passing_Assignment.icl b/src/StdReferee/RefereeCoach_Passing_Assignment.icl new file mode 100644 index 0000000..6ab6e2f --- /dev/null +++ b/src/StdReferee/RefereeCoach_Passing_Assignment.icl @@ -0,0 +1,157 @@ +implementation module RefereeCoach_Passing_Assignment + +import StdEnvExt +import Referee +import Team_Opponent_Passing_Assignment + +RefereeCoach_Passing :: !FootballField -> Referee +RefereeCoach_Passing field = { name = "RefereeCoach Passing" + , brain = { memory = initMem + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Memory = { first :: !Bool + , kickedBy1 :: !Bool // PA: oh dear, you should use [Bool], or better: if in sequence: Int + , kickedBy2 :: !Bool + , kickedBy3 :: !Bool + , kickedBy4 :: !Bool + , kickedBy5 :: !Bool + , kickedBy6 :: !Bool + , pos1 :: !Position // PA: dito, but now [Position] + , pos2 :: !Position + , pos3 :: !Position + , pos4 :: !Position + , pos5 :: !Position + , pos6 :: !Position + , practiceFailed :: !Bool + , gameOver :: !Bool + } + +initMem :: Memory +initMem = { first = True + , kickedBy1 = False + , kickedBy2 = False + , kickedBy3 = False + , kickedBy4 = False + , kickedBy5 = False + , kickedBy6 = False + , pos1 = zero + , pos2 = zero + , pos3 = zero + , pos4 = zero + , pos5 = zero + , pos6 = zero + , practiceFailed = False + , gameOver = False + } + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) +brain field ({RefereeInput | theBall=ballState, team1, team2}, memory) +| memory.gameOver // game over because of succes or failure + = ([GameOver],memory) +| memory.practiceFailed // assignment has failed + = ([TellMessage "Assignment failed, correct your team and try again"],{memory & gameOver = True}) +| length players <> 6 // Check if there are indeed six fielders (to prevent run time errors) + = ([TellMessage "Number of fielders should be six. Correct your team and try again."],{memory & gameOver = True}) +# (refActions,memory) = if memory.first // when first, alter ball pos and remember all positions + ([DirectFreeKick studentHome ballKickoff],{updateAllPos memory & first = False}) + ([],memory) +# playersMovedToFar = getPlayersThatMovedTooFar memory // check if players did not move more than 10 meters from their starting positions +| not (isEmpty playersMovedToFar) + = (refActions ++ getMessagesForTooFarPlayers playersMovedToFar,{memory & practiceFailed = True}) +| not memory.kickedBy1 // first player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 1 memory + = (refActions++more,memory) +| not memory.kickedBy2 // second player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 2 memory + = (refActions++more,memory) +| not memory.kickedBy3 // third player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 3 memory + = (refActions++more,memory) +| not memory.kickedBy4 // fourth player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 4 memory + = (refActions++more,memory) +| not memory.kickedBy5 // fifth player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 5 memory + = (refActions++more,memory) +| not memory.kickedBy6 // sixth player has not kicked the ball yet + # (more,memory) = checkIfPlayerKickedBall 6 memory + = (refActions++more,memory) +| ballIsGoingInWrongDirection // ball is going in the wrong direction + = (refActions ++ [TellMessage "ball should be played towards the goal"],{memory & practiceFailed = True}) +| ballBehindLine // ball is behind the line + | theBall.ballPos.pz > goal_height // ball is over + = (refActions ++ [TellMessage "Try shooting less high, the ball went over"],{memory & practiceFailed = True}) + | isbetween theBall.ballPos.pxy.py south_pole north_pole + = (refActions ++ [TellMessage "Well Done! Move on to the next assignment!"],{memory & gameOver = True}) + | otherwise + = (refActions ++ [TellMessage "Ball is out, try shooting in the goal next time"],{memory & practiceFailed = True}) +| theBall.ballSpeed.vxy.velocity == zero // ball stopped moving + = (refActions ++ [TellMessage "Try shooting harder, the ball stopped moving forwards"],{memory & practiceFailed = True}) +| otherwise // ball may be on its way to the goal + = (refActions,memory) +where + theBall = getFootball ballState (team1 ++ team2) + (compTeam,(studentTeam,studentHome)) = if (stringStarts (nameOf team1) base_TeamName_Opponent_Passing) (team1,(team2,East)) (team2,(team1,West)) + ballKickoff = {zero & px = if (studentHome == West) (scale -0.5 field.flength + penalty_area_depth) (scale 0.5 field.flength - penalty_area_depth)} + getMessagesForTooFarPlayers = map (\fb -> TellMessage ("Your player with number " <+++ fb.playerID.playerNr <+++ " moved further than 10 meters")) + (north_pole,south_pole) = goal_poles field + + players = filter isFielder studentTeam + stud1 = players!!0 + stud2 = players!!1 + stud3 = players!!2 + stud4 = players!!3 + stud5 = players!!4 + stud6 = players!!5 + stud1fa = getAction stud1.playerID + stud2fa = getAction stud2.playerID + stud3fa = getAction stud3.playerID + stud4fa = getAction stud4.playerID + stud5fa = getAction stud5.playerID + stud6fa = getAction stud6.playerID + + getAction :: !FootballerID -> Maybe FootballerEffect + getAction playerID = case [fb.effect \\ fb <- team1 ++ team2 | identify_player playerID fb] of + [effect:_] = effect + _ = Nothing + + ballIsGoingInWrongDirection = if (studentHome == West) > < theBall.ballSpeed.vxy.direction (rad (0.5*pi)) && + if (studentHome == East) < > theBall.ballSpeed.vxy.direction (rad (1.5*pi)) + ballBehindLine = abs theBall.ballPos.pxy.px > scale 0.5 field.flength + + updateAllPos :: !Memory -> Memory + updateAllPos memory = {memory & pos1 = stud1.pos + , pos2 = stud2.pos + , pos3 = stud3.pos + , pos4 = stud4.pos + , pos5 = stud5.pos + , pos6 = stud6.pos + } + + getPlayersThatMovedTooFar :: !Memory -> [Footballer] + getPlayersThatMovedTooFar memory + = [fb \\ fb <- players & pos <- [memory.pos1,memory.pos2,memory.pos3,memory.pos4,memory.pos5,memory.pos6] | dist fb pos > m 10.0] + + checkIfPlayerKickedBall :: !Int !Memory -> (![RefereeAction],!Memory) + checkIfPlayerKickedBall i memory + # (studfa,stud) = case i of + 1 -> (stud1fa,stud1) + 2 -> (stud2fa,stud2) + 3 -> (stud3fa,stud3) + 4 -> (stud4fa,stud4) + 5 -> (stud5fa,stud5) + 6 -> (stud6fa,stud6) + | perhaps isKickedBall studfa = ([], updateMemory i memory) + | perhaps isCaughtBall studfa = ([Hands stud.playerID, ReprimandPlayer stud.playerID RedCard],{memory & practiceFailed = True}) + | otherwise = ([], memory) + where + updateMemory :: !Int !Memory -> Memory + updateMemory 1 m = {m & kickedBy1 = True} + updateMemory 2 m = {m & kickedBy2 = True} + updateMemory 3 m = {m & kickedBy3 = True} + updateMemory 4 m = {m & kickedBy4 = True} + updateMemory 5 m = {m & kickedBy5 = True} + updateMemory 6 m = {m & kickedBy6 = True} diff --git a/src/StdReferee/RefereeCoach_Rounds_Assignment.dcl b/src/StdReferee/RefereeCoach_Rounds_Assignment.dcl new file mode 100644 index 0000000..4fd4c35 --- /dev/null +++ b/src/StdReferee/RefereeCoach_Rounds_Assignment.dcl @@ -0,0 +1,5 @@ +definition module RefereeCoach_Rounds_Assignment + +import Referee + +RefereeCoach_Rounds :: !FootballField -> Referee diff --git a/src/StdReferee/RefereeCoach_Rounds_Assignment.icl b/src/StdReferee/RefereeCoach_Rounds_Assignment.icl new file mode 100644 index 0000000..345b090 --- /dev/null +++ b/src/StdReferee/RefereeCoach_Rounds_Assignment.icl @@ -0,0 +1,103 @@ +implementation module RefereeCoach_Rounds_Assignment + +import Referee + +RefereeCoach_Rounds :: !FootballField -> Referee +RefereeCoach_Rounds field = { name = "RefereeCoach_Rounds" + , brain = { memory = mkMemory + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Memory = { players :: ![(FootballerID, [Checkpoint])] // players and their checkpoints + , stage :: !Stage // current stage of training + } +:: Stage = Begin | Rounds | End Success +:: Checkpoint = { base :: !Position + , distance :: !Metre + , check :: !Bool + } + +mkMemory :: Memory +mkMemory = { players = [] + , stage = Begin + } + +fail :: Memory -> Memory +fail memory = {memory & stage = End Fail} + +ok :: Memory -> Memory +ok memory = {memory & stage = End Success} + +rounds :: Memory -> Memory +rounds memory = {memory & stage = Rounds} + +instance toPosition3D Checkpoint +where toPosition3D {base} = toPosition3D base + +cornerCheckpoints :: !FootballField !Metre -> [Checkpoint] +cornerCheckpoints field d = [ { base = {px = x, py = y}, distance = d, check = False } + \\ x <- [scale -0.5 field.flength, scale 0.5 field.flength] + , y <- [scale 0.5 field.fwidth, scale -0.5 field.fwidth ] + ] + +checkPoint :: !Position !Checkpoint -> Checkpoint +checkPoint pos checkpoint = {checkpoint & check = checkpoint.check || dist pos checkpoint <= checkpoint.distance} + +checkpointsCleared :: ![Checkpoint] -> Bool +checkpointsCleared checks = and [check \\ {check} <- checks] + +distanceFromEdges :== m 5.0 + +isIllegal :: !FootballField !Position !Metre -> Bool +isIllegal field pos distance = point_in_rectangle ({px = scale -0.5 field.flength + distance, py = scale -0.5 field.fwidth + distance} + ,{px = scale 0.5 field.flength - distance, py = scale 0.5 field.fwidth - distance} + ) pos + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) + +// Assignment has started. Locate all players and their checkpoints. +brain field ({RefereeInput | team1,team2},memory=:{stage = Begin}) +| isEmpty players = verdict [TellMessage "No players selected."] (fail memory) +| otherwise = ([], rounds {memory & players = players}) +where + players = [(player.playerID,cornerCheckpoints field distanceFromEdges) \\ player <- team1 ++ team2] + +// Assignment is in the running stage. Monitor players and provide feedback. +brain field ({RefereeInput | playingTime=time,unittime=dt,team1,team2},memory=:{players,stage = Rounds}) +| time <= minutes dt = verdict msg` (next next_memory) + with + (msg`,next) = if (all (checkpointsCleared o snd) checked) + ([], ok) + ([TellMessage "Not all checkpoints have been cleared."],fail) +| isEmpty illegal_positions = ([], next_memory) +| otherwise = ([TellMessage (length illegal_positions +++> " players have moved too far from edge.")], fail next_memory) +where + next_memory = { memory & players = checked } + checked = [ (playerID, map (checkPoint pos) checkpoints) \\ (playerID,checkpoints) <- players + & pos <- positions + ] + positions = [ (find_player playerID all_players).pos \\ (playerID,_) <- players + ] + illegal_positions = [ (playerID,pos) \\ (playerID,_) <- players + & pos <- positions + | isIllegal field pos distanceFromEdges + ] + all_players = team1 ++ team2 + +// Assignment has ended. Stop training session and give final verdict. +brain _ (_,memory) = verdict [] memory + +verdict :: ![RefereeAction] !Memory -> (![RefereeAction],!Memory) +verdict actions memory=:{stage=End how} + = (actions ++ [TellMessage msg,GameOver], memory) +where + msg = if (how == Success) "Well done! Move on to next exercise." + "Improve your assignment and try again." +verdict actions memory = (actions ++ [GameOver], fail memory) + +find_player :: FootballerID [Footballer] -> Footballer +find_player playerID players = case filter (identify_player playerID) players of + [player : _] = player + no_one = abort ("player " <+++ playerID <+++ " lost in oblivion...") diff --git a/src/StdReferee/RefereeCoach_Slalom_Assignment.dcl b/src/StdReferee/RefereeCoach_Slalom_Assignment.dcl new file mode 100644 index 0000000..21c5274 --- /dev/null +++ b/src/StdReferee/RefereeCoach_Slalom_Assignment.dcl @@ -0,0 +1,5 @@ +definition module RefereeCoach_Slalom_Assignment + +import Referee + +RefereeCoach_Slalom :: !FootballField -> Referee diff --git a/src/StdReferee/RefereeCoach_Slalom_Assignment.icl b/src/StdReferee/RefereeCoach_Slalom_Assignment.icl new file mode 100644 index 0000000..1fabe4b --- /dev/null +++ b/src/StdReferee/RefereeCoach_Slalom_Assignment.icl @@ -0,0 +1,126 @@ +implementation module RefereeCoach_Slalom_Assignment + +import Referee + +RefereeCoach_Slalom :: !FootballField -> Referee +RefereeCoach_Slalom field = { name = "RefereeCoach_Slalom" + , brain = { memory = mkMemory + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Stage = Begin | Slalom | Kick | End Success +instance == Stage where == Begin Begin = True + == Slalom Slalom = True + == Kick Kick = True + == (End s1) (End s2) = s1 == s2 + == _ _ = False + +:: Memory = { positions :: ![Position] // all positions of student player, in reverse order + , stage :: !Stage // the current stage of the training + , home :: Home // home of student player, determined at Begin + } + +mkMemory :: Memory +mkMemory = { positions = [] + , stage = Begin + , home = undef + } + +slalom :: Memory -> Memory +slalom memory = {memory & stage = Slalom} + +after_kick :: Memory -> Memory +after_kick memory = {memory & stage = Kick} + +fail :: Memory -> Memory +fail memory = {memory & stage = End Fail} + +ok :: Memory -> Memory +ok memory = {memory & stage = End Success} + +position :: Position Memory -> Memory +position p memory = {memory & positions = [p:memory.positions]} + +knownHome :: Home Memory -> Memory +knownHome home memory = {memory & home = home} + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) +// Assignment has started. Check teams and determine home of student player. +brain field ({RefereeInput | team1,team2},memory=:{stage = Begin}) +| not ok_teams = ([TellMessage "Wrong teams selected."],fail memory) +| otherwise = ([DirectFreeKick home ball],position student.pos (slalom (knownHome home memory))) +where + (ok_teams,home) = case (team1,team2) of + ([p],[_,_:_]) = (True, West) + ([_,_:_],[p]) = (True, East) + otherwise = (False,undef) + student = if (home == West) (hd team1) (hd team2) + west_ball_pos = {zero & px = scale -0.5 field.flength + penalty_area_depth} + ball = if (home == West) (mirror field west_ball_pos) west_ball_pos +// Assignment has ended. Stop training session. +brain _ (_,memory=:{stage = End how}) + = ([TellMessage msg, GameOver],memory) +where + msg = if (how == Success) "Well done! Move on to next exercise." + "Improve your assignment and try again." +// Assignment is in slalom or kicking stage. +brain field ({RefereeInput | playingTime=time, theBall=ballState, team1, team2}, memory=:{home,positions,stage}) +| time <= zero = ([TellMessage "Out of time."],fail memory) // time's up +| ballIsFree ballState && ballIsOut field ball // ball is out + # ball_pos = ball.ballPos.pxy + # (north,south) = goal_poles field + | not (isbetween ball_pos.py south north) // student did not kick ball in goal + = ([TellMessage "You should play the ball in the goal."],fail memory) + | home == West && ball_pos.px < scale -0.5 field.flength + m 1.0 || + home == East && ball_pos.px > scale 0.5 field.flength - m 1.0 // student kicked ball in wrong goal + = ([TellMessage "You should play the ball in the other goal."],fail memory) + | otherwise = ([ContinueGame],ok memory) // student ended exercise correctly +| isMoved action + | compare_pos student.pos last_pos // student is moving in wrong direction + = ([TellMessage "You're moving in the wrong direction."],fail memory) + | any (\other -> dist other student < m 0.5) others // student moves too close to opponents + = ([TellMessage "Don't move so close to opponents."],fail memory) + | not up_and_down = ([TellMessage "You're not doing a slalom."],fail memory) // student is not doing slalom + | otherwise = ([ContinueGame],memory) +| isKickedBall action + | stage == Kick = ([TellMessage "Don't kick the ball twice."],fail memory) // kick the ball only once + | otherwise = ([ContinueGame],after_kick memory) +| otherwise = ([TellMessage ("Illegal action. Perform only Move and KickBall. You did: " <+++ typeOfAction action)],fail memory) +where + ball = getFootball ballState (team1 ++ team2) + (student,others) = if (home == West) (hd team1,team2) (hd team2,team1) + action = fromJust student.effect + last_pos = hd positions + new_positions = [student.pos : positions] + compare_px = if (home == West) < > + compare_pos pos1 pos2 = compare_px pos1.px pos2.px + close_px pos1 pos2 = abs (pos1.px - pos2.px) <= m 1.0 + line_up_others = sortBy compare_pos (map (\{Footballer | pos} -> pos) others) + close_encounters = takeWhile (not o isEmpty) [filter (close_px other_pos) new_positions \\ other_pos <- line_up_others] + up_and_down = isAlternating + [ map (\studentpos -> studentpos.py < other_pos.py) close_encounter + \\ close_encounter <- close_encounters + & other_pos <- line_up_others + ] + +ballIsOut :: !FootballField !Football -> Bool +ballIsOut field ball = not (point_in_rectangle ({px = scale -0.5 field.flength, py = scale -0.5 field.fwidth} + ,{px = scale 0.5 field.flength, py = scale 0.5 field.fwidth} + ) ball.ballPos.pxy) + +typeOfAction :: !FootballerEffect -> String +typeOfAction (Moved _ _) = "Move" +typeOfAction (GainedBall _) = "GainBall" +typeOfAction (KickedBall _) = "KickBall" +typeOfAction (HeadedBall _) = "HeadBall" +typeOfAction (Feinted _) = "Feint" +typeOfAction (Tackled _ _ _) = "Tackle" +typeOfAction (CaughtBall _) = "Catch" + +isAlternating :: [[a]] -> Bool | Eq, ~ a +isAlternating sequences = isEmpty sequences || all isSingleton singletons && map hd singletons == take n (iterate ~ (hd (hd singletons))) +where + singletons = map removeDup sequences + n = length sequences diff --git a/src/StdReferee/RefereeFunctions.dcl b/src/StdReferee/RefereeFunctions.dcl new file mode 100644 index 0000000..4625e3d --- /dev/null +++ b/src/StdReferee/RefereeFunctions.dcl @@ -0,0 +1,29 @@ +definition module RefereeFunctions + +/** Functions for creating miniscule refereeing brains: +*/ + +import Referee + +/** ball_left_field_at field: + if the ball left the field, it returns (Just edge location) of the field where that happened; + if the ball is inside the field, Nothing is returned. +*/ +ball_left_field_at :: !FootballField -> RefereeAI` (Maybe Position) + +/** ball_in_goal field: + if the ball is in a goal, it returns the home of the field where the ball is; + if the ball is not in a goal, Nothing is returned. +*/ +ball_in_goal :: !FootballField -> RefereeAI` (Maybe Home) + +/** half_of_game total_playing_time: + returns which half of the game is currently being played, assuming that @total_playing_time + is the correct time of the entire match. +*/ +half_of_game :: !PlayingTime -> RefereeAI` Half + +/** offside_players field home: + returns the players from @home that are in offside position. +*/ +players_in_offside_position :: !FootballField !Home -> RefereeAI` (AssocList FootballerID Position) diff --git a/src/StdReferee/RefereeFunctions.icl b/src/StdReferee/RefereeFunctions.icl new file mode 100644 index 0000000..be34336 --- /dev/null +++ b/src/StdReferee/RefereeFunctions.icl @@ -0,0 +1,60 @@ +implementation module RefereeFunctions + +import Referee + +ball_left_field_at :: !FootballField -> RefereeAI` (Maybe Position) +ball_left_field_at field=:{fwidth,flength} + = \{RefereeInput | theBall} + -> case theBall of + Free ball = if (point_in_rectangle field_coordinates ball.ballPos.pxy) + Nothing + (Just (point_to_rectangle field_coordinates ball.ballPos.pxy)) + gained = Nothing // footballers are incapable of leaving the football field +where + field_coordinates = ({px = scale -0.5 flength, py = scale -0.5 fwidth}, {px = scale 0.5 flength, py = scale 0.5 fwidth}) + +ball_in_goal :: !FootballField -> RefereeAI` (Maybe Home) +ball_in_goal field=:{flength} + = \{RefereeInput | theBall} + -> case theBall of + Free ball = let ball_inside = isbetween ball.ballPos.pxy.py south north && ball.ballPos.pz <= goal_height + in if (ball.ballPos.pxy.px < scale -0.5 flength && ball_inside) (Just West) + (if (ball.ballPos.pxy.px > scale 0.5 flength && ball_inside) (Just East) + Nothing + ) + gained = Nothing // footballers must kick the ball in the goal to score +where + (north,south) = goal_poles field + +half_of_game :: !PlayingTime -> RefereeAI` Half +half_of_game total_time + = \{RefereeInput | playingTime} + -> if (playingTime >= scale 0.5 total_time) FirstHalf SecondHalf + +players_in_offside_position :: !FootballField !Home -> RefereeAI` (AssocList FootballerID Position) +players_in_offside_position field home + = \{RefereeInput | theBall,playingHalf,team1,team2} + -> let (players1,players2) = if (home == West && playingHalf == FirstHalf || home == East && playingHalf == SecondHalf) + (displacements team1, displacements team2) + (displacements team2, displacements team1) + ball = getFootball theBall (team1 ++ team2) + in offside_players field ball home players1 players2 + +/** offside_players field ball home team opponents: + returns the players from @team that are in offside position. + @home is the current home of @team, and @opponents are the current opponents. + @ball is the current ball. +*/ +offside_players :: !FootballField !Football !Home !Displacements !Displacements -> Displacements +offside_players field ball home team opponents + = [(player,pos) \\ (player,pos) <- team // a player is in offside position if: + | team_ord pos.px middle_x // he is at the opponent's half of the field, and + && team_ord pos.px opponent_x // he is closer to the opponent's base line than the 2nd-last opponent, and + && team_ord pos.px ball_x // he is closer to the opponent's base line than the ball + ] +where + middle_x = zero + ball_x = ball.ballPos.pxy.px + team_ord = if (home == West) (>) (<) + opponent_x = (snd ((sortBy opponent_ord opponents) !! 1)).px + opponent_ord = if (home == West) (\(_,p1) (_,p2) -> p1.px >= p2.px) (\(_,p1) (_,p2) -> p1.px <= p2.px) diff --git a/src/StdReferee/Umpire.dcl b/src/StdReferee/Umpire.dcl new file mode 100644 index 0000000..393faea --- /dev/null +++ b/src/StdReferee/Umpire.dcl @@ -0,0 +1,5 @@ +definition module Umpire + +import Referee + +umpire :: !FootballField -> Referee diff --git a/src/StdReferee/Umpire.icl b/src/StdReferee/Umpire.icl new file mode 100644 index 0000000..643624e --- /dev/null +++ b/src/StdReferee/Umpire.icl @@ -0,0 +1,276 @@ +implementation module Umpire + +import RefereeFunctions + +umpire :: !FootballField -> Referee +umpire field = { name = "Umpire" + , brain = {memory = Nothing, ai = brain field} + , refActionPics = [] + } + +:: Memory = { total_time :: !PlayingTime // the playing time + , current_half :: !Half // the current playing half (initially FirstHalf) + , placing1 :: !Displacements // the placing of team1 at the start of the match + , placing2 :: !Displacements // the placing of team2 at the start of the match + , forbidden :: !Maybe Home // players from (Just home) are not allowed to play the ball + , offside :: ![FootballerID] // players that are offside and thus should not play the ball + , reprimands :: !AssocList FootballerID [Reprimand] // the reprimands collected by each player + , situation :: !Maybe (Situation,Pending) // the situation of the game + } +:: Situation = IsCenterKick | IsCornerKick | IsDirectFreeKick | IsGoalKick | IsPenaltyKick | IsThrowIn | IsKeeperBall !Home +:: Pending = IsPending !Deadline | IsExecuted +:: Deadline :== Seconds + +brain :: !FootballField !(!RefereeInput,!(!Maybe Memory,!RandomSeed)) -> (!RefereeOutput,!(!Maybe Memory,!RandomSeed)) +// Referee enters the game, so (s)he needs to be filled in on the game details: +brain field (input=:{RefereeInput | team1,team2,playingTime},(Nothing,seed)) +| team1_ok && team2_ok = ([CenterKick West,DisplacePlayers ds], (Just memory,seed)) +| otherwise = ([TellMessage wrong_team,GameOver], (Nothing, seed)) +where + team1_ok = isValidTeam team1 && allPlayersAtHome field West team1 + team2_ok = isValidTeam team2 && allPlayersAtHome field East team2 + wrong_team = if (not team1_ok) (nameOf team1 +++ " is invalid. ") "" +++ + if (not team2_ok) (nameOf team2 +++ " is invalid. ") "" + memory = { total_time = playingTime + , current_half = FirstHalf + , placing1 = displacements team1 + , placing2 = displacements team2 + , forbidden = Just East + , offside = [] + , reprimands = [] + , situation = Just (IsCenterKick,IsPending center_kick_deadline) + } + ds = center_kick_positions field West memory + +// Referee stops the game when a team has less than 7 players: +brain field (input=:{RefereeInput | team1, team2},(Just memory,seed)) +| too_few_players = ([GameCancelled winner,TellMessage ("Game cancelled." <+++ msg)],(Just memory,seed)) +where + too_few_players = too_few_team1 || too_few_team2 + too_few_team1 = length team1 < 7 + too_few_team2 = length team2 < 7 + (winner,msg) = if (too_few_team1 && too_few_team2) (Nothing, "Both teams have less than 7 players left.") + (if too_few_team1 (Just East, nameOf team1 +++> " has less than 7 players left.") + (Just West, nameOf team2 +++> " has less than 7 players left.") + ) + +// Referee checks whether the game is at the first half, second half, or completely over: +brain field (input=:{RefereeInput | playingTime},(Just memory=:{current_half,total_time},seed)) +| playingTime <= zero = ([GameOver], (Just memory_no_offside,seed)) +| current_half <> half = ([EndHalf,CenterKick West,DisplacePlayers ds], (Just memory_2nd_half, seed)) +where + half = half_of_game total_time input + memory_no_offside = { memory & situation = Nothing, offside = [] } + memory_2nd_half = { memory_no_offside & situation = Just (IsCenterKick,IsPending center_kick_deadline), current_half = half, forbidden = Just East } + ds = center_kick_positions field West memory_2nd_half + +// Referee checks whether a team has scored a goal: +brain field (input,(Just memory=:{current_half},seed)) +| isJust in_goal = ([Goal scoring_team,CenterKick (other scoring_team),DisplacePlayers ds],(Just memory_goal,seed)) +where + in_goal = ball_in_goal field input + goal = fromJust in_goal + scoring_team = other goal + ds = center_kick_positions field goal memory + memory_goal = { memory & forbidden = Just scoring_team, offside = [], situation = Just (IsCenterKick,IsPending center_kick_deadline) } + +// Referee checks whether the keeper has caught the ball. +// In that case the keeper is obliged to play the ball within 6 seconds. +brain field (input=:{RefereeInput | team1, team2},(Just memory=:{situation},seed)) +| keeper_catches_ball = ([],(Just memory_keeper_ball,seed)) +where + keeper_catches_ball = not (isEmpty catchers) && catcher.playerNr == 1 && ball_was_uncaught + ball_was_uncaught = isNothing situation || isJust situation && fst (fromJust situation) <> IsKeeperBall team_of_catcher + catchers = [playerID \\ {playerID,effect=Just action} <- team1 ++ team2 | isCaughtBall action] + catcher = hd catchers + team_of_catcher = home_of_player catcher input + memory_keeper_ball = { memory & situation = Just (IsKeeperBall team_of_catcher,IsPending keeper_deadline) + , forbidden = Just (other team_of_catcher) + , offside = [] + } + +// Referee checks whether the ball has exited the football field. +// If the last player who played the ball is not known, then the ball is thrown in by the team playing on the half of the field where the ball left the field. +brain field (input=:{RefereeInput | lastContact},(Just memory=:{current_half},seed)) +| isJust ball_exit = if is_throw_in ([ThrowIn (other team) exit_pos], (Just {memory_enter & situation = Just (IsThrowIn, IsPending restart_deadline)},seed)) + (if is_corner ([Corner (other team) edge], (Just {memory_enter & situation = Just (IsCornerKick,IsPending restart_deadline)},seed)) + ([GoalKick (other team)], (Just {memory_enter & situation = Just (IsGoalKick, IsPending keeper_deadline )},seed)) + ) +where + ball_exit = ball_left_field_at field input + exit_pos = fromJust ball_exit + team = case lastContact of + Just fID = home_of_player fID input + unknown = if (home == West) (if (current_half == FirstHalf) West East) (if (current_half == FirstHalf) East West) + is_throw_in = abs exit_pos.py >= scale 0.5 field.fwidth + is_corner = exit_pos.px <= scale -0.5 field.flength && team == West || exit_pos.px >= scale 0.5 field.flength && team == East + home = if (exit_pos.px < zero) West East + edge = if (exit_pos.py > zero) North South + memory_enter = { memory & forbidden = Just team, offside = [] } + +// Referee checks whether the ball is not played correctly: +brain field (input=:{RefereeInput | team1, team2, playingHalf},(Just memory=:{forbidden},seed)) +| improper_team = ([OwnBallIllegally ball_player,DirectFreeKick (other team) player_pos,DisplacePlayers ds:map (ReprimandPlayer ball_player) new_reprimands] + ,(Just memory_illegal,seed) + ) +where + improper_team = isJust forbidden && ball_is_played && team_of_ball_player == team + ball_players = [(playerID,pos) \\ {playerID,pos,effect=Just action} <- team1 ++ team2 | isBallAction action] + ball_is_played = not (isEmpty ball_players) + (ball_player,player_pos)= hd ball_players + team_of_ball_player = home_of_player ball_player input + team = fromJust forbidden + ds = direct_free_kick_positions team player_pos input + (new_reprimands,memory_reprimanded) + = reprimand_player ball_player Warning { memory & offside = [], situation = Just (IsDirectFreeKick,IsPending free_kick_deadline) } + expel = isMember RedCard new_reprimands + memory_illegal = if expel (expel_player ball_player team_of_ball_player playingHalf memory_reprimanded) memory_reprimanded + +// Referee checks whether the hands-rule has been offended: +brain field (input=:{RefereeInput | team1, team2, playingHalf},(Just memory=:{current_half},seed)) +| hands_offense = ([Hands catcher,DirectFreeKick (other team) catcher_pos,DisplacePlayers ds:map (ReprimandPlayer catcher) new_reprimands] + ,(Just memory_hands,seed) + ) +where + hands_offense = ball_is_caught && (catcher.playerNr <> 1 || not (inPenaltyArea field team catcher_pos)) + catchers = [(playerID,pos) \\ {playerID,pos,effect=Just action} <- team1 ++ team2 | isCaughtBall action] + (catcher,catcher_pos) = hd catchers + ball_is_caught = not (isEmpty catchers) + team = home_of_player catcher input + ds = direct_free_kick_positions team catcher_pos input + (new_reprimands,memory_reprimanded) + = reprimand_player catcher YellowCard { memory & forbidden = Just team, offside = [], situation = Just (IsDirectFreeKick,IsPending free_kick_deadline) } + expel = isMember RedCard new_reprimands + memory_hands = if expel (expel_player catcher team playingHalf memory_reprimanded) memory_reprimanded + +// Referee checks whether the offside-rule has been offended: +brain field (input=:{RefereeInput | team1, team2},(Just memory=:{offside},seed)) +| offside_offense = ([Offside offender,DirectFreeKick (other team) player_pos,DisplacePlayers ds],(Just memory_offside_lifted,seed)) // this should really be an indirect free kick, but that is not implemented yet +where + offside_offense = ball_is_played && isMember offender offside // offside is activated by a player in offside position playing the ball + ball_players = [(playerID,pos) \\ {playerID,pos,effect=Just action} <- team1 ++ team2 | isPlayBallAction action] + ball_is_played = not (isEmpty ball_players) + (offender,player_pos) = hd ball_players + team = home_of_player offender input + ds = direct_free_kick_positions team player_pos input + memory_offside_lifted = { memory & forbidden = Just team, offside = [], situation = Just (IsDirectFreeKick,IsPending free_kick_deadline) } + +// Referee checks whether a team is passive: +brain field (input=:{RefereeInput | theBall, team1, team2, playingHalf},(Just memory=:{forbidden=Just team,situation=Just (state,IsPending dt)},seed)) +| passivity = ([TellMessage msg,DirectFreeKick team ball.ballPos.pxy,DisplacePlayers ds],(Just memory_passive,seed)) +where + passivity = dt < zero + memory_passive = { memory & forbidden = Just (other team), offside = [], situation = Just (IsDirectFreeKick,IsPending free_kick_deadline)} + ball = getFootball theBall (team1 ++ team2) + ds = direct_free_kick_positions (other team) ball.ballPos.pxy input + msg = "Passive play by " <+++ nameOf (if (team == West && playingHalf == FirstHalf || team == East && playingHalf == SecondHalf) team2 team1) + +// Referee checks the status of the rules and remains silent to let the game continue: +brain field (input=:{RefereeInput | theBall, team1, team2},(Just memory=:{situation,forbidden},seed)) +# memory = decrease_pending_time input memory +# memory = if ball_is_played { memory & situation = new_situation } memory +# memory = if (ball_is_played && not no_offside_situation) { memory & offside = at_offside } memory +# memory = if (ball_is_played && lift_forbidden_rule) { memory & forbidden = Nothing } memory += ([],(Just memory,seed)) +where + new_situation = if (isJust situation) (case pending of + IsPending _ = Just (state,IsExecuted) + _ = Nothing + ) Nothing + no_offside_situation = isJust situation && isMember state [IsCornerKick,IsGoalKick,IsThrowIn] + lift_forbidden_rule = isJust forbidden && team_of_ball_player == other forbidden_team + (state,pending) = fromJust situation + forbidden_team = fromJust forbidden + ball_players = [playerID \\ {playerID,effect=Just action} <- team1 ++ team2 | isBallAction action] + ball_is_played = not (isEmpty ball_players) + ball_player = hd ball_players + team_of_ball_player = home_of_player ball_player input + at_offside = [playerID \\ (playerID,_) <- players_in_offside_position field team_of_ball_player input | playerID <> ball_player] + +decrease_pending_time :: !RefereeInput !Memory -> Memory +decrease_pending_time input=:{RefereeInput | unittime} memory=:{situation = Just (state,IsPending dt)} + = { memory & situation = Just (state,IsPending (dt - unittime)) } +decrease_pending_time _ memory + = memory + +expel_player :: !FootballerID !Home !Half !Memory -> Memory +expel_player player team half memory=:{placing1,placing2} +| team == West && half == FirstHalf || team == East && half == SecondHalf + = { memory & placing1 = deletekeyvalue player placing1 } +| otherwise = { memory & placing2 = deletekeyvalue player placing2 } + +reprimand_player :: !FootballerID !Reprimand !Memory -> (![Reprimand],!Memory) +reprimand_player player reprimand memory=:{reprimands} +# new_reprimands = [reprimand] +# new_reprimands = if (length (filter ((==) Warning) (new_reprimands ++ player_reprimands)) >= 3) (new_reprimands ++ [YellowCard]) new_reprimands +# new_reprimands = if (length (filter ((==) YellowCard) (new_reprimands ++ player_reprimands)) >= 2) (new_reprimands ++ [RedCard]) new_reprimands += (new_reprimands, {memory & reprimands = addkeyvalue (player,player_reprimands ++ new_reprimands) reprimands}) +where + player_reprimands = lookupd [] player reprimands + +home_of_player :: !FootballerID !RefereeInput -> Home +home_of_player player {RefereeInput | playingHalf,team1} +| sameClub player (hd team1).playerID + = if (playingHalf == FirstHalf) West East +| otherwise = if (playingHalf == FirstHalf) East West + +isPlayBallAction :: !FootballerEffect -> Bool +isPlayBallAction action = isKickedBall action || isHeadedBall action + +isBallAction :: !FootballerEffect -> Bool +isBallAction action = isKickedBall action || isHeadedBall action || isGainedBall action || isCaughtBall action + +center_kick_positions :: !FootballField !Home !Memory -> Displacements +center_kick_positions field home_kicking_off {placing1,placing2,current_half} +| home_kicking_off == West = kick_off positions1 ++ map repell_from_center positions2 +| otherwise = map repell_from_center positions1 ++ kick_off positions2 +where + (positions1,positions2) = if (current_half == FirstHalf) (placing1,placing2) + ([(playerID,mirror field pos) \\ (playerID,pos) <- placing2] + ,[(playerID,mirror field pos) \\ (playerID,pos) <- placing1] + ) + center = zero + repell_from_center = \(player,pos) -> (player,repell radius_centre_circle center pos) + attract_to_center = \(player,pos) -> (player,attract (m 0.5) center pos) + kick_off placement = map attract_to_center closest ++ map repell_from_center others + where + sorted = sortBy (\(_,pos1) (_,pos2) -> dist pos1 center < dist pos2 center) placement + (closest,others) = splitAt 2 sorted + +/** direct_free_kick_positions home pos input: + move players of @home away from @pos, and attract the closest fielder of (other @home) to @pos. +*/ +direct_free_kick_positions :: !Home !Position !RefereeInput -> Displacements +direct_free_kick_positions team free_kick_pos input=:{RefereeInput | team1, team2, playingHalf} + = [attract_kicker : push_away_offenders] +where + (offenders,free_kickers)= if (team == West && playingHalf == FirstHalf || team == East && playingHalf == SecondHalf) (team1,team2) (team2,team1) + push_away_offenders = map (\{playerID,pos} -> (playerID,repell repell_distance free_kick_pos pos)) offenders + closest_player = snd (hd (sortBy (\(d1,_) (d2,_) -> d1 < d2) [(dist free_kick_pos player,player) \\ player <- free_kickers | isFielder player])) + attract_kicker = (closest_player.playerID,attract (m 1.0) free_kick_pos closest_player.pos) + +keeper_deadline :== s 6.0 +center_kick_deadline :== s 1.0 +free_kick_deadline :== s 1.0 +restart_deadline :== s 20.0 + +instance == Situation where == IsCenterKick IsCenterKick = True + == IsCornerKick IsCornerKick = True + == IsDirectFreeKick IsDirectFreeKick = True + == IsGoalKick IsGoalKick = True + == IsPenaltyKick IsPenaltyKick = True + == IsThrowIn IsThrowIn = True + == (IsKeeperBall t1) (IsKeeperBall t2) = t1 == t2 + == _ _ = False +instance == Pending where == (IsPending t1) (IsPending t2) = t1 == t2 + == IsExecuted IsExecuted = True + == _ _ = False +instance toString Situation where toString IsCenterKick = "IsCenterKick" + toString IsCornerKick = "IsCornerKick" + toString IsDirectFreeKick = "IsDirectFreeKick" + toString IsGoalKick = "IsGoalKick" + toString IsPenaltyKick = "IsPenaltyKick" + toString IsThrowIn = "IsThrowIn" + toString (IsKeeperBall h) = "(IsKeeperBall " <+++ h <+++ ")" +instance toString Pending where toString (IsPending t) = "(IsPending " <+++ t <+++ ")" + toString IsExecuted = "IsExecuted" diff --git a/src/StdTeam/Buffer.dcl b/src/StdTeam/Buffer.dcl new file mode 100644 index 0000000..13b172c --- /dev/null +++ b/src/StdTeam/Buffer.dcl @@ -0,0 +1,11 @@ +definition module Buffer + +/** This module implements a footballer who only runs in north-south direction on the + football field. This player can be used for assignments, such as the deep pass + assignments. + + Developed by Wanja Krah. +*/ +import Footballer + +buffer :: !FootballField !Home !Edge !FootballerID -> Footballer diff --git a/src/StdTeam/Buffer.icl b/src/StdTeam/Buffer.icl new file mode 100644 index 0000000..b82a022 --- /dev/null +++ b/src/StdTeam/Buffer.icl @@ -0,0 +1,41 @@ +implementation module Buffer + +import StdEnvExt +import Footballer + +buffer :: !FootballField !Home !Edge !FootballerID -> Footballer +buffer field home edge playerID = {defaultFootballer playerID & name = "buffer" + , length = m 2.2 + , skills = (Running, Gaining, Rotating) + , brain = { memory = {curDir = if (edge == North) (rad (0.5*pi)) (rad (-0.5*pi))} + , ai = the_mind_of_a_buffer field home + } + } + +:: Memory = { curDir :: !Angle + } + +the_mind_of_a_buffer :: !FootballField !Home !(!BrainInput,!Memory) -> (!BrainOutput,!Memory) +the_mind_of_a_buffer field home ({football,others,me},memory) +| dist ball me < maxGainReach me // I can gain the ball + = (GainBall,memory) +| dist ball me < m 30.0 && ballIsInZone // I can not gain the ball, but I can run to it + = (runTowardsBall,memory) +| abs me.pos.py > scale 0.5 field.fwidth - sidebuffer // near the edge, turn around + = (Move {velocity = ms 25.0,direction=new_direction} zero, {memory & curDir = new_direction}) + with + new_direction = if (me.speed.direction < zero) (rad (0.5*pi)) (rad (-0.5*pi)) +| otherwise = (Move {velocity = ms 25.0,direction=memory.curDir} zero,memory) // no ball, no turning, just keep running +where + sidebuffer = scale 0.01 field.fwidth + ball = getFootball football [me:others] + ball_x = ball.ballPos.pxy.px + ballIsInZone = if (home == East) (isbetween ball_x (scale 0.15 field.flength) (scale 0.20 field.flength)) + (isbetween ball_x (scale -0.10 field.flength) (scale -0.10 field.flength)) + nextBallPos = (nextpos ball).ballPos + direction2ball = bearing me.speed.direction me nextBallPos.pxy + runTowardsBall = Move {direction=direction2ball,velocity=ms 10.0} zero + +nextpos :: !Football -> Football +nextpos ball=:{ballSpeed={vxy={velocity=v,direction=d},vz=v3},ballPos} + = {ball & ballPos = move_point3D {zero & dxy={dx=m (cosinus d * toReal v),dy=m (sinus d * toReal v)}} ballPos} diff --git a/src/StdTeam/KeeperChallenger.dcl b/src/StdTeam/KeeperChallenger.dcl new file mode 100644 index 0000000..6022faa --- /dev/null +++ b/src/StdTeam/KeeperChallenger.dcl @@ -0,0 +1,5 @@ +definition module KeeperChallenger + +import Footballer + +keeperChallenger :: !FootballerID -> Footballer diff --git a/src/StdTeam/KeeperChallenger.icl b/src/StdTeam/KeeperChallenger.icl new file mode 100644 index 0000000..427fd07 --- /dev/null +++ b/src/StdTeam/KeeperChallenger.icl @@ -0,0 +1,39 @@ +implementation module KeeperChallenger + +import Team + +keeperChallenger :: !FootballerID -> Footballer +keeperChallenger playerID = { defaultFootballer playerID & name = "Zidane" + , length = m 2.2 + , skills = (Gaining, Catching, Kicking) + , brain = {memory = {waitToKick = 0}, ai = mind} + } + +:: Memory = { waitToKick :: !Int } + +decreaseWait :: !Memory -> Memory +decreaseWait memory=:{waitToKick} = {memory & waitToKick = max 0 (waitToKick-1)} + +startWaiting :: !Memory -> Memory +startWaiting memory = {memory & waitToKick = 20} + +mind :: !(!BrainInput,!Memory) -> (!BrainOutput,!Memory) +mind ({football,others,me},memory) +| memory.waitToKick > 0 = (Move zero zero,decreaseWait memory) +| ballIsGainedBy me.playerID football + = (KickBall {vxy={direction=bearing zero me next_pos,velocity=ms (max 5.0 (toReal (dist me next_pos)))},vz=ms 1.0},startWaiting memory) +| ballIsFree football && i_am_closest_to_ball + | dist_to_free_ball <= maxGainReach me + = (GainBall,memory) + | otherwise = (Move {direction=angle_with_free_ball,velocity=ms 4.0} (angle_with_free_ball - me.nose),memory) +| otherwise = (Move zero zero,memory) +where + team_players = filter (sameClub me) others + my_nr = me.playerID.playerNr + next_nr = ((my_nr-1) rem (length team_players)) + 2 + next_player = hd (filter (identify_player {me.playerID & playerNr=next_nr}) team_players) + next_pos = next_player.pos + free_ball = getFootball football [me:others] + angle_with_free_ball = bearing zero me free_ball + dist_to_free_ball = dist me free_ball + i_am_closest_to_ball = dist_to_free_ball <= minList (map (dist free_ball) team_players) diff --git a/src/StdTeam/TeamMiniEffie.dcl b/src/StdTeam/TeamMiniEffie.dcl new file mode 100644 index 0000000..5d3910f --- /dev/null +++ b/src/StdTeam/TeamMiniEffie.dcl @@ -0,0 +1,10 @@ +definition module TeamMiniEffie + +/** This module implements a team of simple minded football players. + Use it for testing Soccer-Fun. +*/ + +import Team + +Team_MiniEffies :: !Home !FootballField -> Team +base_TeamName_MiniEffie :: String diff --git a/src/StdTeam/TeamMiniEffie.icl b/src/StdTeam/TeamMiniEffie.icl new file mode 100644 index 0000000..13929cb --- /dev/null +++ b/src/StdTeam/TeamMiniEffie.icl @@ -0,0 +1,69 @@ +implementation module TeamMiniEffie + +import StdEnv, StdIO, Footballer, FootballerFunctions + +Team_MiniEffies :: !Home !FootballField -> Team +Team_MiniEffies home field +| home==West = westTeam +| otherwise = eastTeam +where + eastTeam = mirror field westTeam + westTeam = [keeper : fielders] + clubname = base_TeamName_MiniEffie +++ if (home == West) "W" "E" + keeper = MiniEffie clubname home field {zero & px=scale -0.5 field.flength} 1 + fielders = [ MiniEffie clubname home field {px=scale (-0.5*dx) field.flength,py=scale (0.5*dy) field.fwidth} nr + \\ (dx,dy) <- west_positions_fielders + & nr <- [2..] + ] + west_positions_fielders = [(0.20, 0.40) + ,(0.20,-0.40) + ,(0.23, 0.00) + ,(0.50, 0.45) + ,(0.50,-0.45) + ,(0.60, 0.00) + ,(0.70, 0.35) + ,(0.70,-0.35) + ,(0.90, 0.05) + ,(0.90,-0.05) + ] + +base_TeamName_MiniEffie :: String +base_TeamName_MiniEffie = "MiniEffies" + +:: MiniMemory = { home :: !Home } + +MiniEffie :: !ClubName !Home !FootballField !Position !PlayersNumber -> Footballer +MiniEffie club home field position nr + = { playerID = {clubName=club,playerNr=nr} + , name = "MiniF." <+++ nr + , length = min_length + , pos = position + , nose = zero + , speed = zero + , skills = (Running, Kicking, Rotating) + , effect = Nothing + , stamina = max_stamina + , health = max_health + , brain = { memory = {home=home}, ai = minibrain field } + } + +minibrain :: !FootballField !(!BrainInput,!MiniMemory) -> (!BrainOutput,!MiniMemory) +minibrain field (input=:{referee,me}, memory=:{home}) +| i_am_close_to_the_ball + | i_can_see goal = (kick_the_ball, new_memory) + | otherwise = (turn_to_face goal, new_memory) +| i_can_see ball = (run_to_the_ball, new_memory) +| otherwise = (turn_to_face ball, new_memory) +where + new_memory = {home=if (any isEndHalf referee) (other home) home} + my_direction = me.nose + ball = getBall input + goal = centerOfGoal (other home) field + + i_am_close_to_the_ball = dist me ball < maxKickReach me + i_can_see pos = abs (bearing my_direction me pos) < rad (0.05*pi) + + run_to_the_ball = Move {direction=bearing zero me ball,velocity=speed_of_light} zero + turn_to_face pos = Move zero (bearing my_direction me pos) + kick_the_ball = KickBall {vxy={direction=my_direction,velocity=speed_of_light}, vz=ms 1.0} + speed_of_light = ms 299792458.0 diff --git a/src/StdTeam/Team_Opponent_DeepPass_Assignment.dcl b/src/StdTeam/Team_Opponent_DeepPass_Assignment.dcl new file mode 100644 index 0000000..2c232d7 --- /dev/null +++ b/src/StdTeam/Team_Opponent_DeepPass_Assignment.dcl @@ -0,0 +1,10 @@ +definition module Team_Opponent_DeepPass_Assignment + +/** Team_Opponent_DeepPass creates a team of opponents to be used in the deep pass assignment. + The base name of that team is base_TeamName_Opponent_DeepPass1. +*/ + +import Team + +Team_Opponent_DeepPass :: !Home FootballField -> Team +base_TeamName_Opponent_DeepPass :: String diff --git a/src/StdTeam/Team_Opponent_DeepPass_Assignment.icl b/src/StdTeam/Team_Opponent_DeepPass_Assignment.icl new file mode 100644 index 0000000..1871f1f --- /dev/null +++ b/src/StdTeam/Team_Opponent_DeepPass_Assignment.icl @@ -0,0 +1,37 @@ +implementation module Team_Opponent_DeepPass_Assignment + +import StdEnvExt +import Team +from Buffer import buffer + +Team_Opponent_DeepPass :: !Home FootballField -> Team +Team_Opponent_DeepPass home field + = map tagName fielders +where + club = base_TeamName_Opponent_DeepPass +++ if (home == West) "_W" "_E" + fielders = getFielders club home field + +base_TeamName_Opponent_DeepPass :: String +base_TeamName_Opponent_DeepPass = "Opp_Deep_Pass" + +getFielders :: String Home FootballField -> [Footballer] +getFielders club home field + # buf1 = {buffer field home south {clubName=club,playerNr=2 } & pos={px=scale 0.07 field.flength, py=scale 0.40 field.fwidth}} + # buf2 = {buffer field home south {clubName=club,playerNr=3 } & pos={px=scale 0.12 field.flength, py=scale 0.08 field.fwidth}} + # buf3 = {buffer field home north {clubName=club,playerNr=4 } & pos={px=scale 0.06 field.flength, py=scale 0.00 field.fwidth}} + # buf4 = {buffer field home south {clubName=club,playerNr=5 } & pos={px=scale 0.11 field.flength, py=scale -0.20 field.fwidth}} + # buf5 = {buffer field home north {clubName=club,playerNr=6 } & pos={px=scale 0.12 field.flength, py=scale 0.20 field.fwidth}} + # buf6 = {buffer field home south {clubName=club,playerNr=7 } & pos={px=scale 0.13 field.flength, py=scale 0.00 field.fwidth}} + # buf7 = {buffer field home south {clubName=club,playerNr=8 } & pos={px=scale 0.10 field.flength, py=scale -0.19 field.fwidth}} + # buf8 = {buffer field home north {clubName=club,playerNr=9 } & pos={px=scale 0.15 field.flength, py=scale 0.07 field.fwidth}} + # buf9 = {buffer field home north {clubName=club,playerNr=10} & pos={px=scale 0.05 field.flength, py=scale -0.08 field.fwidth}} + # buf10 = {buffer field home south {clubName=club,playerNr=11} & pos={px=scale 0.15 field.flength, py=scale 0.22 field.fwidth}} + # buf11 = {buffer field home north {clubName=club,playerNr=12} & pos={px=scale 0.08 field.flength, py=scale -0.14 field.fwidth}} + # fielders = [buf1,buf2,buf3,buf4,buf5,buf6,buf7,buf8,buf9,buf10,buf11] + | home == East = fielders + | otherwise = mirror field fielders +where + (south,north) = if (home == West) (North,South) (South,North) + +tagName :: !Footballer -> Footballer +tagName fb=:{playerID,name} = {Footballer | fb & name = name <+++ "_" <+++ playerID.playerNr} diff --git a/src/StdTeam/Team_Opponent_Keeper_Assignment.dcl b/src/StdTeam/Team_Opponent_Keeper_Assignment.dcl new file mode 100644 index 0000000..e187581 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Keeper_Assignment.dcl @@ -0,0 +1,10 @@ +definition module Team_Opponent_Keeper_Assignment + +/** Team_Opponent_Keeper creates a team of opponents that can be used to train a keeper. + The base name of that team is base_TeamName_Opponent_Keeper. +*/ + +import Team + +Team_Opponent_Keeper :: !Home FootballField -> Team +base_TeamName_Opponent_Keeper :: String diff --git a/src/StdTeam/Team_Opponent_Keeper_Assignment.icl b/src/StdTeam/Team_Opponent_Keeper_Assignment.icl new file mode 100644 index 0000000..7551174 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Keeper_Assignment.icl @@ -0,0 +1,39 @@ +implementation module Team_Opponent_Keeper_Assignment + +import Team +from KeeperChallenger import keeperChallenger + +Team_Opponent_Keeper :: !Home FootballField -> Team +Team_Opponent_Keeper home field + = getFielders club home field +where + club = base_TeamName_Opponent_Keeper +++ if (home==West) "_W" "_E" + +base_TeamName_Opponent_Keeper :: String +base_TeamName_Opponent_Keeper = "Opp_Keeper" + +getFielders :: String Home FootballField -> [Footballer] +getFielders club home field + # chal1 = {keeperChallenger {clubName=club,playerNr=2} & pos = {px=west_edge + scale 0.025 field.flength,py=scale 0.20 field.fwidth} + , speed = {(keeperChallenger {clubName=club,playerNr=2}).speed & direction = rad (1.4*pi)} + } + # chal2 = {keeperChallenger {clubName=club,playerNr=3} & pos = {px=west_edge + scale 0.060 field.flength,py=scale 0.15 field.fwidth}} + # chal3 = {keeperChallenger {clubName=club,playerNr=4} & pos = {px=west_edge + scale 0.080 field.flength,py=scale 0.00 field.fwidth} + , speed = {(keeperChallenger {clubName=club,playerNr=4}).speed & direction = rad (0.0*pi)} + } + # chal4 = {keeperChallenger {clubName=club,playerNr=5} & pos = {px=west_edge + scale 0.060 field.flength,py=scale -0.15 field.fwidth}} + # chal5 = {keeperChallenger {clubName=club,playerNr=6} & pos = {px=west_edge + scale 0.025 field.flength,py=scale -0.20 field.fwidth} + , speed = {(keeperChallenger {clubName=club,playerNr=6}).speed & direction = rad (0.6*pi)} + } + # fielders = [chal1,chal2,chal3,chal4,chal5] + # fielders = map (mirrorDirection home) fielders + | home == East = fielders + | otherwise = mirror field fielders +where + west_edge = scale -0.5 field.flength + +mirrorDirection :: !Home !Footballer -> Footballer +mirrorDirection home fielder + = {fielder & speed = {fielder.speed & direction = if (d > rad pi) (d - rad pi) (d + rad pi)}} +where + d = fielder.speed.direction diff --git a/src/StdTeam/Team_Opponent_Passing_Assignment.dcl b/src/StdTeam/Team_Opponent_Passing_Assignment.dcl new file mode 100644 index 0000000..a268f19 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Passing_Assignment.dcl @@ -0,0 +1,10 @@ +definition module Team_Opponent_Passing_Assignment + +/** Team_Opponent_Passing creates a team of opponents to be used in the passing assignment. + The base name of that team is base_TeamName_Opponent_Passing. +*/ + +import Team + +Team_Opponent_Passing :: !Home FootballField -> Team +base_TeamName_Opponent_Passing :: String diff --git a/src/StdTeam/Team_Opponent_Passing_Assignment.icl b/src/StdTeam/Team_Opponent_Passing_Assignment.icl new file mode 100644 index 0000000..38907f0 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Passing_Assignment.icl @@ -0,0 +1,12 @@ +implementation module Team_Opponent_Passing_Assignment + +import Footballer + +Team_Opponent_Passing :: !Home FootballField -> Team +Team_Opponent_Passing home field + = [defaultFootballer {clubName=club,playerNr=2}] +where + club = base_TeamName_Opponent_Passing +++ if (home == West) "_W" "_E" + +base_TeamName_Opponent_Passing :: String +base_TeamName_Opponent_Passing = "Opp_Passing" diff --git a/src/StdTeam/Team_Opponent_Slalom_Assignment.dcl b/src/StdTeam/Team_Opponent_Slalom_Assignment.dcl new file mode 100644 index 0000000..cc14ce4 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Slalom_Assignment.dcl @@ -0,0 +1,10 @@ +definition module Team_Opponent_Slalom_Assignment + +/** Team_Opponent_Slalom creates a team of opponents to be used in the slalom assignment. + The base name of that team is base_TeamName_Opponent_Slalom. +*/ + +import Team + +Team_Opponent_Slalom :: !Home FootballField -> Team +base_TeamName_Opponent_Slalom :: String diff --git a/src/StdTeam/Team_Opponent_Slalom_Assignment.icl b/src/StdTeam/Team_Opponent_Slalom_Assignment.icl new file mode 100644 index 0000000..c193d11 --- /dev/null +++ b/src/StdTeam/Team_Opponent_Slalom_Assignment.icl @@ -0,0 +1,21 @@ +implementation module Team_Opponent_Slalom_Assignment + +import StdReal +import Footballer + +Team_Opponent_Slalom :: !Home FootballField -> Team +Team_Opponent_Slalom home field + = if (home == West) dummies (mirror field dummies) +where + club = base_TeamName_Opponent_Slalom +++ if (home == West) "_W" "_E" + keeper = Nothing + dummies = [dummy1,dummy2,dummy3,dummy4,dummy5] + dummy1 = {defaultFootballer {clubName=club,playerNr=2} & pos={zero & px = west_edge + scale 0.09 field.flength}} + dummy2 = {defaultFootballer {clubName=club,playerNr=3} & pos={zero & px = west_edge + scale 0.19 field.flength}} + dummy3 = {defaultFootballer {clubName=club,playerNr=4} & pos={zero & px = west_edge + scale 0.24 field.flength}} + dummy4 = {defaultFootballer {clubName=club,playerNr=5} & pos={zero & px = scale 0.11 field.flength}} + dummy5 = {defaultFootballer {clubName=club,playerNr=6} & pos={zero & px = scale 0.15 field.flength}} + west_edge = scale -0.5 field.flength + +base_TeamName_Opponent_Slalom :: String +base_TeamName_Opponent_Slalom = "Opp_Slalom" diff --git a/src/StdTeam/Team_Student_DeepPass_Assignment.dcl b/src/StdTeam/Team_Student_DeepPass_Assignment.dcl new file mode 100644 index 0000000..455aba6 --- /dev/null +++ b/src/StdTeam/Team_Student_DeepPass_Assignment.dcl @@ -0,0 +1,13 @@ +definition module Team_Student_DeepPass_Assignment + +/** This module is supposed to implement a solution to the deep passing assignment. + For testing purposes, use the RefereeCoach_DeepPass_assignment referee and + Team_Opponent_Pass_Assignment opponent team. + + Further instructions are in the .icl module (press Ctrl+/). +*/ + +import Team + +Team_Student_DeepPass :: !Home FootballField -> Team +base_TeamName_Student_DeepPass :: String diff --git a/src/StdTeam/Team_Student_DeepPass_Assignment.icl b/src/StdTeam/Team_Student_DeepPass_Assignment.icl new file mode 100644 index 0000000..9d735b1 --- /dev/null +++ b/src/StdTeam/Team_Student_DeepPass_Assignment.icl @@ -0,0 +1,25 @@ +implementation module Team_Student_DeepPass_Assignment + +/** Implement a solution to the deep passing assignment. + + Your team consists of two players, with player's numbers 2 and 3 respectively. + Below you should only change the definition of footballer to your solution. + Do not change the positions and player identifications. + Do not change the implementation of base_TeamName_Student_DeepPass. +*/ + +import Footballer + +Team_Student_DeepPass :: !Home FootballField -> Team +Team_Student_DeepPass home field = if (home == West) team (mirror field team) +where + team = [ {footballer {clubName=club,playerNr=nr} & pos = toPosition (scale (0.5*x) field.flength,scale (0.5*y) field.fwidth)} + \\ (x,y) <- positions + & nr <- [2,3] + ] + club = base_TeamName_Student_DeepPass +++ if (home==West) "_W" "_E" + positions = [(0.05,-0.05),(0.35,0.05)] + footballer playerID = defaultFootballer playerID // implement your footballer here + +base_TeamName_Student_DeepPass :: String +base_TeamName_Student_DeepPass = "Student Deep Pass" diff --git a/src/StdTeam/Team_Student_Keeper_Assignment.dcl b/src/StdTeam/Team_Student_Keeper_Assignment.dcl new file mode 100644 index 0000000..a3e89ed --- /dev/null +++ b/src/StdTeam/Team_Student_Keeper_Assignment.dcl @@ -0,0 +1,13 @@ +definition module Team_Student_Keeper_Assignment + +/** This module is supposed to implement a solution to the keeper assignment. + For testing purposes, use the RefereeCoach_Keeper_Assignment referee and + Team_Opponent_Keeper_Assignment opponent team. + + Further instructions are in the .icl module (press Ctrl+/). +*/ + +import Team + +Team_Student_Keeper :: !Home FootballField -> Team +base_TeamName_Student_Keeper :: String diff --git a/src/StdTeam/Team_Student_Keeper_Assignment.icl b/src/StdTeam/Team_Student_Keeper_Assignment.icl new file mode 100644 index 0000000..13e8459 --- /dev/null +++ b/src/StdTeam/Team_Student_Keeper_Assignment.icl @@ -0,0 +1,22 @@ +implementation module Team_Student_Keeper_Assignment + +/** Implement a solution to the keeper assignment. + + Your team consists of a single keeper, with player's number 1. + Below you should only change the definition of footballer to your solution. + Do not change the positions and player identifications. + Do not change the implementation of base_TeamName_Student_Keeper. +*/ + +import Footballer + +Team_Student_Keeper :: !Home FootballField -> Team +Team_Student_Keeper home field = if (home == West) team (mirror field team) +where + team = [{footballer {clubName=club,playerNr=1} & pos = {zero & px = scale -0.485 field.flength}}] + club = base_TeamName_Student_Keeper +++ if (home == West) "_W" "_E" + footballer playerID = defaultFootballer playerID // implement your footballer here + +base_TeamName_Student_Keeper :: String +base_TeamName_Student_Keeper = "Student Keeper" + diff --git a/src/StdTeam/Team_Student_Passing_Assignment.dcl b/src/StdTeam/Team_Student_Passing_Assignment.dcl new file mode 100644 index 0000000..c8bb7a0 --- /dev/null +++ b/src/StdTeam/Team_Student_Passing_Assignment.dcl @@ -0,0 +1,13 @@ +definition module Team_Student_Passing_Assignment + +/** This module is supposed to implement a solution to the passing assignment. + For testing purposes, use the RefereeCoach_Passing_Assignment referee and + Team_Opponent_Passing_Assignment opponent team. + + Further instructions are in the .icl module (press Ctrl+/). +*/ + +import Team + +Team_Student_Passing :: !Home FootballField -> Team +base_TeamName_Student_Passing :: String diff --git a/src/StdTeam/Team_Student_Passing_Assignment.icl b/src/StdTeam/Team_Student_Passing_Assignment.icl new file mode 100644 index 0000000..ce8f846 --- /dev/null +++ b/src/StdTeam/Team_Student_Passing_Assignment.icl @@ -0,0 +1,33 @@ +implementation module Team_Student_Passing_Assignment + +/** Implement a solution to the passing assignment. + + Your team consists of six players, with player's numbers 2 upto 7. + Below you should only change the definition of footballer to your solution. + Do not change the positions, player identifications, nor noses. + Do not change the implementation of base_TeamName_Student_Passing. +*/ + +import Footballer + +Team_Student_Passing :: !Home FootballField -> Team +Team_Student_Passing home field = if (home == West) team (mirror field team) +where + team = [ {footballer {clubName=club,playerNr=nr} & pos = toPosition (scale (0.5*x) field.flength,scale (0.5*y) field.fwidth),nose = rad (dir*pi)} + \\ (x,y) <- positions + & nr <- [2..] + & dir <- noses + ] + club = base_TeamName_Student_Passing +++ if (home==West) "_W" "_E" + positions = [(-0.43, 0.00) + ,(-0.35, 0.30) + ,( 0.00,-0.10) + ,( 0.15, 0.20) + ,( 0.32, 0.10) + ,( 0.43,-0.05) + ] + noses = [1.8,0.0,1.5,0.5,1.2,0.2] + footballer playerID = defaultFootballer playerID // implement your footballer here + +base_TeamName_Student_Passing :: String +base_TeamName_Student_Passing = "Student Passing" diff --git a/src/StdTeam/Team_Student_Rounds_Assignment.dcl b/src/StdTeam/Team_Student_Rounds_Assignment.dcl new file mode 100644 index 0000000..07ee5d5 --- /dev/null +++ b/src/StdTeam/Team_Student_Rounds_Assignment.dcl @@ -0,0 +1,13 @@ +definition module Team_Student_Rounds_Assignment + +/** This module is supposed to implement a solution to the rounds running assignment. + For testing purposes, use the RefereeCoach_Rounds_Assignment referee. + Your opponent can also be the Team_Student_Rounds_Assignment. + + Further instructions are in the .icl module (press Ctrl+/). +*/ + +import Team + +Team_Student_Rounds :: !Home !FootballField -> Team +base_TeamName_Student_Rounds :: String diff --git a/src/StdTeam/Team_Student_Rounds_Assignment.icl b/src/StdTeam/Team_Student_Rounds_Assignment.icl new file mode 100644 index 0000000..8c0e333 --- /dev/null +++ b/src/StdTeam/Team_Student_Rounds_Assignment.icl @@ -0,0 +1,24 @@ +implementation module Team_Student_Rounds_Assignment + +/** Implement a solution to the rounds running assignment. + + Your team consists of one player. + Below you only need to change the definition of footballer to your solution. + Do not change the position and player identification. + Do not change the implementation of base_TeamName_Student_Rounds. +*/ +import Footballer + +Team_Student_Rounds :: !Home !FootballField -> Team +Team_Student_Rounds home field = if (home == West) team (mirror field team) +where + team = [ {footballer {clubName=club,playerNr=nr} & pos = toPosition (scale x field.flength,scale y field.fwidth)} + \\ (x,y) <- positions + & nr <- [2..] + ] + club = base_TeamName_Student_Rounds +++ if (home==West) "_W" "_E" + positions = [(-0.49,0.00)] + footballer playerID = defaultFootballer playerID // implement your footballer here + +base_TeamName_Student_Rounds :: String +base_TeamName_Student_Rounds = "Student Rounds" diff --git a/src/StdTeam/Team_Student_Slalom_Assignment.dcl b/src/StdTeam/Team_Student_Slalom_Assignment.dcl new file mode 100644 index 0000000..64f442f --- /dev/null +++ b/src/StdTeam/Team_Student_Slalom_Assignment.dcl @@ -0,0 +1,12 @@ +definition module Team_Student_Slalom_Assignment + +/** This module is supposed to implement a solution to the slalom assignment. + For testing purposes, use the RefereeCoach_Slalom_Assignment referee and + Team_Opponent_Slalom_Assignment opponent team. + + Further instructions are in the .icl module (press Ctrl+/). +*/ +import Team + +Team_Student_Slalom :: !Home FootballField -> Team +base_TeamName_Student_Slalom :: String diff --git a/src/StdTeam/Team_Student_Slalom_Assignment.icl b/src/StdTeam/Team_Student_Slalom_Assignment.icl new file mode 100644 index 0000000..a77671d --- /dev/null +++ b/src/StdTeam/Team_Student_Slalom_Assignment.icl @@ -0,0 +1,23 @@ +implementation module Team_Student_Slalom_Assignment + +/** Implement a solution to the slalom assignment. + + Your team consists of one field player, with player's number 2. + Below you should only change the definition of footballer to your solution. + Do not change the position and player identification. + Do not change the implementation of base_TeamName_Student_Slalom. +*/ + +import Footballer +import FootballerFunctions + +Team_Student_Slalom :: !Home FootballField -> Team +Team_Student_Slalom home field = team +where + team = [{footballer {clubName=club,playerNr=2} & pos = if (home == West) position (mirror field position)}] + club = base_TeamName_Student_Slalom +++ if (home == West) "_W" "_E" + position = {zero & px = scale -0.5 field.flength + penalty_area_depth} + footballer player_id = defaultFootballer player_id // implement your footballer here + +base_TeamName_Student_Slalom :: String +base_TeamName_Student_Slalom = "Student Slalom" diff --git a/src/afbeeldingen/AmsterdamArenA.bmp b/src/afbeeldingen/AmsterdamArenA.bmp new file mode 100644 index 0000000..5833760 Binary files /dev/null and b/src/afbeeldingen/AmsterdamArenA.bmp differ diff --git a/src/afbeeldingen/Thumbs.db b/src/afbeeldingen/Thumbs.db new file mode 100644 index 0000000..42778ae Binary files /dev/null and b/src/afbeeldingen/Thumbs.db differ diff --git a/src/afbeeldingen/hands.bmp b/src/afbeeldingen/hands.bmp new file mode 100644 index 0000000..e52144b Binary files /dev/null and b/src/afbeeldingen/hands.bmp differ diff --git a/src/afbeeldingen/ivanov_badluck.bmp b/src/afbeeldingen/ivanov_badluck.bmp new file mode 100644 index 0000000..d2d316c Binary files /dev/null and b/src/afbeeldingen/ivanov_badluck.bmp differ diff --git a/src/afbeeldingen/ivanov_fluit.bmp b/src/afbeeldingen/ivanov_fluit.bmp new file mode 100644 index 0000000..0707e3b Binary files /dev/null and b/src/afbeeldingen/ivanov_fluit.bmp differ diff --git a/src/afbeeldingen/ivanov_look.bmp b/src/afbeeldingen/ivanov_look.bmp new file mode 100644 index 0000000..d0542c2 Binary files /dev/null and b/src/afbeeldingen/ivanov_look.bmp differ diff --git a/src/afbeeldingen/ivanov_red.bmp b/src/afbeeldingen/ivanov_red.bmp new file mode 100644 index 0000000..a525b52 Binary files /dev/null and b/src/afbeeldingen/ivanov_red.bmp differ diff --git a/src/afbeeldingen/ivanov_theater.bmp b/src/afbeeldingen/ivanov_theater.bmp new file mode 100644 index 0000000..e4dd3c7 Binary files /dev/null and b/src/afbeeldingen/ivanov_theater.bmp differ diff --git a/src/afbeeldingen/ivanov_warning.bmp b/src/afbeeldingen/ivanov_warning.bmp new file mode 100644 index 0000000..c9ed917 Binary files /dev/null and b/src/afbeeldingen/ivanov_warning.bmp differ diff --git a/src/afbeeldingen/ivanov_wijst_links.bmp b/src/afbeeldingen/ivanov_wijst_links.bmp new file mode 100644 index 0000000..9be93cb Binary files /dev/null and b/src/afbeeldingen/ivanov_wijst_links.bmp differ diff --git a/src/afbeeldingen/ivanov_wijst_rechts.bmp b/src/afbeeldingen/ivanov_wijst_rechts.bmp new file mode 100644 index 0000000..bb89aa4 Binary files /dev/null and b/src/afbeeldingen/ivanov_wijst_rechts.bmp differ diff --git a/src/afbeeldingen/ivanov_yellow.bmp b/src/afbeeldingen/ivanov_yellow.bmp new file mode 100644 index 0000000..392c51c Binary files /dev/null and b/src/afbeeldingen/ivanov_yellow.bmp differ diff --git a/src/sound/CenterKick.wav b/src/sound/CenterKick.wav new file mode 100644 index 0000000..8b7b781 Binary files /dev/null and b/src/sound/CenterKick.wav differ diff --git a/src/sound/ballOut.wav b/src/sound/ballOut.wav new file mode 100644 index 0000000..f4fdf59 Binary files /dev/null and b/src/sound/ballOut.wav differ diff --git a/src/sound/callToTossCoin.wav b/src/sound/callToTossCoin.wav new file mode 100644 index 0000000..004b459 Binary files /dev/null and b/src/sound/callToTossCoin.wav differ diff --git a/src/sound/endGameOrHalf.wav b/src/sound/endGameOrHalf.wav new file mode 100644 index 0000000..e380d0b Binary files /dev/null and b/src/sound/endGameOrHalf.wav differ diff --git a/src/sound/offside.wav b/src/sound/offside.wav new file mode 100644 index 0000000..04051b5 Binary files /dev/null and b/src/sound/offside.wav differ diff --git a/src/sound/stopBecauseOfFoul.wav b/src/sound/stopBecauseOfFoul.wav new file mode 100644 index 0000000..26beedc Binary files /dev/null and b/src/sound/stopBecauseOfFoul.wav differ diff --git a/src/sound/tackles_ed.wav b/src/sound/tackles_ed.wav new file mode 100644 index 0000000..4e376a0 Binary files /dev/null and b/src/sound/tackles_ed.wav differ diff --git a/src/sound/wrongPosition2restartFrom.wav b/src/sound/wrongPosition2restartFrom.wav new file mode 100644 index 0000000..acdd9cc Binary files /dev/null and b/src/sound/wrongPosition2restartFrom.wav differ