用C++命令行实现2048小游戏

用C++命令行实现2048小游戏,基本思路如下。

先凭空在命令行绘制一个4×4的方格,作为游戏界面,中间填充数字的部分用空格表示。定义一个长度为4,4的二维int型数组,不显示数据的地方用0表示,将它动态地填入到游戏界面中。

在接收到按键事件后,对二维数组进行遍历,针对每一个元素,获取它的下一位元素,这里的下一位元素要根据按键事件动态获取(如果按键是向下,则下一位元素就是 arr [ i + 1 ][ j ]),并且对下一位元素进行判断:如果下一位元素是0,则将当前元素赋值给下一位元素,并且将当前下标位置设为0;如果下一位元素等于当前元素(且都不等于0),则进行合并操作。

最后刷新命令行,根据重新赋值的数组生成界面。

关于这个游戏需要注意以下几点:

1,字体颜色:写一个根据数字返回string字符串的函数,将字符串直接插入到数字前面。颜色的实现要用到“\033”相关知识,可以搜索此关键字查看详情,下面是我的函数:

/*
用法:
elem是要改变的字体颜色,可直接插入到此数据两端,
elem是int型,所以要to_string()
string str = setcolor(elem) + to_string(elem) + setcolor(-1);
*/

string setcolor(int elem) {
	if (elem == -1) {return "\033[0m";}
	else if (elem == 2) { return "\033[1m\033[33m"; }
	else if (elem == 4) { return "\033[2m\033[33m"; }
	else if (elem == 8) { return "\033[1m\033[32m"; }
	else if (elem == 16) {  return "\033[2m\033[32m";  }
	else if (elem == 32) {  return "\033[1m\033[36m";  }
	else if (elem == 64) {  return "\033[2m\033[36m";  }
	else if (elem == 128) {  return "\033[1m\033[34m";  }
	else if (elem == 256) {  return "\033[2m\033[34m";  }
	else if (elem == 512) {  return "\033[1m\033[32m";  }
	else if (elem == 1024) {  return "\033[2m\033[32m";  }
	else if (elem == 2048) {  return "\033[1m\033[31m";  }
}

2,此游戏用二维数组代替坐标,极易混淆x和y的关系,假设arr[1][2],其中1才是Y,2才是X。在编码途中要格外注意。

3,倘若按照我的编码逻辑,很容易出现一个问题:连续合并的问题。假如有一行数据是2248,2和2合并后变成了4,继续遍历,就会和4再次合并,合并后变成8又会和8再次合并。这不符合游戏逻辑。

倘若加入一个flag变量控制,似乎能解决这样的问题,但又会出现新的问题。假如有一行存在2288,按照原来的游戏规则,此处2和2,以及8和8都应该各自合并,但由于flag存在,导致只会合并其中一项。

此时就需要重新设置一个4×4的数组,作为flag[4][4],来存储合并标记。在每次合并前,判断当前位置是否经历过合并,合并后,在该数组的对应位置记录标记。

以下是我的代码:

int arr[4][4];
int _flag[4][4];


//初始化flag数组
void initflag() {
	_flag[0][0] = 0;	_flag[0][1] = 0;	_flag[0][2] = 0;	_flag[0][3] = 0;
	_flag[1][0] = 0;	_flag[1][1] = 0;	_flag[1][2] = 0;	_flag[1][3] = 0;
	_flag[2][0] = 0;	_flag[2][1] = 0;	_flag[2][2] = 0;	_flag[2][3] = 0;
	_flag[3][0] = 0;	_flag[3][1] = 0;	_flag[3][2] = 0;	_flag[3][3] = 0;
}

//初始化数组
void initdata() {
	arr[0][0] = 2;	arr[0][1] = 2;	arr[0][2] = 4;	arr[0][3] = 8;
	arr[1][0] = 0;	arr[1][1] = 0;	arr[1][2] = 0;	arr[1][3] = 0;
	arr[2][0] = 0;	arr[2][1] = 0;	arr[2][2] = 0;	arr[2][3] = 0;
	arr[3][0] = 0;	arr[3][1] = 0;	arr[3][2] = 0;	arr[3][3] = 0;
	showpage();
}

//根据数组生成界面
void showpage() {
	system("cls");
	cout << endl;
	cout << "\t" << "|-----|-----|-----|-----|" << endl;
	cout << "\t" << "|"<<setelement(arr[0][0]) << "|" << setelement(arr[0][1]) << "|" << setelement(arr[0][2]) << "|" << setelement(arr[0][3]) << "|" << endl;
	cout << "\t" << "|-----|-----|-----|-----|" << endl;
	cout << "\t" << "|" << setelement(arr[1][0]) << "|" << setelement(arr[1][1]) << "|" << setelement(arr[1][2]) << "|" << setelement(arr[1][3]) << "|" << endl;
	cout << "\t" << "|-----|-----|-----|-----|" << endl;
	cout << "\t" << "|" << setelement(arr[2][0]) << "|" << setelement(arr[2][1]) << "|" << setelement(arr[2][2]) << "|" << setelement(arr[2][3]) << "|" << endl;
	cout << "\t" << "|-----|-----|-----|-----|" << endl;
	cout << "\t" << "|" << setelement(arr[3][0]) << "|" << setelement(arr[3][1]) << "|" << setelement(arr[3][2]) << "|" << setelement(arr[3][3]) << "|" << endl;
	cout << "\t" << "|-----|-----|-----|-----|" << endl;

}

//根据数字长度,返回不同的字符串,用来填充界面
string setelement(int &elem) {
	if (elem == 0) {
		return "     ";
	}
	if (elem >0 && elem < 10) {
		return "  " + setcolor(elem) + to_string(elem) + setcolor(-1) + "  ";
	}
	else if (elem > 9 && elem < 100) {
		return "  " + setcolor(elem) + to_string(elem) + setcolor(-1) + " ";
	}
	else if(elem > 99 && elem < 1000){
		return " " + setcolor(elem) + to_string(elem) + setcolor(-1) + " ";
	}
	else {
		return "" + setcolor(elem) + to_string(elem) + setcolor(-1) + " ";
	}
}

//根据不同数字设置颜色
string setcolor(int elem) {
	if (elem == -1) {return "\033[0m";}
	else if (elem == 2) { return "\033[1m\033[33m"; }
	else if (elem == 4) { return "\033[2m\033[33m"; }
	else if (elem == 8) { return "\033[1m\033[32m"; }
	else if (elem == 16) {  return "\033[2m\033[32m";  }
	else if (elem == 32) {  return "\033[1m\033[36m";  }
	else if (elem == 64) {  return "\033[2m\033[36m";  }
	else if (elem == 128) {  return "\033[1m\033[34m";  }
	else if (elem == 256) {  return "\033[2m\033[34m";  }
	else if (elem == 512) {  return "\033[1m\033[32m";  }
	else if (elem == 1024) {  return "\033[2m\033[32m";  }
	else if (elem == 2048) {  return "\033[1m\033[31m";  }
}


//写一个死循环用来获取按键
void getkeyboard() {
	while (true) {
		if (_kbhit()) {
			int ch = _getch();//使用_getch()函数获取按下的键值
			keyfunc(ch);
		}
	}
}




void keyfunc(int& inbtn) {
	for (int i = 0; i < 3; i++) {//最外层循环,数字移动最多移动三个位置

		for (int indexY = 0;indexY < 4;indexY++) {//此处的双层循环,是二维数组的正常循环
			for (int indexX = 0;indexX < 4;indexX++) {
                //获取当前坐标的“下一坐标”,并用pair接收
				pair<int, int> p = getlastIndex(indexX, indexY, inbtn);
                //当数字一致且不为0时进行合并(为什么要不为0,虽然00合并也是0,但是可能会影响到flag数组)
				if (arr[p.first][p.second] == arr[indexY][indexX] && arr[indexY][indexX] != 0) {
                    //循环到数组末端时,它的“下一位”就是它自己,在此排除掉这种情况
					if (p.first != indexY || p.second != indexX) {
                        //对flag标记进行判断
						if (_flag[p.first][p.second] == 0 && _flag[indexY][indexX] == 0) {

							arr[p.first][p.second] = (arr[indexY][indexX]) * 2;
							arr[indexY][indexX] = 0;

							_flag[p.first][p.second] = 1;
							_flag[indexY][indexX] = 1;
						}
						
					}
				}
                //当下一位是0时,移动数据
				else if (arr[p.first][p.second] == 0) {
					arr[p.first][p.second] = arr[indexY][indexX];
					arr[indexY][indexX] = 0;
				}
			}
		}
	}
	
	initflag();
	showpage();
	insertdata();
}


//根据按键,获取“下一位置”坐标
pair<int,int> getlastIndex(int &indexX, int &indexY,int &keydown) {
	pair<int, int> p;
	p.first = indexY;
	p.second = indexX;
	if (keydown == 119) {
		if (indexY>0) {
			p.first = indexY - 1;
		}
	}
	else if (keydown == 115) {
		if (indexY < 3) {
			p.first = indexY + 1;
		}
	}
	else if (keydown == 97) {
		if (indexX > 0) {
			p.second = indexX - 1;
		}
	}
	else if (keydown == 100) {
		if (indexX < 3) {
			p.second = indexX + 1;
		}
	}
	return p;
}


//每次按键后随机在空格处生成新的数字,此处用了14%的概率生成4
void insertdata() {
	
	int insertdata = 2;
	int randnum = rand() % 100 + 1;
	if (randnum < 14) {
		insertdata = 4;
	}
	vector<pair<int, int>> v;
	for (int y = 0;y < 4;y++) {
		for (int x = 0;x < 4;x++) {
			if (arr[y][x] == 0) {
				pair<int, int> p;
				p.first = y;	p.second = x;
				v.push_back(p);
			}
		}
	}
	int rand1 = rand() % v.size();
	pair<int,int> p1 = v.at(rand1);
	arr[p1.first][p1.second] = insertdata;

	showpage();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值