下午真無聊的不知道幹什麼了,翻翻自己以前寫的代碼,偶然看到大一時寫的這個簡單的貪喫蛇,自己玩了幾把後還是決定發到博客吧。(實在無聊,打發時間)
注:完全基於VC++6.0環境,不支持Linux 下terminal中運行。並且代碼風格基本沒有,寫的十分扯,一大堆代碼都在main()函數中,其中用了switch來搞了兩關,一個是撞牆over,另一個當然可以穿牆了。代碼複用就別提了,兩關由於十分相似,代碼基本相同,由於只是玩,就沒搞個公用調用接口。唉,現在看着以前的代碼,感覺那風格簡直是扯淡。
「正文開始」:
代碼開始那段,其實是用來裝逼的,什麼設置用戶名,代碼最後重新開始遊戲,設置速度(通過sleep的時間實現)之類的,準備着以後修改修改,完善完善,但是現在覺得沒時間再玩這些東西了,也一直沒改。
由於代碼中基本我都寫了註釋以及打印時的英文標註,在這就說下大體的代碼實現思路,其實蛇身是基於雙向鏈表實現的,而蛇的移動是通過以非阻塞的方式從緩衝區中讀出按鍵對應的值,從而控制方向(kbhit()函數可以檢測鍵盤是否按下,以非阻塞的方式從緩衝區讀取數據),而蛇的移動是通過檢測對用的蛇身位置,通過刷屏
(system(”cls“);)的方式不斷打印蛇身的位置,從而實現蛇的移動效果(運動時還需要保證蛇身的運動方向與蛇頭是一致的)。本身其實一切都是在開始定義的那個數組
int a[20][20]={0};// 定義佈局範圍大小
中來實現的,控制的關鍵是這個數組中每個位置的字符樣式(有標記),蛇頭就打印實體框,蛇身就是虛體框,而食物就是隨機產生的英文咯,每當蛇頭與食物在同一個座標是就新建一個節點,添加到蛇身這條鏈表。而遊戲結束的標誌其實也是通過檢測蛇頭與蛇身的座標關係,還有與邊緣的座標關係,判斷是自殘而死還是撞牆而死。「廢話不多說了」
上代碼:
<head.h>
struct Node
{
int x;
int y; //蛇身節點位置的數據類型、
struct Node *pre;
struct Node *next; //雙向鏈表,控制蛇身運動的一致性
};
struct Food
{
int x;
int y;
char c; // 食物種子的數據類型。
};
這是用到的兩個簡單的struct,總體實現,其實是基於雙向鏈表的。
在者就是需要用到win環境下的頭文件:
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <time.h> //key for snake food !
#include <conio.h>
#include "head.h"
由於比較扯,下面實現代碼都是在main函數中,我現在也懶得改了,就這麼看吧。
int main(int argc,char *argv[])
{
int a[20][20]={0};// 定義佈局範圍大小。
char user_name[15];
int i,j,flag=0;
int speed; //蛇運行速度的控制,用sleep()實現,其實也是清屏的間歇速度。。
char c='d',c1='d'; //運動方向初始化
char key;
char speed_key,user_key,stage_key;
struct Food food={9,15,'*'}; //食物得初始位置
int stage; //選擇關卡
int gameover=0; //key data
struct Node *head,*p,*rear,*pt;
int score;
printf("************************ <! careful !> *****************************\n\n");
puts("\n<*>*<*>every time when you touch foods and you will get five points !<*><*>\n\n when you want to stop at once ,please press ‘t’\n\nwhen you want to have a pause ,please press '0'\n\n ");
puts("Direction control help: ** < UP:w > < DOMN :s > < left :a > < right :d > **\n\n\n ");
printf("*****************************************\n");
printf("please input the speed of this snake ( between 0 ~~ 300 ):");
scanf("%d",&speed);
printf("\n\nplease input your user_name :");
scanf("%s",user_name);
key='y';
printf("\n\nplease choose which stage to start game(input the int value bellow:)?\n\n【(*0*):without the wall to stop game,(*1*): with the wall to stop your touch】\n\n");
flushall();
scanf("%d",&stage);
while(key=='y')
{
score=0;
head=(struct Node *)malloc(sizeof(struct Node));
head->x=10;
head->y=10; // 蛇身頭節點的初始位置
head->pre=NULL;
head->next=NULL;
rear=head;
srand((unsigned)time(NULL)); //隨機函數的產生:【食物種子】
switch (stage)
{
case 0:
while(1)
{
if(food.x==head->x && food.y==head->y)
{
p=(struct Node *)malloc(sizeof(struct Node)); //產生曾長段。
pt=head;
while(pt->next!=NULL)
pt=pt->next ; //找出蛇體增長位置pt爲尾指針
p->pre= pt;
pt->next = p;
p->next=NULL;
rear=p; //尾指針
score+=5; //分數增加
food.x=rand()%20; //食物產生的隨機位置算法
food.y=rand()%20;
food.c=65+rand()%26;
flag=1;
}
pt=rear;
if(kbhit()) // key point : 【 檢查鍵盤有無按下。。輸入任意字符繼續 ,要麼,程序只能執行一次,即打一次
{ // kbhit()可以保證循環時可以連續地以非阻塞方式從緩衝區讀入字符。。
c1=getch(); // 清除緩存,從緩衝區讀入一個字符】
if(c1=='0')
{
system("pause");
}
if(c1=='t')
{
exit(0);
}
if(c!='d' && c1=='a')
c=c1;
else if(c!='a' && c1=='d') //保證運行時當蛇延直線前行時,按下與直線方向相反的鍵時,出現遊戲結束。。
c=c1;
else if(c!='w' && c1=='s')
c=c1;
else if(c!='s' && c1=='w')
c=c1;
}
while(pt!=head)
{ //控制每一節蛇身的運動與頭保持一致
pt->x=pt->pre->x;
pt->y=pt->pre->y;
pt=pt->pre;
}
if(c=='d') //方向控制
{
head->y +=1;
if(head->y >=20)
head->y -=20;
}
else if(c=='a')
{
head->y -=1;
if(head->y <0)
head->y +=20;
}
else if(c=='w')
{
head->x -=1;
if(head->x < 0)
head->x +=20;
}
else if(c=='s')
{
head->x+=1;
if(head->x >=20)
head->x -=20;
}
pt=head->next;
while(pt!=NULL)
{
if(head->x==pt->x && head->y==pt->y)
{
gameover=1; //蛇頭與身體相遇時退出遊戲
break;
}
pt=pt->next ;
}
if(gameover==1)
break;
system("cls"); //每次清屏。。。
printf("************************ <! game start !> *****************************\n\n");
printf("your user_name : %s\n\nthe current speed is %d\n\n",user_name,speed);
printf(" the current stage is %d\n\n",stage);
printf("*****************************************\n");
for(i=0;i<20;i++) //打印循環開始,也是遊戲的可視化佈局
{
printf("|");
for(j=0;j<20;j++)
{
flag=0;
pt=head;
while(pt!=NULL)
{
if(i==pt->x && j==pt->y)
{
if(pt==head)
printf("■"); //當pt=head 時,在那個位置打出頭標,
else
printf("□"); //要麼打出身標
flag=1;
break;
}
pt=pt->next;//一直找,直到蛇尾結束打印
}
if(flag==0)
{
if(i==food.x && j==food.y)
{
putchar(food.c); //如果此位置是food的位置,則打印出food的字符,否則打印空格(必須填滿方格佈局)。
putchar(food.c);
continue; //轉去執行下一次循環判斷
}
printf(" "); //不是蛇身,則打印空格
}
}
printf("|\n");
}
printf("*****************************************\n");
_sleep(speed);
}
break;
case 1 :
while(1)
{
if(food.x==head->x && food.y==head->y)
{
p=(struct Node *)malloc(sizeof(struct Node)); //產生曾長段。
pt=head;
while(pt->next!=NULL)
pt=pt->next ; //找出蛇體增長位置pt爲尾指針
p->pre= pt;
pt->next = p;
p->next=NULL;
rear=p; //尾指針
score+=5; //分數
food.x=rand()%20; //食物產生的隨機位置算法
food.y=rand()%20;
food.c=65+rand()%26;
flag=1;
}
pt=rear;
if(kbhit()) // key point : 【 檢查鍵盤有無按下。。輸入任意字符繼續 ,要麼,程序只能執行一次,即打一次
{ // kbhit()可以保證循環時可以連續地以非阻塞方式從緩衝區讀入字符。。
c1=getch(); // 清除緩存,從緩衝區讀入一個字符】
if(c1=='0')
{
system("pause");
}
if(c1=='t')
{
exit(0);
}
if(c!='d' && c1=='a')
c=c1;
else if(c!='a' && c1=='d') //保證運行時當蛇延直線前行時,按下與直線方向相反的鍵時,出現遊戲結束。。
c=c1;
else if(c!='w' && c1=='s')
c=c1;
else if(c!='s' && c1=='w')
c=c1;
}
while(pt!=head)
{ //控制每一節蛇身的運動與頭保持一致
pt->x=pt->pre->x;
pt->y=pt->pre->y;
pt=pt->pre;
}
if(c=='d') //方向控制
{
head->y +=1;
if(head->y >=20)
{
gameover=1;
break;
}
}
else if(c=='a')
{
head->y -=1;
if(head->y <0)
{
gameover=1;
break;
}
}
else if(c=='w')
{
head->x -=1;
if(head->x < 0)
{
gameover=1;
break;
}
}
else if(c=='s')
{
head->x+=1;
if(head->x >=20)
{
gameover=1;
break;
}
}
pt=head->next;
while(pt!=NULL)
{
if(head->x==pt->x && head->y==pt->y)
{
gameover=1; //蛇頭與身體相遇時退出遊戲
break;
}
pt=pt->next ;
}
if(gameover==1)
break;
system("cls"); //每次清屏。。。
printf("************************ <! game start !> *****************************\n\n");
printf("your user_name : %s\n\nthe current speed is %d\n\n",user_name,speed);
printf("*****************************************\n");
for(i=0;i<20;i++)
{
printf("|");
for(j=0;j<20;j++)
{
flag=0;
pt=head;
while(pt!=NULL)
{
if(i==pt->x && j==pt->y)
{
if(pt==head)
printf("■"); //當pt=head 時,在那個位置打出頭標,
else
printf("□"); //要麼打出身標
flag=1;
break;
}
pt=pt->next;//一直找,直到蛇尾結束打印
}
if(flag==0)
{
if(i==food.x && j==food.y)
{
putchar(food.c); //如果此位置是food的位置,則打印出food的字符,否則打印空格(必須填滿方格佈局)。
putchar(food.c);
continue; //轉去執行下一次循環判斷
}
printf(" "); //不是蛇身,則打印空格
}
}
printf("|\n");
}
printf("*****************************************\n");
_sleep(speed);
}
break;
}
if(gameover==1) {
puts("************************《Now the game over!》*****************************\n\n ********!< _ >!*******\n\n");
printf("\n your score is :%d\n",score);
puts("if you want to continue ? (y/n)\n");
flushall();
scanf("%c",&key);
if(key=='y')
{
gameover=0;
flushall();
printf("\nif you want to change speed ? (y/n):");
scanf("%c",&speed_key);
if(speed_key=='y')
{
printf("input speed value:\n");
scanf("%d",&speed);
}
else
printf("\n");
flushall();
printf("\nif you want to change user_name ? (y/n):");
scanf("%c",&user_key);
if(user_key=='y')
{
flushall();
printf("input new user_name:\n");
scanf("%s",user_name);
}
else
printf("\n");
flushall();
printf("\n if you want to change the stage ? (y/n):");
scanf("%c",&stage_key);
if(stage_key=='y')
{
flushall();
printf("\nplease input the stage value :");
scanf("%d",&stage);
}
else
printf("\n");
continue;
}
else
exit(0);
}
}
return 0;
}
大概就寫到這裏吧,唉,還是那句話,代碼風格慘不忍睹。