最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲設(shè)計(jì)

 更新時(shí)間:2020年07月27日 14:54:53   作者:IndPrime number  
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)貪吃蛇游戲設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

C語(yǔ)言實(shí)現(xiàn)貪吃蛇,供大家參考,具體內(nèi)容如下

實(shí)驗(yàn)平臺(tái):DEV C++

 /********************************************************************************
*File name:SnakeGame3.0.c       
*Description:貪吃蛇游戲源代碼(C語(yǔ)言),采用
*寬度優(yōu)先算法,計(jì)算蛇到食物的最短路徑(時(shí)間復(fù)雜度n^3空間復(fù)雜度n^2),這個(gè)算法遇 *
*到自身圍困情況將失效,無(wú)法計(jì)算出最短路徑     *
*********************************************************************************/
#include<stdio.h>
#include<stdlib.h>
#include<Windows.h>
#include<time.h>
#include<math.h>
#include<conio.h>

#define SIZE 25 //定義地圖大小
#define MAX_LENGTH 19 * 19 //定義蛇的最大長(zhǎng)度

typedef struct point //地圖上的點(diǎn)的節(jié)點(diǎn)
{
 int r;
 int c;
} point;
typedef struct queue //迭代搜索最短路徑用到的隊(duì)列
{
 point * body[5 * SIZE]; //保存蛇的身體的數(shù)組(棧的深度最大為5 * SIZE)
 int num; //記錄隊(duì)列中節(jié)點(diǎn)數(shù)
 int first_in_pos; //第一個(gè)進(jìn)入隊(duì)列的元素的索引值
} queue;
HANDLE stdOutput; //聲明windows標(biāo)準(zhǔn)輸出句柄

void init(int * length, point * foodAt, int * dir, point body[], char map[][SIZE]); //初始化
int getDir(int dir); //獲取蛇的行進(jìn)方向
int getAIDir(int dir, int length, point body[], point foodAt); //獲取AI判斷得出的行進(jìn)方向
int moveable(point moveTo, int length, point body[]);
int move(point foodAt, int dir, int length, point body[]); //蛇的運(yùn)動(dòng)
void draw(int length, point foodAt, point body[], char map[][SIZE]); //畫(huà)圖
void food(point * foodAt, point body[], int length, char map[][SIZE]); //生成食物

//棧相關(guān)的操作
point * pop(queue *queue); //從列隊(duì)取出最先進(jìn)入的點(diǎn),返回取出點(diǎn)的指針,取出失敗返回NULL
void push(point *point, queue *queue); //推入列隊(duì)中

int main()
{
 char map[SIZE][SIZE]; //定義地圖
 point body[MAX_LENGTH], foodAt; //整個(gè)蛇身體和食物的所在點(diǎn)(body數(shù)組的第一個(gè)值為蛇頭)
 int length; //蛇的實(shí)際長(zhǎng)度
 int dir; //行進(jìn)方向
 int rate = 1; //行進(jìn)速率
 int result; //保存蛇運(yùn)動(dòng)的結(jié)果:【死亡】、【得分】、【無(wú)】
 init(&length, &foodAt, &dir, body, map); //初始化

 while (1)
 {
 Sleep(100 / rate);
 //dir = getDir(dir); //獲取蛇的行進(jìn)方向
 dir = getAIDir(dir, length, body, foodAt); //獲取AI判斷得出的行進(jìn)方向
 result = move(foodAt, dir, length, body); //蛇的運(yùn)動(dòng)
 if (result == 1) //如果吃到食物
 {
 length++;
 rate = length / 3;
 if (length == MAX_LENGTH)
 {
 printf("您已通關(guān)!");
 break;
 }
 food(&foodAt, body, length, map); //生成食物
 }
 draw(length, foodAt, body, map); //畫(huà)圖
 if (result == -1) //如果死亡
 {
 break;
 }

 }
 Sleep(500); 
 printf(" 失敗,此次得分為%d    ", (length - 3) * 100);
 system("pause");
}
void init(int * length, point * foodAt, int * dir, point body[], char map[][SIZE]) //初始化
{
 memset(map, '*', SIZE * SIZE); //初始化地圖
 body[0].r = 3, body[0].c = 2; //初始化蛇的身體
 body[1].r = 2, body[1].c = 2;
 body[2].r = 1, body[2].c = 2;
 *length = 3; //初始長(zhǎng)度為3
 *dir = 2; //初始方向向下
 food(foodAt, body, *length, map); //生成食物
 draw(*length, *foodAt, body, map); //畫(huà)圖
 printf(" 按下任意鍵開(kāi)始,用ASDW控制方向,ESC暫停\n");
 _getch();
 srand((unsigned)time(NULL)); //生成隨機(jī)數(shù)種子,備用
 stdOutput = GetStdHandle(STD_OUTPUT_HANDLE); //獲取標(biāo)準(zhǔn)輸出句柄
 CONSOLE_CURSOR_INFO cci;
 cci.bVisible = 0;
 cci.dwSize = 1;
 SetConsoleCursorInfo(stdOutput, &cci);
 COORD coord = { 0, SIZE * 2 + 3 };
}
int getDir(int dir) //獲取蛇的行進(jìn)方向,規(guī)定返回值0代表向上,1代表向右,2代表向下,3代表向左
{
 char key;
 int newDir = dir;
 if (_kbhit())
 {
 key = _getch();
 switch (key)
 {
 case 'A': case 'a': newDir = 3; break;
 case 'S': case 's': newDir = 2; break;
 case 'D': case 'd': newDir = 1; break;
 case 'W': case 'w': newDir = 0; break;
 case 27: _getch(); break;
 }
 }
 if (newDir - dir == 2 || newDir - dir == -2) //蛇不能反向
 {
 newDir = dir;
 }
 return newDir;
}
int getAIDir(int dir, int length, point body[], point foodAt) //獲取AI判斷得出的行進(jìn)方向
{
 static int *shortestPathDir, count = 0; //保存最短路徑的方向(方向的先后順序?yàn)榈剐?,即排在后面的方向先走?

 if (count == 0) //如果最短路徑還沒(méi)生成,那么重新生成
 {
 int map_of_steps[SIZE][SIZE]; //保存到達(dá)地圖上某一點(diǎn)的最小步數(shù)
 queue queue = { 0,0 };
 point *last_body = (point *)malloc(length * sizeof(point)); //保存計(jì)算過(guò)程中上次蛇的身體位置
 point *next_body; //保存下一次蛇的身體
 point next_point;
 int i, step = 0;
 point moveTo;
 memcpy(last_body, body, length * sizeof(point));
 memset(map_of_steps, 0, SIZE * SIZE * sizeof(int));

 //向隊(duì)列中放入初始body
 push(last_body, &queue);
 push(NULL, &queue); //插入NULL來(lái)標(biāo)識(shí)寬度優(yōu)先搜索的某一層的結(jié)束
 step++; //用step來(lái)表示步數(shù),也代表層數(shù)

 while (queue.num != 0)
 {
 last_body = pop(&queue);
 if (last_body == NULL) //如果某一層結(jié)束
 {
 if (queue.num != 0) //如果還有下一層的元素
 {
 step++;
 push(NULL, &queue); //插入下一層的結(jié)束標(biāo)志
 continue;
 }
 else
 {
 break;
 }

 }
 for (i = 0; i < 4; i++) //分別檢測(cè)四個(gè)方向能否移動(dòng)
 {
 switch (i)
 {
 case 0: moveTo.r = last_body[0].r - 1, moveTo.c = last_body[0].c; break;
 case 1: moveTo.r = last_body[0].r, moveTo.c = last_body[0].c + 1; break;
 case 2: moveTo.r = last_body[0].r + 1, moveTo.c = last_body[0].c; break;
 case 3: moveTo.r = last_body[0].r, moveTo.c = last_body[0].c - 1; break;
 }
 if (moveable(moveTo, length, last_body) && map_of_steps[moveTo.r][moveTo.c] == 0) //如果移向的點(diǎn)之前沒(méi)有移到過(guò)
    //(即當(dāng)前路徑是到該點(diǎn)的最短路徑),而且該點(diǎn)是moveable的
 {
 map_of_steps[moveTo.r][moveTo.c] = step;
 if (moveTo.r == foodAt.r && moveTo.c == foodAt.c) //如果下一步就可以到達(dá)食物所在點(diǎn)
 {
 //先f(wàn)ree一些沒(méi)用的動(dòng)態(tài)內(nèi)存
 free(last_body);
 while (queue.num != 0)
 {
 free(pop(&queue));
 }
 goto outer; //跳出循環(huán)
 }
 //生成next_body并將其推入隊(duì)列
 next_body = (point *)malloc(length * sizeof(point));
 for (i = length - 1; i > 0; i--) //移動(dòng)蛇的位置
 {
 next_body[i] = body[i - 1];
 }
 next_body[0] = moveTo; //換一個(gè)頭

 push(next_body, &queue);//推入隊(duì)列

 }
 }
 //free一些沒(méi)用的動(dòng)態(tài)內(nèi)存
 free(last_body);
 }
 outer:;
 if (map_of_steps[foodAt.r][foodAt.c] == 0) //如果無(wú)法到達(dá)食物所在點(diǎn),那么按原路走,直到死亡
 {
 return dir;
 }
 //生成shortestPath
 shortestPathDir = (int *)malloc(step * sizeof(int));
 count = step;
 next_point = foodAt;
 for (i = 0; i < step - 1; i++) //利用map_of_steps和下一個(gè)點(diǎn)推知到上一個(gè)點(diǎn)到下一個(gè)點(diǎn)的方向dir
 {
 if (next_point.r + 1 < SIZE && map_of_steps[next_point.r][next_point.c] ==
 map_of_steps[next_point.r + 1][next_point.c] + 1)
 {
 shortestPathDir[i] = 0;
 next_point.r += 1;
 }
 else if (next_point.c - 1 >= 0 && map_of_steps[next_point.r][next_point.c] ==
 map_of_steps[next_point.r][next_point.c - 1] + 1)
 {
 shortestPathDir[i] = 1;
 next_point.c -= 1;
 }
 else if (next_point.r - 1 >= 0 && map_of_steps[next_point.r][next_point.c] ==
 map_of_steps[next_point.r - 1][next_point.c] + 1)
 {
 shortestPathDir[i] = 2;
 next_point.r -= 1;
 }
 else
 {
 shortestPathDir[i] = 3;
 next_point.c += 1;
 }
 }
 //第一步要單獨(dú)判斷(因?yàn)閙ap_of_steps的值為0的點(diǎn)可能是蛇頭,也可能是蛇身,這樣會(huì)對(duì)蛇第一步方向判斷產(chǎn)生干擾)
 if (body[0].r > next_point.r)
 {
 shortestPathDir[step - 1] = 0;
 }
 else if (body[0].r < next_point.r)
 {
 shortestPathDir[step - 1] = 2;
 }
 else if (body[0].c > next_point.c)
 {
 shortestPathDir[step - 1] = 3;
 }
 else
 {
 shortestPathDir[step - 1] = 1;
 }
 /*printf("\n\n\n");
 int j;
 for (i = 0; i < SIZE; i++)
 {
 for (j = 0; j < SIZE; j++)
 {
 printf("%3d", map_of_steps[i][j]);
 }
 printf("\n");
 }
 printf("\n");*/
 }
 //沿著最短路徑走
 return shortestPathDir[--count];
}
int moveable(point moveTo, int length, point body[]) //判斷是否可以移動(dòng)到moveTo點(diǎn),能1,不能0
{
 int i;
 for (i = 0; i < length - 1; i++)
 {
 if (moveTo.r == body[i].r && moveTo.c == body[i].c)
 {
 return 0;
 }
 }
 if (moveTo.r < 0 || moveTo.r >= SIZE || moveTo.c < 0 || moveTo.c >= SIZE) //如果超出邊界
 {
 return 0;
 }
 return 1;
}
int move(point foodAt, int dir, int length, point body[]) //蛇的運(yùn)動(dòng),規(guī)定返回值-1代表死亡,0代表沒(méi)有吃到食物,1代表吃到食物
{
 int i, flag = 0;
 point head = body[0];
 switch (dir)
 {
 case 0: head.r -= 1; break;
 case 1: head.c += 1; break;
 case 2: head.r += 1; break;
 case 3: head.c -= 1; break;
 }
 if (head.r < 0 || head.r >= SIZE || head.c < 0 || head.c >= SIZE) //出界了死亡
 {
 return -1;
 }
 for (i = 0; i < length - 1; i++)
 {
 if (head.r == body[i].r && head.c == body[i].c) //咬到了自己死亡
 {
 return -1;
 }
 }
 if (head.r == foodAt.r && head.c == foodAt.c) //吃到了食物
 {
 length++;
 flag = 1; //標(biāo)記一下,便與等下返回值為1
 }
 for (i = length - 1; i > 0; i--) //移動(dòng)蛇的位置
 {
 body[i] = body[i - 1];
 }
 body[0] = head; //換一個(gè)頭
 if (flag == 1)
 {
 return 1;
 }
 return 0;
}
void draw(int length, point foodAt, point body[], char map[][SIZE]) //畫(huà)圖
{

 static char bitmap[SIZE + 2][SIZE + 2]; //定義一個(gè)數(shù)組,用于把地圖背景、邊界、蛇、食物都畫(huà)上去
 int i, j;
 for (i = 0; i < SIZE; i++) //背景
 {
 for (j = 0; j < SIZE; j++)
 {
 bitmap[i + 1][j + 1] = map[i][j];
 }
 }
 //邊框
 bitmap[0][0] = '0', bitmap[0][SIZE + 1] = '1';
 bitmap[SIZE + 1][0] = '2', bitmap[SIZE + 1][SIZE + 1] = '3';
 for (i = 0; i < SIZE; i++)
 {
 bitmap[0][i + 1] = '4', bitmap[SIZE + 1][i + 1] = '4';
 bitmap[i + 1][0] = '5', bitmap[i + 1][SIZE + 1] = '5';
 }
 bitmap[foodAt.r + 1][foodAt.c + 1] = 'f'; //食物
 bitmap[body[0].r + 1][body[0].c + 1] = 'h'; //蛇頭
 for (i = 1; i < length; i++) //蛇身
 {
 bitmap[body[i].r + 1][body[i].c + 1] = 'b';
 }

 COORD coord = { 0, 0 }; //座標(biāo)0,0
 SetConsoleCursorPosition(stdOutput, coord); //把光標(biāo)設(shè)置到0,0位置
 for (i = 0; i < SIZE + 2; i++)
 {
 for (j = 0; j < SIZE + 2; j++)
 {
 switch (bitmap[i][j])
 {
 case 'f': printf("★"); break;
 case 'b': printf("●"); break;
 case 'h': printf("○"); break;
 case '0': printf("┏"); break;
 case '1': printf("━┓"); break;
 case '2': printf("┗"); break;
 case '3': printf("━┛"); break;
 case '4': printf(" ━"); break;
 case '5': printf("┃ "); break;
 default: printf(" ");
 }
 }
 printf("\n");
 }
}
void food(point * foodAt, point body[], int length, char map[][SIZE]) //生成食物
{
 int i;
 while (1)
 {
 foodAt->r = rand() % SIZE, foodAt->c = rand() % SIZE; //隨機(jī)生成食物位置
 for (i = 0; i < length; i++)
 {
 if (foodAt->r == body[i].r && foodAt->c == body[i].c) //如果該位置在蛇的身體上
 {
 goto retry;
 }
 }
 break;
 retry:;
 }
}

//隊(duì)列相關(guān)的函數(shù)
point * pop(queue *queue) //從隊(duì)列中取出,返回取出點(diǎn)的指針
{
 queue->num--;
 if (queue->first_in_pos == 5 * SIZE - 1) //返回第一進(jìn)入隊(duì)列的點(diǎn),并將變量fist_in_pos改變
 {
 queue->first_in_pos = 0;
 return queue->body[5 * SIZE - 1];
 }
 else
 {
 return queue->body[queue->first_in_pos++];
 }
}
void push(point * body, queue *queue)
{
 if (queue->num == 0) //如果隊(duì)列已空
 {
 queue->num++;
 queue->first_in_pos = 0; //將第一進(jìn)入隊(duì)列的位置設(shè)為0
 queue->body[queue->first_in_pos] = body;
 }
 else //否則插入隊(duì)列
 {
 if (queue->first_in_pos + queue->num > 5 * SIZE - 1)
 {
 queue->body[queue->first_in_pos + queue->num++ - 5 * SIZE] = body;
 }
 else
 {
 queue->body[queue->first_in_pos + queue->num++] = body;
 }
 }
}

更多有趣的經(jīng)典小游戲?qū)崿F(xiàn)專(zhuān)題,分享給大家:

C++經(jīng)典小游戲匯總

python經(jīng)典小游戲匯總

python俄羅斯方塊游戲集合

JavaScript經(jīng)典游戲 玩不停

java經(jīng)典小游戲匯總

javascript經(jīng)典小游戲匯總

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • c++之time_t和struct tm及時(shí)間戳的正確使用方式

    c++之time_t和struct tm及時(shí)間戳的正確使用方式

    C++中處理時(shí)間的常用數(shù)據(jù)類(lèi)型有time_t和struct tm,time_t通常用來(lái)表示時(shí)間戳,即從1970年1月1日至今的秒數(shù),struct tm是一個(gè)結(jié)構(gòu)體,用來(lái)存儲(chǔ)年、月、日、時(shí)、分、秒等信息,時(shí)間戳可以通過(guò)gmtime()轉(zhuǎn)換為struct tm類(lèi)型,反之亦然
    2024-10-10
  • C++基于棧實(shí)現(xiàn)鐵軌問(wèn)題

    C++基于棧實(shí)現(xiàn)鐵軌問(wèn)題

    這篇文章主要介紹了C++基于棧實(shí)現(xiàn)鐵軌問(wèn)題,實(shí)例分析了C++使用棧實(shí)現(xiàn)鐵軌問(wèn)題的思路與解決方法,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • Qt利用QPainter實(shí)現(xiàn)基本繪圖的示例詳解

    Qt利用QPainter實(shí)現(xiàn)基本繪圖的示例詳解

    Qt?中提供了強(qiáng)大的?2D?繪圖系統(tǒng),可以使用相同的?API?在屏幕和繪圖設(shè)備上進(jìn)行繪制,它主要基于QPainter、QPaintDevice?和?QPaintEngine?這三個(gè)類(lèi)。本文主要和大家介紹一下QPainter實(shí)現(xiàn)的基本繪圖,感興趣的可以了解一下
    2022-12-12
  • C++ namespace命名空間解析

    C++ namespace命名空間解析

    考慮一種情況,當(dāng)我們有兩個(gè)同名的人,Zara,在同一個(gè)班里。當(dāng)我們需要對(duì)它們進(jìn)行區(qū)分我們必須使用一些額外的信息和它們的名字,比如它們生活在不同的區(qū)域或者興趣愛(ài)好什么的,在C++程序中也會(huì)遇到同樣的情況,所以命名空間就此產(chǎn)生
    2021-11-11
  • C++中cin>>n的返回值

    C++中cin>>n的返回值

    這篇文章主要介紹了C++中cin>>n的返回值,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • C++中std::ios_base::floatfield報(bào)錯(cuò)已解決

    C++中std::ios_base::floatfield報(bào)錯(cuò)已解決

    在C++編程中,設(shè)置浮點(diǎn)數(shù)輸出格式時(shí)可能遇到std::ios_base::floatfield錯(cuò)誤,解決方法包括使用正確的格式化標(biāo)志組合,避免沖突的格式化設(shè)置,以及檢查流狀態(tài)標(biāo)志是否正確,通過(guò)這些方法可以有效避免浮點(diǎn)數(shù)格式化錯(cuò)誤,并確保輸出精確
    2024-09-09
  • c++ vector對(duì)象相關(guān)總結(jié)

    c++ vector對(duì)象相關(guān)總結(jié)

    這篇文章主要介紹了c++ vector對(duì)象的相關(guān)資料,幫助大家更好的理解和學(xué)習(xí)使用c++,感興趣的朋友可以了解下
    2021-02-02
  • 詳解C語(yǔ)言的mem系列函數(shù)

    詳解C語(yǔ)言的mem系列函數(shù)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言的mem系列函數(shù),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-02-02
  • C/C++ Qt 基本文件讀寫(xiě)的基本使用(2種實(shí)現(xiàn))

    C/C++ Qt 基本文件讀寫(xiě)的基本使用(2種實(shí)現(xiàn))

    文件的讀寫(xiě)是很多應(yīng)用程序具有的功能,本文主要介紹了兩種實(shí)現(xiàn)方法,第一種使用QFile類(lèi)的IODevice讀寫(xiě)功能直接讀寫(xiě),第二種是利用 QFile和QTextStream結(jié)合起來(lái),用流的方式進(jìn)行文件讀寫(xiě)
    2021-11-11
  • C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法示例

    C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法示例

    在C語(yǔ)言中,大小寫(xiě)字母的轉(zhuǎn)換可以通過(guò)標(biāo)準(zhǔn)庫(kù)中的ctype.h頭文件提供的函數(shù)來(lái)實(shí)現(xiàn),具體來(lái)說(shuō),toupper()函數(shù)可以將小寫(xiě)字母轉(zhuǎn)換為大寫(xiě)字母,而tolower()函數(shù)可以將大寫(xiě)字母轉(zhuǎn)換為小寫(xiě)字母,本文給大家介紹了C語(yǔ)言中大小寫(xiě)字母相互轉(zhuǎn)化的方法,需要的朋友可以參考下
    2024-08-08

最新評(píng)論

吉首市| 庆城县| 乐都县| 华阴市| 滁州市| 萍乡市| 湄潭县| 乡宁县| 三亚市| 平潭县| 凌源市| 屏南县| 中方县| 长宁县| 九江县| 沽源县| 垣曲县| 松江区| 西乌珠穆沁旗| 家居| 永福县| 镶黄旗| 辉南县| 乌兰县| 霍山县| 大田县| 马公市| 青田县| 安乡县| 虹口区| 鄯善县| 乳源| 焦作市| 海安县| 定兴县| 西贡区| 青川县| 郴州市| 咸阳市| 中阳县| 缙云县|