本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下
主程序
RussiaBlock.cpp
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 |
//
// Created by adl on 2020/7/17.
//
#include "Block.h"
Block::Action Block::Menu[]={
&Block::up,
&Block::down,
&Block::left,
&Block::right
};
|
Table.cpp
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
//
// 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
?| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
//
// 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对象,后期不容易修改.
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/adlatereturn/article/details/107445014








发表评论
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。