您好,登录后才能下订单哦!
这篇文章主要讲解了C++如何实现俄罗斯方块,内容清晰明了,对此有兴趣的小伙伴可以学习一下,相信大家阅读完之后会有帮助。
本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下
主程序
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++锁和线程接触不多)
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文件中
反思:
未使用类的继承,各种方块理论可以写成子类,因为主线程一开始直接使用了Block对象,后期不容易修改.
看完上述内容,是不是对C++如何实现俄罗斯方块有进一步的了解,如果还想学习更多内容,欢迎关注亿速云行业资讯频道。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。