首页 > 编程语言 > C++实现俄罗斯方块(linux版本)
2020
10-08

C++实现俄罗斯方块(linux版本)

本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下

主程序

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

积累的经验:

1.生成随机数的uniform_int_distribution,defualt_random_engine(time(0))使用时必须用static,缺点是多次执行程序的第一次生成的数字是一样的

2.与c++primer p743类似,使用成员指针函数表可以使用户调用的函数更加明了。

3.给互斥锁加权值,并以权值大小顺序加锁,可以保证线程加锁顺序一致,避免死锁(出现则抛出异常)(这个纯粹活学活用,因为c++锁和线程接触不多)

4.thread xxx([&](){})是可以放在函数内部的线程

5.利用select监控标准输入

6.利用tcgetattr,tcsetaddr,termiosi结构体
nt.c_lflag &= ~ECHO; nt.c_lflag &= ~ISIG; nt.c_lflag &= ~ICANON;
可以在linux关闭回显,实现getch

7.this_thread::sleep_for(std::chrono::milliseconds(400 / tab.getLevel()));可以咋线程中实现毫秒级别睡眠

8.类中静态对象初始化可以写在其对应.cpp文件中

反思:

未使用类的继承,各种方块理论可以写成子类,因为主线程一开始直接使用了Block对象,后期不容易修改.

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持自学编程网。

编程技巧