TCS 贪吃蛇C源码

2024-06-05 07:32
文章标签 源码 贪吃蛇 tcs

本文主要是介绍TCS 贪吃蛇C源码,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

linux版:这是我自己独立制作的自认为比较成功的小游戏,贪吃蛇主要运用了链表技术以及排序算法。

原版是2014年的windows版后期我移植到了linux:

// mtcsV1_2.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h"
#include<stdio.h>
//#include<conio.h>
#include<termios.h>
#include<stdlib.h>
//#include<windows.h>
#include<time.h>			  
#define MAX  3200 
#define LEN  sizeof(Snake)
typedef unsigned char uchar;
//------------------------
typedef struct snake{                   char x;char y;struct snake *next;struct snake *last;
}Snake;//双向链表
Snake *h,*tp1,*tp2;
Snake *t,*hp1,*hp2;//表尾tail
//----------------------(数组图片)结构体化---------------------------------typedef struct Pic{char x[MAX];char y[MAX];int pnum;
}PIC;//-----------------------------------------------------------------------
PIC p0,p1;
//------------------------
char f;//食物标志
int  m=0,n=0;//食物位置 
int a=20;
int BaseCount=0;
//------------------------
int  color=5;//设置蛇头颜色
int  score=0;
int _score=0;//历史分数变量
int step=0;//记录吃食物所用步数
int foodlose=0;//记录未吃到的食物数
//SYSTEMTIME SysTime;
char TimeStr[30];
#define AutoStepNum 40 //自动行走的初始步数
#define AutoStepWidth 1
#define SIMPLE 300
#define DIFFICULT 100
#define ORDINARY 1 	 //180
//运行界面大小设置
#define XStart 10
#define XEnd  40
#define YStart 2
#define YEnd   12
#define XLen (XEnd-XStart)
#define YLen (YEnd-YStart)
#define ALLDISP 1
#define PARTDISP 0
//
//#define AUTOGO
//--------函数声明-------void save();void load();void creat();void gameover();void move(void);char autogo();//------------------------
static struct termios initial_settings,new_settings;
static int peek_character = -1;
void init_keyboard(void)
{tcgetattr(fileno(stdin),&initial_settings);new_settings = initial_settings;new_settings.c_lflag &= (~ICANON) ;//(ICANON|ECHO|ISIG);new_settings.c_lflag &= (~ ECHO) ;//(ICANON|ECHO|ISIG);new_settings.c_lflag |= ISIG ;//(ICANON|ECHO|ISIG);new_settings.c_cc[VMIN]  = 1;new_settings.c_cc[VTIME] = 0;tcsetattr(fileno(stdin),TCSANOW,&new_settings);}
void close_keyboard(void)
{tcsetattr(0,TCSANOW,&initial_settings); }
/*
1.
NTR:该字符使终端驱动程序向与终端相连的进程以送SIGINT信号
QUIT:该字符使终端驱动程序向与终端相连的进程发送SIGQUIT信号
EOF;该字符使终端驱动程序将输入行中的全部字符传递给正在读取输入的应用程序.如果输入行为空,read调用将返回0,就好像在文件尾调用read一样
...
2.TIME和MIN值
这两个值只用于非标准模式,两者结合共同控制对输入的读取方式,还能控制在一个程序试图与一个终端关联的文件描述符时将发生的情况
MIN = 0, TIME = 0时:read立即返回,如果有待处理的字符,它们就会被返回,如果没有,read调用返回0,且不读取任何字符
MIN = 0, TIME > 0时:有字符处理或经过TIME个0.1秒后返回
MIN > 0, TIME = 0时:read一直等待,直到有MIN个字符可以读取,返回值是字符的数量.到达文件尾时返回0
MIN > 0, TIME > 0时:read调用时,它会等待接收一个字符.在接收到第一个字符及其后续的每个字符后,启用一个字符间隔定时器.当有MIN个字符可读或两字符间的时间间隔超进TIME个0.1秒时,read返回
通过设置MIN和TIME值,我们可以逐个字符地对输入进行处理3.通过shell访问终端模式
stty -a:这个命令用来查看当前终端的设置情况
stty sane:如果不小心设错了终端模式,可用这个命令恢复,另一种恢复办法是在设置之前保存当前stty设置,在需要时再读
stty -g > save_stty:将当前设置保存到文件save_atty中
stty $(cat save_stty):读出save_atty文件,恢复原终端设置
第三种恢复的办法是重新打下一个终端模拟器.查看死掉的终端进程,kill掉它4.在命令行模式下设置终端模式
比如想让shell脚本读取单个字符,就需要关闭标准模式,同时将MIN设为1,TIME设为0:
stty -icanon min1 time 0
另一个例子是关闭输入密码时的回显功能:
atty -echo
使用完这个命令后要执行atty echo,将回显功能再次恢复
5.其他函数
这些函数直接作用于文件描述符,不需要读写termios结构:
#include <termios.h>
int tcdrain(int fd);让调用程序一直等待,直到所有排队的输出都发送完毕
int tcflow(int, int flowtype);暂停或重新开始输出
int tcflush(int fd, int in_out_selector);清空输入,输出或两者都清华空*/
int kbhit(void)
{unsigned char ch;int nread;if(peek_character != -1)  return 1;new_settings.c_cc[VMIN] = 0;tcsetattr(fileno(stdin),TCSANOW,&new_settings);nread = read(0,&ch,1);new_settings.c_cc[VMIN] = 1;tcsetattr(fileno(stdin),TCSANOW,&new_settings);if(nread == 1){peek_character = ch;return 1;}return 0;}int readch(void)
{char ch;if(peek_character != -1){ch = peek_character;peek_character = -1;return ch;}read(0,&ch,1);return ch;}//-------颜色设置-----------------
void colorf(unsigned short  t)
{printf("\033[%dm",t);//value=30~40//    HANDLE  color;//创建句柄    color是变量名可以自己定义
//    color=GetStdHandle(STD_OUTPUT_HANDLE);//句柄实例化
//    SetConsoleTextAttribute(color,t);//设置字体颜色
}
//-------光标定位-------------------------
void  gotoxy(int x,int y)
{printf("\033[%d;%dH",y+1,x+1);	//COORD c;//c.X=x;c.Y=y;//SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
} //--------------------------------------
void picture(char DispSle)
{//图框重绘int i;//销前for(i=0;i<p1.pnum;i++){gotoxy(p1.y[i]*2,p1.x[i]);printf("  "); }//重绘if(DispSle){ i=0;   }else{ i=BaseCount;  }//for(;i<p0.pnum;i++){gotoxy(p0.y[i]*2,p0.x[i]);//用于宽字符  if(p0.x[i]==h->x&&p0.y[i]==h->y)     {	//蛇头colorf(color+30);//printf("■");printf("@");colorf(34);}else if(p0.x[i]==YStart||p0.x[i]==YEnd||p0.y[i]==XStart||p0.y[i]==XEnd)   {  colorf(35); printf("□");//墙壁 colorf(34);}else if(p0.x[i]==n&&p0.y[i]==m)	 {  printf("&");//食物}else{//printf("●");//蛇身printf("#");}//if(i>=BaseCount){p1.x[i-BaseCount]=p0.x[i];p1.y[i-BaseCount]=p0.y[i];}}p1.pnum=p0.pnum-BaseCount;putchar(10);
}
//------------------------------
void s_add_t(char a,char b)//加尾
{//---开辟新节点并链接---tp2=(Snake*)malloc(LEN);tp2->x=a;tp2->y=b;tp1->next=tp2;tp2->last=tp1;tp2->next=NULL;//-------------------t=tp1=tp2;
}
void s_add_h(char a,char b)//加头
{hp2=(Snake*)malloc(LEN);hp2->x=a;hp2->y=b;hp2->last=NULL; hp2->next=hp1;hp1->last=hp2;h=hp1=hp2;
}
void  s_sub(char a)      
{   Snake* p;if(a>0){p=h;hp1=h=h->next;//此处要当心hp1应始终和h保持同步,在创建一个新h时默认hp1指向当前h,此处若不更新//hp1将为NULL,导致链接错误h->last=NULL;} //删去蛇头if(a<0){p=t;tp1=t=t->last;t->next=NULL;}//删去蛇尾free(p);
}    
void s_play(Snake *p,char DispSle)
{  int i=BaseCount;//前面点做图框if(f)   { p0.y[i]=m=rand()%(XLen-1)+1+XStart; p0.x[i]=n=rand()%(YLen-1)+1+YStart;  f=0;}//放置食物else  {   p0.y[i]=m;  p0.x[i]=n; }i++;p0.x[i]=p->x;p0.y[i]=p->y;// printf("%d\t%d\n",p->x,p->y);i++;  do     { if(p->next==NULL)   break;p=p->next;p0.x[i]=p->x;p0.y[i]=p->y;// printf("%d\t%d\n",p->x,p->y);i++;  } while(p->next!=NULL);p0.pnum=i;//getch();colorf(31);picture(DispSle);colorf(32);gotoxy(YStart,YEnd);printf("\n\r当前得分:%d\n当前蛇头(%d,%d)\t当前食物(%d,%d)\n\r当前步数:%d(step<=50)\t未吃到食物数:%d\n\r",score,h->x,h->y,m,n,step,foodlose);printf("按z可自动行走步数:%d\t按q退出\t按e暂停\n\r",a);//时间输出// ::GetLocalTime(&SysTime);// sprintf(TimeStr,"%d:%d:%d",SysTime.wHour,SysTime.wMinute,SysTime.wSecond);//文件名中不能含有'/'字符// printf("%s\n",TimeStr);
} void init(void)
{  int j=0;// system("mode con cols=180 lines=60");system("clear");//------食物设置---------srand(time(NULL));f=1;m=n=0;//---------使用说明--------printf("\n\r\n\r\n\r\n\r\n\r\n\r\n\r\t\t按键盘w、s、a、d键控制蛇的上下左右移动\n\r");printf("\t\t按z键可自动行走\n\r");printf("\t\t按键盘q键选择退出 按e键暂停\n\r");  printf("\t\t注意:当蛇头触碰到墙壁时会:game over!\n\r\t\t");colorf(34);printf("进入游戏前请先确定你处于引文输入状态,否则按Shift键切换!\n\r\t\t");colorf(35);printf("输入你希望的蛇头颜色(0-9):\n\r\t\t");scanf("%d",&color);getchar();system("clear");colorf(34);//system("pause");//system("cls");//getchar();//system("color 09");//-----------------------t=h=hp1=tp1=(Snake*)malloc(LEN);tp1->last=NULL;tp1->next=NULL;//空链表tp1->x=(YStart+YEnd)/2;tp1->y=(XStart+XEnd)/2; //蛇头//-----初始化----------s_add_t((YStart+YEnd)/2+1,(XStart+XEnd)/2);//----------------//--------------(墙壁)------------------------//上横(X)框BaseCount=0;for(j=0;j<=XLen;j++){ p0.x[ j+BaseCount]=YStart;p0.y[ j+BaseCount]=XStart+j;}//下横框BaseCount=XLen+1;for(j=0;j<=XLen;j++){ p0.x[ j+BaseCount]=YEnd;p0.y[ j+BaseCount]=XStart+j;}//左竖(Y)框BaseCount+=XLen+1;for(j=0;j<YLen-1;j++){ p0.x[ j+BaseCount]=YStart+j+1;p0.y[ j+BaseCount]=XStart;   }//右竖框BaseCount+=YLen-1;for(j=0;j<YLen-1;j++){ p0.x[ j+BaseCount]=YStart+j+1;p0.y[ j+BaseCount]=XEnd; }BaseCount+=YLen-1;//---------------------------------------------#define  RightBlank 4gotoxy(XEnd*2+2+RightBlank,YStart);//此处乘以2主要用于横宽比调节printf("%s\t%s",__DATE__,__TIME__);gotoxy(XEnd*2+2+RightBlank,YStart+1);	//可以在不破坏原图的情况下定位光标printf("mtcs V1.2 版权制作 xx所有  2014.5.20  ");#undef  RightBlankp1.pnum=0;s_play(h,ALLDISP);
}
void main()
{creat();//外部文件生成判断init();init_keyboard();while(1){move(); }
}
//-----方向控制-------------------------
void move(void)
{ //--捕获键盘//c_(键盘捕获值)  c(当前运行值)  c__(键盘锁存值)static char GetCExit=0;static char GetCha=0;static int GetTime=30;static char c='a';  static char LockFlag=1;//锁存标志#ifdef  AUTOGOstatic char c_='z';static char c__='z';#else static char c_='d';static char c__='a';#endifGetTime=30;while(GetTime--){//捕获时隙if(kbhit()) {   GetCha=readch();//getchar();			  if((c_=='z'||c_=='Z')&&!LockFlag&&(a>=0)){     //退出自动运行 if(GetCha=='z'||GetCha=='Z'){c_=c__;c=c_;//还原原来的方向LockFlag=1;}//自动运行中断if(GetCha=='e'||GetCha=='E') {getchar(); // system("pause"); //暂停break;}c=GetCha;break;}c_=GetCha;//if((c_=='z'||c_=='Z')&&LockFlag&&(a>0))		  { c__=c;LockFlag=0;c=autogo();a--;break;}if((c_=='e'||c_=='E')){getchar(); //system("pause"); //暂停break;}//c=c_;break; }}if((c_=='z'||c_=='Z')&&LockFlag&&(a>0))		  { c__=c;LockFlag=0;c=autogo();a--;}usleep(ORDINARY*200000);//调节该时间可以进行时间难度控制gotoxy(0,0);putchar(c);//--if(h->x<=YStart||h->x>=YEnd||h->y<=XStart||h->y>=XEnd)   gameover(); //撞墙判断switch(c){case 'W':case 'w':{{s_sub(-1);s_add_h(h->x-1,h->y);step++; }break;  }case 'S':case 's':{  {s_sub(-1);s_add_h(h->x+1,h->y);step++;}break;}case 'A':case 'a':{{s_sub(-1);s_add_h(h->x,h->y-1);step++;}break;  }case'D':case 'd':{{ s_sub(-1);s_add_h(h->x,h->y+1);step++; }  break; }case'Q':case 'q':{  system("clear"); colorf(34); //      system("color 0a");printf("\033[38m\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\t\t\t退出?('y' or 'n')\n\r\t\t\t\t");GetCExit=getchar();  if(GetCExit=='y'||GetCExit=='Y')    {printf("\t\t\t\n\r"); close_keyboard();exit(0); }else  {system("clear");s_play(h,ALLDISP); colorf(34); //system("color 09");}}}if(h->x<=YStart||h->x>=YEnd||h->y<=XStart||h->y>=XEnd)   gameover(); //撞墙判断if((h->x==n&&h->y==m)||(t->x==n&&t->y==m))  {  s_add_t(t->x,t->y+1); step=0;score++;f=1;// printf("\007");	// Beep(500,200);printf("\a");//发出ALERT声音if(a<AutoStepNum) a=AutoStepNum;else a+=AutoStepWidth;                                         }  //吃到食物,增加节点,并重新放置食物if(step==50) { step=0;f=1;foodlose++;//	printf("\007"); // Beep(1500,200);printf("\a");    }//走完u步未吃到食物则更新食物//s_play(h,PARTDISP);if(c_=='z'||c_=='Z')   { if(a>0)	{c=autogo();a--;} else{c_=c__;c=c_;//还原原来的方向LockFlag=1;}}
}
//------------自动寻找食物演示----------------
char   autogo()
{char c=0;if(h->x>n)   c='w';if(h->x<n)   c='s';if(h->x==n){if(h->y>m)   c='a';if(h->y<m) c='d';}return c;}
//------------------------------------------
void gameover()
{   load();printf("\033[2J\033H\033[34m");// system("cls");// system("color 0a");printf("\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\t\t\tgame over!\n\r\t\t");printf("\t您的得分是:%d\n\r\t\t\t",score);printf("历史最高分数:%d\n\r\t\t\t\n\r",_score); save();getchar();  sleep(1);close_keyboard();exit(0);
}
//-----------------数据保存-----------------------void save(){FILE *fp; fp=fopen("mtcs.mine","w");if(fp==NULL) printf("\n\r\t\t\t数据保存失败!\n\r");if(score<_score) {fclose(fp); return;}  fprintf(fp,"%d",score);fclose(fp);}
//------------------数据提取------------------void load(){FILE *fp;fp=fopen("mtcs.mine","r");if(fp==NULL)  printf("\n\r\t\t\t加载数据失败!\n\r");fscanf(fp,"%d",&_score);fclose(fp);}//------------------------------------------void  creat() //判断文件是否存在,若无则新建{void save();FILE *fp;fp=fopen("mtcs.mine","a");if(fp==NULL)   save();else fclose(fp);
}
//-------------------------------------------------

这篇关于TCS 贪吃蛇C源码的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1032449

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

red5-server源码

red5-server源码:https://github.com/Red5/red5-server

TL-Tomcat中长连接的底层源码原理实现

长连接:浏览器告诉tomcat不要将请求关掉。  如果不是长连接,tomcat响应后会告诉浏览器把这个连接关掉。    tomcat中有一个缓冲区  如果发送大批量数据后 又不处理  那么会堆积缓冲区 后面的请求会越来越慢。

Windows环境利用VS2022编译 libvpx 源码教程

libvpx libvpx 是一个开源的视频编码库,由 WebM 项目开发和维护,专门用于 VP8 和 VP9 视频编码格式的编解码处理。它支持高质量的视频压缩,广泛应用于视频会议、在线教育、视频直播服务等多种场景中。libvpx 的特点包括跨平台兼容性、硬件加速支持以及灵活的接口设计,使其可以轻松集成到各种应用程序中。 libvpx 的安装和配置过程相对简单,用户可以从官方网站下载源代码