--- /dev/null
+implementation module Buffer\r
+\r
+import StdEnvExt\r
+import Footballer\r
+\r
+buffer :: !FootballField !Home !Edge !FootballerID -> Footballer\r
+buffer field home edge playerID = {defaultFootballer playerID & name = "buffer"\r
+ , length = m 2.2\r
+ , skills = (Running, Gaining, Rotating)\r
+ , brain = { memory = {curDir = if (edge == North) (rad (0.5*pi)) (rad (-0.5*pi))}\r
+ , ai = the_mind_of_a_buffer field home\r
+ }\r
+ }\r
+\r
+:: Memory = { curDir :: !Angle\r
+ }\r
+\r
+the_mind_of_a_buffer :: !FootballField !Home !(!BrainInput,!Memory) -> (!BrainOutput,!Memory)\r
+the_mind_of_a_buffer field home ({football,others,me},memory)\r
+| dist ball me < maxGainReach me // I can gain the ball\r
+ = (GainBall,memory)\r
+| dist ball me < m 30.0 && ballIsInZone // I can not gain the ball, but I can run to it\r
+ = (runTowardsBall,memory)\r
+| abs me.pos.py > scale 0.5 field.fwidth - sidebuffer // near the edge, turn around\r
+ = (Move {velocity = ms 25.0,direction=new_direction} zero, {memory & curDir = new_direction})\r
+ with\r
+ new_direction = if (me.speed.direction < zero) (rad (0.5*pi)) (rad (-0.5*pi))\r
+| otherwise = (Move {velocity = ms 25.0,direction=memory.curDir} zero,memory) // no ball, no turning, just keep running\r
+where\r
+ sidebuffer = scale 0.01 field.fwidth\r
+ ball = getFootball football [me:others]\r
+ ball_x = ball.ballPos.pxy.px\r
+ ballIsInZone = if (home == East) (isbetween ball_x (scale 0.15 field.flength) (scale 0.20 field.flength))\r
+ (isbetween ball_x (scale -0.10 field.flength) (scale -0.10 field.flength))\r
+ nextBallPos = (nextpos ball).ballPos\r
+ direction2ball = bearing me.speed.direction me nextBallPos.pxy\r
+ runTowardsBall = Move {direction=direction2ball,velocity=ms 10.0} zero\r
+\r
+nextpos :: !Football -> Football\r
+nextpos ball=:{ballSpeed={vxy={velocity=v,direction=d},vz=v3},ballPos}\r
+ = {ball & ballPos = move_point3D {zero & dxy={dx=m (cosinus d * toReal v),dy=m (sinus d * toReal v)}} ballPos}\r