コンソールゲームのロシアブロック


最近マルチスレッドを学んでいるので、C++の新しい標準のthreadライブラリを使って、簡単に使って、ロシアのブロックに書いてキーボード入力を傍受しようとしました.
基本的な考え方は、1つのクラスで1つのブロックを表し、ブロッククラスでは1つの座標posでブロックの位置を表し、1つの座標配列offsetはブロックの各小格子のposに対するオフセット量を表す.次の数の呼び出し可能なオブジェクトを生成する2つのクラスを追加して、ブロックをランダムに生成します.
駒類base_Cubeは虚ベースクラスで、他の7つのクラスはbase_から継承されています.cube :O_cube,  I_cube, L_cube, R_cube, S_cube, Z_CubeとT_cube;それぞれ7つのブロックを表します.そしてgameクラスでカプセル化します.
make_random.h
#ifndef _MAKE_RANDOM_H
#define _MAKE_RANDOM_H

#include
class Random4{
public:
	unsigned operator() (){
		static std::default_random_engine e;
		static std::uniform_int_distribution u(1, 4);
		return u(e);
	}
};
class Random7{
public:
	unsigned operator() (){
		static std::default_random_engine e;
		static std::uniform_int_distribution u(1, 7);
		return u(e);
	}
};
#endif

base_cube.h
#ifndef _BASE_CUBE_H
#define _BASE_CUBE_H

#include
#include"make_random.h"

class __pt
{
public:
	__pt(int x = 0, int y = 0) 
		:_x(x), _y(y) { }
	inline void set(int x, int y){
		_y = y, _x = x; 
	}
	inline int x()const{ return _x; }
	inline int y()const{ return _y; }
private:
	int _x, _y;
};

class base_cube
{
public:
	base_cube(int x = 0, int y = 0) :_pos(x, y), _offset(4,__pt()) { }
	virtual ~base_cube(){ }
	inline virtual void turn() = 0;
	inline int x(std::size_t i){ return _pos.x() + _offset[i].x(); }
	inline int y(std::size_t i){ return _pos.y() + _offset[i].y(); }
	inline const void move(int x, int y){ _pos.set(_pos.x() + x, _pos.y() + y); }
protected:
	__pt _pos;
	std::vector<__pt> _offset;
};

#endif

I_cube.h
#ifndef _I_CUBE_H
#define _I_CUBE_H

#include"base_cube.h"


class I_cube : public base_cube
{
public:
	I_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		if (r == 1 || r == 3){
			_stat = vertical;
			turn_vertical();
		}
		else {
			_stat = horizontal;
			turn_horizontal();
		}
	}
	~I_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		if (_stat == horizontal)
			turn_vertical();
		else turn_horizontal();
	}
private:
	enum stat{ vertical, horizontal };
	inline void turn_horizontal(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(0, 2);
		_stat = horizontal;
	}
	inline void turn_vertical(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(2, 0);
		_stat = vertical;
	}
	stat _stat;
};
#endif

L_cube.h
#ifndef _L_CUBE_H
#define _L_CUBE_H

#include"base_cube.h"

class L_cube : public base_cube
{
public:
	L_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		switch (r){
		case 1: turn_top();		break;
		case 2: turn_left();	break;
		case 3: turn_bottom();	break;
		case 4: turn_right();	break;
		default:				break;
		}
	}
	~L_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		switch (_stat){
		case top:		turn_left();		break;
		case left:		turn_bottom();		break;
		case bottom:	turn_right();		break;
		case right:		turn_top();			break;
		default:							break;
		}
	}
private:
	enum stat{ top, left, bottom, right };
	inline void turn_top(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(1, 1);
		_stat = top;
	}
	inline void turn_left(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(-1, 1);
		_stat = left;
	}
	inline void turn_bottom(){
		_offset[0].set(-1, -1);
		_offset[1].set(-1, 0);
		_offset[2].set(0, 0);
		_offset[3].set(1, 0);
		_stat = bottom;
	}
	inline void turn_right(){
		_offset[0].set(1, -1);
		_offset[1].set(0, -1);
		_offset[2].set(0, 0);
		_offset[3].set(0, 1);
		_stat = right;
	}
	stat _stat;
};

#endif

O_cube.h
#ifndef _O_CUBE_H
#define _O_CUBE_H

#include"base_cube.h"


class O_cube : public base_cube
{
public:
	O_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		_offset[0].set(0, 0);
		_offset[1].set(0, 1);
		_offset[2].set(1, 0);
		_offset[3].set(1, 1);
	}
	~O_cube(){ base_cube::~base_cube(); }
	inline void turn() override { }
};

#endif

R_cube.h
#ifndef _R_CUBE_H
#define _R_CUBE_H

#include"base_cube.h"

class R_cube : public base_cube
{
public:
	R_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		switch (r){
		case 1: turn_top();		break;
		case 2: turn_left();	break;
		case 3: turn_bottom();	break;
		case 4: turn_right();	break;
		default:				break;
		}
	}
	~R_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		switch (_stat){
		case top:		turn_left();		break;
		case left:		turn_bottom();		break;
		case bottom:	turn_right();		break;
		case right:		turn_top();			break;
		default:							break;
		}
	}
private:
	enum stat{ top, left, bottom, right };
	inline void turn_top(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(1, -1);
		_stat = top;
	}
	inline void turn_left(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(1, 1);
		_stat = left;
	}
	inline void turn_bottom(){
		_offset[0].set(-1, 1);
		_offset[1].set(-1, 0);
		_offset[2].set(0, 0);
		_offset[3].set(1, 0);
		_stat = bottom;
	}
	inline void turn_right(){
		_offset[0].set(-1, -1);
		_offset[1].set(0, -1);
		_offset[2].set(0, 0);
		_offset[3].set(0, 1);
		_stat = right;
	}
	stat _stat;
};

#endif

S_cube.h
#ifndef _S_CUBE_H
#define _S_CUBE_H

#include"base_cube.h"

class S_cube : public base_cube
{
public:
	S_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		if (r == 1 || r == 3){
			_stat = vertical;
			turn_vertical();
		}
		else {
			_stat = horizontal;
			turn_horizontal();
		}
	}
	~S_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		if (_stat == horizontal)
			turn_vertical();
		else turn_horizontal();
	}
private:
	enum stat{ vertical, horizontal };
	inline void turn_horizontal(){
		_offset[0].set(0, 1);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(1, -1);
		_stat = horizontal;
	}
	inline void turn_vertical(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(1, 1);
		_stat = vertical;
	}
	stat _stat;
};

#endif

T_cube.h
#ifndef _T_CUBE_H
#define _T_CUBE_H

#include"base_cube.h"

class T_cube : public base_cube
{
public:
	T_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		switch (r){
		case 1: turn_top();		break;
		case 2: turn_left();	break;
		case 3: turn_bottom();	break;
		case 4: turn_right();	break;
		default:				break;
		}
	}
	~T_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		switch (_stat){
		case    top:	turn_left();		break;
		case   left:	turn_bottom();		break;
		case bottom:	turn_right();		break;
		case  right:	turn_top();			break;
		default	   :						break;
		}
	}
private:
	enum stat{ top, left, bottom, right };
	inline void turn_top(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(-1, 0);
		_stat = top;
	}
	inline void turn_left(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(0, -1);
		_stat = left;
	}
	inline void turn_bottom(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(1, 0);
		_stat = bottom;
	}
	inline void turn_right(){
		_offset[0].set(-1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(0, 1);
		_stat = right;
	}
	stat _stat;
};

#endif

Z_cube.h
#ifndef _Z_CUBE_H
#define _Z_CUBE_H

#include"base_cube.h"

class Z_cube : public base_cube
{
public:
	Z_cube(int x = 0, int y = 0) :base_cube(x, y)
	{
		auto r = Random4()();
		if (r == 1 || r == 3){
			_stat = vertical;
			turn_vertical();
		}
		else {
			_stat = horizontal;
			turn_horizontal();
		}
	}
	~Z_cube(){ base_cube::~base_cube(); }
	inline void turn() override {
		if (_stat == horizontal)
			turn_vertical();
		else turn_horizontal();
	}
private:
	enum stat{ vertical, horizontal };
	inline void turn_horizontal(){
		_offset[0].set(0, -1);
		_offset[1].set(0, 0);
		_offset[2].set(1, 0);
		_offset[3].set(1, 1);
		_stat = horizontal;
	}
	inline void turn_vertical(){
		_offset[0].set(1, 0);
		_offset[1].set(0, 0);
		_offset[2].set(0, 1);
		_offset[3].set(-1, 1);
		_stat = vertical;
	}
	stat _stat;
};

#endif

game.h
#ifndef _GAME_H
#define _GAME_H

#include
#include
#include
#include"I_cube.h"
#include"L_cube.h"
#include"O_cube.h"
#include"R_cube.h"
#include"T_cube.h"
#include"Z_cube.h"
#include"S_cube.h"

class game
{
public:
	game(int w = 16, int h = 24) :sleep_time(800),
		score(0), width(w), height(h), mtx(),cube(nullptr),
		win(std::vector<:vector>>(height, std::vector(width, false)))
	{
		makecube();
	}
	void start();
	bool Over();
	void keydown(char);
	void printwin();
private:
	void keylistener();
	bool touched();
	void insertwin();
	int fullline();
	void destroyline(int);
	bool outofboard(int,int);
	bool turn();
	bool move(int, int);
	void makecube();
	void setsleeptime(int i){
		if (sleep_time + i >= 100 &&
			sleep_time + i <=1500)
			sleep_time += i;
	}
private:
	int sleep_time;
	int score;
	int width, height;
	std::mutex mtx;
	base_cube * cube;
	std::vector<:vector>> win;
};

#endif

game.cpp
#include"game.h"
#include
#include
#include

void game::keylistener()
{
	char c;
	while (!Over()){
		c = _getch();
		mtx.lock();
			keydown(c);
			printwin();
		mtx.unlock();
	}
}

void game::printwin()
{
	system("cls");
	std::vector<:string> board(height, std::string(width * 2, ' '));
	std::string s = "■";
	for (int i = 0; i != 4; ++i){
		if (cube->x(i) >= 0){
			board[cube->x(i)][cube->y(i) * 2] = s[0];
			board[cube->x(i)][cube->y(i) * 2 + 1] = s[1];
		}
	}
	std::cout << "\t\t\t ";
	for (int i = 0; i <= width * 2 + 1; ++i)
		std::cout << "=";
	std::cout << std::endl;
	s = "□";
	for (int i = 0; i != height; ++i){
		for (int j = 0; j != width; ++j)
			if (win[i][j]){
				board[i][j * 2] = s[0];
				board[i][j * 2 + 1] = s[1];
			}
		std::cout << "\t\t\t||" << board[i]<< "||" << std::endl;
	}
	std::cout << "\t\t\t ";
	for (int i = 0; i <= width * 2 + 1; ++i)
		std::cout << "=";
	std::cout << std::endl;
	std::cout <			//      
		default:							break;
	}
}

bool game::touched()
{
	for (int i = 0; i != 4; ++i){
		int x = cube->x(i) + 1;
		int y = cube->y(i);
		if (x == height || win[x][y])
			return true;
	}
	return false;
}

void game::insertwin()
{
	for (int i = 0; i != 4; ++i){
		int x = cube->x(i);
		int y = cube->y(i);
		if (x >= 0)
			win[x][y] = true;
	}
}
int game::fullline()
{
	for (int j,i = 0; i != height; ++i){
		for (j = 0; j != width; ++j)
			if (!win[i][j])break;
		if (j == width){
			return i;
		}	
	}
	return -1;
}
void game::destroyline(int i)
{
	for (int k = i; k != 0;--k)
		for (int j = 0; j != width; ++j)
			win[k][j] = win[k-1][j];
	for (int k = 0; k != width; ++k)
		win[0][k] = false;
}

bool game::outofboard(int x, int y)
{
	if (y < 0 || x >= height || y >= width)
		return true;
	return false;
}
bool game::turn()
{
	cube->turn();
	for (int i = 0; i != 4; ++i)
		if (outofboard(cube->x(i), cube->y(i))){
			cube->turn(), cube->turn(), cube->turn();
			return false;
		}
	return true;
}
bool game::move(int x,int y)
{
	for (int i = 0; i != 4; ++i)
		if (outofboard(cube->x(i) + x, cube->y(i) + y))
			return false;
		else if (cube->x(i) + x>=0 && win[cube->x(i) + x][cube->y(i) + y])
			return false;
	cube->move(x, y);
	return true;
}
void game::makecube()
{
	auto r = Random7()();
	switch (r){
	case 1:delete cube; cube = new O_cube(0, width / 2); break;
	case 2:delete cube; cube = new T_cube(0, width / 2); break;
	case 3:delete cube; cube = new L_cube(0, width / 2); break;
	case 4:delete cube; cube = new R_cube(0, width / 2); break;
	case 5:delete cube; cube = new I_cube(0, width / 2); break;
	case 6:delete cube; cube = new Z_cube(0, width / 2); break;
	case 7:delete cube; cube = new S_cube(0, width / 2); break;
	default:break;
	}
}

食用方法:
main.cpp
#include"game.h"

int main()
{
	game g;
	g.start();
	return 0;
}