Skip to content

Instantly share code, notes, and snippets.

@thedod
Created December 4, 2010 21:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thedod/728485 to your computer and use it in GitHub Desktop.
Save thedod/728485 to your computer and use it in GitHub Desktop.
Marble disorder - Arduino Marble maze simulator for LCD and 2 tilt-switches

Marble Disorder is a marble maze simulation for Arduino, 16x2 char LCD, and 2 tilt switches. See Instructable.

The current version is marble_disorder_v2.pde. marble_disorder.pde is only kept here for historical reasons. V2 requires setting the tilt switches to point to NW and NE (as opposed to the more intuitive W and N used for marble_disorder.pde - i.e. the 2 versions are not hardware-compatible).

I didn't change the breadboard diagram, because it would require creating a "45 degree rotated tilt switch" component for Fritzing. Instead - there's a photo here showing it like it is :)

Also note that in V2, the potentiomenter and speaker are no longer used, but if you add them - you can also play Ariadne on the same box.

/* *** Note: please use marble_disorder_v2.pde instead ***
*** (see in readme file how to modify the hardware) ***
*** This file is only kept here for historical reasons ***
Marble Disorder - a borderline case of Marble Madness :)
(if you're not MM-aware, see http://bit.ly/marblemadnessvid).
It's a marble maze for a 16x2 LCD display, controled by 2 tilt switches.
There's also a potentiometer to control the marble's "spin":
since tilt switches only have 2 options each (N/S and E/W), i.e. there's
no "stay put" option for an axis, sometimes there are 2 paths for the
marble to chose from. In that case - the spin is the tie-breaker between
these options. In other cases it has no effect.
You can use any Hitachi HD44780 compatible LCD
(Pins are explained at http://www.arduino.cc/en/Tutorial/LiquidCrystal):
rs on pin 2, rw on 3, enable on 4, data on pins 5-8.
Tilt switches are on pins 11 and 12
(with a 10k ohm pull-up resistors between the pin and gnd).
There's a button on pin 10 (with the same pull-resistor trick),
and a potentiometer on analog pin 1 (outer legs go to +5v and gnd).
Optional:
You can put a piezo speaker between pin 9 and gnd.
It beeps whenever there's a spin (i.e. - you can't avoid beeps by
playing better). You can also mute it from code by setting MUTESOUND
to 1 (which is the default :)).
Why have the speaker and mute it?
Glad you asked:
This box can also run Ariadne (a less physical [more mental?] 1st person
maze - http://bit.ly/lcdmaze). Ariadne only beeps when you hit a wall
(something that can be avoided).
Enjoy,
@TheRealDod, Dec 1, 2010
*/
#include <LiquidCrystal.h>
// LiquidCrystal display
// You can use any Hitachi HD44780 compatible. Wiring explained at
// http://www.arduino.cc/en/Tutorial/LiquidCrystal
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);
// Tilt switches. Origin at bottom right
// (x is high when you tilt left, y - when you tilt forward)
// You can reverse these assumptions at movePlayer()
const int XTILTPIN = 11;
const int YTILTPIN = 12;
const int SPEAKERPIN = 9;
// Uncomment one of the next 2 lines
//const int MUTESOUND = 0; // Beep on spins
const int MUTESOUND = 1; // Peace and quiet
const int CLOCKWISETONE = 1760; // in Hz
const int COUNTERCLOCKWISETONE = 440; // 2 octaves lower
const int SPINBEEPDURATION = 100; // should be less than MINSTEPDELAY
const int BUTTONPIN = 10;
const int BUTTONPRESSED = HIGH; // depends on whether button is normally-open/closed
const int SPINCONTROLPIN = 1; // potentiometer on analog 1 form marble's spin
const int RANDSEEDPIN = 0; // analog pin o shouldn't be connected to anything
// Maze can be much larger than this (makeMaze() is pretty fast),
// but this seems to be the right size for a fun game (at least for me).
const int MAZEROWS = 8;
const int MAZECOLS = 16;
const int DISPLAYROWS = 2;
const int DISPLAYCOLS = 16;
const int PLAYERDISPLAYROW = 1;
const int PLAYERDISPLAYCOL = 8;
const int MAXSTEPDELAY = 500; // First level is the slowest
const int LEVELDELAYDIFF = 75; // each level, we subtract this from step_delay
const int MINSTEPDELAY = 200; // That's as fast as we go
int step_delay;
char line_buff[DISPLAYCOLS+1]; // extra char for \0
#define BITMASK(x) (1<<(x))
const byte LEFT=0;
const byte BOTTOM=1;
const byte PLAYER=2;
char *intro_message[DISPLAYROWS] = {
"Marble Disorder.",
"Click to start."};
char *noob_score[DISPLAYROWS] = {
" sec. Click",
"for next level."};
char *pro_score[DISPLAYROWS] = {
"s average.",
"Another round?"};
// glyphs
char BLANK = ' '; // no need to waste a glyph on that :)
char EXIT = '*';
char SPIN = '\0';
const int NGLYPHS = 8;
// note that glyph 0 can't be used in
// lcd.print() of null-terminated strings
byte glyphs[NGLYPHS][8] = {
// 0: SPIN
{B01101,
B10011,
B00111,
B00000,
B00000,
B00111,
B10011,
B01101}
// 1: BITMASK(LEFT)
,{B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000}
// 2: BITMASK(BOTTOM)
,{B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111}
// 3: BITMASK(LEFT)|BITMASK(BOTTOM)
,{B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B11111}
// 4: BITMASK(PLAYER)
,{B00000,
B00000,
B00110,
B01011,
B01111,
B00110,
B00000,
B00000}
// 5: BITMASK(PLAYER)|BITMASK(LEFT)
,{B10000,
B10000,
B10110,
B11011,
B11111,
B10110,
B10000,
B10000}
// 6: BITMASK(PLAYER)|BITMASK(BOTTOM)
,{B00000,
B00000,
B00110,
B01011,
B01111,
B00110,
B00000,
B11111}
// 7: BITMASK(PLAYER)|BITMASK(LEFT)|BITMASK(BOTTOM)
,{B10000,
B10000,
B10110,
B11011,
B11111,
B10110,
B10000,
B11111}
};
const byte NORTH = 0;
const byte EAST = 1;
const byte SOUTH = 2;
const byte WEST = 3;
byte maze[MAZEROWS][MAZECOLS];
int groups[MAZEROWS][MAZECOLS];
int player_row;
int player_col;
// score
const int NOSCORE = -1; // for intro message
unsigned long game_start; // millis
int n_games;
int total_time;
void setup()
{
//Serial.begin(9600);
pinMode(SPEAKERPIN,OUTPUT);
n_games = total_time = 0;
step_delay = MAXSTEPDELAY; // start slow
randomSeed(analogRead(RANDSEEDPIN));
for (int i=0; i<NGLYPHS; i++) {
lcd.createChar(i,glyphs[i]);
}
lcd.begin(DISPLAYCOLS,DISPLAYROWS);
initGame(NOSCORE,intro_message);
}
void loop() {
// Next 2 lines assume origin is at bottom right
// Adjust if you rig the tilt switches in a different way
int xheading = digitalRead(XTILTPIN) ? WEST : EAST;
int yheading = digitalRead(YTILTPIN) ? NORTH : SOUTH;
// Uncomment one of the following lines according to how outer legs go to gnd/+5v
// (look at the game's spin indicator on the right and see if it looks right).
int is_clockwise = analogRead(SPINCONTROLPIN)>511;
//int is_clockwise = analogRead(SPINCONTROLPIN)<512;
int did_spin = movePlayer(xheading, yheading, is_clockwise);
if (did_spin && !MUTESOUND) {
tone(SPEAKERPIN, is_clockwise ? CLOCKWISETONE : COUNTERCLOCKWISETONE, SPINBEEPDURATION);
}
if (!(player_row || player_col)) { // Yay! We won!
int duration = gameDuration()/1000;
total_time += duration;
n_games++;
if (step_delay>MINSTEPDELAY) {
step_delay -= LEVELDELAYDIFF;
initGame(duration,noob_score);
}
else { // "pro" playa, show average
initGame(total_time/n_games,pro_score);
}
}
drawMaze(xheading, yheading, is_clockwise);
delay((did_spin && !MUTESOUND) ? step_delay-SPINBEEPDURATION : step_delay);
}
void initGame(int score, char *msg[]) {
// displays a message, calls makeMaze(), and waits for a tilt
int xtilt=digitalRead(XTILTPIN);
int ytilt=digitalRead(YTILTPIN);
lcd.clear();
for (int r=0; r<2; r++) {
lcd.setCursor(0,r);
if (!r && score!=NOSCORE) {
lcd.print(score);
}
lcd.print(msg[r]);
}
makeMaze();
debugMaze();
while (digitalRead(BUTTONPIN)!=BUTTONPRESSED) {
delay(50); // wait for button
}
lcd.clear();
game_start = millis();
}
unsigned long gameDuration() {
return millis()-game_start;
}
int movePlayer(int xheading, int yheading, int is_clockwise) {
int xfree = !(maze[player_row][player_col]&BITMASK(xheading));
int yfree = !(maze[player_row][player_col]&BITMASK(yheading));
int is_spin = 0;
if (xfree && yfree) {
is_spin = 1;
// is_clockwise is the tie-breaker. Sets desired modulo diff.
// Assumption: (xheading-yheading)%4 can only be 1 or 3.
int diff_of_spin = is_clockwise ? 1 : 3;
if ((xheading-yheading)%4 == diff_of_spin) {
yfree = 0; // spin prefers xheading
}
else {
xfree = 0; // spin prefers yheading
}
}
if (xfree) {
player_col += (xheading==EAST) ? 1 : -1;
return is_spin;
}
if (yfree) {
player_row += (yheading==SOUTH) ? 1 : -1;
return is_spin;
}
}
void drawMaze(int xheading, int yheading, int is_clockwise) {
// leave last 2 cols for spin and tilt indication
line_buff[DISPLAYCOLS-2]='\0';
for (int r=0; r<DISPLAYROWS; r++) {
for (int c=0; c<DISPLAYCOLS-2; c++) {
int absrow=r+player_row-PLAYERDISPLAYROW;
int abscol=c+player_col-PLAYERDISPLAYCOL;
line_buff[c]=rowColChar(absrow,abscol);
}
lcd.setCursor(0,r);
lcd.print(line_buff);
}
// spin indication
lcd.setCursor(DISPLAYCOLS-2,0);
lcd.write(SPIN);
lcd.write(is_clockwise ? '>' : '<');
// heading indication
lcd.setCursor(DISPLAYCOLS-2,1);
lcd.write(yheading==NORTH ? '^' : 'v');
lcd.write(xheading==EAST ? '>' : '<');
}
//===== aux functions
//---- for initGame()
void makeMaze() {
// initialize
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
maze[r][c] = 15; // walls in all directions
groups[r][c] = r*MAZECOLS+c; // each cell is in a different group
}
}
// break walls
int walls_to_break = MAZEROWS*MAZECOLS-1;
while (walls_to_break--) {
breakWall();
}
// put player at bottom right
player_row = MAZEROWS-1;
player_col = MAZECOLS-1;
}
void breakWall() {
int breaking_west,row1,col1,row2,col2,joinfrom,jointo;
while (1) {
breaking_west=random(2); // decide whether it's a western or a southern wall
if (breaking_west) {
row1 = row2 = random(MAZEROWS);
col1 = 1+random(MAZECOLS-1); // can't break west from 1st col
col2 = col1-1;
if (!(maze[row1][col1]&BITMASK(WEST))) {
continue;
} // no wall to break
joinfrom = groups[row1][col1];
jointo = groups[row2][col2];
if (joinfrom==jointo) {
continue;
} // no reason to break this wall
maze[row1][col1] &= ~BITMASK(WEST);
maze[row2][col2] &= ~BITMASK(EAST);
}
else { // breaking south
row1 = random(MAZEROWS-1); // can't break south from last row
row2 = row1+1;
col1 = col2 = random(MAZECOLS);
if (!(maze[row1][col1]&BITMASK(SOUTH))) {
continue;
} // no wall to break
joinfrom = groups[row1][col1];
jointo = groups[row2][col2];
if (joinfrom==jointo) {
continue;
} // no reason to break this wall
maze[row1][col1] &= ~BITMASK(SOUTH);
maze[row2][col2] &= ~BITMASK(NORTH);
}
// join the groups
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
if (groups[r][c]==joinfrom) {
groups[r][c] = jointo;
}
}
}
break;
}
}
//---- for drawMaze()
// rowColChar deals with all special cases, or calls cellChar otherwise
char rowColChar(int row, int col) {
if (row==-1 && col==0) { // the exit
return EXIT;
}
if (row<-1 || row>MAZEROWS || col<-1 || col>MAZECOLS) { // limbo: unconstructed mazespace ;)
return BLANK;
}
if ((row==-1 || row==MAZEROWS) && (col==-1 || col==MAZECOLS)) { // corners are limbo too
return BLANK;
}
if (row==-1) { // northern wall
return cellChar(BITMASK(SOUTH),0);
}
if (col==MAZECOLS) { // eastern wall
return cellChar(BITMASK(WEST),0);
}
if (row==MAZEROWS) { // southern wall
return cellChar(BITMASK(NORTH),0);
}
if (col==-1) { // western wall
return cellChar(BITMASK(EAST),0);
}
// A real cell (at least in this reality)
return cellChar(maze[row][col],row==player_row&&col==player_col); // a real maze cell
}
char cellChar(byte walls, byte is_player) {
// looks a bit trivial - now that it doesn't do rotation
byte result=is_player ? BITMASK(PLAYER) : 0;
if (walls & BITMASK(WEST)) {
result |= BITMASK(LEFT);
}
if (walls & BITMASK(SOUTH)) {
result |= BITMASK(BOTTOM);
}
if (result) {
return result;
}
return BLANK;
}
//---- cheat mode ;)
void debugMaze() {
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
if (maze[r][c]&BITMASK(WEST)) {
Serial.print("|");
}
else {
Serial.print(" ");
}
if (maze[r][c]&BITMASK(SOUTH)) {
Serial.print("_");
}
else {
Serial.print(" ");
}
}
Serial.println('|');
}
}
/* Marble Disorder V2 - a borderline case of Marble Madness :)
(if you're not MM-aware, see http://bit.ly/marblemadnessvid).
It's a marble maze for a 16x2 LCD display, controled by 2 tilt switches.
Note: in V2 The tilt switches have to point to NW and NE (not W an N like
in the original version). See photo at http://bit.ly/lcdmarble
You can use any Hitachi HD44780 compatible LCD
(Pins are explained at http://www.arduino.cc/en/Tutorial/LiquidCrystal):
rs on pin 2, rw on 3, enable on 4, data on pins 5-8.
Tilt switches are on pins 11 and 12
(with a 10k ohm pull-up resistors between the pin and gnd).
There's also a button on pin 10 (with the same pull-resistor trick),
If you want ariadne compatibility (http://bit.ly/lcdmaze), add:
* A potentiometer on analog pin 1 (outer legs go to +5v and gnd).
* A piezo speaker between pin 9 and gnd.
These are not used by Marble Disorer V2, but it's cool to have 2 games
in one if you happen to have these components lying around anyway.
Enjoy,
@TheRealDod, Dec 7, 2010
*/
#include <LiquidCrystal.h>
// LiquidCrystal display
// You can use any Hitachi HD44780 compatible. Wiring explained at
// http://www.arduino.cc/en/Tutorial/LiquidCrystal
LiquidCrystal lcd(2, 3, 4, 5, 6, 7, 8);
// Tilt switches heading NW and NE
// That's the main difference between v1 and v2
// You should place them diagonally on the board
const int TILTPIN1 = 11;
const int TILTPIN2 = 12;
const int BUTTONPIN = 10;
const int BUTTONPRESSED = HIGH; // depends on whether button is normally-open/closed
const int RANDSEEDPIN = 0; // analog pin o shouldn't be connected to anything
// Maze can be much larger than this (makeMaze() is pretty fast),
// but this seems to be the right size for a fun game (at least for me).
const int MAZEROWS = 8;
const int MAZECOLS = 16;
const int DISPLAYROWS = 2;
const int DISPLAYCOLS = 16;
const int PLAYERDISPLAYROW = 1;
const int PLAYERDISPLAYCOL = 8;
const int MAXSTEPDELAY = 500; // First level is the slowest
const int LEVELDELAYDIFF = 75; // each level, we subtract this from step_delay
const int MINSTEPDELAY = 200; // That's as fast as we go
int step_delay;
char line_buff[DISPLAYCOLS+1]; // extra char for \0
#define BITMASK(x) (1<<(x))
const byte LEFT=0;
const byte BOTTOM=1;
const byte PLAYER=2;
char *intro_message[DISPLAYROWS] = {
"Marble Disorder,",
"the sequel."};
char *noob_score[DISPLAYROWS] = {
" sec. Click",
"for next level."};
char *pro_score[DISPLAYROWS] = {
"s average.",
"Another round?"};
// glyphs
char BLANK = ' '; // no need to waste a glyph on that :)
char EXIT = '*';
char PAUSING = '\0';
const int NGLYPHS = 8;
// note that glyph 0 can't be used in
// lcd.print() of null-terminated strings
byte glyphs[NGLYPHS][8] = {
// 0: PAUSING
{B00000,
B01010,
B01010,
B01010,
B01010,
B01010,
B01010,
B00000}
// 1: BITMASK(LEFT)
,{B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000}
// 2: BITMASK(BOTTOM)
,{B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B00000,
B11111}
// 3: BITMASK(LEFT)|BITMASK(BOTTOM)
,{B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B10000,
B11111}
// 4: BITMASK(PLAYER)
,{B00000,
B00000,
B00110,
B01011,
B01111,
B00110,
B00000,
B00000}
// 5: BITMASK(PLAYER)|BITMASK(LEFT)
,{B10000,
B10000,
B10110,
B11011,
B11111,
B10110,
B10000,
B10000}
// 6: BITMASK(PLAYER)|BITMASK(BOTTOM)
,{B00000,
B00000,
B00110,
B01011,
B01111,
B00110,
B00000,
B11111}
// 7: BITMASK(PLAYER)|BITMASK(LEFT)|BITMASK(BOTTOM)
,{B10000,
B10000,
B10110,
B11011,
B11111,
B10110,
B10000,
B11111}
};
const byte NORTH = 0;
const byte EAST = 1;
const byte SOUTH = 2;
const byte WEST = 3;
char compass[]="^>v<";
int heading2row[] = {-1,0,1,0};
int heading2col[] = {0,1,0,-1};
byte tilt2heading[2][2] = {
{NORTH, WEST}
,{EAST,SOUTH}
};
byte maze[MAZEROWS][MAZECOLS];
int groups[MAZEROWS][MAZECOLS];
int player_row;
int player_col;
// score
const int NOSCORE = -1; // for intro message
unsigned long game_start; // millis
int n_games;
int total_time;
void setup()
{
//Serial.begin(9600);
n_games = total_time = 0;
step_delay = MAXSTEPDELAY; // start slow
randomSeed(analogRead(RANDSEEDPIN));
for (int i=0; i<NGLYPHS; i++) {
lcd.createChar(i,glyphs[i]);
}
lcd.begin(DISPLAYCOLS,DISPLAYROWS);
initGame(NOSCORE,intro_message);
}
void loop() {
int heading = tilt2heading[digitalRead(TILTPIN1)][digitalRead(TILTPIN2)];
int pausing = digitalRead(BUTTONPIN)==BUTTONPRESSED;
if (!pausing) {
movePlayer(heading);
if (!(player_row || player_col)) { // Yay! We won!
int duration = gameDuration()/1000;
total_time += duration;
n_games++;
if (step_delay>MINSTEPDELAY) {
step_delay -= LEVELDELAYDIFF;
initGame(duration,noob_score);
}
else { // "pro" playa, show average
initGame(total_time/n_games,pro_score);
}
};
drawMaze();
}
drawNav(heading,pausing);
delay(step_delay);
}
void initGame(int score, char *msg[]) {
// displays a message, calls makeMaze(), and waits for the button
lcd.clear();
for (int r=0; r<2; r++) {
lcd.setCursor(0,r);
if (!r && score!=NOSCORE) {
lcd.print(score);
}
lcd.print(msg[r]);
}
makeMaze();
debugMaze();
while (digitalRead(BUTTONPIN)!=BUTTONPRESSED) {
delay(50); // wait for button
}
lcd.clear();
game_start = millis();
}
unsigned long gameDuration() {
return millis()-game_start;
}
void movePlayer(int heading) {
if (!(maze[player_row][player_col]&BITMASK(heading))) {
player_row += heading2row[heading];
player_col += heading2col[heading];
}
}
void drawMaze() {
// leave last col for tilt indicator
line_buff[DISPLAYCOLS-1]='\0';
for (int r=0; r<DISPLAYROWS; r++) {
for (int c=0; c<DISPLAYCOLS-1; c++) {
int absrow=r+player_row-PLAYERDISPLAYROW;
int abscol=c+player_col-PLAYERDISPLAYCOL;
line_buff[c]=rowColChar(absrow,abscol);
}
lcd.setCursor(0,r);
lcd.print(line_buff);
}
}
void drawNav(int heading,int pausing) {
// heading indication
lcd.setCursor(DISPLAYCOLS-1,0);
lcd.write(compass[heading]);
lcd.setCursor(DISPLAYCOLS-1,1);
lcd.write(pausing? PAUSING : BLANK);
}
//===== aux functions
//---- for initGame()
void makeMaze() {
// initialize
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
maze[r][c] = 15; // walls in all directions
groups[r][c] = r*MAZECOLS+c; // each cell is in a different group
}
}
// break walls
int walls_to_break = MAZEROWS*MAZECOLS-1;
while (walls_to_break--) {
breakWall();
}
// put player at bottom right
player_row = MAZEROWS-1;
player_col = MAZECOLS-1;
}
void breakWall() {
int breaking_west,row1,col1,row2,col2,joinfrom,jointo;
while (1) {
breaking_west=random(2); // decide whether it's a western or a southern wall
if (breaking_west) {
row1 = row2 = random(MAZEROWS);
col1 = 1+random(MAZECOLS-1); // can't break west from 1st col
col2 = col1-1;
if (!(maze[row1][col1]&BITMASK(WEST))) {
continue;
} // no wall to break
joinfrom = groups[row1][col1];
jointo = groups[row2][col2];
if (joinfrom==jointo) {
continue;
} // no reason to break this wall
maze[row1][col1] &= ~BITMASK(WEST);
maze[row2][col2] &= ~BITMASK(EAST);
}
else { // breaking south
row1 = random(MAZEROWS-1); // can't break south from last row
row2 = row1+1;
col1 = col2 = random(MAZECOLS);
if (!(maze[row1][col1]&BITMASK(SOUTH))) {
continue;
} // no wall to break
joinfrom = groups[row1][col1];
jointo = groups[row2][col2];
if (joinfrom==jointo) {
continue;
} // no reason to break this wall
maze[row1][col1] &= ~BITMASK(SOUTH);
maze[row2][col2] &= ~BITMASK(NORTH);
}
// join the groups
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
if (groups[r][c]==joinfrom) {
groups[r][c] = jointo;
}
}
}
break;
}
}
//---- for drawMaze()
// rowColChar deals with all special cases, or calls cellChar otherwise
char rowColChar(int row, int col) {
if (row==-1 && col==0) { // the exit
return EXIT;
}
if (row<-1 || row>MAZEROWS || col<-1 || col>MAZECOLS) { // limbo: unconstructed mazespace ;)
return BLANK;
}
if ((row==-1 || row==MAZEROWS) && (col==-1 || col==MAZECOLS)) { // corners are limbo too
return BLANK;
}
if (row==-1) { // northern wall
return cellChar(BITMASK(SOUTH),0);
}
if (col==MAZECOLS) { // eastern wall
return cellChar(BITMASK(WEST),0);
}
if (row==MAZEROWS) { // southern wall
return cellChar(BITMASK(NORTH),0);
}
if (col==-1) { // western wall
return cellChar(BITMASK(EAST),0);
}
// A real cell (at least in this reality)
return cellChar(maze[row][col],row==player_row&&col==player_col); // a real maze cell
}
char cellChar(byte walls, byte is_player) {
// looks a bit trivial - now that it doesn't do rotation
byte result=is_player ? BITMASK(PLAYER) : 0;
if (walls & BITMASK(WEST)) {
result |= BITMASK(LEFT);
}
if (walls & BITMASK(SOUTH)) {
result |= BITMASK(BOTTOM);
}
if (result) {
return result;
}
return BLANK;
}
//---- cheat mode ;)
void debugMaze() {
for (int r=0; r<MAZEROWS; r++) {
for (int c=0; c<MAZECOLS; c++) {
if (maze[r][c]&BITMASK(WEST)) {
Serial.print("|");
}
else {
Serial.print(" ");
}
if (maze[r][c]&BITMASK(SOUTH)) {
Serial.print("_");
}
else {
Serial.print(" ");
}
}
Serial.println('|');
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment