C语言实战系列一:经典贪食蛇

news2024/10/2 20:30:57

C语言学习必须实战,并且学完语法后就必须立即用实战来巩固。一般需要10来个比较复杂的程序才能掌握C语言。今天就教大家第一个小程序,贪食蛇。

首先上代码

一、代码

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <unistd.h>
#include <time.h>

#define WIDTH 20
#define HEIGHT 10

int score = 0;
int gameover;
int x, y, fruitX, fruitY, flag;

int tailX[100], tailY[100];
int nTail;

void setup() {
    gameover = 0;

    // 初始化蛇的位置
    x = WIDTH / 2;
    y = HEIGHT / 2;

    // 初始化食物的位置
    fruitX = rand() % WIDTH;
    fruitY = rand() % HEIGHT;
}

void draw() {
    clear(); // 清屏

    for (int i = 0; i < WIDTH + 2; i++)
        printw("#");

    printw("\n");

    for (int i = 0; i < HEIGHT; i++) {
        for (int j = 0; j < WIDTH; j++) {
            if (j == 0)
                printw("#"); // 左墙
            if (i == y && j == x)
                printw("O"); // 蛇头
            else if (i == fruitY && j == fruitX)
                printw("F"); // 食物
            else {
                int isTail = 0;
                for (int k = 0; k < nTail; k++) {
                    if (tailX[k] == j && tailY[k] == i) {
                        printw("o"); // 蛇身
                        isTail = 1;
                    }
                }
                if (!isTail)
                    printw(" ");
            }

            if (j == WIDTH - 1)
                printw("#"); // 右墙
        }
        printw("\n");
    }

    for (int i = 0; i < WIDTH + 2; i++)
        printw("#");

    printw("\n");
    printw("Score:%d", score);
    refresh(); // 刷新屏幕
}

void input() {
    int ch = getch(); // 获取键盘输入
    switch (ch) {
        case 'a':
            flag = 1;
            break;
        case 'd':
            flag = 2;
            break;
        case 'w':
            flag = 3;
            break;
        case 's':
            flag = 4;
            break;
        case 'x':
            gameover = 1;
            break;
    }
}

void algorithm() {
    usleep(100000); // 休眠,控制蛇的速度
    int prevX = tailX[0];
    int prevY = tailY[0];
    int prev2X, prev2Y;
    tailX[0] = x;
    tailY[0] = y;

    for (int i = 1; i < nTail; i++) {
        prev2X = tailX[i];
        prev2Y = tailY[i];
        tailX[i] = prevX;
        tailY[i] = prevY;
        prevX = prev2X;
        prevY = prev2Y;
    }

    switch (flag) {
        case 1:
            x--;
            break;
        case 2:
            x++;
            break;
        case 3:
            y--;
            break;
        case 4:
            y++;
            break;
        default:
            break;
    }

    // 判断是否碰到墙
    if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT)
        gameover = 1;

    // 判断是否吃到食物
    if (x == fruitX && y == fruitY) {
        score += 10;
        fruitX = rand() % WIDTH;
        fruitY = rand() % HEIGHT;
        nTail++;
    }
}

int main() {
    srand(time(NULL)); // 设置随机数种子
    initscr(); // 初始化 curses
    keypad(stdscr, TRUE); // 启用键盘输入
    nodelay(stdscr, TRUE); // 非阻塞输入
    noecho(); // 关闭回显

    setup();

    while (!gameover) {
        draw();
        input();
        algorithm();
    }

    endwin(); // 关闭 curses
    return 0;
}

二、编译

代码的运行平台是ubuntu,代码用到了curses库,需要提前安装:

 sudo apt-get install libncurses5-dev

然后用下面命令编译

gcc snake_game.c -o snake_game -lncurses

执行程序:

./snake_game

注意!如果速度过快,就会结束,直接跳出程序到控制台,如何修改速度下面会讲到。

三、编程指导

  1. 初始化 (setup 函数):

    • gameover: 游戏结束标志。
    • xy: 蛇头的初始坐标。
    • fruitXfruitY: 食物的初始坐标。
    • flag: 用于存储用户输入的方向。
    • score: 记录游戏得分。
    • nTail: 蛇身的长度。
    • tailXtailY: 用于存储蛇身各部分的坐标。
  2. 游戏主循环:

    while (!gameover) {
        draw();
        input();
        algorithm();
    }
    

    游戏在一个无限循环中进行,直到 gameover 变为真。在每次循环中,先绘制游戏画面,然后处理用户输入,最后执行游戏逻辑。

  3. 输入处理 (input 函数):

    • 使用 getch 函数获取键盘输入。
    • 根据用户输入的键值设置 flag 的值,表示蛇移动的方向。
    • 'a': 左,'d': 右,'w': 上,'s': 下,'x': 退出游戏。
  4. 游戏逻辑 (algorithm 函数):

    • 使用 usleep 函数添加一点延迟,以控制蛇的速度。(如果速度过快,游戏会很快结束,需要添加延时)
    • 更新蛇身的位置。
    • 根据用户输入的方向移动蛇头。
    • 判断是否碰到墙,如果是则游戏结束。
    • 判断是否吃到食物,如果是则增加得分,重新生成食物,增加蛇身的长度。
  5. 绘制 (draw 函数):

    • 使用 clear 函数清空屏幕。
    • 使用 printw 函数输出字符。
    • 使用 refresh 函数刷新屏幕。
    • 输出游戏画面,包括墙、蛇头、食物和蛇身。
    • 输出得分信息。
  6. 初始化和关闭 curses (initscrendwin 函数):

    • initscr: 初始化 curses 库。
    • keypad: 启用键盘输入。
    • nodelay: 设置非阻塞输入。
    • noecho: 关闭回显。
    • endwin: 关闭 curses 库。
  7. 编译和运行:

    • 使用 gcc 编译器编译程序,并链接 ncurses 库。
    • 运行生成的可执行文件。

四、继续完善

这段贪食蛇游戏代码已经基本完成了一个简单的实现,但仍然有一些方面可以改进和完善,具体包括:

  1. 边界检查:

    当蛇头移动到边界时,游戏会结束。可以考虑在边界处实现蛇穿越的效果,即从一侧穿越到另一侧。
  2. 游戏难度递增:

    目前游戏的难度保持不变,可以考虑逐渐增加蛇的移动速度或者加快食物的生成速度,使得游戏更具挑战性。
  3. 碰撞检测:

    目前只有边界碰撞检测和食物碰撞检测,可以考虑添加对蛇头与蛇身碰撞的检测,以防止游戏结束。
  4. 游戏结束提示:

    当游戏结束时,可以输出更友好的提示信息,告诉玩家是因为碰到墙还是碰到自己身体而导致游戏结束。
  5. 代码结构和模块化:

    将代码进一步模块化,使得各部分功能更清晰、易读、易于维护。可以考虑将一些功能性代码抽象成函数。
  6. 用户界面交互:

    添加开始界面和游戏结束后的界面,以提供更良好的用户体验。
  7. 更多游戏元素:

    考虑添加更多的游戏元素,如障碍物、特殊道具等,以增加游戏的趣味性和多样性。

这些功能给大家作为练习去实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1402173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

windows用mingw(g++)编译opencv,并install安装

windows下用mingw编译opencv貌似不支持cuda&#xff0c;选cuda会报错&#xff0c;我无法解决&#xff0c;所以没选cuda&#xff0c;下面两种编译方式支持。 如要用msvc编译opencv&#xff0c;参考我另外一篇文章。 如要用Ubuntu编译opencv&#xff0c;参考我另外一篇文章http…

UE5 Windows打包时报错“SDK Not Found”解决方案

在Unreal Engine 5.0.3 Windows平台下打包时报错&#xff1a;“Windows的SDK未正常安装&#xff0c;而其是生成数据的必需项。请检查主工具栏中“启动“菜单SDK部分来更新SDK。” 解决方案&#xff1a; 1、打开 Visual Studio Installer&#xff0c;点击“修改”按钮&#xf…

时空预测网络ST-Resnet 代码复现

ST-ResNet&#xff08;Spatio-Temporal Residual Network&#xff09;是一种用于处理时空数据的深度学习模型&#xff0c;特别适用于视频、时间序列等具有时空结构的数据。下面是一个简单的使用PyTorch搭建ST-ResNet的示例代码。请注意&#xff0c;这只是一个基本的示例&#x…

Hadoop基本概论

目录 一、大数据概论 1.大数据的概念 2.大数据的特点 3.大数据应用场景 二、Hadoop概述 1.Hadoop定义 2.Hadoop发展历史 3.Hadoop发行版本 4.Hadoop优势 5.Hadoop1.x/2.x/3.x 6.HDFS架构 7.Yarn架构 8.MapReduce架构 9.大数据技术生态体系 一、大数据概论 1.大数…

【动态规划】【广度优先搜索】【状态压缩】847 访问所有节点的最短路径

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 广度优先搜索 状态压缩 LeetCode847 访问所有节点的最短路径 存在一个由 n 个节点组成的无向连通图&#xff0c;图中的节点按从 0 到 n - 1 编号。 给你一个数组 graph 表示这个图。其中&#xff0c;graph[i] 是一个列…

Java开发分析工具 JProfiler的详细使用方法解析(附 JProfiler for Mac许可证秘钥)

JProfiler 是一款功能强大的Java代码分析工具&#xff0c;JProfiler的直观UI可帮助您解决性能瓶颈&#xff0c;确定内存泄漏并了解线程问题且JProfiler Mac破解版配置会话非常简单&#xff0c;第三方集成使得入门变得轻而易举&#xff0c;并且以自然的方式呈现数据分析。 解…

AlmaLinux 8.9 安装图解

风险告知 本人及本篇博文不为任何人及任何行为的任何风险承担责任&#xff0c;图解仅供参考&#xff0c;请悉知&#xff01;本次安装图解是在一个全新的演示环境下进行的&#xff0c;演示环境中没有任何有价值的数据&#xff0c;但这并不代表摆在你面前的环境也是如此。生产环境…

C++ 知识列表【图】

举例C的设计模式和智能指针 当谈到 C 的设计模式时&#xff0c;以下是一些常见的设计模式&#xff1a; 工厂模式&#xff08;Factory Pattern&#xff09;&#xff1a;用于创建对象的模式&#xff0c;隐藏了对象的具体实现细节&#xff0c;只暴露一个公共接口来创建对象。 单例…

scanpy预处理总结

欢迎关注我们组的微信公众号&#xff0c;更多好文章在等你呦&#xff01; 微信公众号名&#xff1a;碳硅数据 公众号二维码&#xff1a; 记录一下关于scanpy preprocessing的结果 import scanpy as sc adata sc.read("/Users/yxk/Desktop/test_dataset/pbmc/pbmc.h5ad&…

【Proteus仿真】【Arduino单片机】甲醛浓度检测报警器

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用蜂鸣器LED模块、LCD1602显示模块、按键、MS1100甲醛传感器模块等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示甲醛气体浓度检…

SystemC学习笔记(三) - 查看模块的波形

简述 波形在Simulation/Emulation中地位十分重要&#xff0c;尤其是在研发初期&#xff0c;只能通过波形来查看软件hang住的位置。 对于TLM来说&#xff0c;查看波形一般是指查看pvbus上的transaction&#xff0c;而对于SystemC本身来说&#xff0c;查看波形就是使用Gtkwave或…

Python 备份 CSDN 博客

代码来源 根据csdn 中的 一位博主 备份代码修改 新增加 增加了保存图片 到本地&#xff0c;和修改markdown中图片的路径 问题 如果博客的内容太多&#xff0c;需要分多个truck 传输,保存时出现’字符时,无法保存 注意 得获取登陆后的cookie&#xff0c;要不没法从服务器请求回博…

基于时空模型的视频异常检测

假设存在一个运动区域&#xff0c;规则要求只能进行特定的运动项目。 出于安全原因或因为业主不喜欢而禁止进行任何其他活动:)。 我们要解决的问题是&#xff1a;如果我们知道正确行为的列表&#xff0c;我们是否可以创建一个视频监控系统&#xff0c;在出现不常见的行为发出通…

IO、NIO、IO多路复用

IO是什么&#xff1f; IO分为两类&#xff0c;它们之间是有区别的&#xff0c;而且有很大的区别&#xff1b;1. 文件系统的IO 也叫本地io&#xff0c;就是和磁盘或者外围存储设备进行读写操作&#xff0c;外围设备有USB、移动硬盘等等&#xff1b;2. 网络的IO 将数据发送给对方…

获取主流电商平台商品价格,库存信息,数据分析,SKU详情

要接入API接口以采集电商平台上的商品数据&#xff0c;可以按照以下步骤进行&#xff1a; 1、找到可用的API接口&#xff1a;首先&#xff0c;需要找到支持查询商品信息的API接口。这些信息通常可以在电商平台的官方文档或开发者门户网站上找到。 2、注册并获取API密钥&#x…

「 典型安全漏洞系列 」05.XML外部实体注入XXE详解

1. XXE简介 XXE&#xff08;XML external entity injection&#xff0c;XML外部实体注入&#xff09;是一种web安全漏洞&#xff0c;允许攻击者干扰应用程序对XML数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件&#xff0c;并与应用程序本身可以访问的任何后…

Windows 拦截系统睡眠、休眠

前言 在前一篇文章中&#xff0c;我们分析了以编程方式拦截 Winlogon 相关回调过程的具体做法&#xff0c;我们给出了一种拦截 RPC 异步回调的新方法——通过过滤特征码&#xff0c;我们可以对很多系统热键以及跟电源有关的操作做出“提前”响应。但是我们给出的代码并不能真正…

7.前端--CSS-复合选择器

1.什么是复合选择器 复合选择器是由两个或多个基础选择器&#xff0c;通过不同的方式组合而成的&#xff0c;可以更准确、更高效的选择目标元素&#xff08;标签&#xff09; 常用的复合选择器包括&#xff1a;后代选择器、子选择器、并集选择器、伪类选择器等等 2.后代选择器 …

DAY06_SpringBoot—入门properties/YML文件lombok插件及使用

目录 1 SpringBoot1.1 SpringBoot介绍1.2 SpringBoot入门案例1.2.1 安装SpringBoot插件1.2.2 创建SpringBoot项目 1.3 关于SpringBoot项目说明1.3.1 关于POM.xml文件说明1.3.2 依赖配置项1.3.3 build标签 1.4 SpringBoot Maven操作1.4.1 项目打包1.4.2 java命令运行项目 1.5 关…