俄罗斯方块c++linux版本

主程序
RussiaBlock.cpp

//
// Created by adl on 2020/7/18.
//
#include "Block.h"
#include "Table.h"
#include <thread>
#include <mutex>
#include "hierarchical_mutex.h"
#include "fstream"

using namespace std;
thread_local uint64_t
        hierarchical_mutex::this_thread_hierarchical_value = ULONG_MAX;

int main(int argc, char **argv) {
    
    
    int level = 1;
    if (argc == 2) {
    
    
        if ((level = atoi(argv[1])) == 0) {
    
    
            cerr << "./a.out number " << endl;
            exit(-1);
        }

    }
    static int flag = 1;//全局变量
    static Table tab(20, 20, level); //构造一个15,20的棋盘
    static Block bl;      //构造一个落下方块
    hierarchical_mutex table_mtx(2);
    hierarchical_mutex mtx(1);


    thread getkey([&]() {
    
    
        unsigned char buf[2];
        struct termios saveterm, nt;
        fd_set rfds, rs;
        struct timeval tv;
        int i = 0, q, r, fd = 0;//标准输入
        tcgetattr(fd, &saveterm);
        nt = saveterm;
        nt.c_lflag &= ~ECHO;
        nt.c_lflag &= ~ISIG;
        nt.c_lflag &= ~ICANON;
        tcsetattr(fd, TCSANOW, &nt);
        FD_ZERO(&rs);
        FD_SET(fd, &rs);
        tv.tv_usec = 0;
        tv.tv_sec = 0;
        while (1) {
    
    
            read(0, buf, 1);
            buf[1] = '\0';
            r = select(fd + 1, &rfds, nullptr, nullptr, &tv);
            if (r < 0) {
    
    
                write(fileno(stderr), "select error.\n", sizeof("select error.\n"));
            }
            rfds = rs;
            std::unique_lock<hierarchical_mutex> table_lock(table_mtx);
            //上下左右
            switch (buf[0]) {
    
    
                case 'A': {
    
    
                    //旋转
                    tab.clr_block(bl);//
                    if (bl.get_type() == 5)continue;
                    bl.rotate();
                    if (tab.set_block(bl) == -1) {
    
    
                        bl.rotate_back();
                        tab.set_block(bl);
                        continue;
                    }
                    break;
                }
                case 'B': {
    
    
                    //向下(加速)
                    tab.clr_block(bl);
                    bl.move(Block::DOWN);
                    if (tab.set_block(bl) == -1) {
    
    
                        bl.move(Block::UP);
                        tab.set_block(bl);
                    }
                    break;
                }
                case 'C': {
    
    
                    /*向右*/
                    tab.clr_block(bl);
                    bl.move(Block::RIGHT);
                    if (tab.set_block(bl) == -1) {
    
    
                        bl.move(Block::LEFT);
                        tab.set_block(bl);
                    }
                    break;
                }
                case 'D': {
    
    
                    //左
                    tab.clr_block(bl);
                    bl.move(Block::LEFT);
                    if (tab.set_block(bl) == -1) {
    
    
                        bl.move(Block::RIGHT);
                        tab.set_block(bl);
                    }
                    break;
                }
                default:
                    break;
            }
            table_lock.unlock();
            std::unique_lock<hierarchical_mutex> lock(mtx);
            if (flag == 2 || buf[0] == 113) {
    
    

                lock.unlock();

                tcsetattr(fd, TCSANOW, &saveterm);
                std::cout << "game over" << std::endl;
                exit(0);
            } else {
    
    
                lock.unlock();
            }
        }

        tcsetattr(0, TCSANOW, &saveterm);
    });
    thread printloop([&]() {
    
    
        while (1) {
    
    
            system("clear");
            std::unique_lock<hierarchical_mutex> table_lock(table_mtx);
            tab.paint();
            table_lock.unlock();
            this_thread::sleep_for(std::chrono::milliseconds(200 / tab.getLevel()));
            std::unique_lock<hierarchical_mutex> lock(mtx);

            if (flag == 2) {
    
    
                cout << "任意键退出" << endl;
                lock.unlock();
                break;
            } else
                lock.unlock();
        }
    });
    getkey.detach();
    printloop.detach();
    int dir, i, c;
    while (true) {
    
    
        //生成方块
        std::unique_lock<hierarchical_mutex> table_lock(table_mtx);
//        std::unique_lock<std::mutex>table_lock(table_mtx);

        bl.create_block(tab.getWidth(), tab.getHeight());
        table_lock.unlock();
        //判断游戏是否结束
        table_lock.lock();
        if (-1 == tab.set_block(bl)) {
    
    
            std::unique_lock<hierarchical_mutex> lock(mtx);
            flag = 2;
            lock.unlock();
            table_lock.unlock();
            while (1);
        } else
            table_lock.unlock();

        ///行动按键判定
        while (true) {
    
    
            this_thread::sleep_for(std::chrono::milliseconds(400 / tab.getLevel()));
            /向下移动一格
            table_lock.lock();
            tab.clr_block(bl);    //清空上一次方块位置
            bl.move(Block::DOWN);    //向下移动一步
            if (-1 == tab.set_block(bl)) {
    
       //是否触底
                bl.move(Block::UP);    //如果触底,还原触底前位置
                tab.set_block(bl);
                table_lock.unlock();
                break;
            }
            table_lock.unlock();
        }
        //如果满行则消行
        table_lock.lock();
        for (i = 0; i < tab.getHeight(); i++) {
    
    
            if (tab.if_full(i)) {
    
     //是否满行
                tab.clr_line(i); //如果是,消行
                tab.move_line(i); //将所消行的上面的棋盘信息下移
                i--;      //下移后,重新检查这一行是否满(可能出现几行同时消去)
                tab.set_count(100); //记录得分
            }
        }
        table_lock.unlock();
    }
    return 0;
}

grid.h

//
// Created by adl on 2020/7/17.
//

#ifndef UNTITLED_GRID_H
#define UNTITLED_GRID_H

struct grid {
    
    
    int x;
    int y;

    grid();
    grid(grid&&)noexcept ;
    grid(const grid&);
    grid(int x, int y);
    grid&operator=(const grid&);
    grid&operator=( grid&&);
    virtual ~grid();
};    //坐标



#endif //UNTITLED_GRID_H

grid.cpp

//
// Created by adl on 2020/7/17.
//

#include "grid.h"

grid::grid(int x, int y) : x(x), y(y) {
    
    }

grid::grid() : x(0), y(0) {
    
    }

grid::grid(grid &&rhs) noexcept: x(rhs.x), y(rhs.y) {
    
    

}

grid::~grid() {
    
    

}

grid::grid(const grid &rhs) : x(rhs.x), y(rhs.y) {
    
    
}

grid &grid::operator=(const grid &rhs) {
    
    
    if (this != &rhs) {
    
    
        x = rhs.x;
        y = rhs.y;
    }
    return *this;

}

grid &grid::operator=(grid &&rhs) {
    
    
    if (this != &rhs) {
    
    
        x = rhs.x;
        y = rhs.y;
    }
    return *this;
}

Block.h

//
// Created by adl on 2020/7/17.
//

#ifndef UNTITLED_BLOCK_H
#define UNTITLED_BLOCK_H

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <time.h>

#include<termios.h>
#include<fcntl.h>
#include <zconf.h>
#include "grid.h"

#define BLOCK_SIZE 4
#define SLEEP_TIME 500

#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<memory>
#include <random>

class Block {
    
    
public:
    using Action =Block&(Block::*)();
    enum direct {
    
    
        UP, DOWN, LEFT, RIGHT
    };
    grid g[BLOCK_SIZE];

    Block() : center(0, 0), type(0) {
    
    }

    void def_block(grid g1, grid g2, grid g3, grid g4) {
    
    
        g[0] = g1;
        g[1] = g2;
        g[2] = g3;
        g[3] = g4;
    }

    void rotate() {
    
    
        //顺时针旋
        int x, y;
        for (int i = 0; i < 4; i++) {
    
    
            x = g[i].x - center.x;
            y = g[i].y - center.y;
            g[i].x = center.x + y;
            g[i].y = center.y - x;

        }
    }

    Block &up() {
    
    
        for (int i = 0; i < 4; ++i) {
    
    
            g[i].y++;
        }
        center.y++;
        return *this;
    }

    Block &down() {
    
    
        for (int i = 0; i < 4; ++i) {
    
    
            g[i].y--;
        }
        center.y--;
        return *this;
    }

    Block &left() {
    
    
        for (int i = 0; i < 4; ++i) {
    
    
            g[i].x--;
        }
        center.x--;
        return *this;
    }

    Block &right() {
    
    
        for (int i = 0; i < 4; ++i) {
    
    
            g[i].x++;
        }
        center.x++;
        return *this;
    }

    void move(direct dir) {
    
    
        (this->*Menu[dir])();
    }


    void set_cen(grid g) {
    
    
        center = g;
    }

    grid get_cen() const {
    
    
        return center;
    }

    void set_type(int t) {
    
    
        type = t;
    }

    int get_type() const {
    
    
        return type;
    }

    void rotate_back() {
    
    
        //rotate的逆向
        int x, y;
        for (int i = 0; i < 4; i++) {
    
    
            x = g[i].x - center.x;
            y = g[i].y - center.y;
            g[i].x = center.x + y;
            g[i].y = center.y - x;

        }
    }

    void create_block(int x, int y) {
    
    
        unsigned int ran;
        grid g[BLOCK_SIZE];
        static std::uniform_int_distribution<unsigned> u(1, 7);
        static std::default_random_engine e(time(0));
        ran = u(e);
        switch (ran) {
    
    
            case 1: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 3;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x;
                g[2].y = g[0].y + 2;
                g[3].x = g[0].x + 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(1);
                break;
            }
                //反L
            case 2: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 3;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x;
                g[2].y = g[0].y + 2;
                g[3].x = g[0].x - 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(2);
                break;
            }
                //Z
            case 3: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 2;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x + 1;
                g[2].y = g[0].y + 1;
                g[3].x = g[0].x - 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(3);
                break;
            }
                //反Z
            case 4: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 2;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x + 1;
                g[2].y = g[0].y + 1;
                g[3].x = g[0].x - 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(4);
                break;
            }
                //田
            case 5: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 2;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x + 1;
                g[2].y = g[0].y + 1;
                g[3].x = g[0].x + 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(5);
                break;
            }
                //1
            case 6: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 3;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x;
                g[2].y = g[0].y + 2;
                g[3].x = g[0].x;
                g[3].y = g[0].y - 1;
                set_cen(g[0]);
                set_type(6);
                break;
            }
                //山
            case 7: {
    
    
                g[0].x = x / 2;
                g[0].y = y - 2;
                g[1].x = g[0].x;
                g[1].y = g[0].y + 1;
                g[2].x = g[0].x - 1;
                g[2].y = g[0].y;
                g[3].x = g[0].x + 1;
                g[3].y = g[0].y;
                set_cen(g[0]);
                set_type(7);
                break;
            }
            default:
                std::cerr << "someThing err!" << ran << std::endl;
        }
        def_block(g[0], g[1], g[2], g[3]);
    }

private:
    static Action Menu[];
    grid center;
    int type;
};



#endif //UNTITLED_BLOCK_H

Block.cpp

//
// Created by adl on 2020/7/17.
//

#include "Block.h"
Block::Action Block::Menu[]={
    
    
        &Block::up,
        &Block::down,
        &Block::left,
        &Block::right
};

Table.cpp

//
// Created by adl on 2020/7/17.
//

#include "Table.h"
#include "Block.h"

int Table::set_block(const Block &bl) {
    
    
    int x, y;
    for (int i = 0; i < 4; ++i) {
    
    
        x = bl.g[i].x;
        y = bl.g[i].y;
        //比如下降之后 table[x][y]上有方块了
        if (table[x][y] != 0 || x >= width || x < 0 || y >= height || y < 0) {
    
    
            return -1;
        }
    }
    for (int i = 0; i < 4; ++i) {
    
    
        x = bl.g[i].x;
        y = bl.g[i].y;
        table[x][y] = 1;
    }
    return 0;
}

void Table::clr_block(const Block &bl) {
    
    
    int x, y;
    for (int i = 0; i < 4; ++i) {
    
    
        x = bl.g[i].x;
        y = bl.g[i].y;
        table[x][y] = 0;
    }
}

int Table::clr_line(int y) {
    
    
    if (y < 0 || y >= height) return -1;
    for (int i = 0; i < width; i++) {
    
    
        table[i][y] = 0;
    }
    return 0;
}

int Table::getHeight() const {
    
    
    return height;
}

int Table::getWidth() const {
    
    
    return width;
}

int Table::if_full(int y) {
    
    
    for (int i = 0; i < width; ++i) {
    
    
        if (table[i][y] == 0) return 0;
    }
    return 1;
}

int Table::get_table(int x, int y) {
    
    
    return table[x][y];
}

void Table::paint() {
    
    
    int i, j;
    system("clear");
    for (i = 0; i < width + 2; i++) std::cout << "-" << std::flush;
    std::cout << "\n" << std::flush;

    for (i = height - 1; i >= 0; i--) {
    
    
        std::cout << "|" << std::flush;
        for (j = 0; j < width; j++) {
    
    
            if (table[j][i] == 0) std::cout << " " << std::flush;
            else std::cout << "#" << std::flush;
            //▣
        }
        if (i == 13)
            std::cout << "|  等级:" << getLevel() << std::endl;
        else if (i == 10)
            std::cout << "|  得分:" << get_count() << std::endl;
        else if (i == 7)
            std::cout << "|  Press 'q' to quit!" << std::endl;
        else
            std::cout << "|" << std::endl;
    }
    for (i = 0; i < width + 2; i++) std::cout << "-" << std::flush;
    std::cout << "\n" << std::flush;
}

void Table::move_line(int y) {
    
    
    for (int i = y; i < height - 1; ++i) {
    
    
        for (int j = 0; j < width; ++j) {
    
    
            table[j][i] = table[j][i + 1];
        }
    }
}

void Table::set_count(int c) {
    
    
    count += c;
}

int Table::get_count() {
    
    
    return count;
}

int Table::getLevel() const {
    
    
    return level;
}

void Table::setLevel(int level) {
    
    
    Table::level = level;
}

Table.h

//
// Created by adl on 2020/7/17.
//

#ifndef UNTITLED_TABLE_H
#define UNTITLED_TABLE_H

#include <cstring>

#define TABLE_SIZE 20
class Block;
class Table {
    
    
public:

    Table():height(TABLE_SIZE),width(10),count(0),level(1){
    
                 //构造棋盘
        for (int i = 0; i < height; ++i) {
    
    
            for (int j = 0; j < width; ++j) {
    
    
                table[i][j]=0;
            }
        }
    }

    int getLevel() const;

    void setLevel(int level);

    Table(int x, int y,int level):height(y),width(x),count(0),level(level){
    
    
        for (int i = 0; i < height; ++i) {
    
    
            for (int j = 0; j < width; ++j) {
    
    
                table[i][j]=0;
            }
        }
    }
    int set_block(const Block &bl);    //安设方块
    void clr_block(const Block &bl);     //清除方块
    int clr_line(int y);       //消行

    int getHeight() const;

    //获取棋盘宽度
    int if_full(int y);        //判定是否满行
    int get_table(int x, int y);   //获取棋盘上点信息
    void paint();           //绘制棋盘
    void move_line(int y);      //整行下移
    void set_count(int c);      //记录得分
    int get_count();

    int getWidth() const;
    //获取得分

private:
    int table[TABLE_SIZE][TABLE_SIZE];//棋盘
    int height, width;        //棋盘的高和宽
    int count;            //得分
    int level;

};


#endif //UNTITLED_TABLE_H

hierarchical_mutex.h

//
// Created by adl on 2020/7/18.
//

#ifndef UNTITLED_HIERARCHICAL_MUTEX_H
#define UNTITLED_HIERARCHICAL_MUTEX_H
#include<iostream>
#include<string>
#include<vector>
#include<algorithm>
#include<memory>
#include <exception>
#include <mutex>
#include <thread>
#include <climits>

class hierarchical_mutex{
    
    
private:
    std::mutex internal_mutex;
    uint64_t const hierarchical_value;
    uint64_t previous_value;
    static thread_local uint64_t this_thread_hierarchical_value;

    void check_for_hierarchy() noexcept(false) {
    
    
        if(this_thread_hierarchical_value <= hierarchical_value){
    
    
            throw std::logic_error("mutex hierarchical violated.");
        }
    }

    void update_hierarchy_value(){
    
    
        previous_value = this_thread_hierarchical_value;
        this_thread_hierarchical_value = hierarchical_value;
    }

public:
    constexpr explicit hierarchical_mutex(uint64_t value) :
            hierarchical_value(value), previous_value(0) {
    
    }

    void lock() noexcept(false) {
    
    
        check_for_hierarchy();
        internal_mutex.lock();
        update_hierarchy_value();
    }

    void unlock(){
    
    
        this_thread_hierarchical_value = previous_value;
        internal_mutex.unlock();
    }

    bool try_lock() noexcept(false) {
    
    
        check_for_hierarchy();
        if(!internal_mutex.try_lock()) return false;
        update_hierarchy_value();
        return true;
    }
};


#endif //UNTITLED_HIERARCHICAL_MUTEX_H

  • 积累的经验:
  1. 生成随机数的uniform_int_distribution,defualt_random_engine(time(0))使用时必须用static,缺点是多次执行程序的第一次生成的数字是一样的

  2. 与c++primer p743类似,使用成员指针函数表可以使用户调用的函数更加明了。

  3. 给互斥锁加权值,并以权值大小顺序加锁,可以保证线程加锁顺序一致,避免死锁(出现则抛出异常)(这个纯粹活学活用,因为c++锁和线程接触不多)

    扫描二维码关注公众号,回复: 12011206 查看本文章
  4. thread xxx([&](){})是可以放在函数内部的线程

  5. 利用select监控标准输入

  6. 利用tcgetattr,tcsetaddr,termiosi结构体
    nt.c_lflag &= ~ECHO; nt.c_lflag &= ~ISIG; nt.c_lflag &= ~ICANON;
    可以在linux关闭回显,实现getch

  7. this_thread::sleep_for(std::chrono::milliseconds(400 / tab.getLevel()));可以咋线程中实现毫秒级别睡眠

  8. 类中静态对象初始化可以写在其对应.cpp文件中

  • 反思:
  1. 未使用类的继承,各种方块理论可以写成子类,因为主线程一开始直接使用了Block对象,后期不容易修改.

猜你喜欢

转载自blog.csdn.net/adlatereturn/article/details/107445014