FootballPlays.mesa
Last Edited by: Maxwell, March 15, 1983 8:21 am
Last Edited by: Spreitzer, May 1, 1984 11:00:35 pm PDT
Last Edited by: Rumph, May 15, 1984 12:08:07 pm PDT
DIRECTORY
FS USING [StreamOpen, Error],
FootballInternal USING [game, myTeam, Play, PlayRec, selected, viewer],
FootballMaster,
InputFocus USING [SetInputFocus],
IO USING [Close, int, EndOf, EndOfStream, GetInt, GetLineRope, GetTokenRope, IDProc, Put, PutF, RIS, rope, STREAM],
Menus USING [AppendMenuEntry, ClickProc, CreateEntry, FindEntry, Menu, MenuEntry, MenuLine, ReplaceMenuEntry],
MessageWindow USING [Append, Blink, Clear],
Process USING [SetTimeout],
Real USING [RoundI],
Rope USING [Equal, Length, ROPE],
RPC USING [CallFailed],
ViewerOps USING [PaintViewer, SetMenu],
ViewerTools USING [MakeNewTextViewer];
FootballPlays: MONITOR
IMPORTS
FS, FootballInternal, FootballMaster, InputFocus, IO,
Menus, MessageWindow, Process, Real, Rope, RPC, ViewerOps, ViewerTools
EXPORTS FootballInternal
SHARES Menus =
BEGIN OPEN FootballInternal, FootballMaster;
timer: CONDITION;
delay: CARDINAL ← 1;
Init: PROC =
BEGIN
current ← NEW[PlayRec ← []];
planned ← NEW[PlayRec ← []];
END;
******************************************************************
playBooks
******************************************************************
WritePlayBook: PUBLIC PROC[name: Rope.ROPE] =
TRUSTED BEGIN OPEN IO;
ENABLE FS.Error => {MessageWindow.Append["failed."]; CONTINUE};
stream: IO.STREAM;
IF name.Length[] = 0 THEN RETURN;
MessageWindow.Append["Writing plays on ", TRUE];
MessageWindow.Append[name];
MessageWindow.Append[". . . "];
stream ← FS.StreamOpen[name, create];
stream.Put[rope["-- "], rope[name], rope["\n"]];
stream.Put[rope["-- playname: {offensive | defensive} {setup | play}\n"]];
stream.Put[rope["-- {player}: {stop | run | block | guard} {target}\n"]];
stream.Put[rope["-- ball: {pass | kick} {target}\n"]];
stream.Put[rope["-- player = {QB | LE | RE | LG | RG | C}\n"]];
stream.Put[rope["-- target = {null | goal | ball | {player} | location x y (relative to scrimmage)}\n\n"]];
FOR i: Menus.MenuLine IN [1..viewer.menu.linesUsed) DO
FOR entry: Menus.MenuEntry ← viewer.menu.lines[i], entry.link WHILE entry # NIL DO
WritePlay[stream, NARROW[entry.clientData]];
ENDLOOP;
ENDLOOP;
stream.Close[];
MessageWindow.Append["done."];
[] ← ViewerTools.MakeNewTextViewer[[name: name, file: name, iconic: FALSE]];
END;
WritePlay: PROC[stream: IO.STREAM, play: Play] =
BEGIN OPEN IO, Real;
action: Action;
target: Target;
stream.Put[rope[play.name], rope[": "]];
stream.Put[rope[IF play.side = offense THEN "offensive" ELSE "defensive"]];
stream.Put[rope[IF play.setUp THEN " setup" ELSE " play"], rope["\n"]];
FOR i: CARDINAL IN [0..6] DO
IF i = 6 THEN {
IF play.setUp OR play.side = defense THEN LOOP;
action ← play.ball.action;
target ← play.ball.target;
IF action = stop THEN LOOP;
stream.Put[rope["ball:"]]}
ELSE {
stream.Put[rope[PositionName[Add[HQB, i]]], rope[":"]];
action ← play.commands[i].action;
target ← play.commands[i].target};
SELECT action FROM
stop => stream.Put[rope[" stop"]];
run => stream.Put[rope[" run"]];
block => stream.Put[rope[IF play.side = offense THEN " block" ELSE " guard"]];
pass => stream.Put[rope[" pass"]];
kick => stream.Put[rope[" kick"]];
ENDCASE => ERROR;
IF target.type = absolute THEN target ← Translate[target, myTeam];
WITH t: target SELECT FROM
null => stream.Put[rope["\n"]];
goal => stream.Put[rope[" goal\n"]];
player => IF t.position = ball
THEN stream.Put[rope[" ball\n"]]
ELSE stream.Put[rope[" "], rope[PositionName[t.position]], rope["\n"]];
relative => stream.PutF[" location %g %g\n", int[RoundI[t.x]], int[RoundI[t.y]]];
ENDCASE => ERROR;
ENDLOOP;
stream.Put[rope["\n"]];
END;
PositionName: PROC[player: Position] RETURNS[Rope.ROPE] =
BEGIN
SELECT player FROM
VQB, HQB => RETURN["QB"];
VLE, HLE => RETURN["LE"];
VRE, HRE => RETURN["RE"];
VLG, HLG => RETURN["LG"];
VRG, HRG => RETURN["RG"];
VC, HC => RETURN["C"];
ENDCASE => RETURN["ball"];
END;
ReadPlayBook: PUBLIC PROC[name: Rope.ROPE] =
TRUSTED BEGIN
ENABLE FS.Error => {MessageWindow.Append["failed."]; CONTINUE};
play: Play;
line, token: Rope.ROPE;
stream, file: IO.STREAM;
IF name.Length[] = 0 THEN RETURN;
MessageWindow.Append["Reading plays from ", TRUE];
MessageWindow.Append[name];
MessageWindow.Append[". . . "];
file ← FS.StreamOpen[name];
WHILE ~file.EndOf[] DO
ENABLE IO.EndOfStream => LOOP;
line ← file.GetLineRope[]; -- reads but doesn't return CR
stream ← IO.RIS[line, stream];
token ← stream.GetTokenRope[IO.IDProc].token;
SELECT TRUE FROM
Rope.Equal[token, "--"] => LOOP;
Rope.Equal[token, "QB"] => play.commands[0] ← ReadCommand[stream];
Rope.Equal[token, "LE"] => play.commands[1] ← ReadCommand[stream];
Rope.Equal[token, "RE"] => play.commands[2] ← ReadCommand[stream];
Rope.Equal[token, "LG"] => play.commands[3] ← ReadCommand[stream];
Rope.Equal[token, "RG"] => play.commands[4] ← ReadCommand[stream];
Rope.Equal[token, "C"] => play.commands[5] ← ReadCommand[stream];
Rope.Equal[token, "ball"] => play.ball ← ReadCommand[stream, TRUE];
ENDCASE => {
IF play # NIL AND play.name # NIL THEN AddPlay[play];
play ← NEW[PlayRec ← []];
play.name ← token;
token ← stream.GetTokenRope[IO.IDProc].token;
IF Rope.Equal[token, "defensive"] THEN play.side ← defense;
token ← stream.GetTokenRope[IO.IDProc].token;
IF Rope.Equal[token, "play"] THEN play.setUp ← FALSE};
ENDLOOP;
IF play # NIL AND play.name # NIL THEN AddPlay[play];
file.Close[];
MessageWindow.Append["done."];
END;
ReadCommand: PROC[stream: IO.STREAM, ball: BOOLEANFALSE] RETURNS[Command] =
BEGIN
token: Rope.ROPE;
action: Action ← block;
target: Target ← [player[ball]];
WHILE ~stream.EndOf[] DO
token ← stream.GetTokenRope[IO.IDProc].token;
SELECT TRUE FROM
Rope.Equal[token, "stop"] => RETURN[[stop, [null[ ]]]];
Rope.Equal[token, "block"] => action ← block;
Rope.Equal[token, "guard"] => action ← block;
Rope.Equal[token, "run"] => action ← run;
Rope.Equal[token, "pass"] => IF ball THEN action ← pass;
Rope.Equal[token, "kick"] => IF ball THEN action ← kick;
Rope.Equal[token, "goal"] => target ← [goal[]];
Rope.Equal[token, "kick"] => IF ball THEN action ← kick;
Rope.Equal[token, "ball"] => target ← [player[ball]];
Rope.Equal[token, "QB"] => target ← [player[IF myTeam = home THEN VQB ELSE HQB]];
Rope.Equal[token, "LE"] => target ← [player[IF myTeam = home THEN VLE ELSE HLE]];
Rope.Equal[token, "RE"] => target ← [player[IF myTeam = home THEN VRE ELSE HRE]];
Rope.Equal[token, "LG"] => target ← [player[IF myTeam = home THEN VLG ELSE HLG]];
Rope.Equal[token, "RG"] => target ← [player[IF myTeam = home THEN VRG ELSE HRG]];
Rope.Equal[token, "C"] => target ← [player[IF myTeam = home THEN VC ELSE HC]];
Rope.Equal[token, "location"] => {x, y: INTEGER;
x ← stream.GetInt[];
y ← stream.GetInt[];
target ← [relative[x, y]]};
ENDCASE;
ENDLOOP;
RETURN[[action, target]];
END;
******************************************************************
preplanned plays
******************************************************************
SavePlay: PUBLIC PROC[side: Side, name: Rope.ROPE, setUp: BOOL] =
BEGIN
new: Play ← NEW[PlayRec ← []];
new^ ← IF setUp THEN current^ ELSE planned^;
new.setUp ← setUp;
new.side ← side;
new.name ← name;
AddPlay[new];
END;
AddPlay: PROC[new: Play] =
BEGIN
line: Menus.MenuLine;
entry: Menus.MenuEntry;
IF new.name = NIL THEN new.name ← "Play";
FOR i: CARDINAL IN [0..6) DO
IF new.commands[i].target.type # absolute THEN LOOP;
new.commands[i].target ← Translate[new.commands[i].target, myTeam];
ENDLOOP;
IF new.ball.target.type = absolute THEN new.ball.target ← Translate[new.ball.target, myTeam];
line ← IF new.setUp THEN 1 ELSE IF new.side = offense THEN 2 ELSE 3;
entry ← FindEntry[viewer.menu, new.name, line];
IF entry # NIL THEN {entry.clientData ← new; RETURN};
entry ← Menus.CreateEntry[new.name, SetPlay, new];
Menus.AppendMenuEntry[viewer.menu, entry, line];
ViewerOps.SetMenu[viewer, viewer.menu];
END;
FindEntry: PROC[menu: Menus.Menu, name: Rope.ROPE, line: Menus.MenuLine]
RETURNS[entry: Menus.MenuEntry] =
BEGIN
FOR entry ← menu.lines[line], entry.link WHILE entry # NIL DO
IF Rope.Equal[entry.name, name] THEN RETURN;
ENDLOOP;
END;
Translate: PROC[target: Target, team: Team] RETURNS[Target] =
BEGIN
x, y: REAL ← 0;
WITH t: target SELECT FROM
absolute => {
y ← t.y - fieldWidth/2;
x ← (t.x - game.scrimmage)*Direction[team, game.quarter]};
ENDCASE;
RETURN[[relative[x, y]]];
END;
SetPlay: Menus.ClickProc =
TRUSTED BEGIN
old: Play;
new: Play ← NARROW[clientData, Play];
IF new = NIL THEN RETURN;
IF control THEN {
entry: Menus.MenuEntry;
entry ← Menus.FindEntry[viewer.menu, new.name];
IF entry = NIL THEN RETURN;
IF entry.clientData # new THEN RETURN;
Menus.ReplaceMenuEntry[viewer.menu, entry, NIL];
ViewerOps.SetMenu[viewer, viewer.menu];
RETURN};
InputFocus.SetInputFocus[viewer];
old ← IF new.setUp OR game.state > setUp THEN current ELSE planned;
old^ ← new^;
IF game.state < option THEN FootballMaster.SetUp[myTeam];
IF old.setUp THEN RETURN;
MessageWindow.Clear[];
IF (new.side = defense) AND (myTeam = game.offense) THEN {
MessageWindow.Append["You have the ball. Select an offensive play.", TRUE];
MessageWindow.Blink[]};
IF (new.side = offense) AND (myTeam # game.offense) THEN {
MessageWindow.Append["You don't have the ball. Select a defensive play.", TRUE];
MessageWindow.Blink[]};
END;
******************************************************************
interactive user commands
******************************************************************
current: Play;
planned: PUBLIC Play;
SetCommand: PUBLIC PROC[player: Position, command: Command, setUp: BOOLFALSE] =
BEGIN
old: Play ← IF game.state > setUp OR setUp THEN current ELSE planned;
set a default pass
IF player = ball AND old = planned THEN {old.ball ← command; RETURN};
should we use the default pass/kick?
IF player = ball THEN {
player ← game.ballCarrier;
IF command.target = [null[]] THEN
IF old.ball.action # stop THEN command ← old.ball ELSE RETURN};
is this legal?
IF player = ball OR TeamOf[player] # myTeam THEN RETURN;
IF command.action IN [pass..kick] AND player # game.ballCarrier THEN RETURN;
move all of the players down the field
IF command.action = kick THEN FOR i: CARDINAL IN [0..6) DO
old.commands[i] ← [run, [player[ball]]];
ENDLOOP;
set the new command
old.commands[Index[player]] ← command;
END;
Index: PROC[player: Position] RETURNS[CARDINAL] =
BEGIN
IF TeamOf[player] = home
THEN RETURN[LOOPHOLE[Add[player, -1]]]
ELSE RETURN[LOOPHOLE[Add[player, -7]]];
END;
******************************************************************
interface with control module
******************************************************************
carrier: Position ← ball;
state: State ← offField;
Wait: ENTRY PROCEDURE[i: CARDINAL] =
BEGIN
DO IF i = 0 THEN EXIT ELSE i ← i - 1; WAIT timer; ENDLOOP;
END;
Control: PUBLIC PROC =
BEGIN ENABLE RPC.CallFailed => CHECKED {CONTINUE};
player: Player;
commands: Commands ← ALL[[stop, [null[]]]];
Process.SetTimeout[@timer, 1];
InitializePlays[];
FootballMaster.KickOff[myTeam];
DO Wait[delay];
game^ ← FootballMaster.SetCommands[myTeam, commands];
IF game.state # state THEN SELECT game.state FROM
offField => current.commands ← GetOffField[myTeam];
huddle => {
current.commands ← GetHuddle[myTeam];
IF game.offense = myTeam
THEN planned.commands ← ALL[[block, [player[all]]]]
ELSE planned.commands ← ALL[[run, [player[ball]]]]};
option => current^ ← planned^;
ENDCASE;
FOR i: CARDINAL IN [0..6) DO
player ← @game.player[Add[IF myTeam = home THEN HQB ELSE VQB, i]];
[commands[i].action, commands[i].target] ← GetCommand[player, game];
ENDLOOP;
state ← game.state;
carrier ← game.ballCarrier;
IF viewer # NIL THEN ViewerOps.PaintViewer[viewer, client, FALSE, $Players];
ENDLOOP;
END;
GetCommand: PROC[player: Player, game: Game]
RETURNS[action: Action, target: Target] =
BEGIN
x, y: REAL;
OQB: Position;
index: CARDINAL;
QB shouldn't move until the ball gets to him
OQBIF game.offense = home THEN HQB ELSE VQB;
IF player.position = OQB AND game.state = option AND
game.ballCarrier = none THEN RETURN[stop, [null[]]];
check for interesting state changes
IF game.state # state AND game.state IN [pass..run] AND state NOT IN [pass..run]
THEN FOR i: Position IN Players DO
IF i = game.ballCarrier THEN LOOP;
IF TeamOf[game.player[i].position] # game.possessor
THEN SetCommand[i, [run, [player[ball]]]]
ENDLOOP;
IF game.state # state AND game.state = turnover THEN
FOR i: Position IN Players DO
IF i = game.ballCarrier THEN LOOP;
IF TeamOf[game.player[i].position] = game.possessor
THEN SetCommand[i, [block, [player[all]]]]
ELSE SetCommand[i, [run, [player[ball]]]];
ENDLOOP;
IF game.state # state AND game.state = liveBall THEN
FOR i: Position IN Players DO
SetCommand[i, [run, [player[ball]]]]
ENDLOOP;
if the ball is caught anytime but the hike, the receiver should run towards the goal
IF game.ballCarrier # carrier AND player.position = game.ballCarrier
AND game.state # option THEN SetCommand[player.position, [run, [goal[]]]];
index ← Index[player.position];
action ← current.commands[index].action;
target ← current.commands[index].target;
IF selected # none AND player.position = selected THEN RETURN;
translate location relative to scrimmage line
WITH t: target SELECT FROM
relative => {
y ← t.y + fieldWidth/2;
x ← game.scrimmage + t.x*Direction[TeamOf[player.position], game.quarter]};
absolute => {x ← t.x; y ← t.y};
ENDCASE => RETURN;
follow split ends
IF game.state < option AND myTeam # game.offense
AND current.commands[Index[player.position]].action # stop THEN
WITH t: planned.commands[index].target SELECT FROM
player => {
dy: REAL;
p2: Player = @game.player[t.position];
IF ~CenterReady[] OR t.position = ball THEN RETURN;
IF ABS[player.x - game.scrimmage] > 3.5 THEN RETURN;
dy ← ABS[player.y - p2.y];
IF dy < 3.5 AND ABS[player.dy] < .05 THEN RETURN; -- don't move
IF dy < 10 AND p2.dy > .5 AND p2.y < player.y THEN RETURN; -- moving toward me
IF dy < 10 AND p2.dy < -.5 AND p2.y > player.y THEN RETURN; -- moving toward me
IF Blocked[player, p2.y]
THEN IF ABS[player.x - game.scrimmage] < 2.9
THEN target ← [relative[-3, player.y - fieldWidth/2]]
ELSE target ← [relative[-3, p2.y - fieldWidth/2]]
ELSE target ← [relative[-1, p2.y - fieldWidth/2]];
current.commands[Index[player.position]] ← [run, target]};
ENDCASE;
IF action # run OR game.state < option THEN RETURN;
have we reached our target?
IF ABS[player.x - x] < .5 AND ABS[player.y - y] < .5 THEN SELECT TRUE FROM
player.position = game.ballCarrier AND player.position = OQB => NULL;
player.position = game.ballCarrier =>
SetCommand[player.position, [run, [goal[]]]];
TeamOf[player.position] # game.possessor =>
SetCommand[player.position, [run, [player[ball]]]];
game.state = run => SetCommand[player.position, [block, [player[ball]]]];
game.state = pass => SetCommand[player.position, [run, [player[ball]]]];
ENDCASE;
RETURN[action, [absolute[x, y]]];
END;
Blocked: PROC[player: Player, p2y: REAL] RETURNS[BOOLEAN] =
INLINE BEGIN
FOR i: Position IN Players DO
IF i = player.position THEN LOOP;
IF TeamOf[i] # TeamOf[player.position] THEN LOOP;
IF ABS[game.player[i].x - game.scrimmage] > 1.5 THEN LOOP;
IF player.y+1 < game.player[i].y AND p2y+1 < game.player[i].y THEN LOOP;
IF player.y > game.player[i].y+1 AND p2y > game.player[i].y+1 THEN LOOP;
RETURN[TRUE];
ENDLOOP;
RETURN[FALSE];
END;
CenterReady: PROC RETURNS[BOOLEAN] = INLINE
BEGIN
center: Position = IF game.offense = home THEN HC ELSE VC;
RETURN[ABS[game.player[center].x - game.scrimmage] < 2];
END;
Convert: PROC[pos: Position] RETURNS[Position] =
INLINE BEGIN
IF pos IN HomeTeam THEN RETURN[Add[pos, 6]];
IF pos IN VisitorsTeam THEN RETURN[Add[pos, -6]];
RETURN[pos];
END;
Add: PROCEDURE[p: Position, i: INTEGER] RETURNS[Position] =
INLINE {RETURN[LOOPHOLE[LOOPHOLE[p, INTEGER]+i]]};
******************************************************************
simple plays
******************************************************************
OHuddle: Commands = [
[run, [relative[-18, 0]]], [run, [relative[-16, -4]]], [run, [relative[-16, 4]]],
[run, [relative[-14, -4]]], [run, [relative[-14, 4]]], [run, [relative[-12, 0]]]];
DHuddle: Commands = [
[run, [relative[-18, 0]]], [run, [relative[-16, -4]]], [run, [relative[-16, 4]]],
[run, [relative[-14, -4]]], [run, [relative[-14, 4]]], [run, [relative[-14, 0]]]];
LOEndZoneHuddle: Commands = [
[run, [absolute[-8, 26]]], [run, [absolute[-6, 22]]], [run, [absolute[-6, 30]]],
[run, [absolute[-4, 22]]], [run, [absolute[-4, 30]]], [run, [absolute[-2, 26]]]];
LDEndZoneHuddle: Commands = [
[run, [absolute[-8, 26]]], [run, [absolute[-6, 22]]], [run, [absolute[-6, 30]]],
[run, [absolute[-4, 22]]], [run, [absolute[-4, 30]]], [run, [absolute[-4, 26]]]];
ROEndZoneHuddle: Commands = [
[run, [absolute[108, 26]]], [run, [absolute[106, 22]]], [run, [absolute[106, 30]]],
[run, [absolute[104, 22]]], [run, [absolute[104, 30]]], [run, [absolute[102, 26]]]];
RDEndZoneHuddle: Commands = [
[run, [absolute[108, 26]]], [run, [absolute[106, 22]]], [run, [absolute[106, 30]]],
[run, [absolute[104, 22]]], [run, [absolute[104, 30]]], [run, [absolute[104, 26]]]];
offField1: Commands = [
[run, [absolute[23, 55]]], [run, [absolute[26, 55]]], [run, [absolute[29, 55]]],
[run, [absolute[32, 55]]], [run, [absolute[35, 55]]], [run, [absolute[38, 55]]]];
offField2: Commands = [
[run, [absolute[77, -5]]], [run, [absolute[74, -5]]], [run, [absolute[71, -5]]],
[run, [absolute[68, -5]]], [run, [absolute[65, -5]]], [run, [absolute[62, -5]]]];
GetHuddle: PROC[team: Team] RETURNS[commands: Commands] =
BEGIN
SELECT TRUE FROM
Direction[team, game.quarter] = 1 AND game.scrimmage < 10 =>
RETURN[IF team = game.offense THEN LOEndZoneHuddle ELSE LDEndZoneHuddle];
Direction[team, game.quarter] =-1 AND game.scrimmage > 90 =>
RETURN[IF team = game.offense THEN ROEndZoneHuddle ELSE RDEndZoneHuddle];
ENDCASE => RETURN[IF team = game.offense THEN OHuddle ELSE DHuddle];
END;
GetOffField: PROC[team: Team] RETURNS[Commands] =
INLINE {RETURN[IF team = home THEN offField1 ELSE offField2]};
InitializePlays: PROC =
BEGIN
current.commands ← [
[run, [relative[-3, 0]]], [run, [relative[-1, -8]]], [run, [relative[-1, 8]]],
[run, [relative[-1, -4]]], [run, [relative[-1, 4]]], [run, [relative[-1, 0]]]];
SavePlay[offense, "5-1", TRUE];
current.commands ← [
[run, [relative[-1, -2]]], [run, [relative[-6, -2]]], [run, [relative[-6, 2]]],
[run, [relative[-1, -6]]], [run, [relative[-1, 6]]], [run, [relative[-1, 2]]]];
SavePlay[offense, "4-2", TRUE];
current.commands ← [
[run, [relative[-45, 0]]], [run, [relative[-1, -8]]], [run, [relative[-1, 8]]],
[run, [relative[-1, -4]]], [run, [relative[-1, 4]]], [run, [relative[-1, 0]]]];
SavePlay[offense, "punt-reception", TRUE];
offensive plays
planned.commands ← [
[run, [relative[5, -4]]], [block, [player[all]]], [block, [player[all]]],
[block, [player[all]]], [block, [player[all]]], [block, [player[all]]]];
SavePlay[offense, "UpTheMiddle", FALSE];
planned.commands ← [
[run, [relative[-10, 3]]], [block, [player[all]]], [run, [relative[10, 10]]],
[block, [player[all]]], [block, [player[all]]], [block, [player[all]]]];
planned.ball ← [pass, [relative[10, 10]]];
SavePlay[offense, "ShortPassTop", FALSE];
defensive plays
planned.commands ← [
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]],
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]];
SavePlay[defense, "Rush", FALSE];
IF myTeam = home THEN planned.commands ← [
[run, [player[ball]]], [run, [player[VLE]]], [run, [player[VRE]]],
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]];
IF myTeam = visitors THEN planned.commands ← [
[run, [player[ball]]], [run, [player[HLE]]], [run, [player[HRE]]],
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]];
SavePlay[defense, "GuardEnds", FALSE];
IF myTeam = home THEN planned.commands ← [
[run, [player[VQB]]], [run, [player[VLE]]], [run, [player[VRE]]],
[run, [player[VLG]]], [run, [player[VRG]]], [run, [player[VC]]]];
IF myTeam = visitors THEN planned.commands ← [
[run, [player[HQB]]], [run, [player[HLE]]], [run, [player[HRE]]],
[run, [player[HLG]]], [run, [player[HRG]]], [run, [player[HC]]]];
SavePlay[defense, "ManToMan", FALSE];
planned.commands ← [
[run, [player[ball]]], [block, [relative[-10, -15]]], [block, [relative[-10, 15]]],
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]];
SavePlay[defense, "Zone", FALSE];
planned.commands ← [
[stop, [null[]]], [block, [player[ball]]], [block, [player[ball]]],
[run, [player[ball]]], [run, [player[ball]]], [run, [player[ball]]]];
SavePlay[defense, "punt-reception", FALSE];
current.commands ← GetOffField[myTeam];
END;
Init[];
END . . .