欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

用C挑战无准备写2048

程序员文章站 2022-06-10 17:18:24
下午在刷题过程中,忽然想写2048了,以弥补以前写的那个千多行的,所以简单思考了一下准备采取的数据结构就开始了,本以为一个小时能搞定,结果后面改bug还是多花了些时间。因为在医院,所以声音不敢太大,如果看,建议耳机+声音最大,可以考虑倍速。个人感觉用C写这些东西的意义在于,你去掉了一些花里胡哨的东西 ......

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

用C挑战无准备写2048
//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);
}
view code

 

哔哩哔哩配套视频链接: