因为最近在学多线程,用的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
#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
#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;
}