zoukankan      html  css  js  c++  java
  • C语言实现2048小游戏

    代码参考:100 行代码撸了一个 2048 的小游戏

    规则就是 2084 游戏的规则
    j - 左
    k - 下
    l - 右
    i - 上
    相同数字移动过程中会合并

    这里我把按键修改成了方向键,并加了些注释帮助理解

    #include<stdio.h>
    #include<stdlib.h>
    #include<conio.h>
    
    #define GAME_SIZE 4
    
    static void left(int *data)
    {
        int i, j, f;//f标志位判断是否经过合并,每一行(列)有且只能合并一次 
        int row = GAME_SIZE;
        while (row--) {
            for (f=0,j=0,i=0; i<GAME_SIZE; i++) {
                if (data[i]) {
                    if (!f && j>0 && data[j-1] == data[i]) {
                        data[j-1]+= data[i]; f = 1;//j左边有非0格,且与i格相等才合并 
                    } else {
                        data[j++] = data[i]; f = 0;//j记录0格下标 (j在0格和相等合并时不变,否则+1) 
                    }
                }
            }
            while (j < GAME_SIZE) data[j++] = 0;//填充剩余格 
            data += GAME_SIZE;//地址偏移4格 
        }
    }
    
    static void right(int *data)
    {
        int i, j, f;
        int row = GAME_SIZE;
        while (row--) {
            for (j=GAME_SIZE-1,f=0,i=GAME_SIZE-1; i>=0; i--) {
                if (data[i]) {
                    if (!f && j<GAME_SIZE-1 && data[j+1] == data[i]) {
                        data[j+1]+= data[i]; f = 1;
                    } else {
                        data[j--] = data[i]; f = 0;
                    }
                }
            }
            while (j >= 0) data[j--] = 0;
            data += GAME_SIZE;
        }
    }
    
    static void up(int *data)
    {
        int i, j, f;
        int col = GAME_SIZE;
        while (col--) {
            for (j=0,f=0,i=0; i<GAME_SIZE; i++) {
                if (data[i*GAME_SIZE]) {
                    if (!f && j>0 && data[(j-1)*GAME_SIZE] == data[i*GAME_SIZE]) {
                        data[(j-1)*GAME_SIZE]+= data[i*GAME_SIZE]; f = 1;
                    } else {
                        data[(j++)*GAME_SIZE] = data[i*GAME_SIZE]; f = 0;
                    }
                }
            }
            while (j < GAME_SIZE) data[(j++)*GAME_SIZE] = 0;
            data++;
        }
    }
    
    static void down(int *data)
    {
        int i, j, f;
        int col = GAME_SIZE;
        while (col--) {
            for (j=GAME_SIZE-1,f=0,i=GAME_SIZE-1; i>=0; i--) {
                if (data[i*GAME_SIZE]) {
                    if (!f && j<GAME_SIZE-1 && data[(j+1)*GAME_SIZE] == data[i*GAME_SIZE]) {
                        data[(j+1)*GAME_SIZE]+= data[i*GAME_SIZE]; f = 1;
                    } else {
                        data[(j--)*GAME_SIZE] = data[i*GAME_SIZE]; f = 0;
                    }
                }
            }
            while (j >= 0) data[(j--)*GAME_SIZE] = 0;
            data++;
        }
    }
    
    static int next(int *data){
        int empidx[GAME_SIZE*GAME_SIZE];
        int empnum = 0;
        int max = 0;
        int i,j = 0;
        
        for(j=0,i=0; i<GAME_SIZE*GAME_SIZE; i++){
            if(!data[i]){
                empidx[j++]=i;//记录0格的偏移地址 
                empnum++;//判断有几格为0 
            }
            max = max > data[i] ? max : data[i];//保留最大值判断是否游戏已结束 
        }
        if(empnum){
            data[empidx[rand()%empnum]] = 1;
            return max == 2048 ? 1 : 0;
        }
        else return -1;
    }
    
    static void output(int *data){//通过判断i是否被4整除来确定是否换行 
        int i, sum = 0;
        printf("+--------------------+
    
    ");
        for (i=1; i<=GAME_SIZE*GAME_SIZE; i++) {
            if(data[i-1]){
                printf("%4d %s", data[i-1], i%GAME_SIZE ? "" : "
    
    ");
            }else{
                printf("%s %s", "   .", i%GAME_SIZE ? "" : "
    
    ");
            }
            sum+=data[i-1];
        }
        printf("+--------------------+
    
    ");
        printf("分数:%d
    
    ", sum);
    }
    
    int main(){
        int data[GAME_SIZE * GAME_SIZE] = {0};
        int ret = 0;
        
        next(data);
        next(data);
        output(data);
        
        while(1){
            int c;
            if(c=getch()){
                if(c==72||c==75||c==77||c==80) continue;//功能键是两个字节,输入错误则跳过一次 
                c=getch();
                if(c==75) left (data);
                else if(c==77) right(data);
                else if(c==72) up   (data);
                else if(c==80) down (data);
                else if(c=='q') return 0;//q也需要按两次才退出 
                else continue;
            }
            ret = next(data);
            output(data);
            
            if (ret == -1) printf("game over !
    ");
            if (ret ==  1) printf("you  win  !
    ");
        }
    }

    我的测试环境为 Dev-C++ 5.11,亲测有效,如果使用linux 下 gcc 编译,需要解决 getch 问题,具体参考原博客

    算法主要就是 left right up down 四个函数,这里给出 left 函数的前两位图解

    准确的说,i 代表当前遍历格地址, j代表当前填充格地址(如果合并填充j-1格),f为合并标志位(每一行(列)只能合并一次)

    如果用getch()捕获上、下、左、右键

    上、下、左、右键是二个字节的,getch()只读一个字节,ASC码
    想要用getch()得到上、下、左、右键的话,要调用二次getch():

    可参考博客:C语言使用getch()读取方向键

    getch函数在读取一个功能键或者箭头(方向)键盘时,函数会返回两次,第一次调用返回0或者0xE0,第二次调用返回实际的键值,所以使用两次getch()即可。 

  • 相关阅读:
    为什么少有人在Windows电脑上安OS X?
    Xamarin.iOS开发初体验
    MySQL MyISAM/InnoDB高并发优化经验
    windows系统上安装与使用Android NDK r8d(二)
    windows系统上安装与使用Android NDK r8d(一)
    Windows平台下如何使用Android NDK
    Xamarin 手动安装步骤+破解(最新版Xamarin V3)
    MONO,原来你是水中月
    剑客vs刀客 Java vs .NET
    终于理解了什么是LGPL
  • 原文地址:https://www.cnblogs.com/exciting/p/9266205.html
Copyright © 2011-2022 走看看