
Source code of my entry for Retro gaming contest (www.outrageouscircuits.com)
Fork of LCD_DEMO by
NOTE: I don't why mbed says that it's a fork form LCD_DEMO by Chris Taylor -> I don't use that library
SHAKE THE MAZE!!!
Shake your RETRO board and solve the maze!!!
Different maze everytime!
Here a case I built.
More details in main.cpp comments
video:
Revision 1:600980390cf7, committed 2015-03-01
- Comitter:
- gbr1mbed
- Date:
- Sun Mar 01 11:18:52 2015 +0000
- Parent:
- 0:7260a2716edf
- Commit message:
- Hello! this is my source for "Shake the Maze" game.
Changed in this revision
diff -r 7260a2716edf -r 600980390cf7 DisplayN18.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DisplayN18.cpp Sun Mar 01 11:18:52 2015 +0000 @@ -0,0 +1,484 @@ +#include "DisplayN18.h" + +DisplayN18::DisplayN18() : resetPin(P0_20), backlightPin(P0_19), rsPin(P0_7), csPin(P0_2), spi(P0_21, P0_22, P1_15) { + this->resetPin.write(false); + this->backlightPin.write(true); + this->rsPin.write(false); + + this->spi.format(8, 3); + this->spi.frequency(15000000); + + this->initialize(); +} + +void DisplayN18::writeCommand(unsigned char command) { + this->rsPin.write(false); + + this->csPin.write(false); + + this->spi.write(command); + + this->csPin.write(true); +} + +void DisplayN18::writeData(unsigned char data) { + this->writeData(&data, 1); +} + +void DisplayN18::writeData(const unsigned char* data, unsigned int length) { + this->rsPin.write(true); + + this->csPin.write(false); + + for (unsigned int i = 0; i < length; i++) + this->spi.write(data[i]); + + this->csPin.write(true); +} + +void DisplayN18::reset() { + this->resetPin.write(false); + wait_ms(300); + + this->resetPin.write(true); + wait_ms(500); +} + +void DisplayN18::initialize() { + this->reset(); + + this->writeCommand(0x11); + + wait_ms(120); + + this->writeCommand(0xB1); + this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D); + this->writeCommand(0xB2); + this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D); + this->writeCommand(0xB3); + this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D); + this->writeData(0x01); this->writeData(0x2C); this->writeData(0x2D); + + this->writeCommand(0xB4); + this->writeData(0x07); + + this->writeCommand(0xC0); + this->writeData(0xA2); this->writeData(0x02); this->writeData(0x84); + this->writeCommand(0xC1); this->writeData(0xC5); + this->writeCommand(0xC2); + this->writeData(0x0A); this->writeData(0x00); + this->writeCommand(0xC3); + this->writeData(0x8A); this->writeData(0x2A); + this->writeCommand(0xC4); + this->writeData(0x8A); this->writeData(0xEE); + + this->writeCommand(0xC5); + this->writeData(0x0E); + + this->writeCommand(0x36); + this->writeData(0xA8); + + this->writeCommand(0xe0); + this->writeData(0x0f); this->writeData(0x1a); + this->writeData(0x0f); this->writeData(0x18); + this->writeData(0x2f); this->writeData(0x28); + this->writeData(0x20); this->writeData(0x22); + this->writeData(0x1f); this->writeData(0x1b); + this->writeData(0x23); this->writeData(0x37); this->writeData(0x00); + this->writeData(0x07); + this->writeData(0x02); this->writeData(0x10); + + this->writeCommand(0xe1); + this->writeData(0x0f); this->writeData(0x1b); + this->writeData(0x0f); this->writeData(0x17); + this->writeData(0x33); this->writeData(0x2c); + this->writeData(0x29); this->writeData(0x2e); + this->writeData(0x30); this->writeData(0x30); + this->writeData(0x39); this->writeData(0x3f); + this->writeData(0x00); this->writeData(0x07); + this->writeData(0x03); this->writeData(0x10); + + this->writeCommand(0x2a); + this->writeData(0x00); this->writeData(0x00); + this->writeData(0x00); this->writeData(0x7f); + this->writeCommand(0x2b); + this->writeData(0x00); this->writeData(0x00); + this->writeData(0x00); this->writeData(0x9f); + + this->writeCommand(0xF0); + this->writeData(0x01); + this->writeCommand(0xF6); + this->writeData(0x00); + + this->writeCommand(0x3A); + this->writeData(0x05); + + this->writeCommand(0x29); + + this->clear(); +} + +void DisplayN18::setClippingArea(unsigned char x, unsigned char y, unsigned char width, unsigned char height) { + unsigned char data[4] = { 0x00, 0x00, 0x00, 0x00 }; + + data[1] = x; + data[3] = x + width; + this->writeCommand(0x2A); + this->writeData(data, 4); + + data[1] = y; + data[3] = y + height; + this->writeCommand(0x2B); + this->writeData(data, 4); +} + +unsigned short DisplayN18::rgbToShort(unsigned char r, unsigned char g, unsigned char b) { + unsigned short red = r; + unsigned short green = g; + unsigned short blue = b; + + red /= 8; + green /= 4; + blue /= 8; + + red &= 0x1F; + green &= 0x3F; + blue &= 0x1F; + + red <<= 3; + blue <<= 8; + green = ((green & 0x7) << 13) + ((green & 0x38) >> 3); + + return red | green | blue; +} + +void DisplayN18::clear(unsigned short backColor) { + for (unsigned int i = 0; i < DisplayN18::WIDTH; i += 10) + for (unsigned int j = 0; j < DisplayN18::HEIGHT; j += 8) + this->fillRect(i, j, 10, 8, backColor); +} + +void DisplayN18::draw(const unsigned short* data, int x, int y, int width, int height) { + this->setClippingArea(x, y, width - 1, height - 1); + this->writeCommand(0x2C); + this->writeData(reinterpret_cast<const unsigned char*>(data), width * height * 2); +} + +void DisplayN18::setPixel(int x, int y, unsigned short foreColor) { + this->draw(&foreColor, x, y, 1, 1); +} + +void DisplayN18::fillRect(int x, int y, int width, int height, unsigned short foreColor) { + this->setClippingArea(static_cast<unsigned char>(x), static_cast<unsigned char>(y), static_cast<unsigned char>(width - 1), static_cast<unsigned char>(height)); + + this->writeCommand(0x2C); + + unsigned short buffer[50]; + for (int j = 0; j < sizeof(buffer) / 2; j++) + buffer[j] = foreColor; + + this->rsPin.write(true); + + int i; + for (i = sizeof(buffer); i < height * width * 2; i += sizeof(buffer)) + this->writeData(reinterpret_cast<unsigned char*>(buffer), sizeof(buffer)); + + i -= sizeof(buffer); + if (i != height * width * 2) + this->writeData(reinterpret_cast<unsigned char*>(buffer), height * width * 2 - i); +} + +void DisplayN18::drawRect(int x, int y, int width, int height, unsigned short foreColor) { + this->drawLine(x, y, x + width, y, foreColor); + this->drawLine(x, y + height, x + width, y + height, foreColor); + this->drawLine(x, y, x, y + height, foreColor); + this->drawLine(x + width, y, x + width, y + height, foreColor); +} + +void DisplayN18::fillCircle(int x, int y, int radius, unsigned short foreColor) { + int f = 1 - radius; + int dd_f_x = 1; + int dd_f_y = -2 * radius; + int x1 = 0; + int y1 = radius; + + for (int i = y - radius; i <= y + radius; i++) + this->setPixel(x, i, foreColor); + + while (x1 < y1) { + if (f >= 0) { + y1--; + dd_f_y += 2; + f += dd_f_y; + } + + x1++; + dd_f_x += 2; + f += dd_f_x; + + for (int i = y - y1; i <= y + y1; i++) { + this->setPixel(x + x1, i, foreColor); + this->setPixel(x - x1, i, foreColor); + } + + for (int i = y - x1; i <= y + x1; i++) { + this->setPixel(x + y1, i, foreColor); + this->setPixel(x - y1, i, foreColor); + } + } +} + +void DisplayN18::drawCircle(int x, int y, int radius, unsigned short foreColor) { + int f = 1 - radius; + int dd_f_x = 1; + int dd_f_y = -2 * radius; + int x1 = 0; + int y1 = radius; + + this->setPixel(x, y + radius, foreColor); + this->setPixel(x, y - radius, foreColor); + this->setPixel(x + radius, y, foreColor); + this->setPixel(x - radius, y, foreColor); + + while (x1 < y1) { + if (f >= 0) { + y1--; + dd_f_y += 2; + f += dd_f_y; + } + + x1++; + dd_f_x += 2; + f += dd_f_x; + + this->setPixel(x + x1, y + y1, foreColor); + this->setPixel(x - x1, y + y1, foreColor); + this->setPixel(x + x1, y - y1, foreColor); + this->setPixel(x - x1, y - y1, foreColor); + + this->setPixel(x + y1, y + x1, foreColor); + this->setPixel(x - y1, y + x1, foreColor); + this->setPixel(x + y1, y - x1, foreColor); + this->setPixel(x - y1, y - x1, foreColor); + } +} + +void DisplayN18::drawLine(int x0, int y0, int x1, int y1, unsigned short foreColor) { + if (x0 == x1) { + if (y1 < y0) { + int temp = y0; + y0 = y1; + y1 = temp; + } + + this->setClippingArea(static_cast<unsigned char>(x0), static_cast<unsigned char>(y0), 0, static_cast<unsigned char>(y1 - y0 - 1)); + this->writeCommand(0x2C); + + unsigned short data[DisplayN18::STEP]; + for (int i = 0; i < DisplayN18::STEP; i++) + data[i] = foreColor; + + for (unsigned char thisY = y0; thisY < y1; thisY += DisplayN18::STEP) + this->writeData(reinterpret_cast<unsigned char*>(data), (thisY + DisplayN18::STEP <= y1 ? DisplayN18::STEP : y1 - thisY) * 2); + + return; + } + + if (y0 == y1) { + if (x1 < x0) { + int temp = x0; + x0 = x1; + x1 = temp; + } + + this->setClippingArea(static_cast<unsigned char>(x0), static_cast<unsigned char>(y0), static_cast<unsigned char>(x1 - x0 - 1), 0); + this->writeCommand(0x2C); + + unsigned short data[DisplayN18::STEP]; + for (int i = 0; i < DisplayN18::STEP; i++) + data[i] = foreColor; + + for (unsigned char thisX = x0; thisX < x1; thisX += DisplayN18::STEP) + this->writeData(reinterpret_cast<unsigned char*>(data), (thisX + DisplayN18::STEP <= x1 ? DisplayN18::STEP : x1 - thisX) * 2); + + return; + } + + int t; + bool steep = ((y1 - y0) < 0 ? -(y1 - y0) : (y1 - y0)) > ((x1 - x0) < 0 ? -(x1 - x0) : (x1 - x0)); + + if (steep) { + t = x0; + x0 = y0; + y0 = t; + t = x1; + x1 = y1; + y1 = t; + } + + if (x0 > x1) { + t = x0; + x0 = x1; + x1 = t; + + t = y0; + y0 = y1; + y1 = t; + } + + int dx, dy; + dx = x1 - x0; + dy = (y1 - y0) < 0 ? -(y1 - y0) : (y1 - y0); + + int err = (dx / 2); + int ystep; + + ystep = y0 < y1 ? 1 : -1; + + for (; x0 < x1; x0++) { + if (steep) + this->setPixel(y0, x0, foreColor); + else + this->setPixel(x0, y0, foreColor); + + err -= dy; + + if (err < 0) { + y0 += (char)ystep; + err += dx; + } + } +} + +unsigned char characters[95 * 5] = { + 0x00, 0x00, 0x00, 0x00, 0x00, /* Space 0x20 */ + 0x00, 0x00, 0x4f, 0x00, 0x00, /* ! */ + 0x00, 0x07, 0x00, 0x07, 0x00, /* " */ + 0x14, 0x7f, 0x14, 0x7f, 0x14, /* # */ + 0x24, 0x2a, 0x7f, 0x2a, 0x12, /* $ */ + 0x23, 0x13, 0x08, 0x64, 0x62, /* % */ + 0x36, 0x49, 0x55, 0x22, 0x20, /* & */ + 0x00, 0x05, 0x03, 0x00, 0x00, /* ' */ + 0x00, 0x1c, 0x22, 0x41, 0x00, /* ( */ + 0x00, 0x41, 0x22, 0x1c, 0x00, /* ) */ + 0x14, 0x08, 0x3e, 0x08, 0x14, /* // */ + 0x08, 0x08, 0x3e, 0x08, 0x08, /* + */ + 0x50, 0x30, 0x00, 0x00, 0x00, /* , */ + 0x08, 0x08, 0x08, 0x08, 0x08, /* - */ + 0x00, 0x60, 0x60, 0x00, 0x00, /* . */ + 0x20, 0x10, 0x08, 0x04, 0x02, /* / */ + 0x3e, 0x51, 0x49, 0x45, 0x3e, /* 0 0x30 */ + 0x00, 0x42, 0x7f, 0x40, 0x00, /* 1 */ + 0x42, 0x61, 0x51, 0x49, 0x46, /* 2 */ + 0x21, 0x41, 0x45, 0x4b, 0x31, /* 3 */ + 0x18, 0x14, 0x12, 0x7f, 0x10, /* 4 */ + 0x27, 0x45, 0x45, 0x45, 0x39, /* 5 */ + 0x3c, 0x4a, 0x49, 0x49, 0x30, /* 6 */ + 0x01, 0x71, 0x09, 0x05, 0x03, /* 7 */ + 0x36, 0x49, 0x49, 0x49, 0x36, /* 8 */ + 0x06, 0x49, 0x49, 0x29, 0x1e, /* 9 */ + 0x00, 0x36, 0x36, 0x00, 0x00, /* : */ + 0x00, 0x56, 0x36, 0x00, 0x00, /* ; */ + 0x08, 0x14, 0x22, 0x41, 0x00, /* < */ + 0x14, 0x14, 0x14, 0x14, 0x14, /* = */ + 0x00, 0x41, 0x22, 0x14, 0x08, /* > */ + 0x02, 0x01, 0x51, 0x09, 0x06, /* ? */ + 0x3e, 0x41, 0x5d, 0x55, 0x1e, /* @ 0x40 */ + 0x7e, 0x11, 0x11, 0x11, 0x7e, /* A */ + 0x7f, 0x49, 0x49, 0x49, 0x36, /* B */ + 0x3e, 0x41, 0x41, 0x41, 0x22, /* C */ + 0x7f, 0x41, 0x41, 0x22, 0x1c, /* D */ + 0x7f, 0x49, 0x49, 0x49, 0x41, /* E */ + 0x7f, 0x09, 0x09, 0x09, 0x01, /* F */ + 0x3e, 0x41, 0x49, 0x49, 0x7a, /* G */ + 0x7f, 0x08, 0x08, 0x08, 0x7f, /* H */ + 0x00, 0x41, 0x7f, 0x41, 0x00, /* I */ + 0x20, 0x40, 0x41, 0x3f, 0x01, /* J */ + 0x7f, 0x08, 0x14, 0x22, 0x41, /* K */ + 0x7f, 0x40, 0x40, 0x40, 0x40, /* L */ + 0x7f, 0x02, 0x0c, 0x02, 0x7f, /* M */ + 0x7f, 0x04, 0x08, 0x10, 0x7f, /* N */ + 0x3e, 0x41, 0x41, 0x41, 0x3e, /* O */ + 0x7f, 0x09, 0x09, 0x09, 0x06, /* P 0x50 */ + 0x3e, 0x41, 0x51, 0x21, 0x5e, /* Q */ + 0x7f, 0x09, 0x19, 0x29, 0x46, /* R */ + 0x26, 0x49, 0x49, 0x49, 0x32, /* S */ + 0x01, 0x01, 0x7f, 0x01, 0x01, /* T */ + 0x3f, 0x40, 0x40, 0x40, 0x3f, /* U */ + 0x1f, 0x20, 0x40, 0x20, 0x1f, /* V */ + 0x3f, 0x40, 0x38, 0x40, 0x3f, /* W */ + 0x63, 0x14, 0x08, 0x14, 0x63, /* X */ + 0x07, 0x08, 0x70, 0x08, 0x07, /* Y */ + 0x61, 0x51, 0x49, 0x45, 0x43, /* Z */ + 0x00, 0x7f, 0x41, 0x41, 0x00, /* [ */ + 0x02, 0x04, 0x08, 0x10, 0x20, /* \ */ + 0x00, 0x41, 0x41, 0x7f, 0x00, /* ] */ + 0x04, 0x02, 0x01, 0x02, 0x04, /* ^ */ + 0x40, 0x40, 0x40, 0x40, 0x40, /* _ */ + 0x00, 0x00, 0x03, 0x05, 0x00, /* ` 0x60 */ + 0x20, 0x54, 0x54, 0x54, 0x78, /* a */ + 0x7F, 0x44, 0x44, 0x44, 0x38, /* b */ + 0x38, 0x44, 0x44, 0x44, 0x44, /* c */ + 0x38, 0x44, 0x44, 0x44, 0x7f, /* d */ + 0x38, 0x54, 0x54, 0x54, 0x18, /* e */ + 0x04, 0x04, 0x7e, 0x05, 0x05, /* f */ + 0x08, 0x54, 0x54, 0x54, 0x3c, /* g */ + 0x7f, 0x08, 0x04, 0x04, 0x78, /* h */ + 0x00, 0x44, 0x7d, 0x40, 0x00, /* i */ + 0x20, 0x40, 0x44, 0x3d, 0x00, /* j */ + 0x7f, 0x10, 0x28, 0x44, 0x00, /* k */ + 0x00, 0x41, 0x7f, 0x40, 0x00, /* l */ + 0x7c, 0x04, 0x7c, 0x04, 0x78, /* m */ + 0x7c, 0x08, 0x04, 0x04, 0x78, /* n */ + 0x38, 0x44, 0x44, 0x44, 0x38, /* o */ + 0x7c, 0x14, 0x14, 0x14, 0x08, /* p 0x70 */ + 0x08, 0x14, 0x14, 0x14, 0x7c, /* q */ + 0x7c, 0x08, 0x04, 0x04, 0x00, /* r */ + 0x48, 0x54, 0x54, 0x54, 0x24, /* s */ + 0x04, 0x04, 0x3f, 0x44, 0x44, /* t */ + 0x3c, 0x40, 0x40, 0x20, 0x7c, /* u */ + 0x1c, 0x20, 0x40, 0x20, 0x1c, /* v */ + 0x3c, 0x40, 0x30, 0x40, 0x3c, /* w */ + 0x44, 0x28, 0x10, 0x28, 0x44, /* x */ + 0x0c, 0x50, 0x50, 0x50, 0x3c, /* y */ + 0x44, 0x64, 0x54, 0x4c, 0x44, /* z */ + 0x08, 0x36, 0x41, 0x41, 0x00, /* { */ + 0x00, 0x00, 0x77, 0x00, 0x00, /* | */ + 0x00, 0x41, 0x41, 0x36, 0x08, /* } */ + 0x08, 0x08, 0x2a, 0x1c, 0x08 /* ~ */ +}; + +void DisplayN18::drawCharacter(int x, int y, const char character, unsigned short foreColor, unsigned short backColor, unsigned char fontSize) { + if (character > 126 || character < 32) + return; + + unsigned short* horizontal = new unsigned short[DisplayN18::CHAR_HEIGHT * fontSize]; + for (int i = 0; i < DisplayN18::CHAR_WIDTH; i++) { + for (int j = 0; j < DisplayN18::CHAR_HEIGHT; j++) + for (int k = 0; k < fontSize; k++) + horizontal[j * fontSize + k] = characters[(character - 32) * 5 + i] & (1 << j) ? foreColor : backColor; + + for (int k = 0; k < fontSize; k++) + this->draw(horizontal, x + i * fontSize + k, y, 1, DisplayN18::CHAR_HEIGHT * fontSize); + } + + for (int i = 0; i < DisplayN18::CHAR_HEIGHT; i++) + for (int k = 0; k < fontSize; k++) + horizontal[i * fontSize + k] = backColor; + + for (int k = 0; k < fontSize; k++) + this->draw(horizontal, x + DisplayN18::CHAR_WIDTH * fontSize + k, y, 1, DisplayN18::CHAR_HEIGHT * fontSize); + + delete[] horizontal; +} + +void DisplayN18::drawString(int x, int y, const char* str, unsigned short foreColor, unsigned short backColor, unsigned char fontSize) { + if (*str == '\0') + return; + + do { + this->drawCharacter(x, y, *str, foreColor, backColor, fontSize); + + x += (DisplayN18::CHAR_WIDTH + DisplayN18::CHAR_SPACING) * fontSize; + } while (*(++str) != '\0'); +} \ No newline at end of file
diff -r 7260a2716edf -r 600980390cf7 DisplayN18.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DisplayN18.h Sun Mar 01 11:18:52 2015 +0000 @@ -0,0 +1,53 @@ +#include "mbed.h" + +#pragma once + +class DisplayN18 { + static const unsigned char STEP = 4; + + DigitalOut resetPin; + DigitalOut backlightPin; + DigitalOut rsPin; + DigitalOut csPin; + SPI spi; + + void writeCommand(unsigned char command); + void writeData(unsigned char data); + void writeData(const unsigned char* data, unsigned int length); + + void reset(); + void initialize(); + void setClippingArea(unsigned char x, unsigned char y, unsigned char width, unsigned char height); + + public: + DisplayN18(); + + static const unsigned short BLUE = 0x00F8; + static const unsigned short GREEN = 0xE007; + static const unsigned short RED = 0x1F00; + static const unsigned short WHITE = 0xFFFF; + static const unsigned short BLACK = 0x0000; + + static const unsigned int WIDTH = 160; + static const unsigned int HEIGHT = 128; + static const unsigned char CHAR_WIDTH = 5; + static const unsigned char CHAR_HEIGHT = 8; + static const unsigned char CHAR_SPACING = 1; + + static unsigned short rgbToShort(unsigned char r, unsigned char g, unsigned char b); + + void clear(unsigned short backColor = 0x0000); + void draw(const unsigned short* data, int x, int y, int width, int height); + void setPixel(int x, int y, unsigned short foreColor); + + void fillRect(int x, int y, int width, int height, unsigned short foreColor); + void drawRect(int x, int y, int width, int height, unsigned short foreColor); + + void fillCircle(int x, int y, int radius, unsigned short foreColor); + void drawCircle(int x, int y, int radius, unsigned short foreColor); + + void drawLine(int x0, int y0, int x1, int y1, unsigned short foreColor); + + void drawCharacter(int x, int y, const char character, unsigned short foreColor, unsigned short backColor, unsigned char fontSize = 1); + void drawString(int x, int y, const char* str, unsigned short foreColor, unsigned short backColor, unsigned char fontSize = 1); +}; \ No newline at end of file
diff -r 7260a2716edf -r 600980390cf7 LCD_ST7735.lib --- a/LCD_ST7735.lib Tue Jan 13 01:52:04 2015 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -http://mbed.org/users/taylorza/code/LCD_ST7735/#7ecd74dcb8ef
diff -r 7260a2716edf -r 600980390cf7 MMA8453.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA8453.lib Sun Mar 01 11:18:52 2015 +0000 @@ -0,0 +1,1 @@ +http://developer.mbed.org/users/gbr1mbed/code/MMA8453/#78ba7ed0699c
diff -r 7260a2716edf -r 600980390cf7 main.cpp --- a/main.cpp Tue Jan 13 01:52:04 2015 +0000 +++ b/main.cpp Sun Mar 01 11:18:52 2015 +0000 @@ -1,50 +1,514 @@ +/* + * SHAKE THE MAZE!!! + * + * Author: BRUNO Giovanni di Dio [ aka GBr1 ] + * site: www.gbr1industries.altervista.org + * + * video: http://youtu.be/puCMuQ1Li1I + * + * + * + * HOW TO PLAY: + * 1. You need only the RETRO board by Outrageous Circuit + * 2. After loaded the file (I use "cp" command in mac osx terminal ) + * Note: file .bin is about 32KB I don't try if Windows drag and drop works well :( + * 3. Reset + * 4. Left LED is turned on + * 5. Shake the board + * 6. Press start button (alien spaceship button) + * 7. Left LED is turned off + * 8. Wait beep end + * 9. Move the board to put green ball into red square (finish) + * 10. When you finish Right LED is turned on + * 11. Press start to play again + * 12. Right LED is turned off + * 13. You have a new maze to solve (go to 8) + * + * + * NOTE: don't update to a newer version + */ + + + + + + #include "mbed.h" -#include "Color565.h" -#include "font_IBM.h" -#include "LCD_ST7735.h" +//RETRO board display +#include "DisplayN18.h" +//C++ standard stack class +#include <stack> +//RETRO board accelerometer +#include "MMA8453.h" + +//accelerometer +MMA8453 acc(P0_5,P0_4); +//x axis +double xx=0; +//y axis +double yy=0; +//z axis (it will be used in initRand()) +double zz=0; + +//Alien Spaceship button +DigitalIn start(P0_1,PullUp); +//Left LED -> capturing accelerometer data to random seed +DigitalOut ledL(P0_9); +//Right LED -> Do you want to play? +DigitalOut ledR(P0_8); +//Buzzer (due low program memory I use software PWM) +DigitalOut buzzer(P0_18); + +//numbers for random function +unsigned int m_z=0; +unsigned int m_w=0; + +//display object +DisplayN18 Surface; +//colors used +static const unsigned short CLINE = DisplayN18::BLUE; //blue +static const unsigned short CBALL = DisplayN18::GREEN; //green +static const unsigned short CEND = DisplayN18::RED; //red +static const unsigned short CBACK = DisplayN18::BLACK; //black +static const unsigned short CTEXT1 = 0xF81F; //yellow +static const unsigned short CTEXT2 = 0xFFE0; //violet +static const unsigned short CTEXT3 = 0xFFFF; //white + +//constants to indicate cardinal coordinates +//I used 0 to 3 because I will do random from 0 to 3 +const int NORTH=0; +const int SOUTH=1; +const int EAST=2; +const int WEST=3; +//maze blocks size +const int SIZEX=32; +const int SIZEY=23; + +//create maze variables +int nGood = 0; +int locX = 1, locY = 1; + +//ball and generally print coordinates +int x=0; +int y=0; + + +/*my function to explore maze and generate random values*/ +//pseudo-random function +//on lpc11u24 random doesn't work (it equals rand() ) +unsigned int rnd(); + +//random seed & initial window (it equals srand and a simple text show function) +void initRand(); + +//estabilish on which type of pattern you are +//you have to remember that in this case N=1 S=2 E=4 W=8 it allows you to have unique combinations +int evaluateCell(int i, int j,bool grid[SIZEY][SIZEX]); + +//redraw ball and check if there are collisions +void updateBall(int direction, bool grid[SIZEY][SIZEX]); + +//draw the maze +void printGrid(bool grid[SIZEY][SIZEX]); + + +/*maze creation functions*/ +//I used recoursive backtracker http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_backtracker -static const uint16_t bmp[] = { - 0x20, 0x10, - 0x0000, 0x0000, 0x1081, 0x41e4, 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, 0x41e4, 0x1081, 0x0000, 0x0000, 0x0000, 0x0000, 0x1081, 0x4204, 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x4204, 0x1081, 0x0000, 0x0000, - 0x0000, 0x1081, 0x5285, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5285, 0x1081, 0x0000, 0x0000, 0x1081, 0x5a85, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x1081, 0x0000, - 0x1081, 0x5285, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5285, 0x1081, 0x1081, 0x5a85, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x1081, - 0x41e4, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x41e4, 0x4204, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x4204, - 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, 0x83a8, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x4204, 0x5aa5, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x0000, 0x1081, 0x4204, 0x62c5, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x0000, 0x0000, 0x0000, 0x1081, 0x4204, 0x5aa5, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x1081, 0x5244, 0x5aa5, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x0000, 0x1081, 0x4204, 0x4204, 0x6b06, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x0000, 0x4204, 0x5a85, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, - 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, 0x83a8, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, - 0x41e4, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x41e4, 0x4204, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x4204, - 0x1081, 0x5285, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5285, 0x1081, 0x1081, 0x5a85, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x1081, - 0x0000, 0x1081, 0x5285, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5285, 0x1081, 0x0000, 0x0000, 0x1081, 0x5a85, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x1081, 0x0000, - 0x0000, 0x0000, 0x1081, 0x41e4, 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x7b87, 0x41e4, 0x1081, 0x0000, 0x0000, 0x0000, 0x0000, 0x1081, 0x4204, 0x7b87, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0xff2f, 0x5a85, 0x1081, 0x0000, 0x0000, -}; +//move on x axis +int moveEW(int direction, int i); +//move on y axis +int moveNS(int direction, int j); +//check if it can go here +bool isGood(int i, int j, int direction, bool grid[SIZEY][SIZEX]); +//create maze +void createMaze(bool grid[SIZEY][SIZEX]); +//draw finish pattern and mark it on the maze and check also if it will be possible to go there +void checkEnd(bool grid[SIZEY][SIZEX]); + + +/*---game functions---*/ + +//simple beep +void sound(); +//initialize game +void initGame(bool grid[SIZEY][SIZEX]); +//function which allows you to play +void coreGame(bool grid[SIZEY][SIZEX]); + + +/*---main---*/ +int main(){ + //create grid + //using recoursive function is better if grid is here + bool grid[SIZEY][SIZEX]; + + //initialize random (first screen) + initRand(); + //initialize game (second screen - play) + initGame(grid); + //play ;) + while(1){ + coreGame(grid); + } +} + + + + +/*---implementations---*/ + +unsigned int rnd(){ + //pseudo-random function + m_z = 36969 * (m_z & 65535) + (m_z >>16); + m_w = 18000 * (m_w & 65535) + (m_w >>16); + return ((m_z <<16) + m_w); +} + +void initRand(){ + //preserve for pressing button before the game + while(start==0); + //show initial screen + ledL=1; + Surface.clear(); + Surface.drawString(16,30,"Shake it!!!",CTEXT1,CBACK,2); + Surface.drawString(32,90,"press start",CTEXT2,CBACK); + Surface.drawString(48,100,"to continue...",CTEXT2,CBACK); + //wait for checking alien spaceship button + while(start==1){ + //simple function to read values and sum them + //NOTE: you need to do abs because accelerometer values could be negative + acc.getXYZ(xx,yy,zz); + xx=abs(xx)*200; + yy=abs(yy)*200; + zz=abs(zz)*200; + m_z=m_z+xx*yy+zz; + m_w=m_w+xx+yy*zz; + } + ledL=0; +} + + + +int evaluateCell(int i, int j,bool grid[SIZEY][SIZEX]){ + int cell=0; + //estabilish type of pattern (just sum values of walls + if ((i>=0)&&(i<(SIZEX-1))){ + if (grid[j][i+1]==true) { + cell+=4; + } + } + if ((i>0)&&(i<=(SIZEX-1))){ + if (grid[j][i-1]==true) { + cell+=8; + } + } + if ((j>=0)&&(j<(SIZEY-1))){ + if (grid[j+1][i]==true) { + cell+=2; + } + } + if ((j>0)&&(j<=(SIZEY-1))){ + if (grid[j-1][i]==true) { + cell+=1; + } + } + return cell; +} + +void updateBall(int direction, bool grid[SIZEY][SIZEX]){ + //clear old ball + Surface.fillCircle(x+2,y+15,2,CBACK); + //check if is possible to move ball in "direction" + //it checks every situation + int cell=evaluateCell(x/5,y/5,grid); + if ((direction==NORTH)&&((cell%2)==0)){ + y=y-5; + } + if ((direction==SOUTH)&&((cell==0)||(cell==1)||(cell==4)||(cell==5)||(cell==8)||(cell==9)||(cell==12)||(cell==13))){ + y=y+5; + } + if ((direction==EAST)&&((cell==0)||(cell==1)||(cell==2)||(cell==3)||(cell==8)||(cell==9)||(cell==10)||(cell==11))){ + x=x+5; + } + if ((direction==WEST)&&((cell>=0)&&(cell<=7))){ + x=x-5; + } + //draw ball + Surface.fillCircle(x+2,y+15,2,CBALL); +} + -LCD_ST7735 Surface( - P0_19, - P0_20, - P0_7, - P0_21, - P0_22, - P1_15, - P0_2, - LCD_ST7735::RGB); +void printGrid(bool grid[SIZEY][SIZEX]){ + Surface.clear(); + Surface.drawString(2,2,"Shake the Maze!!! GBr1_15",CTEXT3,CBACK); + int cell=0; + for (int j = 0; j < SIZEY; j++){ + for(int i = 0; i < SIZEX; i++){ + cell=0; + if (grid[j][i]==true) { + cell=evaluateCell(i,j,grid); + //offset and 5pixels maze block + x=i*5; + y=(j*5)+13; + //show 16 different cases of maze patterns + //using N=1 E=4 S=2 W=8 -> do combination + //example 11 is + // + // OXO + // XXO + // OXO + //where O is free pattern X is a wall + + switch (cell) { + case 0: + Surface.setPixel(x+2,y+2,CLINE); + break; + case 1: + Surface.drawLine(x+2,y,x+2,y+3,CLINE); + break; + case 2: + Surface.drawLine(x+2,y+2,x+2,y+5,CLINE); + break; + case 3: + Surface.drawLine(x+2,y,x+2,y+5,CLINE); + break; + case 4: + Surface.drawLine(x+2,y+2,x+5,y+2,CLINE); + break; + case 5: + Surface.drawLine(x+2,y,x+2,y+3,CLINE); + Surface.drawLine(x+3,y+2,x+5,y+2,CLINE); + break; + case 6: + Surface.drawLine(x+2,y+2,x+5,y+2,CLINE); + Surface.drawLine(x+2,y+3,x+2,y+5,CLINE); + break; + case 7: + Surface.drawLine(x+2,y,x+2,y+5,CLINE); + Surface.drawLine(x+3,y+2,x+5,y+2,CLINE); + break; + case 8: + Surface.drawLine(x,y+2,x+3,y+2,CLINE); + break; + case 9: + Surface.drawLine(x+2,y,x+2,y+3,CLINE); + Surface.drawLine(x,y+2,x+2,y+2,CLINE); + break; + case 10: + Surface.drawLine(x+2,y+2,x+2,y+5,CLINE); + Surface.drawLine(x,y+2,x+2,y+2,CLINE); + break; + case 11: + Surface.drawLine(x+2,y,x+2,y+5,CLINE); + Surface.drawLine(x,y+2,x+2,y+2,CLINE); + break; + case 12: + Surface.drawLine(x,y+2,x+5,y+2,CLINE); + break; + case 13: + Surface.drawLine(x+2,y,x+2,y+2,CLINE); + Surface.drawLine(x,y+2,x+5,y+2,CLINE); + break; + case 14: + Surface.drawLine(x+2,y+3,x+2,y+5,CLINE); + Surface.drawLine(x,y+2,x+5,y+2,CLINE); + break; + case 15: + Surface.drawLine(x+2,y,x+2,y+5,CLINE); + Surface.drawLine(x,y+2,x+5,y+2,CLINE); + break; + } + } + } + } +} + + +int moveEW(int direction, int i){ + if (direction == EAST) + return i + 1; + else if (direction == WEST) + return i - 1; + else + return i; +} + +int moveNS(int direction, int j){ + if (direction == NORTH) + return j - 1; + else if (direction == SOUTH) + return j + 1; + else + return j; +} + +bool isGood(int i, int j, int direction, bool grid[SIZEY][SIZEX]){ + i = moveEW(direction,i); + j = moveNS(direction,j); + //check if it should be the end + if ((grid[j][i]==false)||(i>=(SIZEX - 1))||(i<=0)||(j<= 0)||(j>=(SIZEY - 1))){ + return false; + } + //check cardinal directions + if (direction == NORTH){ + if ((grid[j][i-1]!=false)&&(grid[j-1][i]!=false)&&(grid[j][i+1]!=false)&&(grid[j-1][i-1]!=false)&&(grid[j-1][i+1]!=false)){ + return true; + } + } + if (direction == SOUTH){ + if ((grid[j][i-1]!=false)&&(grid[j+1][i]!=false)&&(grid[j][i+1]!=false)&&(grid[j+1][i-1]!=false)&&(grid[j+1][i+1]!=false)){ + return true; + } + } + if (direction == EAST){ + if ((grid[j][i+1]!=false)&&(grid[j-1][i]!=false)&&(grid[j+1][i]!=false)&&(grid[j-1][i+1]!=false)&&(grid[j+1][i+1]!=false)){ + return true; + } + } + if (direction == WEST){ + if ((grid[j][i-1]!=false)&&(grid[j-1][i]!=false)&&(grid[j+1][i]!=false)&&(grid[j-1][i-1]!=false)&&(grid[j+1][i-1]!=false)){ + return true; + } + } + return false; +} -main() -{ - Surface.setOrientation(LCD_ST7735::Rotate270, false); +void createMaze(bool grid[SIZEY][SIZEX]){ + //initialize grid + for (int i = 0; i < SIZEY; i++){ + for(int j = 0; j < SIZEX; j++){ + grid[i][j] = true; + } + } + //initialize stacks for xy coordinates + stack<int> xValues; + stack<int> yValues; + + nGood = 0; + int direction = 0; - Surface.setForegroundColor(Color565::White); - Surface.setBackgroundColor(Color565::Blue); - Surface.drawString(font_ibm, 48, 0, "LCD Demo"); + do{ + //find n good moves + for (int i = 0; i < 4; i++){ + if (isGood(locX,locY,i,grid)) + nGood++; + } + // if only 1 good move, move there + if (nGood == 1){ + if (isGood(locX,locY,NORTH,grid)) + locY = moveNS(NORTH,locY); + else if (isGood(locX,locY,SOUTH,grid)) + locY = moveNS(SOUTH,locY); + else if (isGood(locX,locY,EAST,grid)) + locX = moveEW(EAST,locX); + else if (isGood(locX,locY,WEST,grid)) + locX = moveEW(WEST,locX); + } + // if no good moves, move back in stack + else if (nGood == 0){ + locX = xValues.top(); + locY = yValues.top(); + xValues.pop(); + yValues.pop(); + } + //if more than 1 good move, push stack + else if (nGood > 1){ + xValues.push(locX); + yValues.push(locY); + //direction to move randomly chosen + do{ + direction = rnd()%4; + }while (!isGood(locX,locY,direction,grid)); + + locX = moveEW(direction,locX); + locY = moveNS(direction,locY); + } + //set grid + grid[locY][locX] = false; + //reset nGood value + nGood = 0; + }while(!xValues.empty()); +} + +void checkEnd(bool grid[SIZEY][SIZEX]){ + //check low right angle + if (grid[SIZEY-2][SIZEX-2]==true){ + grid[SIZEY-2][SIZEX-2]=false; + } + + int k=1; - while (true) { - Surface.drawBitmap(72, 56, bmp, 0, 0, 16, 16); - wait_ms(150); - Surface.drawBitmap(72, 56, bmp, 16, 0, 16, 16); - wait_ms(150); - } + while(((grid[SIZEY-3][SIZEX-2]==false)&&(grid[SIZEY-2][SIZEX-2-k]==false))&&(k<SIZEX-3)){ + grid[SIZEY-2][SIZEX-2-k]=false; + Surface.fillRect((SIZEX-2-k)*5,(SIZEY-2)*5+13,5,5,CBACK); + k++; + } + + if(k>=SIZEX-3){ + initGame(grid); + } + + //draw finish square + Surface.fillRect((SIZEX-2)*5,(SIZEY-2)*5+13,5,5,CEND); +} + +void sound(){ + //simulate pwm + for(int i=0; i<1000; i++){ + buzzer=1; + wait(0.0005); + buzzer=0; + } +} + +void initGame(bool grid[SIZEY][SIZEX]){ + createMaze(grid); + printGrid(grid); + checkEnd(grid); //it is for checking the possible maze finish (low right angle) + x=5; + y=5; + Surface.fillCircle(x+2,y+15,2,CBALL); + sound(); } + +void coreGame(bool grid[SIZEY][SIZEX]){ + //read x and y on accelerometer + xx=acc.getX(); + yy=acc.getY(); + //increase accelerometer value (generally 0.xx and standard value 0.5G and not G); + xx=2*xx*10; + yy=2*yy*10; + //conditions and relative next move + //I put 2 as filter value so, if you leave you RETRO on a table ball will not move + if(xx<-2){ + updateBall(WEST,grid); + } + else{ + if(xx>2){ + updateBall(EAST,grid); + } + } + if(yy>2){ + updateBall(SOUTH,grid); + } + else{ + if(yy<-2){ + updateBall(NORTH,grid); + } + } + //check if the ball is at the end of the pattern (low right angle) + if ((x/5==(SIZEX-2))&&(y/5==SIZEY-2)){ + ledR=1; + sound(); + //wait for start button + while(start==1); + //init game + initGame(grid); + ledR=0; + } +} + + + + \ No newline at end of file