From: Mart Lubbers Date: Wed, 17 Jun 2015 20:24:11 +0000 (+0200) Subject: outline and randomness. Afterfix now tackles if necessary X-Git-Url: https://git.martlubbers.net/?a=commitdiff_plain;h=43f52c65f532d70dfde0c7cc0141ffa381417b90;p=fp1415-soccerfun.git outline and randomness. Afterfix now tackles if necessary --- diff --git a/src/Game/Footballer.icl b/src/Game/Footballer.icl index ef8d800..c08026f 100644 --- a/src/Game/Footballer.icl +++ b/src/Game/Footballer.icl @@ -410,7 +410,7 @@ 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) +getKickPos field half (Corner home edge) = Just { px = if (home == East) (half_radius_corner_kick_area - half_length) (half_length - half_radius_corner_kick_area) , py = if (edge == North) @@ -421,7 +421,7 @@ 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) +getKickPos field half (Penalty home) = Just { zero & px = if (home == East) (penalty_spot_depth - half_length) (half_length - penalty_spot_depth) } diff --git a/src/Game/Geometry.icl b/src/Game/Geometry.icl index e9b29da..fe22693 100644 --- a/src/Game/Geometry.icl +++ b/src/Game/Geometry.icl @@ -65,12 +65,14 @@ 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 +normalize_radian r = normalize r 100 +where + normalize r 0 = abort "Loop in normalize_radian. Mail p.achten@cs.ru.nl" + normalize r n + | r < ~pi = normalize (r + 2.0*pi) (n-1) + | r > pi = normalize (r - 2.0*pi) (n-1) + | otherwise = r + instance zero Angle where zero = Radian zero instance + Angle where + (Radian r1) (Radian r2) = Radian (normalize_radian (r1 + r2)) @@ -208,6 +210,7 @@ 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 +| abs ratio > 1.0 = Radian zero // Corner-cases: d==0 and "large values of 1.0" | 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 @@ -217,7 +220,8 @@ where 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) + ratio = toReal (abs v.dx) / d + base_angle = acos ratio bearing :: !Angle !base !target -> Angle | toPosition base & toPosition target bearing angle base target = px_bearing base target - angle diff --git a/src/Game/Referee.icl b/src/Game/Referee.icl index 2f88d83..8f8c206 100644 --- a/src/Game/Referee.icl +++ b/src/Game/Referee.icl @@ -3,6 +3,7 @@ implementation module Referee import StdEnvExt import matchGame import Umpire +import NoReferee // When coding for all referees, include following modules: import RefereeCoach_Rounds_Assignment import RefereeCoach_Slalom_Assignment @@ -11,7 +12,7 @@ import RefereeCoach_DeepPass_Assignment import RefereeCoach_Keeper_Assignment allAvailableReferees :: [FootballField -> Referee] -allAvailableReferees = [ umpire ] +allAvailableReferees = [ umpire, NoReferee ] // When coding for all referees, use following list: ++ [ RefereeCoach_Rounds diff --git a/src/Game/Team.icl b/src/Game/Team.icl index d41af0b..f7817b9 100644 --- a/src/Game/Team.icl +++ b/src/Game/Team.icl @@ -14,10 +14,12 @@ import Team_Student_Passing_Assignment import Team_Student_DeepPass_Assignment import Team_Student_Keeper_Assignment import Team_MartLubbers +import Team_Harmless allAvailableTeams :: [Home FootballField -> Team] allAvailableTeams = [ Team_MartLubbers , Team_MiniEffies + , Harmless , Team_Student_Rounds , Team_Student_Slalom , Team_Student_Passing diff --git a/src/Game/matchControl.icl b/src/Game/matchControl.icl index e0505c0..f52e843 100644 --- a/src/Game/matchControl.icl +++ b/src/Game/matchControl.icl @@ -22,6 +22,16 @@ instance toString Seconds where toString (Seconds s) = s +++> " sec." doSoccerFun :: !*World -> *World doSoccerFun world = SoccerFunGUI2D world +simulationGranularity :: Seconds +simulationGranularity = s 0.05 + +// the original simulation expected to run at 0.1s; this function is used to adjust it to different rates +rateAdjust :: (Real -> Real) +rateAdjust = case simulationGranularity of + Seconds 0.1 -> id + Seconds 0.05 -> sqrt + Seconds x -> \y -> y^(10.0*x) + setMatchStart :: !Team !Team !FootballField !Referee !PlayingTime !RandomSeed -> Match setMatchStart fstTeam sndTeam field referee time rs = { team1 = validateTeam fstTeam @@ -31,7 +41,7 @@ setMatchStart fstTeam sndTeam field referee time rs , theReferee = referee , playingHalf = FirstHalf , playingTime = time - , unittime = s 0.05 + , unittime = simulationGranularity , score = (0,0) , nextRandomP = nextRandomP , seed = rs @@ -266,7 +276,7 @@ where 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_vel = scale (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` @@ -404,7 +414,7 @@ where where old_height = ballPos.pz in_the_air = old_height > zero - resistance = if in_the_air air_resistance surface_resistance + resistance = rateAdjust 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} @@ -470,18 +480,18 @@ 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 + | otherwise = stamina^(rateAdjust 0.8) +| otherwise = fatigue * (rateAdjust 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)))) + fv = if (diff >= ms 6.0) (stamina^rateAdjust (stamina^(1.6 + 0.02 * toReal length))) // problematic + (if (diff >= ms 4.0) (stamina^rateAdjust ( 1.5 + 0.01 * toReal length)) + (if (diff >= ms 2.0) (stamina^rateAdjust ( 1.4 - 0.01 * toReal length)) + (stamina^rateAdjust ( 1.3 - 0.02 * toReal length)))) factor = one - (toReal angleDifficulty)/(4.0*pi) fatigue = if (stamina > MaximumFatigue) MaximumFatigue fv diff --git a/src/Gui/Gui2D.icl b/src/Gui/Gui2D.icl index 53902a3..2b59d60 100644 --- a/src/Gui/Gui2D.icl +++ b/src/Gui/Gui2D.icl @@ -108,9 +108,10 @@ where , ("&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)) + :+: SubMenu "Sp&eed" ( RadioMenu [ ("&Slowest",Nothing, Just '`', noLS (changeSpeedf timerId Slowest)) + , ("S&lower", Nothing, Just '1', noLS (changeSpeedf timerId Slower)) + , ("N&ormal", Nothing, Just '2', noLS (changeSpeedf timerId Normal)) + , ("F&ast", Nothing, Just '3', noLS (changeSpeedf timerId Fast)) , ("&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) [] diff --git a/src/Gui/guiInterface.dcl b/src/Gui/guiInterface.dcl index e7e5db4..42c184e 100644 --- a/src/Gui/guiInterface.dcl +++ b/src/Gui/guiInterface.dcl @@ -13,7 +13,7 @@ getActionPicsForGui :: !Match !*env -> (!ActionPics,!*env) | FileSystem env */ stepMatchForGui :: !FootballGame !*env -> (![RefereeAction], !FootballGame, !*env) | FileSystem env -:: DisplaySpeed = Slowest | Slower | Normal | Faster | Fastest +:: DisplaySpeed = Slowest | Slower | Normal | Fast | Faster | Fastest instance toString DisplaySpeed instance fromString DisplaySpeed instance == DisplaySpeed diff --git a/src/Gui/guiInterface.icl b/src/Gui/guiInterface.icl index e6a7dff..1f715ec 100644 --- a/src/Gui/guiInterface.icl +++ b/src/Gui/guiInterface.icl @@ -50,6 +50,7 @@ instance == DisplaySpeed where == Slowest Slowest = True 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 Normal = 1.0 // normal speed +intervalFactor Fast = 1.0 / 2.0 // two times faster intervalFactor Faster = 1.0 / 5.0 // five times faster intervalFactor Fastest = zero // no timer delay diff --git a/src/SoccerFun.prj b/src/SoccerFun.prj index bfb80ed..28de46c 100644 --- a/src/SoccerFun.prj +++ b/src/SoccerFun.prj @@ -401,6 +401,20 @@ OtherModules ReadableABC: False ReuseUniqueNodes: True Fusion: False + Module + Name: NoReferee + 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 @@ -541,6 +555,20 @@ OtherModules ReadableABC: False ReuseUniqueNodes: True Fusion: False + Module + Name: Team_Harmless + 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 diff --git a/src/SoccerFun_options.txt b/src/SoccerFun_options.txt index deea162..787224a 100644 --- a/src/SoccerFun_options.txt +++ b/src/SoccerFun_options.txt @@ -1 +1 @@ -{closeReferee=True,showSplash=False,displaySpeed=Faster,showReferee=True,playingTime=4:00 min,renderStyle=Fixed camera} \ No newline at end of file +{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/StdReferee/NoReferee.dcl b/src/StdReferee/NoReferee.dcl new file mode 100644 index 0000000..202c5dd --- /dev/null +++ b/src/StdReferee/NoReferee.dcl @@ -0,0 +1,7 @@ +definition module NoReferee + +/** This module implements a null referee which doesn't do anything */ + +import Referee + +NoReferee :: !FootballField -> Referee diff --git a/src/StdReferee/NoReferee.icl b/src/StdReferee/NoReferee.icl new file mode 100644 index 0000000..88ef8d9 --- /dev/null +++ b/src/StdReferee/NoReferee.icl @@ -0,0 +1,21 @@ +implementation module NoReferee + +import StdEnvExt +import Referee + +NoReferee :: !FootballField -> Referee +NoReferee field = { name = "NoReferee" + , brain = { memory = initMem + , ai = randomlessRefereeAI (brain field) + } + , refActionPics = [] + } + +:: Memory = Memory + +initMem :: Memory +initMem = Memory + +brain :: !FootballField !(!RefereeInput,!Memory) -> (!RefereeOutput,!Memory) +brain field ({RefereeInput | theBall=ballState,team1,team2},memory) + = ([], memory) diff --git a/src/StdReferee/RefereeCoach_Passing_Assignment.icl b/src/StdReferee/RefereeCoach_Passing_Assignment.icl index d5fdc6a..6ab6e2f 100644 --- a/src/StdReferee/RefereeCoach_Passing_Assignment.icl +++ b/src/StdReferee/RefereeCoach_Passing_Assignment.icl @@ -95,8 +95,7 @@ brain field ({RefereeInput | theBall=ballState, team1, team2}, 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 + scale 2.0 penalty_area_depth) (scale 0.5 field.flength - scale 2.0 penalty_area_depth)} -// ballKickoff = {zero & px = if (studentHome == West) (scale -0.5 field.flength + penalty_area_depth) (scale 0.5 field.flength - penalty_area_depth)} + 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 diff --git a/src/StdTeam/Team_Harmless.dcl b/src/StdTeam/Team_Harmless.dcl new file mode 100644 index 0000000..d4f9554 --- /dev/null +++ b/src/StdTeam/Team_Harmless.dcl @@ -0,0 +1,11 @@ +system module Team_Harmless + +import Team + +:: NumPlayers :== Int +:: Difficulty = Auto | Level Int + +// import this module and add the team 'Harmless (n, level)' in Game\Team.icl +MostlyHarmless :: (!NumPlayers,!Difficulty) Home FootballField -> Team + +Harmless :== MostlyHarmless (11,Auto) diff --git a/src/StdTeam/Team_Student_Passing_Assignment.icl b/src/StdTeam/Team_Student_Passing_Assignment.icl index 075236d..ce8f846 100644 --- a/src/StdTeam/Team_Student_Passing_Assignment.icl +++ b/src/StdTeam/Team_Student_Passing_Assignment.icl @@ -9,13 +9,11 @@ implementation module Team_Student_Passing_Assignment */ import Footballer -import FootballerFunctions -import StdMaybe 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} nr & pos = toPosition (scale (0.5*x) field.flength,scale (0.5*y) field.fwidth),nose = rad (dir*pi)} + 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 @@ -29,49 +27,7 @@ where ,( 0.43,-0.05) ] noses = [1.8,0.0,1.5,0.5,1.2,0.2] - footballer playerID nr = {defaultFootballer playerID & name = "Peter88_" +++ toString nr, brain = {memory=False, ai=mind (getOps field home)}} - + footballer playerID = defaultFootballer playerID // implement your footballer here + base_TeamName_Student_Passing :: String base_TeamName_Student_Passing = "Student Passing" - - -:: Ops = { - c :: Metre Metre -> Bool, - a :: Metre Metre -> Metre, - s :: Metre Metre -> Metre, - g :: Position} - -getOps :: !FootballField !Home -> Ops -getOps field West = {c=(<), a=(+), s=(-), g={px=scale 0.5 field.flength, py=(m 0.0)}} -getOps field East = {c=(>), a=(-), s=(+), g={px= ~(scale 0.5 field.flength), py=(m 0.0)}} - -mind :: !Ops !(!BrainInput, !Bool) -> (!BrainOutput, !Bool) -mind op (x=:{me,others}, mm) -| mm || not (best (me team others) me bp) = halt (x, mm) -| otherwise = (afterfix (((\f.(\(i, _).(f i, True))) o kick`) kickpos) bp (maxKickReach me)) (x, mm) - where - bp = (getBall x).ballPos.pxy - - kickpos = let f = nextPlayer others me in if (isNothing f) op.g (fromJust f).pos - - nextPlayer :: [Footballer] Footballer -> Maybe Footballer - nextPlayer [] me = Nothing - nextPlayer [x:xs] me - | op.c x.pos.px me.pos.px = nextPlayer xs me - | otherwise = Just x - - best :: [Footballer] Footballer Position -> Bool - best [] _ _ = True - best [x:xs] me bp - | dist x.pos bp < dist me.pos bp = False - | otherwise = best xs me bp - - afterfix after point diff (input=:{me}, m) - | d < diff = after (input, m) - | otherwise = (move, m) - where - d = dist me point - a = bearing zero me point - r = bearing me.nose me point - v = ms (max 6.0 (toReal d)) - move = Move {direction=a, velocity=v} r \ No newline at end of file diff --git a/src/StdTeam/Team_Student_Rounds_Assignment.icl b/src/StdTeam/Team_Student_Rounds_Assignment.icl index a68889c..8c0e333 100644 --- a/src/StdTeam/Team_Student_Rounds_Assignment.icl +++ b/src/StdTeam/Team_Student_Rounds_Assignment.icl @@ -8,7 +8,6 @@ implementation module Team_Student_Rounds_Assignment Do not change the implementation of base_TeamName_Student_Rounds. */ import Footballer -import FootballerFunctions Team_Student_Rounds :: !Home !FootballField -> Team Team_Student_Rounds home field = if (home == West) team (mirror field team) @@ -19,18 +18,7 @@ where ] club = base_TeamName_Student_Rounds +++ if (home==West) "_W" "_E" positions = [(-0.49,0.00)] - footballer playerID = {defaultFootballer playerID & name = "Peter88", brain = {memory = Void, ai = mind field}} + footballer playerID = defaultFootballer playerID // implement your footballer here base_TeamName_Student_Rounds :: String base_TeamName_Student_Rounds = "Student Rounds" - -mind :: !FootballField !(!BrainInput, !Void) -> (!BrainOutput, !Void) -mind field (i=:{me}, mm) -| y >= (t -o) && x > (~r+o) = (fix {px= ~r,py= t} c) (i, mm) -| x <= (~r+o) && y > (~t+o) = (fix {px= ~r,py= ~t} c) (i, mm) -| y <= (~t+o) && x < (r -o) = (fix {px= r, py= ~t} c) (i, mm) -| x >= (r -o) && y < (t -o) = (fix {px= r, py= t} c) (i, mm) - where - (x, y, o, c) = (me.pos.px, me.pos.py, m 4.0, m 1.5) - t = scale 0.5 field.fwidth - r = scale 0.5 field.flength \ No newline at end of file diff --git a/src/StdTeam/Team_Student_Slalom_Assignment.icl b/src/StdTeam/Team_Student_Slalom_Assignment.icl index a62f4a5..a77671d 100644 --- a/src/StdTeam/Team_Student_Slalom_Assignment.icl +++ b/src/StdTeam/Team_Student_Slalom_Assignment.icl @@ -1,4 +1,3 @@ - implementation module Team_Student_Slalom_Assignment /** Implement a solution to the slalom assignment. @@ -18,26 +17,7 @@ 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 & name = "Peter88", brain = {memory = Void, ai = mind field home}} + footballer player_id = defaultFootballer player_id // implement your footballer here base_TeamName_Student_Slalom :: String base_TeamName_Student_Slalom = "Student Slalom" - -mind :: !FootballField !Home !(!BrainInput, !Void) -> (!BrainOutput, !Void) -mind field home (x=:{me,others}, mm) -| dist (getBall x).ballPos me.pos < (maxKickReach me) = (kick {px=sig (scale 0.5 field.flength), py=m 0.0}) (x, mm) -| otherwise = (fix {px=pp2 cp.px (m 2.5), py=up cp.py (m 3.5)} (maxKickReach me)) (x, mm) - where - (comparator, pp1, pp2, sig) = if (home == West) ((<), (-), (+), (\w.w)) ((>), (+), (-), (~)) - sf2 = sortBy (\x y.comparator x.pos.px y.pos.px) others - sf = sf2 % (0, (length sf2) - 2) - (cp, up) = closestPos (zip2 [1..] sf) (pp1 me.pos.px xWidthFootballer) (getBall x).ballPos.pxy comparator - -closestPos :: [(Int, Footballer)] Metre Position (Metre Metre -> Bool) -> (Position, (Metre Metre -> Metre)) -closestPos [] _ d _ = (d, (\x y.x)) -closestPos [(i, x):xs] p d c -| c p x.pos.px = (x.pos, if (i rem 2 == 0) (+) (-)) -| otherwise = closestPos xs p d c - - - diff --git a/src/Team_MartLubbers.icl b/src/Team_MartLubbers.icl index ee0de18..ef3ff01 100644 --- a/src/Team_MartLubbers.icl +++ b/src/Team_MartLubbers.icl @@ -47,7 +47,10 @@ where ,(0.90,-0.05) ] -:: Mem = {home :: !Home, origpos :: Position} +:: Mem = {home :: !Home, origpos :: Position, seed :: !RandomSeed} + +mirrorMem :: !Mem !FootballField -> Mem +mirrorMem mm field = {mm & home=other mm.home, origpos=mirror field mm.origpos} Aesir :: !ClubName !Home !FootballField !Position !PlayersNumber !String -> Footballer Aesir club home field position nr name @@ -61,55 +64,67 @@ Aesir club home field position nr name , effect = Nothing , stamina = max_stamina , health = max_health - , brain = {memory = {home=home, origpos=position}, ai = mind field } + , brain = {memory=if (home == West) mm (mirrorMem mm field), ai = mind field} } - -closerToGoal :: !Home -> Metre Metre -> Bool -closerToGoal East = (<) -closerToGoal West = (>) - -getMin :: !Home -> Metre Metre -> Metre -getMin h = getMax (other h) - -getMax :: !Home -> Metre Metre -> Metre -getMax East = (max) -getMax West = (min) + where + mm = {home=West, origpos=position, seed=nullRandomSeed} + +nextRandomNumber :: !Mem -> (Int, !Mem) +nextRandomNumber mm=:{seed} = let (i, newseed) = random seed in (i rem 100, {mm & seed=newseed}) mind :: !FootballField !(!BrainInput, !Mem) -> (!BrainOutput, !Mem) mind field (x=:{referee,football,others,me}, mm=:{home,origpos}) -# mm=:{home,origpos} = if (any isEndHalf referee) {home=other home, origpos=mirror field origpos} mm -| ballIsGainedBy me.playerID football - | dist nextPos me.pos < (m 10.0) = kick nextPos (x, mm) - | otherwise = fix nextPos (m 1.0) (x, mm) -| isClosest others me ballPos.pxy = afterfix (\(_, m).(GainBall, m)) ballPos.pxy (scale 0.5 (maxKickReach me)) (x, mm) -| otherwise - | we_have_ball = fix {px=getMin home ballPos.pxy.px (field.flength-me.pos.px), py=me.pos.py} (m 1.0) (x, mm) - | otherwise - | me.stamina > 0.5 = fix origpos (m 1.0) (x, mm) - | otherwise = halt (x, mm) +// In case of the end of the half, mirror memory +| any (isEndHalf) referee = mind field ({x & referee=filter (\x.not (isEndHalf x)) referee}, mirrorMem mm field) +// In case of a pause or end, just halt +| any (isPauseGame) referee || any (isGameOver) referee = halt (x, mm) +// TODO:: The ball is free +| ballIsFree football + // I'm closest to the ball + | isClosest us me ballPos.pxy = afterfix (\(_,_).(GainBall, mm)) ballPos.pxy prec (x, mm) + // TODO: Some other player is the closest to the ball + | otherwise = halt (x, mm) +// TODO: We have the ball +| any (\x.ballIsGainedBy x.playerID football) us = halt (x, mm) + // TODO: I have the ball + | ballIsGainedBy me.playerID football + // TODO: Someone else has the ball + | otherwise = halt (x, mm) +// TODO: The ball is with the others +| otherwise = halt (x, mm) where - us = me team others ballPos = (getBall x).ballPos - nextPos = nextPlayer home field us me.pos - we_have_ball = or (map (\x.ballIsGainedBy x.playerID football) us) - -nextPlayer :: !Home !FootballField [Footballer] Position -> Position -nextPlayer home field xs pos -# xs = filter (\x.closerToGoal home x.pos.px pos.px) xs -| xs == [] = centerOfGoal (other home) field -| otherwise = (minListBy (\x y.(dist x.pos pos) < (dist y.pos pos)) xs).pos - + them = me opponents others + us = me team others + prec = scale 0.5 (maxKickReach me) + closest :: [Footballer] Position -> Footballer closest xs p = minListBy (\x y.(dist x.pos p) < (dist y.pos p)) xs isClosest :: [Footballer] Footballer Position -> Bool isClosest xs x p = closest [x:xs] p == x -afterfix :: (FootballerAI m) !Position !Metre !(!BrainInput, m) -> (BrainOutput, m) -afterfix after point diff (input=:{me}, m) -| d < diff = after (input, m) -| otherwise = (move, m) +closerToGoal :: !Home -> Metre Metre -> Bool +closerToGoal East = (<) +closerToGoal West = (>) + +distToLine :: Position Position Position -> Metre +distToLine a b c = (abs (((b.px-a.px)*(a.py-c.py))-((a.px-c.px)*(b.py-a.py))))/d + where + (*) m1 m2 = (m (toReal m1)/(toReal m2)) + (/) m1 m2 = (m (toReal m1)/(toReal m2)) + d = sqrt(((b.px-a.px)*(b.px-a.px))+((b.py-a.py)*(b.py-a.py))) + +//afterfix :: (FootballerAI m) !Position !Metre !(!BrainInput, !Mem) -> (BrainOutput, !Mem) +afterfix after point diff (input=:{me,others}, mm) +# (i, mm) = nextRandomNumber mm +| d < diff = after (input, mm) +// There is a enemy standing in the way and I feel like it +| (dist closestOpp me.pos) < (maxTackleReach me) && i < 15 = (Tackle closestOpp.playerID (ms 6.0), mm) +// There is no enemy standing in the way +| otherwise = (move, mm) where + closestOpp = closest (me opponents others) me.pos d = dist me point a = bearing zero me point r = bearing me.nose me point