Skip to content

Commit

Permalink
Merge pull request #36 from SOPSLab/ballroom-demo
Browse files Browse the repository at this point in the history
Ballroom (Coordination) Demo
  • Loading branch information
josephbriones committed Jun 12, 2020
2 parents f3a44a5 + f285895 commit ce75c9d
Show file tree
Hide file tree
Showing 11 changed files with 737 additions and 208 deletions.
4 changes: 2 additions & 2 deletions AmoebotSim.pro
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ QMAKE_INFO_PLIST = res/Info.plist
win32:RC_FILE = res/AmoebotSim.rc

HEADERS += \
alg/demo/ballroomdemo.h \
alg/demo/discodemo.h \
alg/demo/metricsdemo.h \
alg/demo/pulldemo.h \
alg/demo/tokendemo.h \
alg/compression.h \
alg/infobjcoating.h \
Expand All @@ -38,9 +38,9 @@ HEADERS += \
alg/leaderelection.h

SOURCES += \
alg/demo/ballroomdemo.cpp \
alg/demo/discodemo.cpp \
alg/demo/metricsdemo.cpp \
alg/demo/pulldemo.cpp \
alg/demo/tokendemo.cpp \
alg/compression.cpp \
alg/infobjcoating.cpp \
Expand Down
172 changes: 172 additions & 0 deletions alg/demo/ballroomdemo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
/* Copyright (C) 2020 Joshua J. Daymude, Robert Gmyr, and Kristian Hinnenthal.
* The full GNU GPLv3 can be found in the LICENSE file, and the full copyright
* notice can be found at the top of main/main.cpp. */

#include "alg/demo/ballroomdemo.h"

BallroomDemoParticle::BallroomDemoParticle(const Node head,
const int globalTailDir,
const int orientation,
AmoebotSystem &system,
State state)
: AmoebotParticle(head, globalTailDir, orientation, system),
_state(state),
_partnerLbl(-1) {
_color = getRandColor();
}

void BallroomDemoParticle::activate() {
if (_state == State::Leader) {
if (isContracted()) {
// Attempt to expand into an random adjacent position.
int expandDir = randDir();
if (canExpand(expandDir)) {
expand(expandDir);
}
} else {
// Find the follower partner and pull it, if possible.
for (int label : tailLabels()) {
if (hasNbrAtLabel(label) && nbrAtLabel(label)._partnerLbl != -1
&& pointsAtMe(nbrAtLabel(label), nbrAtLabel(label)._partnerLbl)) {
if (canPull(label)) {
nbrAtLabel(label)._partnerLbl =
dirToNbrDir(nbrAtLabel(label), (tailDir() + 3) % 6);
pull(label);
}
break;
}
}
}
} else { // _state == State::Follower.
if (isContracted()) {
if (canPush(_partnerLbl)) {
// Update the pair's color.
auto leader = nbrAtLabel(_partnerLbl);
if (_color != leader._color) {
_color = leader._color;
} else {
nbrAtLabel(_partnerLbl)._color = getRandColor();
}

// Push the leader and update the partner direction label.
int leaderContractDir = nbrDirToDir(leader, (leader.tailDir() + 3) % 6);
push(_partnerLbl);
_partnerLbl = leaderContractDir;
}
} else {
contractTail();
}
}
}

int BallroomDemoParticle::headMarkColor() const {
switch(_color) {
case Color::Red: return 0xff0000;
case Color::Orange: return 0xff9000;
case Color::Yellow: return 0xffff00;
case Color::Green: return 0x00ff00;
case Color::Blue: return 0x0000ff;
case Color::Indigo: return 0x4b0082;
case Color::Violet: return 0xbb00ff;
}

return -1;
}

int BallroomDemoParticle::headMarkDir() const {
return _partnerLbl;
}

int BallroomDemoParticle::tailMarkColor() const {
return headMarkColor();
}

QString BallroomDemoParticle::inspectionText() const {
QString text;
text += "Global Info:\n";
text += " head: (" + QString::number(head.x) + ", "
+ QString::number(head.y) + ")\n";
text += " orientation: " + QString::number(orientation) + "\n";
text += " globalTailDir: " + QString::number(globalTailDir) + "\n\n";
text += "Local Info:\n";
text += " state: ";
text += [this](){
switch(_state) {
case State::Leader: return "leader\n";
case State::Follower: return "follower\n";
}
return "no state\n";
}();
text += [this](){
switch(_color) {
case Color::Red: return "red\n";
case Color::Orange: return "orange\n";
case Color::Yellow: return "yellow\n";
case Color::Green: return "green\n";
case Color::Blue: return "blue\n";
case Color::Indigo: return "indigo\n";
case Color::Violet: return "violet\n";
}
return "no color\n";
}();
text += " partnerLbl: " + QString::number(_partnerLbl);

return text;
}

BallroomDemoParticle& BallroomDemoParticle::nbrAtLabel(int label) const {
return AmoebotParticle::nbrAtLabel<BallroomDemoParticle>(label);
}

BallroomDemoParticle::Color BallroomDemoParticle::getRandColor() const {
// Randomly select an integer and return the corresponding color via casting.
return static_cast<Color>(randInt(0, 7));
}

BallroomDemoSystem::BallroomDemoSystem(unsigned int numParticles) {
// To enclose an area that's roughly 6x the # of particles using a rhombus,
// the rhombus should have side length 2.6*sqrt(# particles).
int sideLen = static_cast<int>(std::round(2.6 * std::sqrt(numParticles)));
Node boundNode(0, 0);
std::vector<int> rhombusDirs = {0, 1, 3, 4};
for (int dir : rhombusDirs) {
for (int i = 0; i < sideLen; ++i) {
insert(new Object(boundNode));
boundNode = boundNode.nodeInDir(dir);
}
}

// Let s be the bounding rhombus side length. When the rhombus is created as
// above, the nodes (x,y) strictly within the rhombus have (i) 0 < x < s and
// (ii) 0 < y < s. We want to instantiate particles in Leader/Follower pairs,
// or "dance partners".
std::set<Node> occupied;
unsigned int numParticlesAdded = 0;
while (numParticlesAdded < numParticles) {
// Choose an (x,y) position within the rhombus for the Leader and a random
// adjacent node for its Follower partner.
Node leaderNode(randInt(2, sideLen - 1), randInt(2, sideLen - 1));
int followerDir = randDir();
Node followerNode = leaderNode.nodeInDir(followerDir);

// If both nodes are unoccupied, place the pair there, linking them together
// by setting the Follower's partner label to face the Leader.
if (occupied.find(leaderNode) == occupied.end()
&& occupied.find(followerNode) == occupied.end()) {
BallroomDemoParticle* leader =
new BallroomDemoParticle(leaderNode, -1, randDir(), *this,
BallroomDemoParticle::State::Leader);
insert(leader);
occupied.insert(leaderNode);

BallroomDemoParticle* follower =
new BallroomDemoParticle(followerNode, -1, randDir(), *this,
BallroomDemoParticle::State::Follower);
follower->_partnerLbl = follower->globalToLocalDir((followerDir + 3) % 6);
insert(follower);
occupied.insert(followerNode);

numParticlesAdded += 2;
}
}
}
83 changes: 83 additions & 0 deletions alg/demo/ballroomdemo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/* Copyright (C) 2020 Joshua J. Daymude, Robert Gmyr, and Kristian Hinnenthal.
* The full GNU GPLv3 can be found in the LICENSE file, and the full copyright
* notice can be found at the top of main/main.cpp. */

// Defines the particle system and composing particles for the Ballroom code
// tutorial, demonstrating inter-particle coordination. This tutorial covers
// read/write functionality and pull/push handovers.

#ifndef AMOEBOTSIM_ALG_DEMO_BALLROOMDEMO_H_
#define AMOEBOTSIM_ALG_DEMO_BALLROOMDEMO_H_

#include <QString>

#include "core/amoebotparticle.h"
#include "core/amoebotsystem.h"

class BallroomDemoParticle : public AmoebotParticle {
public:
enum class State {
Leader,
Follower
};

enum class Color {
Red,
Orange,
Yellow,
Green,
Blue,
Indigo,
Violet
};

// Constructs a new particle with a node position for its head, a global
// compass direction from its head to its tail (-1 if contracted), an offset
// for its local compass, a system which it belongs to, and an initial state.
BallroomDemoParticle(const Node head, const int globalTailDir,
const int orientation, AmoebotSystem& system,
State _state);

// Executes one particle activation.
void activate() override;

// Functions for altering the particle's color. headMarkColor() (resp.,
// tailMarkColor()) returns the color to be used for the ring drawn around the
// particle's head (resp., tail) node. In this demo, the tail color simply
// matches the head color. headMarkDir returns the label of the port
// on which the head marker is drawn; in this demo, this points from the
// follower dance partner to its leader.
int headMarkColor() const override;
int headMarkDir() const override;
int tailMarkColor() const override;

// Returns the string to be displayed when this particle is inspected; used
// to snapshot the current values of this particle's memory at runtime.
QString inspectionText() const override;

// Gets a reference to the neighboring particle incident to the specified port
// label. Crashes if no such particle exists at this label; consider using
// hasNbrAtLabel() first if unsure.
BallroomDemoParticle& nbrAtLabel(int label) const;

protected:
// Returns a random Color.
Color getRandColor() const;

// Member variables.
const State _state;
Color _color;
int _partnerLbl;

private:
friend class BallroomDemoSystem;
};

class BallroomDemoSystem : public AmoebotSystem {
public:
// Constructs a system of the specified number of BallroomDemoParticles in
// "dance partner" pairs enclosed by a rhombic ring of objects.
BallroomDemoSystem(unsigned int numParticles = 30);
};

#endif // AMOEBOTSIM_ALG_DEMO_BALLROOMDEMO_H_
114 changes: 0 additions & 114 deletions alg/demo/pulldemo.cpp

This file was deleted.

0 comments on commit ce75c9d

Please sign in to comment.