packages feed

swarm-0.7.0.0: data/scenarios/Challenges/Ranching/_beekeeping/queenbee.sw

// Spawns worker bees when structures are detected

def doN = \n. \f. if (n > 0) {f; doN (n - 1) f} {}; end;
def mod : Int -> Int -> Int = \a. \b. a - (a/b)*b end;
def abs = \n. if (n < 0) {-n} {n} end;
def min = \x. \y. if (x < y) {x} {y} end;

def elif = \t. \then. \else. {if t then else} end
def else = \t. t end

def λcase = \f. \g. \s. case s f g end
def λmatch = \f. \p. match p f end

def mapTuple = \f. λmatch \a. \b. (f a, f b) end;

def sumTuples = λmatch \t11. \t12. λmatch \t21. \t22.
    (t11 + t21, t12 + t22);
    end;

def negateTuple = \t.
    mapTuple (\x. -x) t;
    end;

def subtractTuple = \t1. \t2.
    sumTuples t1 $ negateTuple t2;
    end;

// Deprecated
def moveTuple = λmatch \x. \y.
    turn $ if (x > 0) {east} {west};
    doN (abs x) move;

    turn $ if (y > 0) {north} {south};
    doN (abs y) move;
    end;

def randomDir =
    r <- random 4;
    pure $ if (r == 1) {north}
        $ elif (r == 2) {west}
        $ elif (r == 3) {south}
        $ else {east};
    end;

def moveHorizontal = \maxDirect. \dist.
    turn $ if (dist > 0) {east} {west};
    doN (min maxDirect $ abs dist) move;
    end;

def moveVertical = \maxDirect. \dist.
    turn $ if (dist > 0) {north} {south};
    doN (min maxDirect $ abs dist) move;
    end;

def randomStep =
    randDir <- randomDir;
    turn randDir;
    move;
    end;

def moveToward = \maxDirect. \goal.

    currLocOrig <- whereami;
    if (currLocOrig == goal) {} {

        // Include some random motion
        randomStep;

        currLoc <- whereami;
        let delta = subtractTuple goal currLoc in
        match delta \x. \y.

        moveHorizontal maxDirect x;
        moveVertical maxDirect y;

        moveToward maxDirect goal;
    }
    end;

def watchForHoneycombRemoval = \dist.
    if (dist > 0) {
        move;
        honeycombHere <- ishere "honeycomb";
        if honeycombHere {
            watch down;
        } {};

        watchForHoneycombRemoval $ dist - 1;
    } {};
    end;

/**
Tries to find an open cell to deposit
the honeycomb. Gives up when distance
threshold exceeded.
*/
def depositHoneycomb = \dist.
    if (dist < 5) {
        emptyHere <- isempty;
        if emptyHere {
            place "honeycomb";
        } {
            move;
            depositHoneycomb $ dist + 1;
        };
    } {
        turn back;
        watchForHoneycombRemoval dist;

        // Hibernate
        wait 2000;

        // Alternative method to get rid of honeycomb
        make "buzz";
    };
    end;

def goToHive = λmatch \hivex. \hivey.
    let depositLoc = (hivex - 1, hivey) in
    moveToward 2 depositLoc;
    turn north;
    depositHoneycomb 0;
    end;

/**
Harvests an item when reached
*/
def takeStepTowardItem = \item.
    // NOTE: Max radius is hard-coded to 256
    // (see maxSniffRange in Syntax.hs)
    direction <- chirp item;
    if (direction == down) {
        // Need a try block in case
        // another bee gets here first
        try {
            harvest;
            pure ();
        } {};
    } {
        // Include some random motion
        r <- random 4;
        if (r == 0) {
            randomStep;
        } {
            turn direction;
            move;
        };

        takeStepTowardItem item;
    }
    end;

def workerProgram = \structureLoc.
    try {make "honeycomb";} {};
    hasHoneycomb <- has "honeycomb";
    if hasHoneycomb {
        goToHive structureLoc;
    } {
        takeStepTowardItem "wildflower";
        pure ();
    };
    workerProgram structureLoc;
    end;

def mkBeeName = \structureLoc.
    "bee" ++ format structureLoc;
    end;

def workerProgramInit = \beename. \structureLoc.
    setname beename;
    appear "B" (inl ());
    workerProgram structureLoc;
    end;

def createWorkerForStructure = \loc.
    // Build worker bee, assign ID, location
    create "wax gland";
    create "proboscis";

    create "ADT calculator";
    create "beaglepuss";
    create "bitcoin";
    create "branch predictor";
    create "comparator";
    create "compass";
    create "detonator";
    create "dictionary";
    create "fast grabber";
    create "GPS receiver";
    create "harvester";
    create "hourglass";
    create "lambda";
    create "net";
    create "rolex";
    create "scanner";
    create "strange loop";
    create "solar panel";
    create "treads";
    create "workbench";

    teleport self $ loc;
    let beename = mkBeeName loc in
    build {
        stock 1 "wax gland";
        workerProgramInit beename loc;
    };
    pure ();
    end;

def associateHive = \loc.
   let beename = mkBeeName loc in
   try {
       // Fails if the robot does not exist
       robotnamed beename;
       pure ();
   } {
       createWorkerForStructure loc;

       // Give the child robot time to register its new
       // name so that we don't end up spawning multiple
       // bees for the same location
       wait 1;
   };
   end;

def mapM_ : (a -> Cmd b) -> (rec l. Unit + a * l) -> Cmd Unit = \f. λcase
  (\_. pure ())
  (λmatch \hd. \tl. f hd; mapM_ f tl)
  end;

/**
Each tick, iterates through all hives,
and makes sure a "bee" robot is associated with
their location.
If a structure exists without such an association,
creates a bee named after the location.
*/
def observeHives =

    beehives <- structures "beehive";
    mapM_ associateHive beehives;

    // Wait at least 1 tick so that we do not spin infinitely until
    // we saturate our computation quota for the tick.
    wait 1;
    observeHives;
    end;

def go =
    instant $ observeHives;
    end;

go;