控制台小游戏之俄罗斯方块

因为最近在学多线程,用的C++新标准的thread库,就尝试简单用了一下,写进俄罗斯方块里监听键盘输入。


基本的思路就是用一个类代表一种方块,方块类中用一个坐标pos表示方块位置,然后一个坐标数组offset代表方块的各个小方格相对于pos的偏移量。加上两个生成随即数的可调用对象的类来随机生成方块。

棋子类base_cube是个虚基类,另外有七个类都继承自base_cube :O_cube,  I_cube, L_cube, R_cube, S_cube, Z_cube 和 T_cube;分别代表七种方块。然后用一个game类封装起来。

make_random.h


#ifndef _MAKE_RANDOM_H
#define _MAKE_RANDOM_H

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

base_cube.h


#ifndef _BASE_CUBE_H
#define _BASE_CUBE_H

#include<vector>
#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<string>
#include<mutex>
#include<Windows.h>
#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<std::vector<bool>>(height, std::vector<bool>(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<std::vector<bool>> win;
};

#endif



game.cpp


#include"game.h"
#include<conio.h>
#include<thread>
#include<iostream>

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

void game::printwin()
{
	system("cls");
	std::vector<std::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 <<"\t\t\t\t    SCORE:"<< score << std::endl;
}
bool game::Over()
{
	for (int i = 0; i != width; ++i)
		if (win[0][i])
			return true;
	return false;
}

void game::start()
{
	std::thread t(&game::keylistener,this);
	t.detach();
	while (!Over()){
		Sleep(sleep_time);
		move(1, 0);
		mtx.lock();
			printwin();
		mtx.unlock();
		if (touched()){
			insertwin();
			makecube();
			mtx.lock();
				printwin();
			mtx.unlock();
		}
		int i = fullline();
		while (i != -1){
			destroyline(i);
			++score;
			mtx.lock();
				printwin();
			mtx.unlock();
			i = fullline();
		}
	}
	mtx.lock();
		printwin();
	mtx.unlock();
	std::cout << "\t\t\t\t    GAMEOVER!" << std::endl;
}

void game::keydown(char c)
{
	switch (c){
		case'w':turn();		  				break;
		case'a':move(0,-1);					break;
		case's':move(1, 0);					break;
		case'd':move(0, 1);					break;
		case' ':system("pause");			break;
		case']':setsleeptime(100);			break;
		case'[':setsleeptime(-100);			break;
		case'q':++score;			break;<span style="white-space:pre">			</span>//作弊你咬我呀
		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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值