← index
libmx2/libmx/mp3d/quadtris.cpp
Source: libmx2/libmx/mp3d/quadtris.cpp
#include"quadtris.hpp"
#include <cstdlib>
#include <ctime>
#include <iostream>


namespace puzzle {

    Block::Block(): x{0}, y{0}, color{0}, rotate_x{0} {}


    Block::Block(int x, int y, int color) {
        this->x = x;
        this->y = y;
        this->color =  color;
        this->rotate_x = 0.0;
    }

    Block::Block(const Block &b)  :x{b.x}, y{b.y}, color{b.color}, rotate_x{b.rotate_x}{

    }
    Block::Block(Block&& b) :x{b.x}, y{b.y}, color{b.color}, rotate_x{b.rotate_x} {

    }

	Block &Block::operator=(const Block &b) {
        color = b.color;
        x = b.x;
        y =  b.y;
        rotate_x = b.rotate_x;
        return *this;
    }
	
    Block &Block::operator=(Block&& b) {
        color = b.color;
        x = b.x;
        y =  b.y;
        rotate_x = b.rotate_x;
        return *this;
    }

	bool Block::operator==(const Block &b) const {
        if(b.color == color && b.x == x  && b.y == y)
            return true;

        return false;
    }
	
    bool Block::operator==(const int &color) const {
        if(this->color == color)
            return true;
        return false;
    }

    Piece::Piece(GameGrid *g) : x{0}, y{0}, grid{g} {}
	
    void Piece::reset() {
        x = grid->width()/2;
        y = 0;
        for(int i = 0; i < 3; ++i) {
            blocks[i].x = grid->width()/2;
            blocks[i].y = i;
        }
        do {
            blocks[0].color = 1+(rand()%(grid->numBlocks()-1));
            blocks[1].color = 1+(rand()%(grid->numBlocks()-1));
            blocks[2].color = 1+(rand()%(grid->numBlocks()-1));
        } while(blocks[0].color == blocks[1].color && blocks[0].color == blocks[2].color);
        direction = 0;
    }

    void Piece::setPosition(int x, int y) {
        if(checkLocation(x, this->y)) {
            this->x = x;
        }
    }

    void Piece::shiftColors() {
        Block b[3];
        b[0] = blocks[0];
        b[1] = blocks[1];
        b[2] = blocks[2];
        blocks[0] = b[2];
        blocks[1] = b[0];
        blocks[2] = b[1];
    }

    Block *Piece::at(int index) {
        if(index >= 0 && index <= 2)
            return &blocks[index];
        return nullptr;
    }
    

    void Piece::moveLeft() {

        if(checkLocation(x-1,y)) {
            if(x > 0) {
                x --;
            }
        }
    }

		
    void Piece::moveRight() {
        if(checkLocation(x+1, y)) {
            if(x < grid->width()-1) {
                x ++;
            }
        }
    }

		
    void Piece::moveDown() {
        if(checkLocation(x, y+1)) {
            int stop = (direction == 0) ? 3 : 0;
            if(y < grid->height()-stop) {
                y++;
            } else {
                setBlock();
            }
        } else {
            setBlock();
        }
    }

    void Piece::drop() {
        for(int y = getY(); y < grid->height(); ++y) {
            if(checkLocation(getX(), y)) {
                setBlock();
                return;
            }
        }
    }

    void Piece::setCallback(Callback switch_) {
        switch_grid = switch_;
    }

    void Piece::setBlock() {
        Block *b[3] = {nullptr};

        switch(direction) {
            case 0:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x, y+1);
                b[2] = grid->at(x, y+2);
                break;
            case 1:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x+1, y);
                b[2] = grid->at(x+2, y);
                break;
            case 2:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x-1, y);
                b[2] = grid->at(x-2, y);
                break;
            case 3:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x, y-1);
                b[2] = grid->at(x, y-2);
                break;

        }

        if(b[0] != nullptr &&  b[1] != nullptr && b[2] != nullptr) {
            b[0]->color = blocks[0].color;
            b[1]->color = blocks[1].color;
            b[2]->color = blocks[2].color;
            reset();
            switch_grid();
        }
    }

    bool Piece::checkLocation(int x, int y) {

        Block *b[3] = {nullptr};
        switch(direction) {
            case 0:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x, y+1);
                b[2] = grid->at(x, y+2);
                break;
            case 1:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x+1, y);
                b[2] = grid->at(x+2, y);
                break;
            case 2:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x-1, y);
                b[2] = grid->at(x-2, y);
                break;
            case 3:
                b[0] = grid->at(x, y);
                b[1] = grid->at(x, y-1);
                b[2] = grid->at(x, y-2);
                break;
        }

        if(b[0] != nullptr && b[1] != nullptr && b[2] != nullptr) {
            if(b[0]->color == 0 && b[1]->color == 0 && b[2]->color == 0)
                return true;
        }
        return false;
    }

    void Piece::shiftDirection() {
        int old_dir = direction;
        direction ++;
        if(direction > 3)
            direction = 0;

        if(!checkLocation(x, y)) {
            direction = old_dir;
        }
    }

    GameGrid::GameGrid()  : blocks{nullptr}, grid_w{0}, grid_h{0}, game_piece{this} {
    }

    GameGrid::~GameGrid() {
        releaseGrid();
    }

    void GameGrid::spin() {
        for(int i = 0; i < grid_w; ++i) {
            for(int z  = 0; z < grid_h; ++z) {
                Block *b = at(i, z);
                if(b != nullptr && b->color == -1) {
                    b->rotate_x += 20.0f;
                    if(b->rotate_x >= 360.0f) {
                        b->rotate_x = 0;
                        b->color = 0;
                    }
                }
            }
        }
    }
    
    void GameGrid::releaseGrid() {
        if(blocks != nullptr) {
            for(int i = 0; i < grid_w; ++i) {
                delete [] blocks[i];
            }
            delete [] blocks;
            blocks = nullptr;
        }
    }

    void GameGrid::initGrid(int size_x, int size_y) {
        if(blocks != nullptr)
            releaseGrid();

        blocks = new Block*[size_x];
        for(int i = 0; i < size_x; ++i) {
            blocks[i] = new Block[size_y];
        }
        grid_w = size_x;
        grid_h = size_y;
        game_piece.reset();
    }
    
    Block *GameGrid::at(int x, int y) {
        if(x >= 0  && x < grid_w && y >= 0 && y < grid_h && blocks != nullptr) {
            return &blocks[x][y];
        }
        return nullptr;
    }

    int GameGrid::width() const {
        return grid_w;
    }

    int GameGrid::height() const {
        return grid_h;
    }

    bool GameGrid::canMoveDown() {
        if(game_piece.getDirection() != 3 && game_piece.checkLocation(game_piece.getX(), game_piece.getY()) == false && game_piece.getY() == 0) {
            return false;
        }
        return true;
    }

    
    PuzzleGame::PuzzleGame(int difficulty) : diff{difficulty} {
        newGame();
    }

    void PuzzleGame::newGame() {
        srand(static_cast<int>(time(0)));
        score = 0;
        switch(diff) {
            case 0:
            timeout = 1200;
            break;
            case 1:
            timeout = 900;
            break; 
            case 2:
            timeout = 650;
            break;
        }
        
        clears = 0;
        grid[0].initGrid(12, (720/16/2)+1);
        grid[1].initGrid(12, 28);
        grid[2].initGrid(12, 720/16/2);
        grid[3].initGrid(12, 28);
    }

    void PuzzleGame::setCallback (Callback callback) {
        grid[0].game_piece.setCallback(callback);
        grid[1].game_piece.setCallback(callback);
        grid[2].game_piece.setCallback(callback);
        grid[3].game_piece.setCallback(callback);
    }

    void PuzzleGame::procBlocks() {

        if (timeout > 1100) {
            level = 0;
        } else if (timeout <= 1100 && timeout > 1000) {
            level = 1;
        } else if (timeout <= 1000 && timeout > 900) {
            level = 2;
        } else if (timeout <= 900 && timeout > 800) {
            level = 3;
        } else if (timeout <= 800 && timeout > 700) {
            level = 4;
        } else if (timeout <= 700 && timeout > 600) {
            level = 5;
        }else if (timeout <= 600 && timeout > 500) {
            level = 6;
        }else if (timeout <= 500 && timeout > 400) {
            level = 7;
        }else if (timeout <= 400 && timeout > 300) {
            level = 8;
        }else if (timeout <= 300 && timeout > 200) {
            level = 9;
        }else if (timeout <= 200) {
            level = 10;
        }

        for(int j = 0; j < 4; ++j) {
            for(int i = 0; i < grid[j].width(); ++i) {
                for(int z = 0; z < grid[j].height(); ++z) {
                    Block *blocks[4];
                    blocks[0] = grid[j].at(i, z);
                    blocks[1] = grid[j].at(i, z+1);
                    blocks[2] = grid[j].at(i, z+2);
                    blocks[3] = grid[j].at(i, z+3);

                    if(blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                        if(blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                            if(blocks[3] != nullptr) {
                                if(blocks[0]->color == blocks[3]->color) {
                                    blocks[3]->color = -1;
                                    score += 10;
                                    #ifdef HAS_SOUND
                                        snd::playsound(0);
                                    #endif
                
                                }
                            }
                            blocks[0]->color = -1;
                            blocks[1]->color = -1;
                            blocks[2]->color = -1;
                            score += 1;
                            clears ++;
                            if((clears%4)==0) {
                                timeout -= 25;
                            }

                            #ifdef HAS_SOUND
                            snd::playsound(0);
                            #endif

                            return;
                        }
                    }

                    blocks[0] = grid[j].at(i, z);
                    blocks[1] = grid[j].at(i+1, z);
                    blocks[2] = grid[j].at(i+2, z);
                    blocks[3] = grid[j].at(i+3, z);

                    if(blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                        if(blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                            if(blocks[3] != nullptr) {
                                if(blocks[0]->color == blocks[3]->color) {
                                    blocks[3]->color = -1;
                                    score += 10;
                                    #ifdef HAS_SOUND
                                        snd::playsound(0);
                                    #endif

                                }
                            }
                            blocks[0]->color = -1;
                            blocks[1]->color = -1;
                            blocks[2]->color = -1;
                            score += 1;
                            clears ++;
                            if((clears%4)==0) {
                                timeout -= 25;
                            }

                            #ifdef HAS_SOUND
                            snd::playsound(0);
                            #endif


                            return;
                        }
                    }

                    blocks[0] = grid[j].at(i, z);
                    blocks[1] = grid[j].at(i+1, z+1);
                    blocks[2] = grid[j].at(i+2, z+2);
                    blocks[3] = grid[j].at(i+3, z+3);

                    if (blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                        if (blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                            if (blocks[3] != nullptr) {
                                if (blocks[0]->color == blocks[3]->color) {
                                    blocks[3]->color = -1;
                                    score += 10;
                                    #ifdef HAS_SOUND
                                        snd::playsound(0);
                                    #endif

                                }
                            }
                            blocks[0]->color = -1;
                            blocks[1]->color = -1;
                            blocks[2]->color = -1;
                            score += 1;
                            clears ++;
                            if((clears%4)==0) {
                                timeout -= 25;
                            }
                            return;
                        }
                    }
                
                    blocks[0] = grid[j].at(i, z);
                    blocks[1] = grid[j].at(i-1, z+1);
                    blocks[2] = grid[j].at(i-2, z+2);
                    blocks[3] = grid[j].at(i-3, z+3);

                    if (blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                        if (blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                            if (blocks[3] != nullptr) {
                                if (blocks[0]->color == blocks[3]->color) {
                                    blocks[3]->color = -1;
                                    score += 10;
                                    #ifdef HAS_SOUND
                                        snd::playsound(0);
                                    #endif

                                }
                            }
                            blocks[0]->color = -1;
                            blocks[1]->color = -1;
                            blocks[2]->color = -1;
                            score += 1;
                            clears ++;
                            if((clears%4)==0) {
                                timeout -= 25;
                            }

                            #ifdef HAS_SOUND
                            snd::playsound(0);
                            #endif


                            return;
                        }
                    }
                }
            }
        }

        for(int i = 0; i < grid[0].width(); i++) {
            puzzle::Block *b[4];
            b[0] = grid[0].at(i, grid[0].height()-1);
            b[1] = grid[0].at(i, grid[0].height()-2);
            b[2] = grid[2].at(i, grid[2].height()-1);
            b[3] = grid[2].at(i, grid[2].height()-2);

            if(b[0] && b[1] && b[2]) {
                if(b[0]->color > 0 && b[0]->color == b[1]->color && b[0]->color == b[2]->color) {
                    if(b[0]->color > 0 && b[3] && b[0]->color == b[3]->color) {
                        score += 10;
                        b[3]->color = -1;
                        #ifdef HAS_SOUND
                            snd::playsound(0);
                        #endif
                    }

                    score++;
                    clears++;
                    if((clears%4)==0) {
                        timeout -= 25;
                    }
                    b[0]->color = -1;
                    b[1]->color = -1;
                    b[2]->color = -1;

                        #ifdef HAS_SOUND
                        snd::playsound(0);
                        #endif


                    return;
                }
            }
            if(b[2] && b[3] && b[0]) {
                if(b[2]->color > 0 && b[2]->color == b[0]->color && b[2]->color == b[3]->color) {
                    if(b[1] && b[2]->color == b[1]->color) {
                        score += 10;
                        b[1]->color = -1;
                        #ifdef HAS_SOUND
                            snd::playsound(0);
                        #endif

                    }

                    score ++;
                    clears++;
                    if((clears%4)==0) {
                        timeout -= 25;
                    }
                    b[2]->color = -1;
                    b[3]->color = -1;
                    b[0]->color = -1;

                    #ifdef HAS_SOUND
                    snd::playsound(0);
                    #endif
                }
            }
        }
      
        for(int i = 0; i < grid[0].width() - 3; ++i) {
            puzzle::Block *b[4];
            int y0 = grid[0].height() - 1; 
            int y1 = grid[2].height() - 1; 

            b[0] = grid[0].at(i, y0);
            b[1] = grid[2].at(i + 1, y1);
            b[2] = grid[2].at(i + 2, y1 - 1);
            b[3] = grid[2].at(i + 3, y1 - 2);

            if(b[0] && b[1] && b[2]) {
                if(b[0]->color > 0 && b[0]->color == b[1]->color && b[0]->color == b[2]->color) {
                    if(b[3] && b[0]->color == b[3]->color) {
                        score += 10;
                        b[3]->color = -1;
                        #ifdef HAS_SOUND
                            snd::playsound(0);
                        #endif
                    }

                    score++;
                    clears++;
                    if((clears % 4) == 0) {
                        timeout -= 25;
                    }
                    b[0]->color = -1;
                    b[1]->color = -1;
                    b[2]->color = -1;
                    #ifdef HAS_SOUND
                    snd::playsound(0);
                    #endif
                    return;
                }
            }
        }

        for(int i = 3; i < grid[0].width(); ++i) {
            puzzle::Block *b[4];
            int y0 = grid[0].height() - 1; 
            int y1 = grid[2].height() - 1; 

            b[0] = grid[0].at(i, y0);
            b[1] = grid[2].at(i - 1, y1);
            b[2] = grid[2].at(i - 2, y1 - 1);
            b[3] = grid[2].at(i - 3, y1 - 2);

            if(b[0] && b[1] && b[2]) {
                if(b[0]->color > 0 && b[0]->color == b[1]->color && b[0]->color == b[2]->color) {
                    if(b[3] && b[0]->color == b[3]->color) {
                        score += 10;
                        b[3]->color = -1;
                        #ifdef HAS_SOUND
                            snd::playsound(0);
                        #endif
                    }
                    score++;
                    clears++;
                    if((clears % 4) == 0) {
                        timeout -= 25;
                    }
                    b[0]->color = -1;
                    b[1]->color = -1;
                    b[2]->color = -1;
                    #ifdef HAS_SOUND
                    snd::playsound(0);
                    #endif
                    return;
                }
            }
        }
        moveDown_Blocks();
    }
    	
    void PuzzleGame::moveDown_Blocks() {
        for(int j = 0; j < 4; ++j) {
            for(int i = 0; i < grid[j].width(); ++i) {
                for(int z = 0; z < grid[j].height(); ++z) {
                    Block *b1 = grid[j].at(i, z);
                    Block *b2 = grid[j].at(i, z+1);
                    if(b1 != nullptr && b2 != nullptr) {
                        if(b2->color == 0 && b1->color > 0) {
                            std::swap(b1->color, b2->color);
                            return;
                        }
                    }

                }
            }
        }
    }

    MasterPiece::MasterPiece(int difficulty) : diff{difficulty} {
        newGame();
    }
    void MasterPiece::setCallback (Callback callback) {
        grid.game_piece.setCallback(callback);
    }
    void MasterPiece::newGame() {
        srand(static_cast<int>(time(0)));
        score = 0;
        switch(diff) {
            case 0:
            timeout = 1200;
            break;
            case 1:
            timeout = 900;
            break; 
            case 2:
            timeout = 650;
            break;
        }
        
        clears = 0;
        grid.initGrid(15, 18);
    }
    void MasterPiece::procBlocks() {
        if (timeout > 1100) {
            level = 0;
        } else if (timeout <= 1100 && timeout > 1000) {
            level = 1;
        } else if (timeout <= 1000 && timeout > 900) {
            level = 2;
        } else if (timeout <= 900 && timeout > 800) {
            level = 3;
        } else if (timeout <= 800 && timeout > 700) {
            level = 4;
        } else if (timeout <= 700 && timeout > 600) {
            level = 5;
        }else if (timeout <= 600 && timeout > 500) {
            level = 6;
        }else if (timeout <= 500 && timeout > 400) {
            level = 7;
        }else if (timeout <= 400 && timeout > 300) {
            level = 8;
        }else if (timeout <= 300 && timeout > 200) {
            level = 9;
        }else if (timeout <= 200) {
            level = 10;
        }

        for(int i = 0; i < grid.width(); ++i) {
            for(int z = 0; z < grid.height(); ++z) {
                Block *blocks[4];
                blocks[0] = grid.at(i, z);
                blocks[1] = grid.at(i, z+1);
                blocks[2] = grid.at(i, z+2);
                blocks[3] = grid.at(i, z+3);

                if(blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                    if(blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                        if(blocks[3] != nullptr) {
                            if(blocks[0]->color == blocks[3]->color) {
                                blocks[3]->color = -1;
                                score += 10;
                                #ifdef HAS_SOUND
                                    snd::playsound(0);
                                #endif
            
                            }
                        }
                        blocks[0]->color = -1;
                        blocks[1]->color = -1;
                        blocks[2]->color = -1;
                        score += 1;
                        clears ++;
                        if((clears%4)==0) {
                            timeout -= 25;
                        }

                        #ifdef HAS_SOUND
                        snd::playsound(0);
                        #endif

                        return;
                    }
                }

                blocks[0] = grid.at(i, z);
                blocks[1] = grid.at(i+1, z);
                blocks[2] = grid.at(i+2, z);
                blocks[3] = grid.at(i+3, z);

                if(blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                    if(blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                        if(blocks[3] != nullptr) {
                            if(blocks[0]->color == blocks[3]->color) {
                                blocks[3]->color = -1;
                                score += 10;
                                #ifdef HAS_SOUND
                                    snd::playsound(0);
                                #endif

                            }
                        }
                        blocks[0]->color = -1;
                        blocks[1]->color = -1;
                        blocks[2]->color = -1;
                        score += 1;
                        clears ++;
                        if((clears%4)==0) {
                            timeout -= 25;
                        }

                        #ifdef HAS_SOUND
                        snd::playsound(0);
                        #endif


                        return;
                    }
                }

                blocks[0] = grid.at(i, z);
                blocks[1] = grid.at(i+1, z+1);
                blocks[2] = grid.at(i+2, z+2);
                blocks[3] = grid.at(i+3, z+3);

                if (blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                    if (blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                        if (blocks[3] != nullptr) {
                            if (blocks[0]->color == blocks[3]->color) {
                                blocks[3]->color = -1;
                                score += 10;
                                #ifdef HAS_SOUND
                                    snd::playsound(0);
                                #endif

                            }
                        }
                        blocks[0]->color = -1;
                        blocks[1]->color = -1;
                        blocks[2]->color = -1;
                        score += 1;
                        clears ++;
                        if((clears%4)==0) {
                            timeout -= 25;
                        }
                        return;
                    }
                }
            
                blocks[0] = grid.at(i, z);
                blocks[1] = grid.at(i-1, z+1);
                blocks[2] = grid.at(i-2, z+2);
                blocks[3] = grid.at(i-3, z+3);

                if (blocks[0] != nullptr && blocks[1] != nullptr && blocks[2] != nullptr) {
                    if (blocks[0]->color > 0 && blocks[0]->color == blocks[1]->color && blocks[0]->color == blocks[2]->color) {
                        if (blocks[3] != nullptr) {
                            if (blocks[0]->color == blocks[3]->color) {
                                blocks[3]->color = -1;
                                score += 10;
                                #ifdef HAS_SOUND
                                    snd::playsound(0);
                                #endif

                            }
                        }
                        blocks[0]->color = -1;
                        blocks[1]->color = -1;
                        blocks[2]->color = -1;
                        score += 1;
                        clears ++;
                        if((clears%4)==0) {
                            timeout -= 25;
                        }

                        #ifdef HAS_SOUND
                        snd::playsound(0);
                        #endif

                        return;
                    }
                }
            }
        }
        moveDown_Blocks();
    }

    void MasterPiece::moveDown_Blocks() {
        for(int i = 0; i < grid.width(); ++i) {
            for(int z = 0; z < grid.height(); ++z) {
                Block *b1 = grid.at(i, z);
                Block *b2 = grid.at(i, z+1);
                if(b1 != nullptr && b2 != nullptr) {
                    if(b2->color == 0 && b1->color > 0) {
                        std::swap(b1->color, b2->color);
                        return;
                    }
                }
            }
        }
        drop = false;
    }
}