用C挑战无准备写2048

下午在刷题过程中,忽然想写2048了,以弥补以前写的那个千多行的,所以简单思考了一下准备采取的数据结构就开始了,本以为一个小时能搞定,结果后面改bug还是多花了些时间。因为在医院,所以声音不敢太大,如果看,建议耳机+声音最大,可以考虑倍速。个人感觉用C写这些东西的意义在于,你去掉了一些花里胡哨的东西,而真的用你的逻辑思考出了这个东西怎么写,并写出来了。乱花渐欲迷人眼,难的是坚守本心!明白学一个东西的意义,有时候比学习它更重要!嗯就这样。下面贴上代码和录制的视频链接

//2019年3月16日 17:29:07
//2048
//1、地图数据结构   2、合并和移动?   3、判断胜负
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#include<conio.h>
#include<time.h>
#include<string.h> 
#define N 5//地图大小 
#define M 13//table表的长度 
#define WINFLAG 11


char map[N][N];//地图 
int table[M];//查表使用


void Init();
void Run();
void Print();
int Win();
void Lose();
int IsLose();
int Up(int *isChange);
int Down(int *isChange);
int Left(int *isChange);
int Right(int *isChange);
void Generator(int dir);


void gotoxy(int x, int y); //将光标调整到(x,y)的位置


//光标隐藏
void HideCursor() ; //隐藏光标显示

int main(void)
{
	srand((unsigned)time(NULL));
	HideCursor();
	Init(); 
	Run();
	return 0;
}


void Generator(int dir)
{
	//按下右,就按列扫,从左往右随机选一个数生成
	//按下上,就按行扫,从下网上随机选一个数生成	
//	int begin;
//	int end;
//	int mul;//增量
//	for(int i = begin;i != end;i += mul) 
//	for(int i = 0;i < N;++i)
//		for(j = N-1;j >= 0;--j) 
	int flag = 0;
	int i1 = -1,i2 = -1; 
	if(dir == 1 || dir == 2)
	{
		int begin,end,mul;
		dir == 1?begin = 0,end = N,mul = 1:begin = N-1,end = -1,mul = -1;
		for(int i = 0;i < N;++i)
			for(int j = begin;j != end;j += mul) 
			{
				//保证选一个数,然后其他的随机
				if(map[i][j] == 0)//选到了一个数
				{
					if(flag == 0)//之前没选到过
					{
						i1 = i;
						i2 = j;
						flag = 1;  
					}
					else
					{
						if(rand()%3 < 2)
						{
							i1 = i;
							i2 = j;
						}
					}	
				} 
			}
	}
	else if(dir == 3 ||  dir == 4)
	{
		int begin,end,mul;
		dir == 3?begin = 0,end = N,mul = 1:begin = N-1,end = -1,mul = -1;
		for(int j = begin;j != end;j += mul)
			for(int i = 0;i < N;++i)
			{
				//保证选一个数,然后其他的随机
				if(map[i][j] == 0)//选到了一个数
				{
					if(flag == 0)//之前没选到过
					{
						i1 = i;
						i2 = j;
						flag = 1;  
					}
					else
					{
						if(rand()%3 < 2)
						{
							i1 = i;
							i2 = j;
						}
					}	
				} 
			}
	}
	if(i1 == i2 && i2 == -1)
		return;
	map[i1][i2] = 1;
}

int Up(int *isChange)
{
	//往上,所以是从上往下扫描
	//一列一列的算 

	for(int j = 0;j < N;++j)
	{
		int k = 0;
		for(int i = 1;i < N;++i)
		{
			if(map[i][j] != 0)//当前处理的这一位是有数字的 
			{
				//只要是非0,且没有合并,则相加 
				//这里保证map[i][j]是有数字的 
				if(map[i][j] == map[k][j])
				{
					//与那个数字进行交互。合并操作 
					map[k][j] += 1;
					map[i][j] = 0; 
					if(map[k][j] == 12)
						return 5;
					*isChange = 1;
				} 
				else if(map[k][j] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的
				{
					//把当前位置上的数移过去   特判的移动操作 
					map[k][j] = map[i][j];
					map[i][j] = 0; 
					*isChange = 1;
				}
				else if(k+1 != i)//移动操作 
				{
					map[k+1][j] = map[i][j];//2 0 0 4  2 4 0 0     
					map[i][j] = 0;//4 2 0 0
					++k; 
					*isChange = 1;
				}
				
				else//没有合并,且不是特判的 
					++k; 
			}
		}
	}
	return 1;
}
int Down(int *isChange)
{
	for(int j = 0;j < N;++j)
	{
		int k = N-1;
		for(int i = N-2;i >= 0;--i)
		{
			if(map[i][j] != 0)//当前处理的这一位是有数字的 
			{
				//只要是非0,且没有合并,则相加 
				//这里保证map[i][j]是有数字的 
				if(map[i][j] == map[k][j])
				{
					//与那个数字进行交互。合并操作 
					map[k][j] += 1;
					map[i][j] = 0; 
					if(map[k][j] == 12)
						return 5;
					*isChange = 1;
				} 
				else if(map[k][j] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的
				{
					//把当前位置上的数移过去   特判的移动操作 
					map[k][j] = map[i][j];
					map[i][j] = 0; 
					*isChange = 1;
				}
				else if(k-1 != i)//移动操作 
				{
					map[k-1][j] = map[i][j];//2 0 0 4  2 4 0 0     
					map[i][j] = 0;//4 2 0 0
					--k; 
					*isChange = 1;
				}
				else//没有合并,且不是特判的 
					--k; 
			}
		}
	}
	return 2;
}
int Left(int *isChange)
{
	//合并?什么情况下合并?什么情况下移动?
	//一行一行处理
	//从左往右处理
	//这个有数字,我们才需要处理,没数字不用管  2 0 4 8    2 4 0 8    2 4 8 0
	for(int i = 0;i < N;++i)
	{
		int k = 0;
		for(int j = 1;j < N;++j)
		{
			if(map[i][j] != 0)//当前处理的这一位是有数字的 
			{
				//这里保证map[i][j]是有数字的 
				if(map[i][j] == map[i][k])
				{
					//与那个数字进行交互。合并操作 
					map[i][k] += 1;
					map[i][j] = 0; 
					if(map[i][k] == 12)
						return 5;
					*isChange = 1;
				}
				else if(map[i][k] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的
				{
					//把当前位置上的数移过去   特判的移动操作 
					map[i][k] = map[i][j];
					map[i][j] = 0; 
					*isChange = 1;
				} 
				else if(k+1 != j)//移动操作 
				{
					map[i][k+1] = map[i][j];//2 0 0 4  2 4 0 0     
					map[i][j] = 0;//4 2 0 0
					++k; 
					*isChange = 1;
				}
				else
					++k; 
			}
		}
	}
	return 3;
}
int Right(int *isChange)
{
	//从右至左 
	for(int i = 0;i < N;++i)
	{
		int k = N-1;
		for(int j = N-2;j >= 0;--j)
		{
			if(map[i][j] != 0)//当前处理的这一位是有数字的 
			{
				//这里保证map[i][j]是有数字的 
				if(map[i][j] == map[i][k])
				{
					//与那个数字进行交互。合并操作 
					map[i][k] += 1;
					map[i][j] = 0; 
					if(map[i][k] == 12)
						return 5;
					*isChange = 1;
				}
				else if(map[i][k] == 0)//我们是说k是第一个非零的,但初始的时候我们为了好运算,是没做判断的
				{ 
					map[i][k] = map[i][j];
					map[i][j] = 0; 
					*isChange = 1;
				} 
				else if(k-1 != j)//移动操作 
				{
					map[i][k-1] = map[i][j];    
					map[i][j] = 0;
					--k; 
					*isChange = 1;
				}
				else
					--k;
			}
		}
	}
	return 4;
}


void Init()
{
	int n = 16;//随机地图的数目 
	//先求table
	table[0] = 1;
	for(int i = 1;i < M;++i) 
		table[i] = table[i-1]<<1;//等同于*2 
//	for(int i = 0;i < M;++i)
//		printf("%5d",table[i]);
//及时测试,验证正确性,免得日后找bug麻烦
	
	//随机地图   随机生成3个2? 
	memset(map,0,sizeof(map));
	for(int i = 0;i < n;++i)
	{
		int i1 = rand()%N;
		int i2 = rand()%N;
		//随机一组下标,让地图那个位置变成1
		map[i1][i2] = 1; //这个1代表2的一次,最终展现的是2 
	}
}
void Run()
{
	int isChange = 0;//检测是否发生了变化 
	int flag = 0;
	while(1)
	{
		Print();
		isChange = 0;
		switch(getch())
		{
			case 'w':flag = Up(&isChange);break;
			case 's':flag = Down(&isChange);break;
			case 'a':flag = Left(&isChange);break;
			case 'd':flag = Right(&isChange);break;
		}
		if(flag != 5 && isChange)
			Generator(flag);
		if(flag == 5)
		{
			Win();
			break;
		}
		else if(IsLose())
		{
			Print();
			Lose();
			break;
		}	
	}
}
void Print()
{
	gotoxy(0,0);
	for(int i = 0;i < N;++i)
	{
		for(int j = 0;j < N;++j)
			if(map[i][j] != 0)
				printf("%3d  ",table[map[i][j]]);
			else
				printf("     ");
		putchar('\n');
	}
}
int Win()
{
	printf("You are winner!\n");
}
void Lose()
{
	printf("You are loser!\n");
}
int IsLose()
{
	//判断是否还具备可操作空间
	for(int i = 0;i < N;++i)
	 	for(int j = 0;j < N-1;++j)
	 	{
	 		if(map[i][j] == map[i][j+1])
			 	return 0;
			else if(map[i][j]*map[i][j+1] == 0)
				return 0;	
		}
	for(int j = 0;j < N;++j)
	 	for(int i = 0;i < N-1;++i)
	 	{
	 		if(map[i][j] == map[i+1][j])
			 	return 0;
			else if(map[i][j]*map[i+1][j] == 0)
				return 0;	
		}
	Print();
	return 1;
}
//光标跳转
void gotoxy(int x, int y) //将光标调整到(x,y)的位置
{
    HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X = x;
    pos.Y = y;
    SetConsoleCursorPosition(handle, pos);
}


//光标隐藏
void HideCursor()  //隐藏光标显示
{
    CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);
}

哔哩哔哩配套视频链接:https://www.bilibili.com/video/av46465862/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值