Skip to content

Commit

Permalink
state pattern DSL, had to resort to macros as lambdas have significan…
Browse files Browse the repository at this point in the history
…t memory overhead
  • Loading branch information
gabrieljones committed Feb 27, 2020
1 parent 10c7140 commit 19308d0
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 70 deletions.
125 changes: 65 additions & 60 deletions DungeonCrawl.ino
Original file line number Diff line number Diff line change
Expand Up @@ -11,54 +11,55 @@ bool revealed = false;
byte heading = 0;
Timer timer;

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;
STATE_DEC(avatarS);
STATE_DEC(avatarMovingS);
STATE_DEC(pathS);
STATE_DEC(wallS);
STATE_DEC(resetBroadcastS);
STATE_DEC(resetIgnoreS);
STATE_DEC(resetS);

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

const State avatarS {
[]() { //entry
STATE_DEF(avatarS,
{ //entry
setValueSentOnAllFaces(AVATAR);
setColor(AVATAR_COLOR);
revealed = true; //will become revealed path after adventurer leaves
},
[]() { //loop
{ //loop
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case MOVE: //avatar is being pulled to neighbor revert to path
changeState(pathS);
changeState(pathS::state);
break;
}
}
}
}
};
)

const State avatarMovingS {
[]() { //entry
STATE_DEF(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
{ //loop
bool doneMoving = true;
FOREACH_FACE(f) {
if (!isValueReceivedOnFaceExpired(f)) {
Expand All @@ -67,34 +68,34 @@ const State avatarMovingS {
doneMoving = false;
break;
case RESET:
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
break;
}
}
}
if (doneMoving) { //after avatar is confirmed to be here then transition to actual Avatar state
changeState(avatarS);
changeState(avatarS::state);
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
}
}
};
)

const State pathS {
[]() { //entry
STATE_DEF(pathS,
{ //entry
setValueSentOnAllFaces(PATH);
setColor(revealed ? PATH_COLOR : FOG_COLOR);
},
[]() { //loop
if (buttonSingleClicked()) {
{ //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);
changeState(avatarMovingS::state);
break;
}
}
Expand All @@ -104,31 +105,31 @@ const State pathS {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case RESET:
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
break;
}
}
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
}
}
};
)

const State wallS {
[]() { //entry
STATE_DEF(wallS,
{ //entry
setValueSentOnAllFaces(revealed ? WALL_REVEALED : WALL);
setColor(revealed ? WALL_COLOR : FOG_COLOR);
},
[]() { //loop
if (buttonSingleClicked()) {
{ //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);
changeState(wallS::state);
break;
}
}
Expand All @@ -138,68 +139,72 @@ const State wallS {
if (!isValueReceivedOnFaceExpired(f)) {
switch(getLastValueReceivedOnFace(f)) {
case RESET:
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
break;
}
}
}
if (buttonLongPressed()) {
changeState(resetBroadcastS);
changeState(resetBroadcastS::state);
}
}
};
)

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

)

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

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

void setup() {
changeState(setupS);
changeState(setupS::state);
}

void loop() {
stateFn();
}

/*
* 3422, 700
* /
*/
48 changes: 38 additions & 10 deletions State.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
typedef void (*Function0) ();

void NoOp() {}

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

State * state;
State* state;

Function0 stateFn;

Expand All @@ -16,16 +14,46 @@ void enterState() {
stateFn = state -> loopFn;
}

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


#define STATE_DEC(stateName) namespace stateName { extern const State* state; }

#define STATE_DEF(stateName, entryBody, loopBody) \
namespace stateName { \
void entry() entryBody \
void loop() loopBody \
const State _state { entry, loop }; \
extern const State* state = &_state; \
}

/* Usage
const State nameS {
[]() { //entry
},
[]() { //loop
STATE_DEC(stateName1)
STATE_DEC(stateName2)
STATE_DEF(stateName1,
{
//entry function body, called once before state starts looping
},
{
//loop function body, called repeatedly while this is the current state
//some condition
changeState(stateName2::state);
}
)
STATE_DEF(name2,
{
//entry function body
},
{
//loop function body
//some condition
changeState(stateName1::state);
}
};
)
*/

0 comments on commit 19308d0

Please sign in to comment.