【第十三节】C语言小项目(windows控制台版2048小游戏)

目录

一、2048游戏玩法规则

二、需掌握的C语言知识点

三、实现流程

四、实现代码

五、游戏运行截图


一、2048游戏玩法规则

1)游戏开始时,会出现一个4x4的方格,上面会有两个随机数字方块(通常是2或者4)。
玩家可以通过滑动屏幕上的上、下、左、右四个方向来移动所有的方块,直到碰到边界或者另一个方块。
2)当两个相同数字的方块碰到一起时,它们会合并成一个价值为两者之和的新方块。例如:两个2合并成一个4,两个4合并成一个8,以此类推。
3)棋盘被数字填满,无法进行有效移动,判负,游戏结束。
4)棋盘上出现2048,判胜,游戏结束。

还不知道怎么玩的同学,可以下载这个小游戏先玩玩了解熟悉。

二、需掌握的C语言知识点

要实现一个控制台版本的2048小游戏,需要掌握以下C语言知识点:

1)数组和二维数组:用来表示游戏中的格子,每个格子是一个二维数组,行表示列数,列表示格子的状态(是否有数字、数字是多少)。方便表示游戏中的方块,包括方块的位置和数字,以及实现方块的移动和合并。
2)循环语句:使用循环语句来控制游戏的流程,包括初始化游戏、生成随机数字、移动方块、合并方块等。
3)条件语句:用来判断游戏是否结束,以及输出游戏结果。
4)随机数生成:使用随机数生成函数来生成随机数字,以实现方块的随机移动和生成。
5)输入输出:使用输入输出函数来读取用户输入和输出游戏结果。
6)函数:将游戏的不同功能模块化,使得代码更加清晰和易于维护。

除了以上知识点,还需要了解C语言的常用库函数和数据类型,例如stdio.h、stdlib.h、time.h等库函数。

三、实现流程

1)初始化游戏:创建一个4x4的二维数组,用来表示游戏棋盘。初始时,随机生成两个数字方块,分别放在棋盘上。
2)生成随机数字:在游戏过程中,每次生成一个随机数字,用来表示新生成的方块。
3)移动方块:根据用户的输入,将所有的方块向前移动靠拢至边缘。如果两个方块相撞,则合并成一个新的方块。
4)合并方块:当两个相同数字的方块碰到一起时,它们会合并成一个价值为两者之和的新方块。合并方块时,需要使用递归来寻找可以合并的方块。
5)判断游戏结束:如果棋盘被数字填满,无法进行有效移动,或者出现2048的方块,则游戏结束。
6)输出游戏结果:输出棋盘上每个方块的数字和位置,以及游戏得分。

四、实现代码

#include"stdafx.h"
#include"stdlib.h"
#include"stdio.h"
#include"time.h"
#include"conio.h"
#include"windows.h"

int grid[4][4] = { 0 };  //保存4*4的格子数字
int score = 0;//游戏分数

void gotoXY(int x, int y)      //设定输出位置
{
    COORD c;   //光标位置
    c.X = x - 1;
    c.Y = y - 1;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c);//获取句柄,设置位置

    HANDLE hOutStd = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO cci;   //控制台光标信息结构类型
    cci.dwSize = 1;   //光标大小
    cci.bVisible = 0;      //是否显示光标  true显示
    SetConsoleCursorInfo(hOutStd, &cci);   //设置控制台屏幕光标大小和可见性
}



void printGrid() {   //打印游戏表格
    system("cls");
    printf("======C语言控制台版2048游戏======\n");
    for (int i = 0; i < 4; i++) {
        printf("---------------------------------\n");
        for (int j = 0; j < 4; j++) {
            if (grid[i][j] == 0) { printf("|  \t"); }//打印空数
            else printf("| %d\t", grid[i][j]);//打印数字
        }
        printf("|\n");//换行
    }

    printf("---------------------------------\n");

    gotoXY(18 * 2, 5);//定位输出
    printf("目前得分:%d", score);
    gotoXY(18 * 2, 7);
    printf("《请按四个方向箭头进行操作》");
}


void  randomNum() {
    srand((unsigned int)time(NULL));
    int x = rand() % 4;   //随机坐标
    int y = rand() % 4;

    while (grid[x][y] != 0) {//生成的位置已经有数字就重新生成
        x = rand() % 4;
        y = rand() % 4;
    }

    int z = rand() % 5;//概率媒介

    if (z == 0)grid[x][y] = 4;//五分之一的概率产生数字4
    else grid[x][y] = 2;//五分之四的概率产生数字2
}


//获取格子中的最大的数字
int getMax() {
    int max = 0;
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (grid[i][j] > max) {
                max = grid[i][j];
            }
        }
    }
    return max;
}


int  gameOver() {

    int result = 1;//等于0继续游戏,等于1结束游戏

    //计算最大的数为2048时赢得游戏结束
    if (getMax() == 2048) {
        result = 1;
        printf("恭喜你赢得游戏!/n");
        system("pause");
    }

    //判断存在空格子,继续
    for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
            if (grid[i][j] == 0) result = 0;
            break;
        }
    }


    //如果格子都不为空,需要进一步判断相邻格子数字是否相同
    if (result == 1) {
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 4; j++) {
                if (i != 0 && grid[i][j] == grid[i - 1][j]) result = 0;  //与上面的数比较
                if (i != 3 && grid[i][j] == grid[i + 1][j]) result = 0;  //与下面的数比较
                if (j != 0 && grid[i][j] == grid[i][j - 1]) result = 0;//与左边的数比较
                if (j != 3 && grid[i][j] == grid[i][j + 1]) result = 0;//与右边的数比较
            }
        }
    }

    return result;

}


//向上划
int toUp() {

    int col, row;
    int isMove = 0;//默认0不移动,设置为1表明已经移动

    for (col = 0; col < 4; col++) {
        for (row = 1; row < 4; row++) {//纵向开始
            if (grid[row][col] && grid[row - 1][col] == 0) {  //本格不为空,上一格数为空,补空位
                grid[row - 1][col] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                //重置row,补位到最终位置
                if (row > 1) row -= 2;
                isMove = 1;
            }
        }

        //纵向相邻相同的数字则累加合位
        for (int row = 1; row < 4; row++) {
            if (grid[row][col] && grid[row - 1][col] == grid[row][col]) {//本格不为空,且与上一格数字相同则合并
                grid[row - 1][col] *= 2;
                score += grid[row][col];
                grid[row][col] = 0;//合并完后置空
                isMove = 1;
            }
        }

        //合并后再次补空位
        for (row = 1; row < 4; row++) {
            if (grid[row][col] && grid[row - 1][col] == 0) {  //本格数不为空,上一格数为空,补空位
                grid[row - 1][col] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                //重置row,补位到最终位置
                if (row > 1) row -= 2;
            }
        }

    }


    return isMove;

}

//向下划
int toDown() {
    int col, row;
    int isMove = 0;//默认0不移动

    for (col = 0; col < 4; col++) {
        for (row = 2; row >= 0; row--) {//纵向开始
            if (grid[row][col] && grid[row + 1][col] == 0) {  //本格数不为空,下一格数为空,补空位
                grid[row + 1][col] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                 //重置row,补位到最终位置
                if (row < 2) row += 2;
                isMove = 1;
            }
        }

        //纵向相邻相同的数字则累加合位
        for (row = 2; row >= 0; row--) {
            if (grid[row][col] && grid[row + 1][col] == grid[row][col]) {//本格不为空,且与下一格数字相同则合并
                grid[row + 1][col] *= 2;
                score += grid[row][col];
                grid[row][col] = 0;//合并完后置空
                isMove = 1;
            }
        }

        //合并后再次补空位
        for (row = 2; row >= 0; row--) {
            if (grid[row][col] && grid[row + 1][col] == 0) {  //本格数不为空,下一格数为空,补空位
                grid[row + 1][col] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                 //重置row,补位到最终位置
                if (row < 2) row += 2;
            }
        }

    }


    return isMove;

}


//向左划
int toLeft() {
    int col, row;
    int isMove = 0;//默认0不移动

    for (row = 0; row < 4; row++) {
        for (col = 1; col < 4; col++) {//横向开始
            if (grid[row][col] && grid[row][col - 1] == 0) {  //本格数不为空,左格数为空,补空位
                grid[row][col - 1] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                //重置col,补位到最终位置
                if (col > 1) col -= 2;
                isMove = 1;
            }
        }

        //横向相邻相同的数字则累加合位
        for (int col = 1; col < 4; col++) {
            if (grid[row][col] && grid[row][col - 1] == grid[row][col]) {//本格不为空,且与左边数字相同则合并
                grid[row][col - 1] *= 2;
                score += grid[row][col];
                grid[row][col] = 0;//合并完后置空
                isMove = 1;
            }
        }

        //合并后再次补空位
        for (col = 1; col < 4; col++) {
            if (grid[row][col] && grid[row][col - 1] == 0) {  //本格数不为空,左格数为空,补空位
                grid[row][col - 1] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                //重置col,补位到最终位置
                if (col > 1) col -= 2;
            }
        }

    }

    return isMove;

}


//向右划
int toRight() {
    int col, row;
    int isMove = 0;//默认0不移动

    for (row = 0; row < 4; row++) {
        for (col = 2; col >= 0; col--) {//横向开始
            if (grid[row][col] && grid[row][col + 1] == 0) {  //本格数不为空,右格数为空,补空位
                grid[row][col + 1] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                //重置col,补位到最终位置
                if (col < 2) col += 2;
                isMove = 1;
            }
        }

        //横向相邻相同的数字则累加合位
        for (col = 2; col >= 0; col--) {
            if (grid[row][col] && grid[row][col + 1] == grid[row][col]) {//本格不为空,且与右边数字相同则合并
                grid[row][col + 1] *= 2;
                score += grid[row][col];
                grid[row][col] = 0;//合并完后置空
                isMove = 1;
            }
        }

        //合并后再次补空位
        for (col = 2; col >= 0; col--) {
            if (grid[row][col] && grid[row][col + 1] == 0) {  //本格数不为空,右格数为空,补空位
                grid[row][col + 1] = grid[row][col];
                grid[row][col] = 0;//补位后置空
                 //重置col,补位到最终位置
                if (col < 2) col += 2;
            }
        }

    }

    return isMove;
}

//接收移动按键并刷新格子移动
void moveDirection() {
    int ch = _getch();

    switch (ch) {
        //向上箭头 224 72  判断接收两次
    case 72: //上划
        if (toUp() == 1) {
            randomNum();
            printGrid();
        }
        break;
        //向下箭头 224 80  判断接收两次
    case 80://下划
        if (toDown() == 1) {
            randomNum();
            printGrid();
        }
        break;
        //向左箭头 224 75  判断接收两次
    case 75: //左划
        if (toLeft() == 1) {
            randomNum();
            printGrid();
        }
        break;
        //向右箭头 224 77  判断接收两次
    case 77://右划
        if (toRight() == 1) {
            randomNum();
            printGrid();
        }
        break;
    default:break;
    }
}


void playGame() {   //开始游戏

    int flag = 1;

    while (flag) {
        //初始化格子,设置为0
        memset(grid, 0, sizeof(grid));
        //产生两个随机数字
        randomNum();
        randomNum();
        //打印格子
        printGrid();

        //游戏没有结束就可以一直操作,1是结束游戏
        while (gameOver() == 0) {
            //接收移动按键并进行移动
            moveDirection();
        }

        system("cls");
        printf("游戏结束,您的分数为:%d\n", score);
        printf("按y继续游戏,按n退出游戏!\n");


        //切换英文输入法
        keybd_event(VK_SHIFT, 0, 0, 0);
        Sleep(100);
        keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

        int mark = 1;
        while (mark) {

            //接收按键
            char ch = _getch();

            if (ch == 'y' || ch == 'Y') {
                flag = 1;
                mark = 0;
                score = 0;
            }
            else if (ch == 'n' || ch == 'N') {
                system("cls");
                printf("欢迎下次来玩!\n");
                system("pause");
                exit(1);
            }
            else {
                printf("输入错误,请重新输入!\n");
            }
        }
    }
}

int main() {
    //进行2048游戏
    playGame();
    system("pause");
    return 0;
}

五、游戏运行截图

  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

攻城狮7号

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值