Terminator — 10 of 33

Matt Weiner

Release 0

Section 3 - Figuring out what the robots can see

Every turn (this is the set robot vision rule):

repeat with bot running through responsive robots in the Planet: [This will restrict things to robots that are in play during the tutorial]

calculate the vision table for bot.

Definition: a thing is movable if it is not a terrain feature.

To calculate the vision table for (bot - a robot):

blank out the whole of the current vision table of the bot;

find movable things near the bot;

find terrain features near the bot.

To find movable things near (bot - a robot):

repeat with item running through movable things in Planet:

if the x-coordinate of item is the x-coordinate of bot and the y-coordinate of item is the y-coordinate of bot and the item is not the bot: [the item is right there; add it with a direction of down as a placeholder for right there]

choose a blank row in the current vision table of the bot;

now the seen thing entry is the item;

now the orientation entry is down;

otherwise if item is within sight of bot: [close enough but maybe obstructed; trace a ray]

let obstructed be a truth state;

now obstructed is false; [so far]

let x-displacement be the integer absolute value of (the x-coordinate of the item minus the x-coordinate of the bot);

let y-displacement be the integer absolute value of (the y-coordinate of the item minus the y-coordinate of the bot);

let y-init be a number;

let y-final be a number;

let x-init be a number;

let x-final be a number;

let z-init be a number;

let z-final be a number;

if x-displacement < y-displacement:

if the y-coordinate of the bot is less than the y-coordinate of the item:

now y-init is the y-coordinate of the bot;

now x-init is the x-coordinate of the bot;

now z-init is the z-coordinate of the bot;

now y-final is the y-coordinate of the item;

now x-final is the x-coordinate of the item;

now z-final is the z-coordinate of the item;

otherwise:

now y-init is the y-coordinate of the item;

now x-init is the x-coordinate of the item;

now z-init is the z-coordinate of the item;

now y-final is the y-coordinate of the bot;

now x-final is the x-coordinate of the bot;

now z-final is the z-coordinate of the bot;

repeat with y-mark running from y-init to y-final:

let x-mark be x-init plus (((x-final minus x-init) times (y-mark minus y-init)) roundly divided by (y-displacement));

let z-mark be z-init plus (((z-final minus z-init) times (y-mark minus y-init)) roundly divided by (y-displacement)); [x-mark and z-mark are the x and z coordinates on the line from the initial xyz point to the final one, scaled by the fraction of the distance we moved on the y-axis]

choose row x-mark graphed by y-mark in the Table of planetary surface; [so we need to look up that xy point]

debug say "[bot], [item] y loop; checking [x-mark], [y-mark], [z-mark]; [x-coordinate entry], [y-coordinate entry], elevation [elevation entry][if there is a feature entry] [feature entry][end if].";

if the elevation entry is greater than z-mark: [and if the ground is higher than the z-mark, the view is obstructed]

now obstructed is true;

otherwise: [that is, if x-displacement < y-displacement]

if the x-coordinate of the bot is less than the x-coordinate of the item:

now y-init is the y-coordinate of the bot;

now x-init is the x-coordinate of the bot;

now z-init is the z-coordinate of the bot;

now y-final is the y-coordinate of the item;

now x-final is the x-coordinate of the item;

now z-final is the z-coordinate of the item;

otherwise:

now y-init is the y-coordinate of the item;

now x-init is the x-coordinate of the item;

now z-init is the z-coordinate of the item;

now y-final is the y-coordinate of the bot;

now x-final is the x-coordinate of the bot;

now z-final is the z-coordinate of the bot;

repeat with x-mark running from x-init to x-final:

let y-mark be y-init plus (((y-final minus y-init) times (x-mark minus x-init)) roundly divided by (x-displacement));

let z-mark be z-init plus (((z-final minus z-init) times (x-mark minus x-init)) roundly divided by (x-displacement)); [y-mark and z-mark are the y and z coordinates on the line from the initial xyz point to the final one, scaled by the fraction of the distance we moved on the x-axis]

choose row x-mark graphed by y-mark in the Table of planetary surface; [so we need to look up that xy point]

debug say "[bot], [item] x loop; checking [x-mark], [y-mark], [z-mark]; [x-coordinate entry], [y-coordinate entry], elevation [elevation entry][if there is a feature entry] [feature entry][end if].";

if the elevation entry is greater than z-mark: [and if the ground is higher than the z-mark, the view is obstructed]

now obstructed is true;

if obstructed is false:

choose a blank row in the current vision table of the bot;

now the seen thing entry is the item;

now the orientation entry is the direction the item lies from the bot.

To find terrain features near (bot - a robot):

gather the features within sight of bot; [this loads the terrain features that are within sight into the Table of Nearby Features, closest first]

repeat through Table of Nearby Features:

let feature be the feature entry;

if the squared distance entry is 0: [the item is right there; add it with a direction of down as a placeholder for right there]

choose a blank row in the current vision table of the bot;

now the seen thing entry is the feature;

now the orientation entry is down;

otherwise: [trace a line of sight again, but this time since we can have partial obstruction, keep track of any partial obstructors. Any visible partical obstructors will already be listed in the current vision table, since we're doing the nearest ones first]

let obstructed be a truth state;

now obstructed is false; [so far]

let tracing from feature be a truth state; [keeps track of whether the ray is going from the feature to the bot or vice versa--we want to know this so we make sure the partial obstructor is the candidate that's closest to the feature]

let partial obstructor be an object; [this will store anything that is partly in the way of the feature]

let feature-x be the x-coordinate of the feature;

let feature-y be the y-coordinate of the feature;

[we have to adjust these for craters and ridges so they don't block their own centers from view]

if feature is a crater:

if feature-x is less than the x-coordinate of the bot:

now feature-x is feature-x plus 1;

otherwise if feature-x is greater than the x-coordinate of the bot:

now feature-x is feature-x minus 1;

if feature-y is less than the y-coordinate of the bot:

now feature-y is feature-y plus 1;

otherwise if feature-y is greater than the y-coordinate of the bot:

now feature-y is feature-y minus 1;

otherwise if feature is a north-south ridge:

if feature-y is less than the y-coordinate of the bot:

now feature-y is feature-y plus 1;

otherwise if feature-y is greater than the y-coordinate of the bot:

now feature-y is feature-y minus 1;

otherwise if feature is an east-west ridge:

if feature-x is less than the x-coordinate of the bot:

now feature-x is feature-x plus 1;

otherwise if feature-x is greater than the x-coordinate of the bot:

now feature-x is feature-x minus 1;

let x-displacement be the integer absolute value of (feature-x minus the x-coordinate of the bot);

let y-displacement be the integer absolute value of (feature-y minus the y-coordinate of the bot);

let y-init be a number;

let y-final be a number;

let x-init be a number;

let x-final be a number;

let z-init be a number;

let z-final be a number;

if x-displacement < y-displacement:

if the y-coordinate of the bot is less than the feature-y:

now y-init is the y-coordinate of the bot;

now x-init is the x-coordinate of the bot;

now z-init is the z-coordinate of the bot;

now y-final is feature-y;

now x-final is feature-x;

now z-final is the z-coordinate of the feature;

now tracing from feature is false;

otherwise:

now y-init is feature-y;

now x-init is feature-x;

now z-init is the z-coordinate of the feature;

now y-final is the y-coordinate of the bot;

now x-final is the x-coordinate of the bot;

now z-final is the z-coordinate of the bot;

now tracing from feature is true;

repeat with y-mark running from y-init to y-final:

let x-mark be x-init plus (((x-final minus x-init) times (y-mark minus y-init)) roundly divided by (y-displacement));

let z-mark be z-init plus (((z-final minus z-init) times (y-mark minus y-init)) roundly divided by (y-displacement)); [x-mark and z-mark are the x and z coordinates on the line from the initial xyz point to the final one, scaled by the fraction of the distance we moved on the y-axis]

choose row x-mark graphed by y-mark in the Table of planetary surface; [so we need to look up that xy point]

debug say "[bot], [feature] y loop; checking [x-mark], [y-mark], [z-mark]; [x-coordinate entry], [y-coordinate entry], elevation [elevation entry][if there is a feature entry] [feature entry][end if].";

if the elevation entry is greater than z-mark: [and if the ground is higher than the z-mark, the view is obstructed]

now obstructed is true;

otherwise if (tracing from feature is false or partial obstructor is nothing) and there is a feature entry: [if we're tracing from feature and we've already found a partial obstructor, don't bother checking]

let new feature be the feature entry;

if new feature is a feature listed in the current vision table of the bot: [if we can see the new feature, it'll already be loaded into the vision table, since we do nearest first]

now the partial obstructor is new feature;

otherwise [that is, if x-displacement >= y-displacement] if x-displacement > 0: [we have to check that x-displacement is not 0 because the shifts for craters and ridges could have pushed them both to 0; and if it is 0, then we can fall down to where obstructed is false and we succeed--without this check we might divide by zero]

if the x-coordinate of the bot is less than the x-coordinate of the feature:

now y-init is the y-coordinate of the bot;

now x-init is the x-coordinate of the bot;

now z-init is the z-coordinate of the bot;

now y-final is feature-x;

now x-final is feature-y;

now z-final is the z-coordinate of the feature;

now tracing from feature is false;

otherwise:

now y-init is feature-y;

now x-init is feature-x;

now z-init is the z-coordinate of the feature;

now y-final is the y-coordinate of the bot;

now x-final is the x-coordinate of the bot;

now z-final is the z-coordinate of the bot;

now tracing from feature is true;

repeat with x-mark running from x-init to x-final:

let y-mark be y-init plus (((y-final minus y-init) times (x-mark minus x-init)) roundly divided by (x-displacement));

let z-mark be z-init plus (((z-final minus z-init) times (x-mark minus x-init)) roundly divided by (x-displacement)); [y-mark and z-mark are the y and z coordinates on the line from the initial xyz point to the final one, scaled by the fraction of the distance we moved on the y-axis]

choose row x-mark graphed by y-mark in the Table of planetary surface; [so we need to look up that xy point]

debug say "[bot], [feature] x loop; checking [x-mark], [y-mark], [z-mark]; [x-coordinate entry], [y-coordinate entry], elevation [elevation entry][if there is a feature entry] [feature entry][end if].";

if the elevation entry is greater than z-mark: [and if the ground is higher than the z-mark, the view is obstructed]

now obstructed is true;

otherwise if (tracing from feature is false or partial obstructor is nothing) and there is a feature entry: [if we're tracing from feature and we've already found a partial obstructor, don't bother checking]

let new feature be the feature entry;

if new feature is a feature listed in the current vision table of the bot: [if we can see the new feature, it'll already be loaded into the vision table, since we do nearest first]

now the partial obstructor is new feature;

if obstructed is false:

choose a blank row in the current vision table of the bot;

now the seen thing entry is the feature;

now the orientation entry is the direction the feature lies from the bot;

if the partial obstructor is not nothing:

now the partial obstructor entry is the partial obstructor.

To gather the features within sight of (bot - a robot):

blank out the whole of the Table of Nearby Features;

repeat with feature running through terrain features in the Planet:

if feature is within sight of bot:

choose a blank row in the Table of Nearby Features;

now the feature entry is feature;

now the squared distance entry is the squared distance from feature to bot;

sort the Table of Nearby Features in squared distance order. [This puts the nearest features first]

Table of Nearby Features

featuresquared distance
a terrain featurea number
with 20 blank rows

Robots looking for the first time is initially true. [This flag keeps us from printing "now" or "still" when the robots are looking for the first time.]

Every turn (this is the report robot vision rule):

repeat with bot running through responsive robots in the Planet: [again, during the tutorial this restricts it to robots in play]

report vision for the bot;

swap vision tables for the bot;

now robots looking for the first time is false;

now every robot is unsuccessful.

To report vision for (bot - a robot):

[start by figuring out which things bot could see previous turn]

let previously seen list be a list of things;

repeat through the previous vision table of the bot:

if there is a seen thing entry, add the seen thing entry to the previously seen list;

if the current vision table of the bot is empty:

say "[if bot is a hauler]Hauler [otherwise if bot is a scout]Scout [end if][Bot] reports nothing notable visible in the vicinity.";

otherwise:

say "[if bot is a hauler]Hauler [otherwise if bot is a scout]Scout [end if][Bot] reports that:[line break]";

let x-by-y be the x-coordinate of the bot graphed by the y-coordinate of the bot; [we might need this later to look up a row in the Table of Planetary Surface]

repeat through the current vision table of the bot:

let the item in sight be the seen thing entry;

if the orientation entry is down:

if the item in sight is a crater:

say "It is in [an item in sight].";

otherwise if the item in sight is a terrain feature:

say "It is on [an item in sight].";

otherwise if the item in sight is the spaceship exterior:

say "It has arrived at your spaceship and can prepare for takeoff when necessary.";

otherwise:

say "In its immediate vicinity it can see [action description of the item in sight].";

otherwise if the item in sight is a terrain feature and there is a feature in row x-by-y of the Table of Planetary Surface and the feature in row x-by-y of the Table of Planetary Surface is the item in sight: [that awful thing is looking up the coordinates of bot in the table and checking to see whether the item in sight is the feature there; we have to do this instead of choosing a row because choosing a row in a different table messes up our repeat through the current vision table]

if the item in sight is a crater:

let way be the opposite of the orientation entry;

say "It is on the [way] wall of [an item in sight].";

otherwise:

say "It is on [an item in sight].";

otherwise:

say "To [the orientation entry] it can [if robots looking for the first time is true or the action name part of the current action is the looking action][otherwise if the item in sight is listed in the previously seen list]still [otherwise]now [end if]see [action description of the item in sight][sun-caught status of the item in sight][if there is a partial obstructor entry] behind [the partial obstructor entry][end if]."; [about that first clause; the first time we look, and any time we do a look action, we don't say "now" or "still"]

remove the item in sight from the previously seen list, if present;

remove the list of things held by the bot from the previously seen list; [this prevents the "no longer seen" message for something the bot has just picked up]

if the previously seen list is not empty and robots looking for the first time is false: [after the tutorial robots looking for the first time is reset, but the previously seen list is not reset, so we use the looking for the first time flag to prevent this message from printing]

say "It can no longer see ";

write previously seen list as seen names, disjunctively;

say ".";

say conditional paragraph break;

To write (L - list of things) as seen names, disjunctively: [currently I never use this non-disjunctively, but it's good to be prepared]

let N be the number of entries in L;

if N is 0:

say "nothing";

otherwise if N is 1:

say "[a seen name of entry 1 of L]";

otherwise if N is 2:

say "[a seen name of entry 1 of L] [if disjunctively]or[otherwise]and[end if] [a seen name of entry 2 of L]";

otherwise:

repeat with M running from 1 to N - 1:

say "[a seen name of entry M of L], ";

if disjunctively:

say "or ";

otherwise:

say "and ";

say "[a seen name of entry N of L]".

Carry out a robot looking: now every robot is unsuccessful. [Just to make sure that "looking" doesn't describe what the robots are doing.]

After a robot (called bot) looking in the hold of the Tiptree: say "[Bot] is in the hold of the Tiptree. (To allow it to move again, tell it to EXIT.)"

After a robot (called bot) looking: ["After" so it cuts off the other people looking rule.]

swap vision tables for the bot;

report vision for the bot;

swap vision tables for the bot. [After the most recent time the every turn rules run the vision tables will have been swapped in preparation for the next time. We swap them back to rerun the looking action and then swap them back again. I don't think swapping the vision tables before reporting vision in the report robot vision rule would work because the vision report counts on the current vision table being the one that just got filled. Probably there's a better way to do this; I guess by swapping the tables at the beginning for the set robot vision rule? But if this works I'll leave it as is.]