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

来源:互联网 发布:ubuntu apt get jdk8 编辑:程序博客网 时间:2024/05/16 16:10

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




0 0