贪吃蛇(C语言)

2023-10-26


贪吃蛇项目

核心算法:循环数组,发牌算法,二维坐标一维化
编译环境:TC 2.0

准备工作:学习gotoxy()函数,了解bioskey()函数使用,知道bioskey(1)与bioskey(0)的区别,了解键盘扫描码,并且知道如何使用。

核心工作:1.了解循环数组的下标循环规律
2.理解发牌算法的核心代码
3.掌握如何对二维坐标进行一维化的处理,以及二者之间的转换


那么,首先我们先来了解一下gotoxy()这个函数:
gotoxy (int x, int y)是 Borland C 扩充函数库 conio.h 中声明的一个函数,功能是将光标移动到指定位置。 在当代的 Visual C++ 或 GCC 中可以自定义这个函数。 在上世纪80-90年代流行的集成开发环境 Turbo C 或 Borland C 中的扩充函数库 conio.h 提供了 gotoxy 函数,用于屏幕输出,功能是将 光标 移动到屏幕指定位置。 在屏幕的左上角被定义为光标的坐标原点 (0, 0),横向为 X 轴,纵向为 Y 轴。
因为我们是Turbo C的环境,所以在使用时应该写上#include <conio.h>这个头文件。
接下来我们再来看bioskey()这个函数:
函数原型:int bioskey (int cmd)
说明:bioskey()的函数原型在bios.h中
bioskey()完成直接键盘操作,cmd的值决定执行什么操作。
cmd = 0:
当cmd是0,bioskey()返回下一个在键盘键入的值(它将等待到按下一个键)。它返回一个16位的二进制数,包括两个不同的值。当按下一个普通键时,它的低8位数存放该字符的ASCII码,高8位存放该键的扫描码;对于特殊键(如方向键、F1~F12等等),低8位为0,高8位字节存放该键的扫描码。
cmd = 1:
当cmd是1,bioskey()查询是否按下一个键,若按下一个键则返回非零值,否则返回0。
重要的一点是bioskey()函数检测后该键的键值被留在键盘缓冲区中,需要的话可以将它从键盘缓冲区中取出。

做完准备工作后,我们开始进行第一个核心算法—发牌算法
例如:
int arr[10] = {1,5,9,3,7,2,8,4,0,6};
从这10个数中挑选出六个完全随机且绝对不重复的数。
n个元素,随机生成0到n-1的下标,将被选出的元素调整(交换)的末尾,使得未挑选元素的下标,在0到n-2之间,下一轮随机生成生成0到n-2的下标,如此往复。
代码示例如下:

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

void swap(int *p, int *q);

void swap(int *p, int *q) {
	int temp;
	temp = *p;
	*p = *q;
	*q = temp;
}

int main() {
	int arr[10] = {3,8,1,2,0,9,6,5,7,4};
	int i;
	int index;
	int n = 10;
	srand((unsigned) time(NULL));
	for(i = 0; i < 6; i++) {
		index = rand()%n;
		printf("%d\t",arr[index]);
		swap(&arr[index],&arr[n--]);
	}
}

接下来的核心算法就是循环数组,目的是实现蛇的移动,使用数组而不使用链表的原因是因为没有必要,不划算,数组的操作相较于链表更加简单也更加方便。
而循环数组相较于普通数组,在蛇进行移动时更加方便,时间复杂度也会降低。

如何使得下标循环起来呢?这里有一个公式:
headIndex(蛇头坐标) = (index + 数组的长度 + 1)%数组的长度
tailIndex(蛇尾坐标) = (index + 数组的长度 - 蛇的长度 + 1)%数组的长度

移动蛇
使用循环数组来存储蛇身体每个点的行,列坐标
初始显示一个蛇头,慢慢增多,直到等于设定的蛇的长度
蛇移动的过程:
1.if(当前长度 < 蛇本身长度) {
当前长度++;
} else {
消尾;
}
2.改颈:在原来蛇头的地方画上蛇的身体
3.画头

二维坐标一维化:
i,j
1,1 1,2 1,3 1,4 2*4的二维数组 4:COL_COUNT
0 1 2 3
2,1 2,2 2,3 2,4
4 5 6 7

index(下标) = (i-1) *COL_COUNT+(j-1)
i = t / COL_COUNT + 1
j = t % COL_COUNT + 1

部分源码如下:

#include <stdio.h>
#include <bios.h>
#include <conio.h>
#include <stdlib.h>
#include <time.h>

#include "keyValue.h"
#include "snakeValue.h" 

const int delta[][2] = {
	{0, -1},
	{0, 1},
	{-1, 0},
	{1, 0}, 
};

void keyOperate(ARG *arg);
boolean moveSnake(ARG *arg, SIT *sit, int *map);
void printHead(ARG *arg);
void produceFood(ARG *arg, SIT *sit, int *map);
void swap(int *p, int *q);
void printMap(int *map);

void printMap(int *map) {
	int i;
	int x;
	int y;
	int j;
	for(i = 0; i < 2000; i++) {
		
		x = i % COL_COUNT + 1;
		y = i / COL_COUNT + 1;

		if((x == 26 || x == 55) && ((y >= 4 && y <= 8)||(y >= 18 && y <=22))) {
			map[i] = 4;
			for (j = 0; j < 6; j++) {
				gotoxy(x,y);
				printf("%c",254);
			}
		}

		if((y == 8 || y == 18) && ((x >= 6 && x <= 26) || (x >= 55 && x <= 74))) {
			map[i] = 4;
			for(j = 0 ; j < 20; j++) {
				gotoxy(x,y);
				printf("%c",254);
			}
		}

		if(map[i] == 3) {
			gotoxy(x,y);
			printf("%c",254);
			
		}
	}
}

void swap(int *p, int *q) {
	int temp;
	temp = *p;
	*p = *q;
	*q = temp;
}

void produceFood(ARG *arg, SIT *sit, int *map) {
	int foodMap[2000] = {0};
	int i;
	int x;
	int y;
	int index = 0;
	int q;
	srand((unsigned) time(NULL));
	for (i = 0, q = 0; i < 2000; i++) {
		if (map[i] == 0) {
			foodMap[q] = i;
			q++;
		}
	}
	q++;
	for (i = 0; i < 10; i++) {
		index = rand()%q;
		
		map[foodMap[index]] = 2;
		
		x = foodMap[index] % COL_COUNT + 1;
		y = foodMap[index] / COL_COUNT + 1;
		
		gotoxy(x,y);
		printf("%c",157);
		swap(&foodMap[index],&foodMap[--q]);
	}

}

void printHead(ARG *arg) {
	if (arg->direct == LEFT ) {

		printf("<");
	}
	if (arg->direct == RIGHT ) {

		printf(">");
	}
	if (arg->direct == UP ) {
							
		printf("^");
	}
	if (arg->direct == DOWN ) {

		printf("v");
	}
}

boolean moveSnake(ARG *arg,SIT *sit,int *map) {
	int tailIndex;
	int x;
	int y;
	int index;
	
	tailIndex = (arg->headIndex + MAXLEN - arg->length + 1) % MAXLEN;
	if(arg->curLength < arg->length) {
		arg->curLength++;
	} else {
		gotoxy(sit[tailIndex].row,sit[tailIndex].col);
		printf(" ");
		index = (sit[tailIndex].row - 1) * COL_COUNT + (sit[tailIndex].col - 1);
		map[index] = 0;
	}
	index = (sit[arg->headIndex].col - 1) * COL_COUNT + (sit[arg->headIndex].row - 1);
	gotoxy(sit[arg->headIndex].row,sit[arg->headIndex].col);
	printf("%c",233);
	map[index] = 5;
	x = sit[arg->headIndex].row;
	y = sit[arg->headIndex].col; 
	arg->headIndex = (arg->headIndex + MAXLEN + 1) % MAXLEN;
	sit[arg->headIndex].row = x + delta[arg->direct][0];
	sit[arg->headIndex].col = y + delta[arg->direct][1];
	index = (sit[arg->headIndex].col - 1) * COL_COUNT + (sit[arg->headIndex].row - 1);
	
	if(map[index] == 2) {
		arg->eatCount++;
		arg->length++;
	}

	if(map[index] == 3 || map[index] == 4 || map[index] == 5) {
		return FALSE;
	}
	map[index] = 1;
	
	gotoxy(sit[arg->headIndex].row,sit[arg->headIndex].col);
	printHead(arg); 
	return TRUE;
	

} 

void keyOperate(ARG *arg) {
	if (arg->key == KEY_UP) {
		arg->direct = UP;	
	} else if (arg->key == KEY_DOWN) {
		arg->direct = DOWN;	
	} else if (arg->key == KEY_LEFT) {
		arg->direct = LEFT;
	} else if (arg->key == KEY_RIGHT) {
		arg->direct = RIGHT;	
	} else if (arg->key == KEY_ESC) {
		arg->finished = TRUE;
	} else if (arg->key == KEY_ADD) {
		if(arg->delayTime > 1000) {
			arg->judgeSpeed = -1000;
		}
	}else if (arg->key == KEY_SUB) {
		if(arg->delayTime < 15000) {
			arg->judgeSpeed = 1000;
		}
	} else if(arg->key == KEY_SPACE) {
		arg->gameOut = !arg->gameOut;
	}

}

需要源码的可以在下面留言,如果觉得代码还有什么可以改进的,也可以在下面进行交流。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

贪吃蛇(C语言) 的相关文章

  • VScode调试php文件(详细且简单易操作)

    之前也不懂 看了网上好多帖子 按照它们步骤操作一遍之后 还是不行 头都大了 现在懂了 原来几步就搞定了 被它们搞得这么复杂 又是配置这个文件 又是配置那个文件 1 下载XAMPP Download XAMPP apachefriends o
  • Java程序员面试常问试题大全

    Java程序员面试常问试题大全 1 面向对象的特征有哪些方面 1 抽象 抽象就是忽略一个主题中与当前目标无关的那些方面 以便更充分地注意与当前目标有关的方面 抽象并不打算了解全部问题 而只是选择其中的一部分 暂时不用部分细节 抽象包括两个方
  • 详解 cryptogen 的内容和配置

    目录 1 cryptogen 模块命令说明 2 cryptogen 模块的配置文件 3 cryptogen 实例 创建测试配置文件 4 Fabric 证书文件的结构 cryptogen 模块主要用来生成组织结构和账号相关的文件 任何 Fab
  • 【react】实现数据双向绑定之不用柯里化的方式

    直接给onChange事件绑定一个箭头函数 这个箭头函数的参数就是event 在箭头函数内再调用saveFormData方法 saveFormData方法里面this setState dataType value
  • 学Python该看什么书?12本精华好书推荐!

    为了让更多想通过看书来学习Python的人能够把时间花在刀刃上 小编总结了Python目前所有热门方向上我个人觉得性价比很高 值得一看的书籍 今天小编来分享给大家 一 Python新手入门 新手学Python的话我推荐这本 Python编程

随机推荐

  • java:面向对象(多态中成员的特点)。

    这次我们说说多态中成员的特点 我们写这样一个代码 class Fu void method1 System out println fu method1 void method2 System out println fu method 2
  • 秒解小米bl锁 无需等待时间_小米全新系统曝光:小米9推送Android Q体验版

    点击上方蓝字订阅每日最新国产手机资讯 对于米粉来说 MIUI系统是他们坚持使用小米手机的重要原因 就在今天上午 MIUI官方微博发布消息 小米9的MIUI Android Q Beta优先体验版现已推送 已获得测试资格的朋友可以升级体验 据
  • 大厂笔试真题

    1 复数相乘 2 K个一组翻转链表 include
  • 浅谈 Python中if __name__ == ‘__main__‘:的工作原理

    为了理解if name main 的工作原理 我们需要先了解Python中的特殊变量 name 每个Python模块都有一个内置的变量 name 这个变量的值取决于如何执行模块 如果模块是被直接运行的 例如 你使用命令python mysc
  • 「网络安全」如何搭建MySQL恶意服务器读取文件?

    前言 注 本文不涉及对MySQL协议报文研究 仅讲解原理 并且做部分演示 搭建MySQL恶意服务器读取文件这件事 虽然直接利用门槛较高 但是由于在网上看到了一种比较新颖的利用方式 利用社会工程学引诱用户连接MySQL进而读取用户文件 个人觉
  • Day【4】字符串解码

    原题链接 思路 对于字符串k encoding 对于这样的形式 我们要加encoding重复k次 从左向右扫描字符串 如果说遇见字符 就直接将该字符添加到结果中 如果说 遇见 k encoding 的形式 我们首先要做的是就是将k和enco
  • GCC参数详解

    gcc and g 分别是gnu的c c 编译器 gcc g 在执行编译工作的时候 总共需要4步 1 预处理 生成 i的文件 预处理器cpp 2 将预处理后的文件不转换成汇编语言 生成文件 s 编译器egcs 3 有汇编变为目标代码 机器代
  • 9.OB4.0调用存储过程通过临时表返回多行记录

    MYSQL存储过程返回多行 1 表数据准备 drop table if exists t1 drop table if exists t2 drop table if exists t3 create table t1 id varchar
  • 任何程序都必须加载到什么中才能被cpu执行

    任何程序都必须加载到内存中才能被cpu执行 内存是计算机中的重要部件之一 它是外存与cpu进行沟通的桥梁 计算机中所有程序的运行都在内存中进行 内存性能的强弱影响计算机整体发挥的水平 任何程序都必须加载到内存中才能被cpu执行 学习视频分享
  • WPF 性能优化建议

    本章讲述 WPF 性能优化建议 20180930 WPF性能优化问题 运行软件发现CPU使用率很大 80 95 程序中含有委托 线程 定时器的处理 之前优化时 主要优化线程和定时器相关线程方面的处理 但是效果甚微 无意间看到博客中说程序界面
  • Android onInterceptTouchEvent与onTouchEvent调用关系

    概述 onInterceptTouchEvent 是用来拦截Touch事件 ViewGroup有 View没有 onTouchEvent 是Touch事件 ViewGroup与View都有 实例讲解 当一个Touch事件发生后 会由父布局开
  • connect错误:no route to host

    linux下 socket 用vmware装了两个虚拟机 分别运行客户端和服务器端 客户端连接的时候报错 connect error no route to host 但是在同一虚拟机下运行正常 我检查了socket返回值 正常 地址和端口
  • U-boot引导流程分析一

    U Boot 全称 Universal Boot Loader 即通用引导程序 是遵循GPL条款的开放源码项目 它的源码目录 编译形式与Linux内核很相似 事实上 不少U Boot源码就是相应的Linux内核源程序的简化 尤其是一些设备的
  • linuxptp源码研究

    目录 1 检查网卡是否支持相应的时间戳 2 linuxptp的目录架构 3 ptp4l的大致流程分析 4 gptp协议对应的sync follow up delay request delay response消息在代码的位置 5 slav
  • Deeplearning4j 实战 (13):基于TextCNN的文本分类实现

    Eclipse Deeplearning4j GitChat课程 Deeplearning4j 快速入门 专栏Eclipse Deeplearning4j 系列博客 万宫玺的专栏 wangongxi CSDN博客Eclipse Deeple
  • java native

    1 java lang Boolean中没有 native方法2 java lang Character中没有native方法3 java lang Byte中没有本地方法4 java labg Short中没有本地方法5 java lan
  • Go语言学习笔记(六)---map

    4 7 map map是key value数据结构 又称为字段或者给关联数组 类似其他编程语言的集合 映射 基本语法 var map变量名 map keytype valuetype keytype可以是bool int string 指针
  • ubuntu 忘记root密码

    方法一 如果用户具有sudo权限 那么直接可以运行如下命令 sudo su root 输入当前用户的密码 passwd 输入密码 再次输入密码 方法二 如果用户不具备sudo权限 则方法一不能用 并需进入GRUB修改kernel镜像启动参数
  • 如何用 Python 批量循环读取 Excel ?

    在使用 Python 批量处理 Excel 时经常需要批量读取数据 常见的方式是结合glob模块 可以实现将当前文件夹下的所有csv批量读取 并且合并到一个大的DataFrame中 df list for file in glob glob
  • 贪吃蛇(C语言)

    贪吃蛇项目 核心算法 循环数组 发牌算法 二维坐标一维化 编译环境 TC 2 0 准备工作 学习gotoxy 函数 了解bioskey 函数使用 知道bioskey 1 与bioskey 0 的区别 了解键盘扫描码 并且知道如何使用 核心工