Skip to content

Commit

Permalink
state pattern domain specific language first draft
Browse files Browse the repository at this point in the history
  • Loading branch information
gabrieljones committed Feb 27, 2020
1 parent 7ffe159 commit 10c7140
Show file tree
Hide file tree
Showing 2 changed files with 183 additions and 144 deletions.
296 changes: 152 additions & 144 deletions DungeonCrawl.ino
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
typedef void (*State) ();

void Setup();

State state = Setup;
#include "State.h"

#define PATH_COLOR dim(BLUE, 64)
#define AVATAR_COLOR GREEN
Expand All @@ -15,183 +11,195 @@ bool revealed = false;
byte heading = 0;
Timer timer;

void Setup() {
revealed = false;
randomize();
if(startState() == START_STATE_WE_ARE_ROOT) {
state = Avatar0;
} else {
state = random(1) ? Path0 : Wall0;
}
}

void Avatar0() {
setValueSentOnAllFaces(AVATAR);
setColor(AVATAR_COLOR);
revealed = true; //will become revealed path after adventurer leaves
state = Avatar;
}

void Avatar() {
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case MOVE: //avatar is being pulled to neighbor revert to path
state = Path0;
break;
}
extern const State avatarS;
extern const State avatarMovingS;
extern const State pathS;
extern const State wallS;
extern const State resetBroadcastS;
extern const State resetIgnoreS;
extern const State resetS;

const State setupS {
NoOp,
[]() {
revealed = false;
randomize();
if(startState() == START_STATE_WE_ARE_ROOT) {
changeState(avatarS);
} else {
changeState(random(2) == 0 ? wallS : pathS);
}
}
}

void AvatarMoving0() {
setValueSentOnFace(MOVE, heading); //tell neighbor avatar is moving here
setColorOnFace(AVATAR_COLOR, heading);
setColorOnFace(AVATAR_COLOR, (heading + 1) % 6);
setColorOnFace(AVATAR_COLOR, (heading + 5) % 6);
state = AvatarMoving;
}
};

void AvatarMoving() {
bool doneMoving = true;
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case AVATAR: //wait for all neighbors to be not AVATARs
doneMoving = false;
break;
case RESET:
state = ResetBroadcast0;
break;
const State avatarS {
[]() { //entry
setValueSentOnAllFaces(AVATAR);
setColor(AVATAR_COLOR);
revealed = true; //will become revealed path after adventurer leaves
},
[]() { //loop
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case MOVE: //avatar is being pulled to neighbor revert to path
changeState(pathS);
break;
}
}
}
}
if (doneMoving) { //after avatar is confirmed to be here then transition to actual Avatar state
state = Avatar0;
}
if (buttonLongPressed()) {
state = ResetBroadcast0;
}
}

void Path0() {
setValueSentOnAllFaces(PATH);
setColor(revealed ? PATH_COLOR : FOG_COLOR);
state = Path;
}

void Path() {
if (buttonSingleClicked()) {
FOREACH_FACE(f) { //check if avatar is on neighbor
};

const State avatarMovingS {
[]() { //entry
setValueSentOnFace(MOVE, heading); //tell neighbor avatar is moving here
setColorOnFace(AVATAR_COLOR, heading);
setColorOnFace(AVATAR_COLOR, (heading + 1) % 6);
setColorOnFace(AVATAR_COLOR, (heading + 5) % 6);
},
[]() { //loop
bool doneMoving = true;
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case AVATAR: //reveal and pull avatar
revealed = true;
heading = f;
state = AvatarMoving0;
case AVATAR: //wait for all neighbors to be not AVATARs
doneMoving = false;
break;
case RESET:
changeState(resetBroadcastS);
break;
}
}
}
if (doneMoving) { //after avatar is confirmed to be here then transition to actual Avatar state
changeState(avatarS);
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
}
}
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case RESET:
state = ResetBroadcast0;
break;
};

const State pathS {
[]() { //entry
setValueSentOnAllFaces(PATH);
setColor(revealed ? PATH_COLOR : FOG_COLOR);
},
[]() { //loop
if (buttonSingleClicked()) {
FOREACH_FACE(f) { //check if avatar is on neighbor
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case AVATAR: //reveal and pull avatar
revealed = true;
heading = f;
changeState(avatarMovingS);
break;
}
}
}
}
}
if (buttonLongPressed()) {
state = ResetBroadcast0;
}
}

void Wall0() {
setValueSentOnAllFaces(revealed ? WALL_REVEALED : WALL);
setColor(revealed ? WALL_COLOR : FOG_COLOR);
state = Wall;
}

void Wall() {
if (buttonSingleClicked()) {
FOREACH_FACE(f) { //check if avatar is on neighbor
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case AVATAR: //reveal and don't pull avatar
revealed = true;
heading = f;
state = Wall0;
case RESET:
changeState(resetBroadcastS);
break;
}
}
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
}
}
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case RESET:
state = ResetBroadcast0;
break;
};

const State wallS {
[]() { //entry
setValueSentOnAllFaces(revealed ? WALL_REVEALED : WALL);
setColor(revealed ? WALL_COLOR : FOG_COLOR);
},
[]() { //loop
if (buttonSingleClicked()) {
FOREACH_FACE(f) { //check if avatar is on neighbor
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case AVATAR: //reveal and don't pull avatar
revealed = true;
heading = f;
changeState(wallS);
break;
}
}
}
}
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case RESET:
changeState(resetBroadcastS);
break;
}
}
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
}
}
if (buttonLongPressed()) {
state = ResetBroadcast0;
}
}

void ResetBroadcast0() {
setValueSentOnAllFaces(RESET);
setColor(RESET_COLOR);
timer.set(512);
state = ResetBroadcast;
}
};

//broadcast reset for a bit
void ResetBroadcast() {
if (timer.isExpired()) {
state = ResetIgnore0;
const State resetBroadcastS {
[]() { //entry
setValueSentOnAllFaces(RESET);
setColor(RESET_COLOR);
timer.set(512);
},
[]() { //loop
if (timer.isExpired()) {
changeState(resetIgnoreS);
}
}
}
};

void ResetIgnore0() {
setValueSentOnAllFaces(NONE);
setColor(dim(RESET_COLOR, 128));
timer.set(512);
state = ResetIgnore;
}

//stop broadcasting reset after a bit, then ignore the reset broadcast
void ResetIgnore() {
if (timer.isExpired()) {
state = Reset0;
}
if (buttonLongPressed()) {
state = ResetBroadcast0;
const State resetIgnoreS {
[]() { //entry
setValueSentOnAllFaces(NONE);
setColor(dim(RESET_COLOR, 128));
timer.set(512);
},
[]() { //loop
if (timer.isExpired()) {
changeState(resetS);
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
}
}
}


void Reset0() {
timer.set(512);
state = Reset;
}
};

//ignore reset wave for a bit more, then reinitialize
void Reset() {
if (timer.isExpired()) {
state = Setup;
}
if (buttonLongPressed()) {
state = ResetBroadcast0;
const State resetS {
[]() { //entry
timer.set(512);
},
[]() { //loop
if (timer.isExpired()) {
changeState(setupS);
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
}
}
}
};

void setup() {
changeState(setupS);
}

void loop() {
state();
stateFn();
}
31 changes: 31 additions & 0 deletions State.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
typedef void (*Function0) ();

void NoOp() {}

typedef struct {
Function0 entryFn;
Function0 loopFn;
} State;

State * state;

Function0 stateFn;

void enterState() {
state -> entryFn();
stateFn = state -> loopFn;
}

void changeState(State _nextState) {
state = & _nextState;
stateFn = enterState;
}

/* Usage
const State nameS {
[]() { //entry
},
[]() { //loop
}
};
*/

0 comments on commit 10c7140

Please sign in to comment.