/* * Aurora: https://github.com/pixelmatix/aurora * Copyright (c) 2014 Jason Coon * * Many thanks to Jamis Buck for the documentation of the Growing Tree maze generation algorithm: http://weblog.jamisbuck.org/2011/1/27/maze-generation-growing-tree-algorithm * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef PatternMaze_H #define PatternMaze_H class PatternMaze : public Drawable { private: enum Directions { None = 0, Up = 1, Down = 2, Left = 4, Right = 8, }; struct Point{ int x; int y; static Point New(int x, int y) { Point point; point.x = x; point.y = y; return point; } Point Move(Directions direction) { switch (direction) { case Up: return New(x, y - 1); case Down: return New(x, y + 1); case Left: return New(x - 1, y); case Right: default: return New(x + 1, y); } } static Directions Opposite(Directions direction) { switch (direction) { case Up: return Down; case Down: return Up; case Left: return Right; case Right: default: return Left; } } }; // int width = 16; // int height = 16; static const int width = MATRIX_WIDTH / 2; static const int height = MATRIX_HEIGHT / 2; Directions grid[width][height]; Point point; Point cells[256]; int cellCount = 0; int algorithm = 0; int algorithmCount = 1; byte hue = 0; byte hueOffset = 0; Directions directions[4] = { Up, Down, Left, Right }; void removeCell(int index) {// shift cells after index down one for (int i = index; i < cellCount - 1; i++) { cells[i] = cells[i + 1]; } cellCount--; } void shuffleDirections() { for (int a = 0; a < 4; a++) { int r = random(a, 4); Directions temp = directions[a]; directions[a] = directions[r]; directions[r] = temp; } } Point createPoint(int x, int y) { Point point; point.x = x; point.y = y; return point; } CRGB chooseColor(int index) { byte h = index + hueOffset; switch (algorithm) { case 0: default: return effects.ColorFromCurrentPalette(h); case 1: return effects.ColorFromCurrentPalette(hue++); } } int chooseIndex(int max) { switch (algorithm) { case 0: default: // choose newest (recursive backtracker) return max - 1; case 1: // choose random(Prim's) return random(max); // case 2: // // choose oldest (not good, so disabling) // return 0; } } void generateMaze() { while (cellCount > 1) { drawNextCell(); } } void drawNextCell() { int index = chooseIndex(cellCount); if (index < 0) return; point = cells[index]; Point imagePoint = createPoint(point.x * 2, point.y * 2); //effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, CRGB(CRGB::Gray)); shuffleDirections(); CRGB color = chooseColor(index); for (int i = 0; i < 4; i++) { Directions direction = directions[i]; Point newPoint = point.Move(direction); if (newPoint.x >= 0 && newPoint.y >= 0 && newPoint.x < width && newPoint.y < height && grid[newPoint.y][newPoint.x] == None) { grid[point.y][point.x] = (Directions) ((int) grid[point.y][point.x] | (int) direction); grid[newPoint.y][newPoint.x] = (Directions) ((int) grid[newPoint.y][newPoint.x] | (int) point.Opposite(direction)); Point newImagePoint = imagePoint.Move(direction); effects.drawBackgroundFastLEDPixelCRGB(newImagePoint.x, newImagePoint.y, color); cellCount++; cells[cellCount - 1] = newPoint; index = -1; break; } } if (index > -1) { Point finishedPoint = cells[index]; imagePoint = createPoint(finishedPoint.x * 2, finishedPoint.y * 2); effects.drawBackgroundFastLEDPixelCRGB(imagePoint.x, imagePoint.y, color); removeCell(index); } } public: PatternMaze() { name = (char *)"Maze"; } unsigned int drawFrame() { if (cellCount < 1) { effects.ClearFrame(); // reset the maze grid for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { grid[y][x] = None; } } int x = random(width); int y = random(height); cells[0] = createPoint(x, y); cellCount = 1; hue = 0; hueOffset = random(0, 256); } drawNextCell(); if (cellCount < 1) { algorithm++; if (algorithm >= algorithmCount) algorithm = 0; return 1000; } effects.ShowFrame(); return 0; } void start() { matrix.fillScreen(0); cellCount = 0; hue = 0; } }; #endif