您好,登錄后才能下訂單哦!
這篇文章主要講解了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進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。