C++實現俄羅斯方塊(linux版本)
阿新 • • 發佈:2020-07-22
本文例項為大家分享了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,&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,&saveterm); std::cout << "game over" << std::endl; exit(0); } else { lock.unlock(); } } tcsetattr(0,&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),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物件,後期不容易修改.
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。