# 自主學習計畫 貪食蛇程式設計 主旨:利用c++的list紀錄蛇身的座標,接著利用conio.h裡的GetAsyncKeyState讀取玩家輸入的移動方向,並利用srand隨機產生一個食物的位置,藉此達到貪食蛇遊玩之目的 [影片](https://youtu.be/xWOJrd5cWCo) ```cpp= #include <bits/stdc++.h> #include <windows.h> #include <conio.h> #define edgex 60 //X軸邊界 #define edgey 28 //y軸邊界 using namespace std; list<int> snakex; //記錄蛇x座標的list list<int> snakey; //記錄蛇y座標的list char kbinput; //紀錄鍵盤輸入的值 int endgame,score; //紀錄是否結束遊戲和分數 typedef struct f{ //宣告存放食物座標的struct int x,y; }foodtyp; foodtyp food; void to(int x, int y){ //設置游標 COORD pos; HANDLE hOutput; pos.X = x; pos.Y = y; hOutput = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hOutput, pos); } void print(){ //印出蛇的身體 //遍歷x座標的list與y座標的list auto x=snakex.begin(); auto y=snakey.begin(); for(;x!=snakex.end();x++,y++){ to(*x,*y); //設置游標到x,y cout << "■"; //印出身體 } } void creatfood(){ //創造食物 int checkfood=1; //紀錄食物是否合理 while(true){ food.x=(rand()%(edgex-1))+1; //隨機產生食物的x座標 food.y=(rand()%(edgey-1))+1; //隨機產生食物的y座標 if(food.x%2!=0) continue; //檢查食物的x是否為偶數 //檢查食物是否和蛇的身體重疊 for(auto itx=snakex.begin(),ity=snakey.begin();itx!=snakex.end();itx++,ity++){ if(*itx==food.x&&*ity==food.y){ checkfood=0; //有重疊的話就把checkfood設成0 break; } } if(checkfood) break; //如果符合條件就break,否則就重新產生 } to(food.x,food.y); //設置游標到食物的x與y cout << "■"; //印出食物 } void setup(){ //初始化 int dx[]={2,0,-2,0,0}; int dy[]={0,1,0,-1,0}; int x=0,y=0,p=0; kbinput='a',endgame=score=0; //印出邊界 while(p!=4){ to(x,y); cout << "■"; if(x+dx[p]>edgex||y+dy[p]>edgey||x+dx[p]<0||y+dy[p]<0){ //如果下一個超出邊界就換另一個方向 p++; } x+=dx[p],y+=dy[p]; //每次x或y加一 } //設定蛇的初始位置 for(int i=0;i<=10;i+=2){ snakex.push_back(24+i); //把蛇的x座標放入List snakey.push_back(20); //把蛇的y座標放入List } print(); //印出蛇 to(80,12),cout << "Score = " << score; //印出初始分數 srand(time(NULL)); //設定亂數 creatfood(); //創造食物 } void getmove(){ //讀取鍵盤輸入的值 if(kbinput!='s'&&GetAsyncKeyState(VK_UP)) kbinput='w'; if(kbinput!='w'&&GetAsyncKeyState(VK_DOWN)) kbinput='s'; if(kbinput!='a'&&GetAsyncKeyState(VK_RIGHT)) kbinput='d'; if(kbinput!='d'&&GetAsyncKeyState(VK_LEFT)) kbinput='a'; } int check(int x,int y){ //確認蛇是否碰到邊界或者碰到自己 if(x==0||x==edgex||y==0||y==edgey) return 1; //如果碰到邊界就回傳1 for(auto cx=snakex.begin(),cy=snakey.begin();cx!=snakex.end();cx++,cy++){ if(*cx==x&&*cy==y) return 1; //如果碰到自己就回傳1 } return 0; //否則回傳0 } void movesnake(){ int movex=snakex.front(); //取出蛇的x頭座標 int movey=snakey.front(); //取出蛇的y頭座標 //預覽蛇要走的位置 if(kbinput=='w') movey--; //如果往上,y就-1 if(kbinput=='a') movex-=2; //如果往左,x就-2 if(kbinput=='s') movey++; //如果往下,y就+1 if(kbinput=='d') movex+=2; //如果往下,x就+2 if(check(movex,movey)){ //判斷有沒有符合規則 endgame=1; //如果不符合規則就遊戲結束 return; } snakex.push_front(movex); //把新的x座標放入list裡 snakey.push_front(movey); //把新的y座標放入list裡 if(snakex.front()==food.x&&snakey.front()==food.y){ //判斷有沒有吃到食物 to(88,12),cout << ++score; //印出新的分數 creatfood(); //創造新的食物 }else{ //沒有的話要刪除最後一個節點,否則會留在螢幕上 to(snakex.back(),snakey.back()); //設置游標到蛇最後一個節點的位置 cout << " "; //把原本的 ■ 覆蓋掉 snakex.pop_back(); //移除最後一個x snakey.pop_back(); //移除最後一個y } print(); //印出蛇 } int main(){ setup(); while(endgame==0){ getmove(); movesnake(); Sleep(100); } to(80,14),cout << "Game Over!"; to(80,16),system("pause"); return 0; } ```