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对象,后期不容易修改.

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

(0)

相关推荐

  • C++制作俄罗斯方块

    缘起: 在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制.所以想自己再写一个. 程序效果: 主要内容: 程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分都存储1. 如下图: shape采用4*4数组(shape)保存.如: 0 0 0 0 0 1 0 0 1 1 1 0 0 0 0 0 另外用变量row和column保存shape数组左上角在board中的位置. 每次下落或左右移动,先对row和column做出改变,然后检测当前row和column

  • VC++ 6.0 C语言实现俄罗斯方块详细教程

    今天把我之前写的大作业分享一下吧,并教你们如何实现,希望你们看了前面的教程也能自己写一个. 1.要先下载一个 graphics.h 的头文件来绘图. 2.初始化窗口:initgraph(x, y);这是先创建一个窗口的函数,以左上角为(0,0),向右为x轴,向下为y轴,其中x表示长x个单位,y表示宽y个单位. 3.关闭图像窗口:closegraph();结束时用来关闭用的. 4.按任意键继续:getch();这个就和getchar();差不多,为了防止以运行完就关了,这样能停顿一下,他的头文件是

  • 使用C++一步步实现俄罗斯方块

    一.实验介绍 1.1 实验内容 本节实验我们进行设计俄罗斯方块前的思路分析,以及介绍ncurses 库的使用方法. 1.2 实验知识点 C++ 编程基础 ncurses 库的使用 俄罗斯方块逻辑设计 1.3 实验环境 xface 终端 g++ 编译器 ncurses 库 1.4 适合人群 本课程难度一般,适合有 C++ 编程基础,对游戏设计.逻辑分析感兴趣的同学. 1.5 代码获取 git clone https://github.com/Gamerchen/game_zero.git 二.开发

  • 使用C++一步步实现俄罗斯方块后续

    一.实验简介 1.1 实验内容 本节实验我们将实现俄罗斯方块主要函数的设计,完成基本功能并运行. 1.2 实验知识点 窗口的绘制 方块类的设计 旋转算法 移动.消除函数 1.3 实验环境 xface 终端 g++ 编译器 ncurses 库 1.4 编译程序 编译命令要加上 -l 选项引入 ncurses 库: g++ main.c -l ncurses 1.5 运行程序 ./a.out 1.6 运行结果 二.实验步骤 2.1 头文件 首先包含头文件以及定义一个交换函数和随机数函数,后面用到(交

  • C++俄罗斯方块游戏 无需图形库的俄罗斯方块

    本文实例为大家分享了C++俄罗斯方块游戏的具体实现代码,供大家参考,具体内容如下. #include<stdio.h> #include<stdlib.h> #include<windows.h> #include<time.h> #include<conio.h> #define MOD 28 #define SIZE_N 19 #define SIZE_M 12 int cur_x,cur_y; int score,mark,next,map

  • C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下 工具:vc++2010,图库:EasyX 先看效果图片 纯手写,没有面向对象思想,看全部源码 #include <stdio.h> #include <graphics.h> #include <time.h> #include <conio.h> #define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5

  • linux环境下C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块的具体代码,供大家参考,具体内容如下 本程序的运行环境是linux,用到了多线程.创建了一个用来绘图的线程和一个获取按键的线程.程序中有一些需要改善的地方,比如336-338行定义的全局变量以及声明的对象.本来声明的Block和Table对象应该在main函数里面,然后将这两个对象作为参数传递给线程函数getkey.但是好像只能传递一个对象参数给线程函数.希望高手能够对程序进行改进. ps:由于用到了多线程,而pthread不是linux的默认库,所以编译

  • C++实现俄罗斯方块(windows API)

    本文分享的这些俄罗斯方块代码是我最近放假在家里自己写的,虽然以前有过看别人写的代码,但是那个游戏代码好像不是很全面,因为无法实现全部的方块和实现随机的产生任意方向的方块,现在也基本上是忘光了当时的代码,下面的这些代码是我最近写的,没有参考其他人的代码,真正写俄罗斯方块起来感觉真的是挺难的,关键是在于方块的旋转.当然下面的代码仅仅是一个框架,只能够实现大致上的功能,还不全面,贴出来和大家交流学习. 编译器是code::block  +  MinGW ,感觉CB这个IDE真的是太强大,太棒了,下面的

  • C++控制台实现俄罗斯方块游戏

    之前学了些C++的课程,一直想着说编点小游戏,可是MFC又不想学,所以就只能变成控制台的小游戏. 俄罗斯方块一定是很多人小时候玩过的游戏.接下来就说说设计想法. 主要实现,选择游戏的等级,加速下降,不同形状不同颜色,暂停和退出功能. 首先是类的设计. class Box { private: int map[23][12];//画面坐标,记录有方块的点,也是游戏界面 int hotpoint[2];//当前活动的点,所有图形都是以此为基准绘制的 int top;//当前最高位置 int poin

  • Linux下用C++实现俄罗斯方块

    本文实例为大家分享了C++实现俄罗斯方块游戏代码,供大家参考,具体内容如下 1.block.c #include <stdio.h> #include <termios.h> #include <unistd.h> #include <stdlib.h> #include <setjmp.h> #include <sys/time.h> #include <string.h> #include "block.h&

随机推荐