【C++】2048游戏系列---功能模块第三稿【添加新数】

2048游戏系列---功能模块第三稿【添加新数】

(更新中……)
参考博客:https://blog.csdn.net/qq_39151563/article/details/104283217
由于放在一篇会导致篇幅太长,所以分成了几个部分。
(可能有个10篇吧=.=)

前几篇:
2048游戏系列—总览篇
2048游戏系列—功能模块第一稿【矩阵操作】
2048游戏系列—功能模块第二稿【键盘输入】
本篇介绍如何根据条件生成新的数字

一、判断一下是否要添加

  1. 在我们添加新数之前,要判断一下是否要添加,例如下列矩阵 grid 向上滑动时,移动前后并没有变化,因此也不需要添加新数:

    int grid[4][4] = {
    	{0,1,2,3},
    	{0,0,0,0},
    	{0,0,0,0},
    	{0,0,0,0}
    };
    
  2. 如何判断移动是否有效,这提供两种思路:
    2.1将 grid 移动前后的每个元素进行比较:如果每个元素都一样,则可以判断移动无效,反之,只要有一个元素不同,则移动有效。(此逻辑在主函数中实现

    2.2.在移动过程中判断:如果移动了数字,则移动有效,反之,移动无效。(此逻辑在 Move() 函数中实现

二、添加新数逻辑

在知道移动有效后,添加新数的逻辑如图:添加新数流程图

2.1 找到一个空位

  1. 如果 EmptyBlock = 0,已经没有空位了
  2. 利用 EGE 的 random 函数
random(n);//返回一个 0 ~ n-1 的整数

假设 grid 如下:

int grid[4][4] = {
	{0,1,2,3},
	{0,0,0,0},
	{0,0,0,0},
	{0,0,0,0}
};

EmptyBlock应为 16-3=13,所以我们有13个位置可选择,random(EmptyBlock)+1正好随机返回 1~13 中的一个整数

2.2 代码

(小知识点:多维数组在计算机存储中是映射成一维的)

//添加新数
//有很多调试注释可以删掉
void addnum(int n)
{	
	while(n--)//添加n个
	{
		EmptyBlock = CalculateEmpty();
		//cout << "addnum Test" << endl;
		if(EmptyBlock<=0)	
		{
			//cout << "addnum EmptyBlock = " << EmptyBlock << endl; 
			//cout << "addnum Test1" << endl;
			return;	
		}
		int cnt = random(EmptyBlock)+1;//随机得到一个空格数以内的数	
		//cout << "找到第" << cnt << "个空位" << endl; 
		//cout << "cnt = " << cnt << endl;

		int *p = &grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++ 
		//cout << "n = "<< n <<endl;
		for(int i=0; i<4&&cnt; i++)
			for(int j=0; j<4&&cnt; j++)
			{
				if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效	
				{
					//cout << "cnt = " << cnt << endl;
					cnt--;//找到一个划一个
				}
                p++;//p 指向下一个再进行判断
			}
        //循环结束时 p 指向我们之前随机指定的空格
		*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
		//cout << "插入成功" << endl; 
		//*p = (random(10)==0)+1;//这样写也可以
		EmptyBlock--;
	}
}

测试代码:添加新数测试代码

测试结果(成功在随机位置添加了2个数):添加新数测试结果

三、整合到上篇的代码中

3.1 程序的小改动

  1. 矩阵置0

    int grid[4][4] = {0};//矩阵置0
    
  2. ShowInfo()打印信息函数

    //显示信息-将一些要打印的信息集中
    void ShowInfo()
    {
    	cout << "dir = " << dir << endl;
        cout<< "EmptyBlock = " << CalculateEmpty() << endl;
        PrintGrid();
    } 
    
  3. 判断移动是否有效(用的第一种思路)

   bool flag = false;    //移动标志位 
   int tempGrid[4][4];	 //暂存数组 
   int i,j; 
   for(i=0;i<4;i++)
   	for(j=0;j<4;j++)
   		tempGrid[i][j] = grid[i][j];	
//			cout << "tempGrid[4][4] = " << endl;	
//			for(i=0; i<4; i++)
//		    {
//		        for(j=0; j<4; j++)
//		            cout << tempGrid[i][j] << " ";
//		        cout << endl;
//		    }
//		    cout << endl;	
			Move(dir);//移动
			//比较 
			for(i=0; i<4; i++)
				for(j=0; j<4; j++)
					if(grid[i][j]!=tempGrid[i][j])	
					{
						flag = true;
						break;
					} 
			if(flag)	
            {
                addnum(1);
            	cout << "有效移动" << endl;
            }
			//else	cout << "无效移动" << endl;					 
			ShowInfo(); 
			dir = -1;//将 dir 置为无效,否则控制台会一直刷新 

3.2 所有代码!

#include <iostream>
#include "graphics.h"
using namespace std;
//测试矩阵 
int grid[4][4] = {0
//    {1,2,3,4},
//    {4,5,6,7},
//    {7,8,9,10},
//    {1,1,1,0}
};

int EmptyBlock = 4 ;	//空格数 
int dir = -1;				// 0-左,1-上,2-右,3-下 
//打印函数 
void PrintGrid()
{
    for(int i=0; i<4; i++)
    {
        for(int j=0; j<4; j++)
            cout << grid[i][j] << " ";
        cout << endl;
    }
    cout << endl;
}
//计算空格函数 
int CalculateEmpty()
{
    int cnt = 0;
    for(int i=0; i<4; i++)
        for(int j=0; j<4; j++)
            if(grid[i][j]==0)   cnt++;
    return cnt;
}


//显示信息
void ShowInfo()
{
	cout << "dir = " << dir << endl;
    cout<< "EmptyBlock = " << CalculateEmpty() << endl;
	cout << "grid[4][4] = " << endl;
	PrintGrid();
} 

//移动函数 
static int x0[4] = {0, 0, 3, 0};
static int y0[4] = {0, 0, 0, 3};
static int firstOffset[4][2]  = {{1,0},{0,1},{-1,0},{0,-1}};
static int secondOffset[4][2] = {{0,1},{1,0},{0,1} ,{1,0}};
void Move(int dir)
{
	//bool moved = false; 
	if(dir==-1)	return;
    int tx, ty;
    int t1x, t1y;
    int t2x, t2y;
    for(int i=0; i<4; i++)
    {
    	
        tx = x0[dir] + i*secondOffset[dir][0];
        ty = y0[dir] + i*secondOffset[dir][1];
       //cout << "(" << tx << ", " << ty << ")" << endl;
       
        t1x = tx;
        t1y = ty;
        t2x = tx + firstOffset[dir][0]; 
        t2y = ty + firstOffset[dir][1];
        for( ;t2x>=0&&t2x<=3&&t2y>=0&&t2y<=3; t2x+=firstOffset[dir][0],t2y+=firstOffset[dir][1])
        {
            if(grid[t2y][t2x]!=0)
            {
                if(grid[t1y][t1x]==0)
                {
                    grid[t1y][t1x] = grid[t2y][t2x];
                    grid[t2y][t2x] = 0;
                   // moved = true;
                }
                else if(grid[t1y][t1x]==grid[t2y][t2x])
                {
                    grid[t1y][t1x]++;
                    grid[t2y][t2x] = 0;
                    t1x += firstOffset[dir][0];
                    t1y += firstOffset[dir][1];
                   // moved = true;
                }
                else if(t1x+firstOffset[dir][0]!=t2x||t1y+firstOffset[dir][1]!=t2y)
                {
                    grid[t1y+firstOffset[dir][1]][t1x+firstOffset[dir][0]] = grid[t2y][t2x];
                    grid[t2y][t2x] = 0;
                    t1x += firstOffset[dir][0];
                    t1y += firstOffset[dir][1];
                    //cout << "Move Test" << endl;
                   // moved = true;
                }
                else
                {
                    t1x += firstOffset[dir][0];
                    t1y += firstOffset[dir][1];
                }
            }
            
        }
    }
    //return moved;
}

//添加新数
void addnum(int n)
{	
	while(n--)//添加n个
	{
		EmptyBlock = CalculateEmpty();
		if(EmptyBlock<=0)	
		{
			//cout << "addnum EmptyBlock = " << EmptyBlock << endl; 
			//cout << "addnum Test1" << endl;
			return;	
		}
		int cnt = random(EmptyBlock)+1;//随机得到一个空格数以内的数	
		//cout << "找到第" << cnt << "个空位" << endl; 
		//cout << "cnt = " << cnt << endl;

		int *p = &grid[0][0]-1;//记录矩阵首地址前一个 ,因为后面的 p 在找到时还会 ++ 
		//cout << "n = "<< n <<endl;
		for(int i=0; i<4&&cnt; i++)
			for(int j=0; j<4&&cnt; j++)
			{
				if(grid[i][j]==0 && cnt)//如果有空格并且cnt有效	
				{
					//cout << "cnt = " << cnt << endl;
					cnt--;//找到一个划一个
				}
                p++;//p 指向下一个再进行判断
			}
        //循环结束时 p 指向我们之前随机指定的空格
		*p = (random(10)==0)?2:1;// 0.1 的概率为2,0.9 的概率为1
		//cout << "插入成功" << endl; 
		//*p = (random(10)==0)+1;//这样写也可以
		EmptyBlock--;
	}
}
  
int main()
{
	initgraph(200, 200);
	addnum(2); //在随机2个位置添加新数 
	ShowInfo();   
    for ( ; is_run(); delay_fps(60) )
	{
		cleardevice();
		
		// todo: 逻辑更新(数据更新)
		//按键检测	
		while(kbmsg())
		{
		    key_msg keyMsg = getkey();
		    if(keyMsg.msg == key_msg_down)
		    {
		        switch(keyMsg.key)
		        {
		            case 'A':case key_left  : dir = 0; break;//左 
		            case 'W':case key_up  	: dir = 1; break;//上 
		            case 'D':case key_right : dir = 2; break;//右 
		            case 'S':case key_down	: dir = 3; break;//下 
		        }
		    }
		}   
		// todo: 图形更新
		if(dir!=-1)
		{
			system("cls");
			switch(dir)
		        {
		            case  0: cout << "按下了 A/左 键" << endl; break;//左 
		            case  1: cout << "按下了 W/上 键" << endl; break;//上 
		            case  2: cout << "按下了 D/右 键" << endl; break;//右 
		            case  3: cout << "按下了 S/下 键" << endl; break;//下 
		        }
		        
		        
		    bool flag = false;    //移动标志位 
			int tempGrid[4][4];	 //暂存数组 
			int i,j; 
			for(i=0;i<4;i++)
				for(j=0;j<4;j++)
					tempGrid[i][j] = grid[i][j];
			{ 
			//cout << "tempGrid[4][4] = " << endl;	
//			for(i=0; i<4; i++)
//		    {
//		        for(j=0; j<4; j++)
//		            cout << tempGrid[i][j] << " ";
//		        cout << endl;
//		    }
//		    cout << endl;
			}	
		
			Move(dir);
			//比较 
			for(i=0; i<4; i++)
				for(j=0; j<4; j++)
					if(grid[i][j]!=tempGrid[i][j])	
					{
						flag = true;
						break;
					} 
		
			//if(flag) cout << "是否移动:" <<	flag << endl;
			if(flag)
			{
				cout << "有效移动" << endl;
				addnum(1);
			}	
			else	cout << "无效移动" << endl;						 
			ShowInfo(); 
			dir = -1;//将 dir 置为无效,否则控制台会一直刷新 
		}		
	} 
	getch();
    closegraph();  
    return 0;
}

四、运行效果展示048-具体功能实现三稿-添加新数


结语:

到这里这个游戏的“内核”部分就差不多结束了,看上去像是一个2048了,但是它太丑了……=。=
下面小结一下功能实现部分:

  1. 移动逻辑
  2. 键盘输入控制
  3. 添加新数字

接下来的稿子是写优化部分(暂定以下几点):

  1. 将数字用图形替代
  2. 加入计分
  3. 类封装

冲鸭

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值