Keep talking and nobody explodes Docs

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.

Foto van de maze puzzel

    #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);  
    Servo servo;


    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;
      }
      void resetPos(Vector pos){
        m_pos = pos;
      }
    };
    class EndPoint{
      const Vector m_pos;
      public:
      EndPoint(Vector pos){
        m_pos = pos;
      }
      Vector getPos(){
        return m_pos;
      }
    };
    class MazeGame{
      Vector m_startPoint;
      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_startPoint = player->getPos();
        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){
            m_player->resetPos(m_startPoint);
            //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");
          Serial.write('M');
          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;
    bool mazeMade = false;



    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() {
      servo.attach(3);
      servo.write(0);
      for(int i = 0 ; i < 64 ; ++i)
      {
        maze[i] = makeCell(i);
      }
      irrecv.enableIRIn(); // Start the receiver
      Serial.begin(9600);
    }


    void loop() {
      char rx = Serial.read();
      if(!mazeMade)
      {
        if(rx == 'C' || rx == 'L' || rx == 'H' || rx == 'O' )
        {
          servo.write(90);
          mazeGame = MazeGame(new Player(maze, Vector(3,7)), maze);
          mazeMade = true;
          switch(rx){
            case 'O':
              mazeGame.StartGame(new EndPoint(Vector(4,6)));
              break;
            case 'H':
              mazeGame.StartGame(new EndPoint(Vector(7,2)));
              break;
            case 'L':
              mazeGame.StartGame(new EndPoint(Vector(3,0)));
              break;
            case 'C':
              mazeGame.StartGame(new EndPoint(Vector(0,6)));
              break;
          }
        }
      }
      else{
        mazeGame.Update();
      }
      if(rx == 'R')
      {
        servo.write(0);
        mazeGame.ClearScreen();
        mazeMade = false;
      }
      
    }
  
Tinkercad schema voor de maze puzzel