主程序
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
- 积累的经验:
-
生成随机数的uniform_int_distribution,defualt_random_engine(time(0))使用时必须用static,缺点是多次执行程序的第一次生成的数字是一样的
-
与c++primer p743类似,使用成员指针函数表可以使用户调用的函数更加明了。
-
给互斥锁加权值,并以权值大小顺序加锁,可以保证线程加锁顺序一致,避免死锁(出现则抛出异常)(这个纯粹活学活用,因为c++锁和线程接触不多)
-
thread xxx([&](){})
是可以放在函数内部的线程 -
利用select监控标准输入
-
利用tcgetattr,tcsetaddr,termiosi结构体
nt.c_lflag &= ~ECHO; nt.c_lflag &= ~ISIG; nt.c_lflag &= ~ICANON;
可以在linux关闭回显,实现getch -
this_thread::sleep_for(std::chrono::milliseconds(400 / tab.getLevel()));
可以咋线程中实现毫秒级别睡眠 -
类中静态对象初始化可以写在其对应.cpp文件中
- 反思:
- 未使用类的继承,各种方块理论可以写成子类,因为主线程一开始直接使用了Block对象,后期不容易修改.