Devos — Maze
Deze puzzel, gemaakt door David, is een labyrintspel waarbij de speler een stipje moeten navigeren van de startpositie naar het eindpunt. De speler bestuurt de bewegingen van het stipje met behulp van een afstandsbediening die infrarood signalen uitzendt. De positie van het stipje wordt weergegeven op een 8x8 led matrix.
#include <ShiftRegister74HC595.h>
#include <IRremote.h>
#include <Servo.h>
// https://blog.timodenk.com/shift-register-arduino-library/
// https://learn.adafruit.com/74hc595/pinouts
// https://osoyoo.com/2017/07/15/8x8-led-matrix/
ShiftRegister74HC595<2> sr(10,13,2);
uint8_t binary[] = {
B00000001,
B00000010,
B00000100,
B00001000,
B00010000,
B00100000,
B01000000,
B10000000
};
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN);
decode_results results;
struct Vector{
int x, y;
Vector(){}
Vector(int xpos, int ypos){
x = xpos;
y = ypos;
}
};
struct HEXstring
{
long unsigned int h1;
long unsigned int h2;
Vector dir;
HEXstring(long unsigned int hex1, long unsigned int hex2, Vector direction)
{
h1 = hex1;
h2 = hex2;
dir = direction;
}
bool Compare(long unsigned int hex)
{
return hex == h1 || hex == h2;
}
};
static HEXstring upHEX = HEXstring(0x511DBB, 0xFF629D, Vector(0, 1));
static HEXstring downHEX = HEXstring(0xA3C8EDDB, 0xFFA857, Vector(0, -1));
static HEXstring leftHEX = HEXstring(0x20FE4DBB, 0xFFC23D, Vector(1, 0));
static HEXstring rightHEX = HEXstring(0x52A3D41F, 0xFF22DD, Vector(-1, 0));
static HEXstring IRhexes[4] = {upHEX, downHEX, leftHEX, rightHEX};
struct Cell{
const Vector m_pos;
bool m_allowed[4];
Cell(Vector pos, bool allowed[4])
{
m_pos = pos;
for(int i = 0; i < 4; ++i){
m_allowed[i] = allowed[i];
}
// !! up right down left !!
}
};
class Player{
Vector m_pos;
Cell ** m_mazeRef;
public:
Player(Cell* maze[64], Vector pos)
{
m_pos = pos;
m_mazeRef = maze;
}
bool move(Vector dir){
bool checkMove = false;
switch(dir.x){
case 1:
checkMove = m_mazeRef[m_pos.y*8 + m_pos.x]->m_allowed[1];
break;
case -1:
checkMove = m_mazeRef[m_pos.y*8 + m_pos.x]->m_allowed[3];
break;
}
switch(dir.y){
case 1:
checkMove = m_mazeRef[m_pos.y*8 + m_pos.x]->m_allowed[0];
break;
case -1:
checkMove = m_mazeRef[m_pos.y*8 + m_pos.x]->m_allowed[2];
break;
}
if(checkMove){
m_pos.x += dir.x;
m_pos.y -= dir.y;
}
return checkMove;
}
Vector getPos(){
return m_pos;
}
};
class EndPoint{
const Vector m_pos;
public:
EndPoint(Vector pos){
m_pos = pos;
}
Vector getPos(){
return m_pos;
}
};
class MazeGame{
Player * m_player;
EndPoint * m_endPoint = nullptr;
Cell ** m_maze;
bool m_gameActive = false;
public:
MazeGame(){}
MazeGame(Player * player, Cell * maze[64])
{
m_player = player;
m_maze = maze;
}
void StartGame(EndPoint * endPoint)
{
m_endPoint = endPoint;
m_gameActive = true;
}
void Update()
{
if(m_gameActive)
{
int IRresult = CheckIR();
bool moveResult = true;
switch(IRresult){
case -1:
moveResult = true;
break;
case 0:
moveResult = m_player->move(Vector(0,1));
IRresult = -1;
break;
case 1:
moveResult = m_player->move(Vector(1,0));
IRresult = -1;
break;
case 2:
moveResult = m_player->move(Vector(0,-1));
IRresult = -1;
break;
case 3:
moveResult = m_player->move(Vector(-1,0));
IRresult = -1;
break;
}
WriteToScreen();
m_gameActive = moveResult;
if(!moveResult){
//Serial.println("Hit a wall");
}
else{
m_gameActive = CheckEnd();
}
}
}
void ClearScreen()
{
uint8_t pinValues[] = {B00000000, B11111111};
sr.setAll(pinValues);
}
bool CheckEnd(){
Vector ppos = m_player->getPos();
Vector epos = m_endPoint->getPos();
if(ppos.x == epos.x && ppos.y == epos.y){
//Serial.println("YOU WIN");
return false;
}
return true;
}
int CheckIR()
{
// !! up right down left !!
int result = -1;
// IR example
if (irrecv.decode(&results)) {
for(HEXstring currHex : IRhexes){
if(currHex.Compare(results.value))
{
switch(currHex.dir.x){
case 1:
result = 1;
break;
case -1:
result = 3;
break;
default:
switch(currHex.dir.y){
case 1:
result = 0;
break;
case -1:
result = 2;
break;
}
}
}
}
irrecv.resume(); // Receive the next value
}
delay(100);
return result;
//
}
void WriteToScreen()
{
Vector currPos = m_player->getPos();
uint8_t pinValues[] = {binary[currPos.y], B11111111 - binary[currPos.x]};
sr.setAll(pinValues);
}
};
char testMaze[64] = {
'9', '5', '5', '4', '9', '5', '5', '7',
'0', '9', '4', '9', '1', '9', '7', '0',
'0', '3', 'A', 'B', '9', '1', '0', '2',
'0', '9', '1', '0', '3', '7', '3', '7',
'0', '3', '7', '3', '7', '0', '9', 'B',
'3', '7', '0', '9', '1', '0', '0', '2',
'8', '0', '0', '0', '6', '1', '3', '7',
'3', 'C', '1', '3', '5', '5', '5', '1'
};
/*
95549557
09491970
03AB9102
09103737
0373709B
37091002
80006137
3C135551
voort gemak
https://www.mazegenerator.net/
https://textfancy.com/character-wrapper/
*/
MazeGame mazeGame;
Cell* makeCell(int i) {
Vector pos;
pos.x = i%8;
pos.y = i/8;
switch(testMaze[i]){
case '0':{
bool dirs[4] = {true, false, true, false};
return new Cell(pos, dirs);
}
case '1':{
bool dirs[4] = {true, false, false, true};
return new Cell(pos, dirs);
}
case '2':{
bool dirs[4] = {true, false, false, false};
return new Cell(pos, dirs);
}
case '3':{
bool dirs[4] = {true, true, false, false};
return new Cell(pos, dirs);
}
case '4':{
bool dirs[4] = {false, false, false, true};
return new Cell(pos, dirs);
}
case '5':{
bool dirs[4] = {false, true, false, true};
return new Cell(pos, dirs);
}
case '6':{
bool dirs[4] = {false, true, false, false};
return new Cell(pos, dirs);
}
case '7':{
bool dirs[4] = {false, false, true, true};
return new Cell(pos, dirs);
}
case '8':{
bool dirs[4] = {false, false, true, false};
return new Cell(pos, dirs);
}
case '9':{
bool dirs[4] = {false, true, true, false};
return new Cell(pos, dirs);
}
case 'A':{
bool dirs[4] = {false, true, true, true};
return new Cell(pos, dirs);
}
case 'B':{
bool dirs[4] = {true, false, true, true};
return new Cell(pos, dirs);
}
case 'C':{
bool dirs[4] = {true, true, false, true};
return new Cell(pos, dirs);
}
case 'D':{
bool dirs[4] = {true, true, true, false};
return new Cell(pos, dirs);
}
case 'E':{
bool dirs[4] = {true, true, true, true};
return new Cell(pos, dirs);
}
}
return nullptr;
}
Cell *maze[64];
void setup() {
for(int i = 0 ; i < 64 ; ++i)
{
maze[i] = makeCell(i);
}
mazeGame = MazeGame(new Player(maze, Vector(0,0)), maze);
mazeGame.StartGame(new EndPoint(Vector(7,7)));
irrecv.enableIRIn(); // Start the receiver
//
Serial.begin(9600);
//Serial1.begin(115200);
}
void loop() {
mazeGame.Update();
Serial.write(Serial.read());
}