swarm-0.4: data/scenarios/Challenges/_maypole/monitor.sw
def elif = \t. \then. \else. {if t then else} end
def else = \t. t end
def abs = \n. if (n < 0) {-n} {n} end
// modulus function (%)
def mod : int -> int -> int = \i.\m.
i - m * (i / m)
end
/*
Quadrants are numbered counter-clockwise, staring in the northeast:
|
1 | 0
_____|_____
|
2 | 3
|
This is same as the standard graph quadrants in mathematics, except
for 0-based numbering rather than 1-based.
*/
def getQuadrant : (int * int) -> (int * int) -> int = \baseLoc. \myLoc.
let baseX = fst baseLoc in
let baseY = snd baseLoc in
let myX = fst myLoc in
let myY = snd myLoc in
let isUp = myY < baseY in
let isRight = myX < baseX in
if (isUp && isRight) {0}
$ elif (isUp) {1}
$ elif (isRight) {3}
$ else {2}
end;
/*
Possible edge case:
----
If the difference in quadrants is 2, then either
the monitor is not making observations with high
enough frequency, or the target has teleported
diagonally.
Either way, the direction of rotation is ambiguous,
so we should make the increment zero.
*/
def getQuadrantIncrement = \oldQuadrant. \newQuadrant.
let rawDifference = newQuadrant - oldQuadrant in
let difference = if (abs rawDifference == 3) {-rawDifference} {rawDifference} in
if (difference > 0) {1}
$ elif (difference < 0) {-1}
$ else {0}
end;
def getCurrentQuadrant : (int * int) -> cmd int = \myLoc.
baseLoc <- as base {whereami};
return $ getQuadrant baseLoc myLoc;
end;
def checkNewQuadrant = \myLoc. \prevQuadrant. \quadrantTraversalCount.
currentQuadrant <- getCurrentQuadrant myLoc;
let changeCount = getQuadrantIncrement prevQuadrant currentQuadrant in
let newQuadrantCount = quadrantTraversalCount + changeCount in
if (changeCount != 0) {
swap $ "maypole " ++ format currentQuadrant;
return ();
} {};
return (currentQuadrant, newQuadrantCount);
end;
/*
Although conceivably the current quadrant could
be derived from the quadrant traversal count,
since it is possible to start "traversing" from
any quadrant we just keep track of them separately.
Also, the edge case for disregarding "diagonal" teleportation
means that the traversal number could get out of sync
with the absolute quadrant index.
*/
def monitorAngle : (int * int) -> int -> int -> int -> cmd unit =
\myLoc. \targetQuadrantCount. \prevQuadrant. \quadrantTraversalCount.
result <- instant $ checkNewQuadrant myLoc prevQuadrant quadrantTraversalCount;
let currentQuadrant = fst result in
let newQuadrantCount = snd result in
if (newQuadrantCount < targetQuadrantCount) {
monitorAngle myLoc targetQuadrantCount currentQuadrant newQuadrantCount;
} {
create "dizzy";
swap "bitcoin";
return ();
}
end;
def go =
myLoc <- whereami;
currentQuadrant <- getCurrentQuadrant myLoc;
monitorAngle myLoc 12 currentQuadrant 0;
end;
go;
selfdestruct;