Hakkun communication (Idea)

From 8x9craft
Jump to: navigation, search

What if you wanted to create a Hakkun hive-mind?

Choose the one to run

Let's say you have a group of Hakkuns and want them to work together, but move only one at the same time with the choice of which is going to move dictated by some strategy.

Basic course of action for each Hakkun of a group is:

  1. Calculate a score based on your abilities and known state of the field / world.
  2. Wait for everyone to be ready to share their scores.
  3. Share your score.
  4. If your score is the highest go on, otherwise wait.
  5. Make a move.
  6. Announce what you did, so everyone can synchronize their internal state.
// This fragment would be included on every Hakkun of the same team

function calculateScore() {
    // calculate this Hakkun's strategy score based on current situation
    ...
    crab.processMessagesCollapse('everyoneReady?', () => {
        crab.broadcastMessage('notReady!');
    });
    ...
    return 42;
}

function makeMove() {
    // make a move
    var prevPos = crab.getPos();
    var newPos = ...
    ...
    crab.broadcastMessage('move:', [
        { type: 'blockChanged', pos: prevPos, block: 'Air' },
        { type: 'blockChanged', pos: newPos, block: 'Hakkun' }
    ]);
}

var updateMaxScore = function (score) {
    maxScore = Math.max(score, maxScore);
});

var updateState = function (changes) {
    // update internal state with changes
});

while (true) {
    // Start messages capture
    crab.startGatheringMessages();
    var maxScore = Number.MIN_SAFE_INTEGER;
    // Calculate own score
    var myScore = calculateScore();

    // Ask if everyone is ready
    crab.broadcastMessage('everyoneReady?');
    while (true) {
        var processedSome = crab.processMessagesCollapse('notReady!', () => { /* Do nothing */ }, 5);
        if (!processedSome) break;
    }

    crab.broadcastMessage('score:', myScore);
    while (true) {
        var processedSome = crab.processMessages('score:', updateMaxScore, 5);
        if (!processedSome) break;
    }

    if (myScore == maxScore) {
        // decide who takes precedence
    } else if (myScore > maxScore) {
        makeMove();
    } else {
        crab.waitForMessage('move:', updateState);
    }
}

What do we need to implement?

// Ignore all messages coming before reaching this point (clear messages queue)
crab.startGatheringMessages(): void

// Send a message to everyone listening nearby with an optional data payload.
crab.broadcastMessage(selector: String, data?: any): void

// Blocking with a timeout or non-blocking. Process one message matching a selector running a callback and clear all other instances matching it. Return whether processed any message while running.
crab.processMessagesCollapse(selector: String, callback: Function, timeout?: Number): boolean

// Blocking with a timeout. Process all messages matching a selector running a callback. Return whether processed any message while running.
crab.processMessages(selector: String, callback: Function, timeout: Number): boolean

// Blocking. Wait for single message matching a selector, run a callback and continue execution.
crab.waitForMessage(selector: String, callback: Function): void

It's probably a good idea to divide message types into messages with data and notifications without it. Then processMessagesCollapse would become processNotifications. Otherwise how do we choose which message to process -- the first one? the last one? they can have different data and we might lose some of it.

Synchronize two Hakkuns actions

Make them mirror each other actions.

// First crab
crab.setMessagingDistance(50);
crab.waitForMessage('Are you ready?');
crab.sendMessage("I'm ready!");
while (true) {
    var msg = crab.waitForMessage();
    if (msg == "Let's move forward!") crab.forward();
    if (msg == "Let's turn left!") crab.turnRight();
    if (msg == "Let's turn right!") crab.turnLeft();
    if (msg == "Let's dig!") crab.dig();
    if (msg == "Let's end this!") break;
    crab.sendMessage('Ok!');
}

// Second crab (leader)
function forward() {
    crab.sendMessage("Let's move forward!");
    crab.waitForMessage('Ok!');
    crab.forward();
}
function turnLeft() {
    crab.sendMessage("Let's turn left!");
    crab.waitForMessage('Ok!');
    crab.turnLeft();
}
function turnRight() {
    crab.sendMessage("Let's turn right!");
    crab.waitForMessage('Ok!');
    crab.turnRight();
}
function dig() {
    crab.sendMessage("Let's dig!");
    crab.waitForMessage('Ok!');
    crab.dig();
}
crab.setMessagingDistance(50);
crab.sendMessage('Are you ready?');
crab.waitForMessage("I'm ready!");
forward();
for (let i = 0; i < 3; ++i) {
    turnLeft();
    forward();
    dig();
}
turnLeft();
forward();
crab.sendMessage("Let's end this!");

See also