swarm-0.4: data/scenarios/Challenges/_gopher/gopher.sw
def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
def abs = \n. if (n < 0) {-n} {n} end;
def elif = \t. \then. \else. {if t then else} end
def else = \t. t end
def randSign = \x.
opposite <- random 2;
if (opposite == 1) {
return (-x);
} {
return x;
}
end;
def goDir = \dist. \d1. \d2.
if (dist < 0) {
turn d1;
} $ elif (dist > 0) {
turn d2;
} {};
doN (abs dist) move;
end;
def randSwap = \f. \g.
r <- random 2;
if (r == 0) {
f; g;
} {
g; f;
};
end;
def converge = \dest. \currentLoc.
let xDist = fst currentLoc - fst dest in
let yDist = snd currentLoc - snd dest in
randSwap (goDir xDist east west) (goDir yDist north south);
end;
def navigateTo = \destTuple.
loc <- whereami;
converge destTuple loc;
end;
def arrive = \fieldWidth. \fieldHeight.
newDestinationX <- random fieldWidth;
newDestinationYtemp <- random fieldHeight;
let newDestinationY = -newDestinationYtemp in
navigateTo (newDestinationX, newDestinationY);
turn down;
end;
def getTauntStage = \startingAmount. \newCount.
if ((newCount * 5) / startingAmount < 1) {
(0, "Hey, maybe we can work this out?")
} $ elif ((newCount * 5) / startingAmount < 2) {
(1, "I didn't hear no bell!")
} $ elif ((newCount * 5) / startingAmount < 3) {
(2, "Why don't you just give up?")
} $ elif ((newCount * 5) / startingAmount < 4) {
(3, "Close one!")
} $ elif (newCount < startingAmount - 2) {
(4, "OK, no more Mr. Nice Gopher!")
} $ elif (newCount < startingAmount - 1) {
(5, "Bet you can't do that again!")
} $ elif (newCount < startingAmount) {
(6, "Beginner's luck!")
} $ else {(7, "You'll never catch me!")};
end;
def waitWhileHere = \e. \remainingTime.
here <- isHere e;
if here {
wait 1;
if (remainingTime > 0) {
waitWhileHere e $ remainingTime - 1;
} {
// Pick up the "dropping"
try {
// Note: There exists a race condition;
// if the user happens to drill the mound
// *after* the gopher checks it with `ishere`
// but *before* it executes `grab`, the gopher will crash.
// Thus we have wrapped this `grab` in a `try`.
grab;
return ();
} {};
};
} {};
end;
def go = \width. \height. \lastTauntIndex. \startingAmount. \dropping.
newCount <- count dropping;
if (newCount > 0) {
let tauntStage = getTauntStage startingAmount newCount in
let tauntIndex = fst tauntStage in
if (tauntIndex != lastTauntIndex) {
say $ snd tauntStage;
} {};
appear "o";
arrive width height;
place dropping;
appear "G";
waitWhileHere dropping 150;
go width height tauntIndex startingAmount dropping;
} {
say "Argh! I give up.";
// Allow the player to salvage their robots
let reward = "toolkit" in
try {
place reward;
} {
swap reward;
return ();
};
baseloc <- as base {whereami};
teleport self baseloc;
give base "serenity";
selfdestruct;
};
end;
let dropping = "mound" in
startingAmount <- count dropping;
go 28 18 (-1) startingAmount dropping;