C++在控制台上实现2048游戏

    刚学完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   右   77
int 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>  //setw

using 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   右   77
int 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");
}
  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值