---
# System prepended metadata

title: 自主學習計畫

---

# 自主學習計畫

貪食蛇程式設計

主旨:利用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;
}
```