C++在控制台上实现2048游戏
来源:互联网 发布:读地理地图软件 编辑:程序博客网 时间:2024/04/24 19:17
刚学完C++基础,想找一个项目练练手,萌发写一个2048的游戏的想法,既然有想法,就是干!!自己第一次独立完成一个项目(也不是全部是独立的,开始之前参考过代码),虽然只有几百行代码,但这是一个开始,朝着自己梦想一步一个脚印。fighting!! 首先在网上找了一个2048的项目,http://www.jb51.net/article/51111.htm,用这个代码运行了一下,大概有了整体的认识,并且粗略的看了一下模块。在这个程序中,有一些bug: ①和我们平常玩的2048不同,这个游戏生成的随机数是2的次方,我们一般只会生成2和4; ②游戏中每一次移动后生成新数的位置是第一个空格,降低游戏的体验; ③游戏只有两个相邻的大小相同的数才会结合,中间存在0的话,不会结合;其实是由于每次移动只会移动一格导致的; ④游戏中含有零,看起来不舒服; 虽然有这些问题,但是这个程序给了我整体的思路,让我能够自己接下来走自己的路。
接下来是自己做项目遇到的一些问题和解决方法,最后附上自己的源代码
一、控制台如何从键盘上获得方向键 之前简单的以为方向键就是简单的ASCII码,too young too simple。 http://blog.csdn.net/feilong911hao/article/details/42081967,看完这篇博客之后弄明白。之前问过很多人,各种搜也没找到,感谢博主和万能的CSDN。 总结:①方向键有两个字节,第一个字节不是ASCII码,后面一个字节才是 ②使用getch()没有回显的从键盘输入。
代码:
//返回值// 1 上 72// 2 下 80// 3 左 75// 4 右 77int get_direction(){ char c1,c2; int ret = 0; c1 = getch(); if (!isascii(c1)) { c2 = getch(); switch(c2) { case 72: ret = 1;break; case 80: ret = 2;break; case 75: ret = 3;break; case 77: ret = 4;break; default: break; } } return ret;}
二、随机数的生成 使用srand()和rand(),srand()使用time(0)当前的时间当做随机数种子,避免伪随机数; http://wenku.baidu.com/link?url=XkB5uCfIkKL_LyBqEoM5ueoxl29mwXtEyfAzGSwfHsgGRB3-N9eR0O0EFoElSa1-YISWXb1mevClbOLytYDhFMoJrnrkhnlxK-brQsslt4O
代码:
//随机产生一个0-n-1的数字int rand_pro_s(int n){ srand(time(0)); int k = rand()%n; return k;}
三、移动(难点) 将移动分为两步,第一步是合并相邻两个相同的数字(中间可以含有0);第二步,方格里面的数字全部向移动的方向移动,去除中间的零。 第一步:之前没有理清思想,只合并了相邻的两个数字,没有考虑含有0的情况。思路:遍历每一行或者列,k来存放每一个非零的数,遇见一个非零,如果和k相等,那么就将这个数变为2k,另外的数变为0. 第二步:使用一个k来作为记录非零的个数,然后遍历。
代码
void up_dir(){ //完成第一步 int i,j; for (i=0; i<4; i++) { /*for (j=0; j<3;) { if (array[j][i] == array[j+1][i]) { array[j][i] = array[j][i] + array[j+1][i]; array[j+1][i] = 0; j += 2; continue; } j++; }*/ int k = 0; int x = 0; int y = 0; for (j=0; j<4; j++) { if (k==array[j][i] && k!=0) { //array[x][y] = 2*array[x][y]; //array[x][y] = 2*k; array[x][y] = 2*k; array[j][i] = 0; k = 0; continue; } if (array[j][i]!=0) { k = array[j][i]; //此处的bug是x和y分别应该存储j和i x = j; y = i; } } } for (i=0; i<4; i++) { int k = 0; for (j=0; j<4; j++) { //if (array[j][i])//此处有bug,假如k和j相等 if (array[j][i]) { if (k != j) { array[k][i] = array[j][i]; array[j][i] = 0; } k++; } } } insert_num(); system("cls");//清屏 display();}
四、如何随机插入一个数(难点) 使用剩余空格数N,并且将空格的坐标记录下来,生成1-N的随机数n,并且在第n个空格插入2或者4. tips:①vector<vector<int>> v(16 ,vector<int>());vector中含有vector不能定义为空 ②插入数字的时候需要判断空格数五、如何判定游戏结束 看是否能够水平移动或者竖直移动,在移动操作的函数中修改,不改变二维数组的值即可
程序所有的代码
#include <iostream>#include <cstdlib> //rand(),time()#include <ctime> #include <conio.h> //getch()#include <ctype.h> //#include <vector>#include <math.h> //pow#include <iomanip> //setwusing namespace std;int array[4][4] = {0};//申请全局数组作为方格里面的数//0—3的随机数产生int rand_pro(){ srand(time(0)); int k = rand()%4; return k;}////////////////////////////////////界面函数//////////////////////////////////////////////////////////////之前的界面void display1(){ int i,j; for (i=0; i<4; i++) { for(j=0; j<4; j++) { cout<<array[i][j]<<" "; } cout<<endl; } cout<<"----------------------------------"<<endl;}//界面美化,不显示0,显示外框void display2(){ int i,j; for (i=0; i<4; i++) { for(j=0; j<4; j++) { if (array[i][j] == 0) { cout<<" "<<" "; } else cout<<array[i][j]<<" "; } cout<<endl; } cout<<"----------------------------------"<<endl;}void display() //显示棋盘 { cout<<setw(46)<<"X2048 by ziyunmumu"<<endl; cout<<setw(50)<<" |-----------------------|"<<endl; for(int i=0;i<=3;i++) { cout<<setw(24)<<""; for(int j=0;j<=3;j++) { //SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),FOREGROUND_RED); if (array[i][j] == 0) { cout<<setw(2)<<"|"<<setw(4)<<" "; } else cout<<setw(2)<<"|"<<setw(4)<<array[i][j]; if(j==3) { cout<<setw(2)<<"|"<<endl; cout<<setw(50)<<" |-----------------------|"<<endl; } } } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////新游戏的开始////////////////////////////////////////////////////////////void new_game(){ //初始化内容 int i,j; for(i=0;i<4;i++) { for (j=0;j<4;j++) { array[i][j] = 0; } } int m = rand_pro(); int n = rand_pro(); array[m][n] = 2; display();}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////随机产生一个0-n-1的数字int rand_pro_s(int n){ srand(time(0)); int k = rand()%n; return k;}//随机产生一个1-n的数字int rand_pro_ss(int n){ srand(time(0)); int k = rand()%n+1; return k;}//统计0的个数,并且通过一个vector来存放坐标//p需要判断vector<vector<int>> zero_num(int* p){ int i,j; int k = 0; vector<vector<int>> v(16 ,vector<int>()); for (i=0; i<4; i++) { for (j=0; j<4; j++) { if (array[i][j] == 0) { v[k].push_back(i); v[k].push_back(j); k++; } } } *p = k; return v;}//随机插入一个数字,通空格的个数随机插入//返回值为true就说明成功插入,否则未能插入bool insert_num(){ int k = 0; vector<vector<int>> v; v = zero_num(&k); if (k>0) { int m = rand_pro_s(k); int x = v[m][0]; int y = v[m][1]; array[x][y] = pow(2.0,rand_pro_ss(2)); return true; } return false;}////////////////////////////////////获得键盘方向//////////////////////////////////////////////////////////////获取方向//返回值// 1 上 72// 2 下 80// 3 左 75// 4 右 77int get_direction(){ char c1,c2; int ret = 0; c1 = getch(); if (!isascii(c1)) { c2 = getch(); switch(c2) { case 72: ret = 1;break; case 80: ret = 2;break; case 75: ret = 3;break; case 77: ret = 4;break; default: break; } } return ret;}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////移动操作//////////////////////////////////////////////////////////////上下左右操作//操作分为两步,首先将相邻的相同数字加起来,然后去除空格//操作完之后需要插入数字//之前分为两步的想法有问题,假如是两个相同数字之间有0的话,也是可以结合的void up_dir(){ //完成第一步 int i,j; for (i=0; i<4; i++) { /*for (j=0; j<3;) { if (array[j][i] == array[j+1][i]) { array[j][i] = array[j][i] + array[j+1][i]; array[j+1][i] = 0; j += 2; continue; } j++; }*/ int k = 0; int x = 0; int y = 0; for (j=0; j<4; j++) { if (k==array[j][i] && k!=0) { //array[x][y] = 2*array[x][y]; //array[x][y] = 2*k; array[x][y] = 2*k; array[j][i] = 0; k = 0; continue; } if (array[j][i]!=0) { k = array[j][i]; //此处的bug是x和y分别应该存储j和i x = j; y = i; } } } for (i=0; i<4; i++) { int k = 0; for (j=0; j<4; j++) { //if (array[j][i])//此处有bug,假如k和j相等 if (array[j][i]) { if (k != j) { array[k][i] = array[j][i]; array[j][i] = 0; } k++; } } } insert_num(); system("cls");//清屏 display();}void down_dir(){ //完成第一步 int i,j; for (i=0; i<4; i++) { /*for (j=3; j>0;) { if (array[j][i] == array[j-1][i]) { array[j][i] = array[j][i] + array[j-1][i]; array[j-1][i] = 0; j -= 2; continue; } j--; }*/ int k = 0; int x = 0; int y = 0; for (j=3; j>=0; j--) { if (k==array[j][i] && k!=0) { array[x][y] = 2*k; array[j][i] = 0; k = 0; continue; } if (array[j][i]!=0) { k = array[j][i]; x = j; y = i; } } } for (i=0; i<4; i++) { int k = 3; for (j=3; j>=0; j--) { if (array[j][i]) { if (k != j) { array[k][i] = array[j][i]; array[j][i] = 0; } k--; } } } insert_num(); system("cls");//清屏 display();}void left_dir(){ int i,j; for (i=0; i<4; i++) { int k = 0; int x = 0; int y = 0; for (j=0; j<4; j++) { if (k==array[i][j] && k!=0) { array[x][y] = 2*k; array[i][j] = 0; k = 0; continue; } if (array[i][j]!=0) { k = array[i][j]; x = i; y = j; } } } for (i=0; i<4; i++) { int k = 0; for (j=0; j<4; j++) { if (array[i][j]) { if (k != j) { array[i][k] = array[i][j]; array[i][j] = 0; } k++; } } } insert_num(); system("cls");//清屏 display();}void right_dir(){ //完成第一步 int i,j; for (i=0; i<4; i++) { int k = 0; int x = 0; int y = 0; for (j=3; j>=0; j--) { if (k==array[i][j] && k!=0) { array[x][y] = 2*k; array[i][j] = 0; k = 0; continue; } if (array[i][j]!=0) { k = array[i][j]; x = i; y = j; } } } for (i=0; i<4; i++) { int k = 3; for (j=3; j>=0; j--) { if (array[i][j]) { if (k != j) { array[i][k] = array[i][j]; array[i][j] = 0; } k--; } } } insert_num(); system("cls");//清屏 display();}////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////游戏结束//////////////////////////////////////////////////////////////判断游戏结束//将求解最大值和判断2048糅合在一起bool iswin(){ int i,j; for (i=0; i<4; i++) { for (j=0; j<4; j++) { if (array[i][j] == 2048) { return true; } } } return false;}//构造函数can_up...,不能改变全局变量的值//只需要两个方向,水平或者垂直;bool can_ver(){ int i,j; for (i=0; i<4; i++) { int k = 0; for (j=0; j<4; j++) { if (k==array[j][i] && k!=0) { return true; } if (array[j][i]!=0) { k = array[j][i]; } } } return false;}bool can_hor(){ int i,j; for (i=0; i<4; i++) { int k = 0; for (j=3; j>=0; j--) { if (k==array[i][j] && k!=0) { return true; } if (array[i][j]!=0) { k = array[i][j]; } } } return false;}//怎么做到提前预判已经不能左右移动了bool islose(){ int k = 0; zero_num(&k); if (k>0) { return false; } if (can_ver() || can_hor()) { return false; } return true;}////////////////////////////////////////////////////////////////////////////////////////////////void main(){ new_game(); int dir = 0; while(1) { if (iswin()) { cout<<"you win"<<endl; break; } if (islose()) { cout<<"you lose"<<endl; break; } dir = get_direction(); switch(dir) { case 1: up_dir();break; case 2: down_dir();break; case 3: left_dir();break; case 4: right_dir();break; default:break; } } system("pause");}
0 0
- C++在控制台上实现2048游戏
- C在控制台上实现鼠标画图功能
- c/c++ 入门之控制台上实现贪吃蛇
- 使用canto+w3m实现在控制台上完美阅读RSS
- 实现控制台上的进度条
- Lesson_for_java_day15--java小练习:贪吃蛇游戏(在控制台上操作)
- C#: 控制台上输出显示进度条/百分比
- 在Windows控制台上显示中文
- 如何在Windows控制台上显示中文
- 000021:在控制台上输出"test Java"
- 定义方法实现在控制台上打印n*n乘法表
- 一个控制台上永远都是你赢的五子棋游戏,囧
- ibatis 在控制台上写sql语句 log4j配置
- 编写一个People类,在控制台上输出个人信息
- 如何在Windows控制台上利用Perl处理UTF8
- 读取一个.java文件,并打印在控制台上。
- 读取一个.java文件并打印在控制台上
- 将文件中的数据显示在控制台上
- 数据库隔离级别
- Android AsyncTask两种线程池分析和总结
- hdu 1323 Perfection
- 确定两串乱序同构(程序员面试金典)
- spring实现javaMail
- C++在控制台上实现2048游戏
- iOS开发:图片的异步加载
- AdapterViewFliper 的用法
- TCP/IP 协议详解内容总结
- Spring MVC 环境搭建
- 多线程
- 今天终于申请到了CSDN,我来了
- PAT(甲级)1021
- JAVA编程基础(三)