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

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

本程序的运行环境是linux,用到了多线程。创建了一个用来绘图的线程和一个获取按键的线程。程序中有一些需要改善的地方,比如336-338行定义的全局变量以及声明的对象。本来声明的Block和Table对象应该在main函数里面,然后将这两个对象作为参数传递给线程函数getkey。但是好像只能传递一个对象参数给线程函数。希望高手能够对程序进行改进。

ps:由于用到了多线程,而pthread不是linux的默认库,所以编译的时候需要指定线程库。即:g++ -o block -lpthread block.cpp

#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <time.h> 

#include<termios.h>
#include<fcntl.h> 

#define TABLE_SIZE 20
#define BLOCK_SIZE 4
#define SLEEP_TIME 500 

using namespace std; 

struct grid{int x; int y;};    //坐标 

/////////////////////Block 类//////////////////////
class Block
{
public:
  enum direct{UP, DOWN, LEFT, RIGHT};         //定义方向
  grid g[BLOCK_SIZE];                 //方块的坐标信息 

  void def_block(grid g1, grid g2, grid g3, grid g4); //定义方块
  void rotate();                   //旋转方块
  void move(int dir);                 //移动方块
  void set_cen(grid g);                //设置方块旋转中心
  grid get_cen();                   //获取方块旋转中心
  void set_type(int t);                //设置方块种类
  int get_type();                   //获取方块种类
  void back();                    //旋转还原
  void creat_block(int x, int y);           //随机生成方块 

private:
  grid center;                    //方块旋转中心
  int type;                      //方块类型 

}; 

void Block::def_block(grid g1, grid g2, grid g3, grid g4) {
  g[0]=g1; g[1]=g2; g[2]=g3; g[3]=g4;
} 

void Block::rotate() {
  int x, y, i=0; 

  for(i; i<=3; 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 Block::move(int dir) {
  int d=dir, i=0; 

  switch(d) {
  case UP: {
    for(i; i<=3; i++) g[i].y++;
    center.y++; break;
       }
  case DOWN: {
    for(i; i<=3; i++) g[i].y--;
    center.y--; break;
        }
  case LEFT: {
    for(i; i<=3; i++) g[i].x--;
    center.x--; break;
        }
  case RIGHT: {
    for(i; i<=3; i++) g[i].x++;
    center.x++; break;
        }
  }
} 

void Block::set_cen(grid g) {
  center=g;
} 

grid Block::get_cen() {
  return center;
} 

void Block::set_type(int t) {
  type=t;
} 

int Block::get_type() {
  return type;
} 

void Block::back() {
  int x, y, i=0; 

  for(i; i<=3; 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 Block::creat_block(int x, int y) {  //随机创建方块
  int ran;
  grid g[BLOCK_SIZE]; 

  ran=1+rand()%7;
  switch(ran) {
  //L
  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: ;
  }
  def_block(g[0], g[1], g[2], g[3]);
} 

///////////////////////////////////////// 

////////////////////Table 类//////////////////////
class Table
{
public: 

  Table() {             //构造棋盘
    height=20; width=10; count=0;
    init_table();
  }
  Table(int x, int y);
  int set_block(Block bl);     //安设方块
  void clr_block(Block bl);     //清除方块
  int clr_line(int y);       //消行
  int get_h();           //获取棋盘高度
  int get_w();           //获取棋盘宽度
  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();         //获取得分 

private:
  int table[TABLE_SIZE][TABLE_SIZE];//棋盘
  int height, width;        //棋盘的高和宽
  int count;            //得分 

  void init_table();        //棋盘初始化 

}; 

void Table::init_table() {
  int i=0, j=0; 

  for(i; i<width; i++) {
    for(j=0; j<height; j++) {
      table[i][j]=0;
    }
  }
} 

Table::Table(int x, int y) {
  height=y; width=x; count=0;
  init_table();
} 

int Table::set_block(Block bl) {
  int x, y;
  int i;
  for(i=0; i<=3; i++) {
    x=bl.g[i].x; y=bl.g[i].y;
    if(table[x][y]!=0 || x>=width || x<0 || y>=height || y<0) {
      return 0;
    }
  }
  for(i=0; i<=3; i++) {
    x=bl.g[i].x; y=bl.g[i].y;
    table[x][y]=1;
  }
  return 1;
} 

void Table::clr_block(Block bl) {
  int x, y; 

  for(int i=0; i<=3; 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 0;
  for(int i=0; i<width; i++) {
    table[i][y]=0;
  }
  return 1;
} 

int Table::get_h() {
  return height;
} 

int Table::get_w() {
  return width;
} 

int Table::if_full(int y) {
  int i=0; 

  for(i; 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; 

  for(i=0; i<width+2; i++) cout<<"-"<<flush;
  cout<<"\n"<<flush;
  for(i=height-1; i>=0; i--) {
    cout<<"|"<<flush;
    for(j=0; j<width; j++) {
      if(table[j][i]==0) cout<<" "<<flush;
      else cout<<"▣"<<flush;
    }
    if(i==10)
      cout<<"|  得分:"<<get_count()<<endl;
    else if(i==7)
      cout<<"|  Press 'q' to quit!"<<endl;
    else
      cout<<"|"<<endl;
  }
  for(i=0; i<width+2; i++) cout<<"-"<<flush;
  cout<<"\n"<<flush;
  //cout<<"得分:"<<get_count()<<endl;
} 

void Table::move_line(int y) {
  int i, j; 

  for(i=y; i<height-1; i++) {
    for(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;
} 

///////////////////////////////////////////////////////
class Mythread
{
public:
  void init();
  static void *getkey(void *arg);//线程函数在类里面定义必须定义为static型,以去除类指针。
  static void *paint_loop(void *arg);
}; 

void Mythread::init()
{
  pthread_t ntid,ntid2;
  int err,err2;
  err = pthread_create(&ntid,NULL,getkey,NULL);
  err2 = pthread_create(&ntid2,NULL,paint_loop,NULL);
  if(err != 0 || err2 != 0){
    cout<<"can't create thread!"<<endl;
    exit(0);
  }
} 

unsigned char flag=1,buf[2];//全局变量
Table tab(15, 20); //构造一个15,20的棋盘
Block bl;      //构造一个落下方块
void* Mythread::paint_loop(void *arg)
{
  while(1)
  {
    system("clear");
    tab.paint();
    usleep(50000);    //暂停50 MS
  }
}
void* Mythread::getkey(void *arg)
{
  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_sec=0;
  tv.tv_usec=0;
  while(1)
  {
    read(0,buf,1);
    r=select(fd+1,&rfds,NULL,NULL,&tv);
    if(r<0)
    {
      write(1,"select() error.\n",16);
    }
    rfds=rs;
    if(flag==2||buf[0]==113)//游戏结束或者用户按下'q'键,则程序退出
    {
      tcsetattr(0,TCSANOW,&saveterm);
      exit(0);
    }
    if(buf[0]<=68&&buf[0]>=65) flag=0;//如果按的键是方向键,则将标志位置0并执行相应的处理.
    if(flag==0)
    {
      if(buf[0]==65) {
      //if(dir!=0) {
        if(bl.get_type()==5) continue; //如果出现田字形则不作旋转
        tab.clr_block(bl);      //清空方块上一次位置
        bl.rotate();         //开始旋转
        if(!tab.set_block(bl)) {   //将旋转后的方块写在棋盘上
          bl.back();       //如果写失败(例如到边线了,或卡住了)则还原旋转前位置
          continue;
          tab.set_block(bl);
        }
      }
      //下(加速下落)
      //dir=GetAsyncKeyState(VK_DOWN);  //获取向下
      if(buf[0]==66) {
        tab.clr_block(bl);     //清空方块上一次位置
        bl.move(bl.DOWN);      //向下移动一步
        if(!tab.set_block(bl)) {  //将移动后的方块写在棋盘上
          bl.move(bl.UP);     //如果失败,则还原到移动前的位置(即上移一步)
          tab.set_block(bl);
        }
      }
      //左(左移)
      //dir=GetAsyncKeyState(VK_LEFT);
      if(buf[0]==68) {
        tab.clr_block(bl);
        bl.move(bl.LEFT);
        if(!tab.set_block(bl)) {
          bl.move(bl.RIGHT);
          tab.set_block(bl);
        }
      }
      //右(右移)
      //dir=GetAsyncKeyState(VK_RIGHT);
      if(buf[0]==67) {
        tab.clr_block(bl);
        bl.move(bl.RIGHT);
        if(!tab.set_block(bl)) {
          bl.move(bl.LEFT);
          tab.set_block(bl);
        }
      }
      flag=1;
    }
  }
  tcsetattr(0,TCSANOW,&saveterm);
} 

////////////主函数部分/////////////////////// 

int main()
{
  //Table tab(15, 20); //构造一个15,20的棋盘
  //Block bl;      //构造一个落下方块
  Mythread thread;
  thread.init();
  int dir,i,c;
  while(true) {
    //生成方块
    srand(time(0));
    bl.creat_block(tab.get_w(), tab.get_h());
    //判断游戏是否结束
    if( !tab.set_block(bl) ) {
      system("clear");
      cout<<"GAME OVER!"<<endl;
      flag=2;
      cout<<"PRESS ANY KEY TO CONTINUE!"<<endl;
      while(1);
    }
    ///////////行动按键判定
    while(true){
      usleep(500000);    //暂停500 MS
      /////////////向下移动一格
      tab.clr_block(bl);    //清空上一次方块位置
      bl.move(bl.DOWN);    //向下移动一步
      if(!tab.set_block(bl)) {   //是否触底
        bl.move(bl.UP);    //如果触底,还原触底前位置
        tab.set_block(bl);
        break;
      }
    }
    //如果满行则消行
    for(i=0; i<tab.get_h(); i++) {
      if(tab.if_full(i)) { //是否满行
        tab.clr_line(i); //如果是,消行
        tab.move_line(i); //将所消行的上面的棋盘信息下移
        i--;      //下移后,重新检查这一行是否满(可能出现几行同时消去)
        tab.set_count(100); //记录得分
      }
    } 

  }
  return 0;
} 

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

(0)

相关推荐

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

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

  • 使用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 头文件 首先包含头文件以及定义一个交换函数和随机数函数,后面用到(交

  • 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++实现俄罗斯方块(windows API)

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

  • 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&

  • 使用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++俄罗斯方块游戏 无需图形库的俄罗斯方块

    本文实例为大家分享了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++制作俄罗斯方块

    缘起: 在玩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

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

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

  • Linux 环境下编译安装MySQL5.6的笔记记录

    一.首先搭建好Linux环境,我这边使用的是redhat enterprise 6.5,并且建议磁盘划分逻辑卷,以便后期的扩容工作. 二.环境搭建好了之后,我们就要去准备MySQL的安装文件,到现在为止mysql仍然是免费开源,可以直接在官网下载,大家可以自行访问官网去下载, 网址是:https://www.mysql.com/downloads/ ,当然下载前大家需要先去注册一个Oracle账户,然后选择社区免费版进行下载. 三.安装依赖包以及cmake编译工具 yum install -y

  • 浅谈Linux环境下gcc优化级别

    代码优化可以说是一个非常复杂而又非常重要的问题,以笔者多年的linux c开发经验来说优化通常分为两个方面,一是人为优化,也就是基于编程经验采用更简易的数据结构函数等来降低编译器负担,二是采用系统自带的优化模式,也就是gcc - o系列,下面我将简述一下各级优化的过程以及实现. gcc - o1 首先o1上面还有一个o0,那个是不提供任何优化,项目中几乎不会使用,而o1使用就非常广泛了,o1是最基本的优化,主要对代码的分支,表达式,常量来进行优化,编译器会在较短的时间下将代码变得更加短小,这样体

  • Linux环境下nodejs的安装图文教程

    1.在官网下载nodejs,选择左边的. 2.选择文件右击点击extract here进行解压 3.进入bin目录,右击选择properties,解压文件可以随意放在系统里一个位置.复制location里的路径 4.添加路径 进入.bashrc文件,在末尾处添加步骤三的location里的路径. 6.在终端输入source .bashrc按回车键,再输出路径:echo $PATH检查路径是否已经添加成功 7.检测是否安装nodejs成功.在js文件目录下点击右键,再点击open in termi

  • Linux环境下python2.7.6升级python3.5.2

    需求 Linux环境下有些是自带的Python2版本有时是刚安装号的Python其他版本,当新版本出来的时候,在开发的时候往往会选择新版本的软件进行安装. 原因 在开发的时候选用新版本的软件进行安装的时候,出于以下角度来考虑的. 老版本的一些第三方软件库会随着新版本软件的更新,老本版所支持的第三方库就没有人去维护和更新了,后面在使用的过程中,如果出现了bug,就会花很大的精力去解决. 步骤 基于上面的要求,我将生产虚机上的ython2.7.6升级python3.5.2,主要步骤如下所示: 去py

  • Linux环境下php实现给网站截图的方法

    本文实例讲述了Linux环境下php实现给网站截图的方法.分享给大家供大家参考,具体如下: 第一步:下载wkhtmltopdf 复制代码 代码如下: [root@iZ94aawoublZ ~]# wget http://download.gna.org/wkhtmltopdf/0.12/0.12.3/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz 第二步:解压 复制代码 代码如下: [root@iZ94aawoublZ ~]# xz -d wkhtmlto

  • Linux环境下段错误的产生原因及调试方法小结

    最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的"段错误"(Segmentation Fault).借此机会系统学习了一下,这里对Linux环境下的段错误做个小结,方便以后同类问题的排查与解决. 1. 段错误是什么 一句话来说,段错误是指访问的内存超出了系统给这个程序所设定的内存空间,例如访问了不存在的内存地址.访问了系统保护的内存地址.访问了只读的内存地址等等情况.这里贴一个

  • PHPExcel在linux环境下导出报500错误的解决方法

    原先我导出为 XLSX 格式,用的是 $objWriter = IOFactory::createWriter($objPHPExcel, 'Excel2007'); 报错,纠结就纠结在,在开发环境和测试环境都没问题,放在生产环境直接 500 错误. 后来我改成导出 XLS 格式, $objWriter = IOFactory::createWriter($objPHPExcel, 'Excel5'); 问题解决了,具体为什么待有空了研究下!!! 以上这篇PHPExcel在linux环境下导出报

  • windows及linux环境下永久修改pip镜像源的方法

    一.在windows环境下修改pip镜像源的方法(以python3.5为例) (1):在windows文件管理器中,输入 %APPDATA% (2):会定位到一个新的目录下,在该目录下新建pip文件夹,然后到pip文件夹里面去新建个pip.ini文件 (3):在新建的pip.ini文件中输入以下内容,搞定 [global] timeout = 6000 index-url = http://pypi.douban.com/simple trusted-host = pypi.douban.com

  • script_tool_for_linux.bash: Linux 环境下的 hosts 一键部署脚本

    Linux 环境下的 hosts 一键部署脚本,由 @lstoars 贡献; @fluviusmagnus 提供增强版本. 官方网站:https://github.com/racaljk/hosts/tree/master/hosts_tools #!/bin/sh # # script_tool_for_linux # # Use command: `sudo sh script_tool_for_linux.sh` or # `su -c 'sh script_tool_for_linux.

随机推荐