swarm-0.4: data/scenarios/Challenges/Ranching/_powerset/solution.sw
def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
def until = \p. \c. q <- p; if q {} {c; until p c} end;
def while = \p. until (x <- p; return $ not x) end;
def abs = \n. if (n < 0) {-n} {n} end;
def intersperse = \n. \f2. \f1.
if (n > 0) {
f1;
if (n > 1) {
f2;
} {};
intersperse (n - 1) f2 f1;
} {};
end;
def mapTuple = \f. \t.
(f $ fst t, f $ snd t)
end;
def sumTuples = \t1. \t2.
(fst t1 + fst t2, snd t1 + snd t2);
end;
def negateTuple = \t.
mapTuple (\x. -x) t;
end;
def getRelativeLocation = \absCurrentLoc. \absDestLoc.
let negatedLoc = negateTuple absCurrentLoc in
return $ sumTuples negatedLoc absDestLoc;
end;
def splitStride = \n.
let dist = abs n in
if (dist > 64) {
stride 64;
splitStride $ dist - 64;
} {
stride dist;
}
end;
def moveTuple = \tup.
let x = fst tup in
let y = snd tup in
turn $ if (x > 0) {east} {west};
// doN (abs x) move;
splitStride x;
turn $ if (y > 0) {north} {south};
// doN (abs y) move;
splitStride y;
end;
def goToLocation = \currentLoc. \absoluteDestination.
relativeDestination <- getRelativeLocation currentLoc absoluteDestination;
moveTuple relativeDestination;
end;
def recordFirstEncounter = \stashLoc. \item.
originalHeading <- heading;
originalLoc <- whereami;
goToLocation originalLoc stashLoc;
turn south;
until isempty move;
place item;
newCurrentLoc <- whereami;
goToLocation newCurrentLoc originalLoc;
turn originalHeading;
end;
def tryHarvest = \stashLoc.
maybeItem <- scan down;
case maybeItem return (\item.
hasSome <- has item;
harvest;
if hasSome {} {
while isempty $ wait 1;
// Grab another one so that our "sentinel condition" won't
// be invalidated when we go on to place it
harvest;
recordFirstEncounter stashLoc item;
};
);
end;
def doRow = \stashLoc. \sandLength.
intersperse (sandLength - 1) move $ tryHarvest stashLoc;
end;
def turnaround = \d.
turn d;
move;
turn d;
end;
/**
Precondition:
At the start of the line, facing along the line.
*/
def countLine = \tally.
emptyhere <- isempty;
if emptyhere {
turn back;
splitStride tally;
return tally;
} {
move;
countLine $ tally + 1;
}
end;
def placeFinalCopy = \item.
originalLoc <- whereami;
goToLocation originalLoc (fst originalLoc, 0);
until isempty move;
place item;
newLoc <- whereami;
goToLocation newLoc originalLoc;
end;
def copyIfNeeded = \targetCount.
maybeItem <- scan down;
case maybeItem return (\item.
quantity <- count item;
if (quantity < targetCount) {
placeFinalCopy item;
} {};
);
move;
end;
def harvestForCounts = \rowLength. \stashLoc. \sweepCount.
intersperse sweepCount (turnaround right) $
intersperse 2 (turnaround left) $ doRow stashLoc rowLength;
turnaround right;
doRow stashLoc rowLength;
end;
def go = \sweepCount.
until (has "bell") $ wait 2;
move;
rowLength <- countLine 0;
let stashLoc = (rowLength - 1, -2) in
turnaround right;
harvestForCounts rowLength stashLoc sweepCount;
originalLoc <- whereami;
goToLocation originalLoc stashLoc;
turn south;
entityCardinality <- countLine 0;
turn back;
let expectedCount = 2^(entityCardinality - 1) - 1 in
doN entityCardinality $ copyIfNeeded expectedCount;
// Mark goal-checkability sentinel
place "bell";
end;
go 3;