神秘博客

纯C控制台俄罗斯方块

#ifndef _BLOCK_H_
#define _BLOCK_H_
#include <stdbool.h>
#define SIZE 26
#define SLEN 14
//游戏池占有状态
static int mblock[SIZE][SLEN] = {
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,0,0,0,0,0,0,0,0,0,0,0,0,1 },
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1 }
};
//保存每个位置方块颜色
static int colour[SIZE][SLEN]=
{
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 },
{ 7,7,7,7,7,7,7,7,7,7,7,7,7,7 }
};

//方块类型
static int block[7][4] = {
{ 0x0660, 0x0660, 0x0660, 0x0660 },  // 方块
{ 0x0072, 0x0262, 0x0270, 0x0232 },  // T
{ 0x0223, 0x0074, 0x0622, 0x0170 },  // L
{ 0x0226, 0x0470, 0x0322, 0x0071 },  // J
{ 0x0063, 0x0264, 0x0063, 0x0264 },  // Z
{ 0x006C, 0x0462, 0x006C, 0x0462 },  // S
{ 0x00F0, 0x2222, 0x00F0, 0x2222 },  // I
};

//游戏历史排行榜
typedef struct fraction
{
  int one;
  int two;
  int three;
} Fraction;

//游戏当前统计
typedef struct nowfraction
{
  int score;
  int grade;
  int difficulty;
} NowFraction;

//保存当前方块和下一个方块
typedef struct random
{
  int a;
  int b;
} Random;

//游戏暂停
static int PauseGame = 0;

//指定坐标打印
void gotoxy(int x, int y);

//初始化地图
void MapBlock();

//随机生成方块
void rollblock(Random *temp);

//打印下一个方块
void ShowBlock(int n, int m);

//移动方块
void MoveBlock(int n, int m, const NowFraction *pst);


//检测顶部满池
bool GameOver();


//游戏说明
void Explain(const NowFraction *pst1, const Fraction *pst2);

//满行消除
void CleanBlock(NowFraction *pst);

//写入分数
bool WriteScore(const NowFraction *pst1, Fraction *pst2);




#endif

#include <stdio.h>
#include <Windows.h>
#include <string.h>
#include "block.h"


void gotoxy(int x, int y) 
{
  COORD pos = { x,y };
  HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);// 获取标准输出设备句柄
  SetConsoleCursorPosition(hOut, pos);//两个参数分别是指定哪个窗体,具体位置
}

//游戏说明
void Explain(const NowFraction *pst1, const Fraction *pst2)
{
  gotoxy(40, 0);
  printf("历史排行榜:");
  gotoxy(44, 2);
  printf("第1名: %d", pst2->one);
  gotoxy(44, 4);
  printf("第2名: %d", pst2->two);
  gotoxy(44, 6);
  printf("第3名: %d", pst2->three);
  gotoxy(40, 8);
  printf("游戏说明:");
  gotoxy(44, 10);
  printf("控制: ↑ ↓ ← → 空格");
  gotoxy(40, 12);
  printf("游戏统计:");
  gotoxy(44, 14);
  printf("得分: %d", pst1->score);
  gotoxy(44, 16);
  printf("等级: %d", pst1->grade);
  gotoxy(44, 18);
  printf("难度: %d", pst1->difficulty);

  gotoxy(40, 20);
  printf("游戏状态: ");
  gotoxy(40, 24);
  printf("By:   Mr. Lei");

  
}

//初始化地图
void MapBlock()
{
  int i;

  for (i = 0; i < SIZE; i++)
  {
    gotoxy(0, i);	
    printf("■");
    gotoxy(26, i);
    printf("■");
  }
  for (i = 2; i < 26; i += 2)
  {
    gotoxy(i, 25);
    printf("■");
  }

  for (i = 30; i < 38; i += 2)
  {
    gotoxy(i, 0);
    printf("─");
    gotoxy(i, 6);
    printf("─");
  }
  gotoxy(28, 0);
  printf("┌");
  gotoxy(38, 0);
  printf("┐");
  gotoxy(28, 6);
  printf("└");
  gotoxy(38, 6);
  printf("┘");
  for (i = 1; i < 6; i++)
  {
    gotoxy(28, i);
    printf("│");
    gotoxy(38, i);
    printf("│");
  }

  gotoxy(0, SIZE);

}


//随机生成方块
void rollblock(Random *temp)
{
  static int count = 0;
  if (count == 0)
  {
    temp[0].a = rand() % 7;
    temp[0].b = rand() % 4;
    temp[1].a = rand() % 7;
    temp[1].b = rand() % 4;
    count++;
  }
  else
  {
    temp[0].a = temp[1].a;
    temp[0].b = temp[1].b;
    temp[1].a = rand() % 7;
    temp[1].b = rand() % 4;
  }

}

//打印下一个方块
void ShowBlock(int n, int m)
{
  int i, j;
  int x, y;
  int t;
  static int a, b;


  t = 0;
  for (i = 0, y = 0; i < 4; i++)
  {
    for (j = 0, x = 0; j < 4; j++)
    {
      gotoxy(36 - x, 4 - y);
      printf("  ");
      t++;
      x += 2;
    }
    y++;
  }
  t = 0;
  for (i = 0, y = 0; i < 4; i++)
  {
    for (j = 0, x = 0; j < 4; j++)
    {
      if (((block[n][m] >> t) & 01) == 1)
      {
        gotoxy(36 - x, 4 - y);
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n + 1);
        printf("■");
        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
      }
      x += 2;
      t++;
    }
    y++;
  }
  
}

//移动方块
void MoveBlock(int n, int m, const NowFraction *pst)
{
  int i, j;
  int x, y;
  int t;
  int Y;
  int count;
  int counttemp;
  int countline = 0;
  int countY = 0;
  int num = m;
  int line;
  line = 0;
  int speed = 400 - (pst->difficulty - 1) * 20;
  int templine = 0;  //保存左右移动用来检测是否可以移动
  int tempnum = m;

  for (Y = 0; Y < SIZE; Y++)
  {

    //清空上一行打印方块
    for (i = 0, y = 0, t = 0; i < 4; i++)
    {
      for (j = 0, x = 0; j < 4; j++)
      {
        if (Y - 1 - y < 0)
          break;
        if (((block[n][num] >> t) & 01) == 1)
        {
          gotoxy(16 + templine - x, Y - 1 - y);
          printf("  ");
        }
        t++;
        x += 2;
      }
      y++;
    }

    //按键检测
    if (GetAsyncKeyState(VK_UP))
    {
      tempnum = (tempnum + 1) % 4;
    }
    else if (GetAsyncKeyState(VK_LEFT) && Y >= 2)
    {
      line -= 2;
    }
    else if (GetAsyncKeyState(VK_RIGHT) && Y >= 2)
    {
      line += 2;
    }
    else if (GetAsyncKeyState(VK_SPACE))
    {
      speed = 10;
    }
    else if (GetAsyncKeyState(VK_RETURN) && PauseGame == 1)
    {
      PauseGame = 2;
    }
    //角度旋转碰撞检测
    if (tempnum != num)
    {

      for (i = 0, count = 0, y = 0, t = 0; i < 4; i++)
      {
        for (j = 0, x = 0; j < 4; j++)
        {
          if (Y - y < 0)
            break;
          if (((block[n][tempnum] >> t) & 01) == 1)
          {
            if (mblock[Y - y][(16 + templine - x) / 2] == 1)
              count++;
          }
          t++;
          x += 2;
        }
        y++;
      }
      if (count > 0)
      {
        tempnum = num;
      }
      else
        num = tempnum;
    }

    //平移碰撞检测
    if (templine != line)
    {
      Y--;
      
      if (countY == 0 || countline == 0)
        countY = Y;
      for (i = 0, count = 0, y = 0, t = 0; i < 4; i++)
      {
        for (j = 0, x = 0; j < 4; j++)
        {
          if (Y - y < 0)
            break;
          if (((block[n][num] >> t) & 01) == 1)
          {
            if (mblock[Y - y][(16 + line - x) / 2] == 1)
              count++;
            if ((16 + line - x) <= 0 || (16 + line - x) / 2 >= 13)
              count++;
          }
          t++;
          x += 2;
        }
        y++;
      }
      if (count > 0)
      {
        Y++;
        templine = templine;
        line = templine;
      }
      else
      {
        countline++;
        if (countline >= 1 && countY == Y)
        {
          speed = 50;
          countline = 0;
        }
        templine = line;

      }
    }
    //连续平移加速后恢复
    if (countY != Y && speed != 10)
      speed = 400 - (pst->difficulty - 1) * 20;

    

    //下一行检测碰撞如果检测到那么本行即为最后一行
    for (i = 0, count = 0, y = 0, t = 0; i < 4; i++)
    {
      for (j = 0, x = 0; j < 4; j++)
      {
        if (Y - y < 0)
          break;
        if (((block[n][num] >> t) & 01) == 1)
        {
          if (mblock[Y + 1 - y][(16 + templine - x) / 2] == 1)
            count++;
        }
        t++;
        x += 2;
      }
      y++;
    }
    //检测碰撞前的平移
    if (count > 0)
    {
      if (GetAsyncKeyState(VK_LEFT) && Y >= 2)
      {
        line -= 2;
      }
      else if (GetAsyncKeyState(VK_RIGHT) && Y >= 2)
      {
        line += 2;
      }
      if (templine != line)
      {
        for (i = 0, counttemp = 0, y = 0, t = 0; i < 4; i++)
        {
          for (j = 0, x = 0; j < 4; j++)
          {
            if (Y - y < 0)
              break;
            if (((block[n][num] >> t) & 01) == 1)
            {
              if (mblock[Y - y][(16 + line - x) / 2] == 1)
                counttemp++;
              if ((16 + line - x) <= 0 || (16 + line - x) / 2 >= 13)
                counttemp++;
            }
            t++;
            x += 2;
          }
          y++;
        }
        if (counttemp > 0)
        {
          templine = templine;
          line = templine;
        }
        else
        {
          templine = line;

        }
      }
    }
    //打印方块
    for (i = 0, y = 0, t = 0; i < 4; i++)
    {
      for (j = 0, x = 0; j < 4; j++)
      {
        if (Y - y < 0)
          break;
        if (((block[n][num] >> t) & 01) == 1)
        {
          if (count > 0)
          {
            if (Y - y >= 0)
            {
              mblock[Y - y][(16 + templine - x) / 2] = 1;
              colour[Y - y][(16 + templine - x) / 2] = n + 1;
            }
          }
          gotoxy(16 + templine - x, Y - y);
          SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n + 1);
          printf("■");
          SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), 7);
        }
        t++;
        x += 2;
      }
      y++;
    }
    //检测到下一行有碰撞直接结束循环
    if (count > 0)
      return;

    //游戏状态
    if (PauseGame == 0)
    {
      gotoxy(52, 20);
      printf("请按Enter键开始");
      while (1)
      {
        if (GetAsyncKeyState(VK_RETURN) && PauseGame == 0)
        {
          PauseGame = 1;
          break;
        }
      }
      gotoxy(0, SIZE);
      printf("                    ");
      PauseGame = 1;
    }
    else if (PauseGame == 1)
    {
      gotoxy(52, 20);
      printf("游戏运行中     ");
      gotoxy(52, 22);
      printf("Enter键暂停游戏");
      gotoxy(0, SIZE);
    }
    else if (PauseGame == 2)
    {
      gotoxy(52, 20);
      printf("游戏暂停中    ");
      gotoxy(52, 22);
      printf("Enter键开始游戏");
      while (1)
      {
        if (GetAsyncKeyState(VK_RETURN) && PauseGame == 2)
        {
          PauseGame = 1;
          break;
        }
      }
      gotoxy(0, SIZE);
      printf("                    ");
      PauseGame = 1;
    }

    if (GetAsyncKeyState(VK_DOWN))
    {
      Sleep(80);
    }
    else
      Sleep(speed);

    gotoxy(0, SIZE);
    
  }
  
}

//检测顶部满池
bool GameOver()
{
  int i;

  for (i = 1; i < 13; i++)
  {
    if (mblock[0][i] == 1)
      return false;
  }
  return true;
}

//满行消除
void CleanBlock(NowFraction *pst)
{
  int i, j;
  int Count;
  int tot;
  int Line[SIZE - 1];
  int x;
  int z;

  for (i = SIZE - 2, Count = 0; i >= 0; i--)
  {
    for (j = 1, tot = 0; j < 13; j++)
    {
      if (mblock[i][j] == 1)
        tot++;
    }
    if (tot == 12)
    {
      Line[Count] = i;
      Count++;
    }
  }
  if (Count > 0)
  {
    if (Count == 4 || Count == 1)
    {
      memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
      memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
      for (i = Count - 1; i >= 0; i--)
      {
        for (j = 1; j < 13; j++)
        {
          mblock[i][j] = 0;
          colour[i][j] = 7;
        }
      }
      
    }
    else if (Count == 2)
    {
      if (Line[0] - 1 == Line[1])
      {
        memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
        memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
        for (i = Count - 1; i >= 0; i--)
        {
          for (j = 1; j < 13; j++)
          {
            mblock[i][j] = 0;
            colour[i][j] = 7;
          }
        }
      }
      else
      {
        for (z = 0; z < Count; z++)
        {
          memmove(mblock[1], mblock[0], (Line[z] + 1 - 1)*SLEN * sizeof(int));
          memmove(colour[1], colour[0], (Line[z] + 1 - 1)*SLEN * sizeof(int));
          for (j = 1; j < 13; j++)
          {
            mblock[0][j] = 0;
            colour[0][j] = 7;
          }
        }
        
      }
    }
    else
    {
      if (Line[0] - 1 == Line[1] && Line[1] - 1 == Line[2])
      {
        memmove(mblock[Count], mblock[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
        memmove(colour[Count], colour[0], (Line[0] + 1 - Count)*SLEN * sizeof(int));
        for (i = Count - 1; i >= 0; i--)
        {
          for (j = 1; j < 13; j++)
          {
            mblock[i][j] = 0;
            colour[i][j] = 7;
          }
        }
      }
      else if (Line[0] - 1 == Line[1] && Line[1] - 1 != Line[2])
      {
        memmove(mblock[2], mblock[0], (Line[0] + 1 - 2)*SLEN * sizeof(int));
        memmove(colour[2], colour[0], (Line[0] + 1 - 2)*SLEN * sizeof(int));
        for (i = 1; i >= 0; i--)
        {
          for (j = 1; j < 13; j++)
          {
            mblock[i][j] = 0;
            colour[i][j] = 7;
          }
        }
        memmove(mblock[1], mblock[0], (Line[2] + 1 - 1)*SLEN * sizeof(int));
        memmove(colour[1], colour[0], (Line[2] + 1 - 1)*SLEN * sizeof(int));
        for (i = Line[2]; i >= 0; i--)
        {
          for (j = 1; j < 13; j++)
          {
            if (i - 1 < 0)
              break;
            mblock[i][j] = mblock[i - 1][j];
            colour[i][j] = colour[i - 1][j];
          }
        }
        for (j = 1; j < 13; j++)
        {
          mblock[0][j] = 0;
          colour[0][j] = 7;
        }
      }
      else if (Line[0] - 1 != Line[1] && Line[1] - 1 == Line[2])
      {
        memmove(mblock[1], mblock[0], (Line[0] + 1 - 1)*SLEN * sizeof(int));
        memmove(colour[1], colour[0], (Line[0] + 1 - 1)*SLEN * sizeof(int));
        for (j = 1; j < 13; j++)
        {
          mblock[0][j] = 0;
          colour[0][j] = 7;
        }
        memmove(mblock[2], mblock[0], (Line[1] + 1 - 2)*SLEN * sizeof(int));
        memmove(colour[2], colour[0], (Line[1] + 1 - 2)*SLEN * sizeof(int));
        for (i = 1; i >= 0; i--)
        {
          for (j = 1; j < 13; j++)
          {
            mblock[i][j] = 0;
            colour[i][j] = 7;
          }
        }
      }
    }

    

    for (i = Line[0]; i >= 0; i--)
    {
      for (j = 1, x = 2; j < 13; j++)
      {
        if (mblock[i][j] == 1)
        {
          gotoxy(x, i);
          SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), colour[i][j]);
          printf("■");
          SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
        }
        else
        {
          gotoxy(x, i);
          printf(" ");
        }
        x += 2;
      }
    }
    pst->score += Count * 10;
    pst->grade = pst->score / 100 + 1;
    pst->difficulty = pst->score / 150 + 1;
  }


}

//写入分数
bool WriteScore(const NowFraction *pst1, Fraction *pst2)
{
  bool judge;

  if (pst1->score > pst2->one&&pst1->score > pst2->two&&pst1->score > pst2->three)
  {
    pst2->three = pst2->two;
    pst2->two = pst2->one;
    pst2->one = pst1->score;
    judge = true;
  }
  else if (pst1->score <= pst2->one&&pst1->score > pst2->two&&pst1->score > pst2->three)
  {
    pst2->three = pst2->two;
    pst2->two = pst1->score;
    judge = true;
  }
  else if (pst1->score <= pst2->one&&pst1->score <= pst2->two&&pst1->score > pst2->three)
  {
    pst2->three = pst1->score;
    judge = true;
  }
  else
    judge = false;

  return judge;
}

 

 

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "block.h"



int main()
{
  Random roll[2];
  NowFraction last1 = { 0,1,1 };
  Fraction last2;
  errno_t err;
  FILE *fp;

  //如果没有数据文件,则创建新文件并初始化结构数据写入文件
  while ((err = fopen_s(&fp, "data.dat", "rb")) != 0)
  {
    if ((err = fopen_s(&fp, "data.dat", "wb")) != 0)
    {
      fputs("错误: 创建数据文件失败\n", stderr);
      exit(EXIT_FAILURE);
    }
    last2.one = last2.two = last2.three = 0;
    fwrite(&last2, sizeof(Fraction), 1, fp);
    fclose(fp);
  }
  rewind(fp); //设置文件开头
  fread(&last2, sizeof(Fraction), 1, fp);  //读取文件数据
  srand((unsigned int)time(0)); //随机种子
  //地图初始化
  MapBlock();

  while (1)
  {
    Explain(&last1, &last2);
    rollblock(roll);
    ShowBlock(roll[1].a, roll[1].b);
    MoveBlock(roll[0].a, roll[0].b, &last1);
    CleanBlock(&last1);
    if (!GameOver())
    {
      if (WriteScore(&last1, &last2))
      {
        fclose(fp);
        if ((err = fopen_s(&fp, "data.dat", "wb")) != 0)
        {
          fputs("错误: 创建数据文件失败\n", stderr);
          exit(EXIT_FAILURE);
        }
        fwrite(&last2, sizeof(Fraction), 1, fp);
      }
      gotoxy(52, 20);
      printf("游戏结束, 按任意键退出游戏");
      gotoxy(0, 27);
      break;
    }
  }
  //关闭文件
  fclose(fp);
  system("pause");
  return 0;
}

 

版权说明:
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注

觉得文章有用就请我吃包辣条吧

微信扫一扫打赏