用純命令行編寫貪喫蛇

開發環境爲linux+gcc+netbeans

本來我喜歡gvim但是實在不會調試c語言。於是轉戰netbeans,能很方便地調試,就是爽。

 

首先要說一下思路。就是多線程,一個線程負責邏輯和畫圖,一個線程監聽按鍵。看一下線程創建的代碼。

 

void * waitForKey(void *para) {
    while (1) {
        input = getch();
    }
}

pthread_t id; //聲明一個linux線程,按鍵等待線程

 int ret;
    ret = pthread_create(&id, NULL, waitForKey, NULL);//創建線程
    if (ret != 0) {
        exit(1);
    }
 

我還用到了一個庫,就是curses,這個好象是專門用來繪圖ui用的。但是在/usr/include裏面是沒有的,要到網上去下

sudo apt-get install libncurses-dev

使用時的格式應該是這樣

 

initscr();

do_some_drawing();

refresh();

endwin();

其中我用到的函數有move(x,y)是把光標定位在某行某列上。還有addStr(s)和addch(c)。是在光標處寫字符串和寫字符。

還有getch()等待用戶按鍵。還有refresh(),將緩衝的addch阿還有addStr等等的繪圖操作都輸出到屏幕上。

 

此外還用到了usleep(int )函數這裏的參數是 int型的,表示的是微秒數,1秒等於1000000微秒。這裏的時間間隔是蛇每次移動時的間隔時間。

 

代碼如下

#include<stdio.h>
#include <pthread.h>
#include <sys/time.h>
#include <curses.h>
#include <stdlib.h>

#define MAX_X 70   //場地寬
#define MAX_Y 20  //場地長
#define CORNER_X 4  //左上角x座標
#define CORNER_Y 2   //左上角y座標

struct point { 
    int x;
    int y;
};
struct point SnakeBody[50]; 
struct point food;

int Length = 4;  //初始蛇長
int life = 1;   //是否還活着
int input = 0;  //記錄鍵盤按鍵的ascii
pthread_t id; //聲明一個linux線程,按鍵等待線程


void FoodCheck();
void FoodProduce();
void Initializition();
void SnakeHeadMovement();
void DeathCheck();
void Paint();
void * waitForKey(void *);
void drawDot(int x, int y,char s);
void clearDot(int x, int y);
void end();


//主函數

int main(int argc, char** argv) {

    Initializition();
    while (life) {
        Paint();
        usleep(200000);
        SnakeHeadMovement();
        DeathCheck();
    }
    end();
    return 0;
}

void * waitForKey(void *para) {
    while (1) {
        input = getch();
    }
}

void end() {

    move(1, 0);
    addstr("Press any key to quit!");
    refresh();
    getch();
   endwin();
}


//食物的隨機產生

void FoodProduce() {
    int superposition = 0;
    int i;
    srand(time(NULL));
    do {
        food.x = (rand() % ((MAX_X-2) / 2))*2+2;  //2 to MAX_X-2  and is 偶數
        food.y = rand() % (MAX_Y-1)+1;   //1 to MAX_Y-1
        for (i = 0; i < Length; i++) {
            if (food.x == SnakeBody[i].x && food.y == SnakeBody[i].y)
                superposition = 1;
        }
    } while (superposition); /*直到沒有重合*/
}

//蛇身和食物的初始化 初始化的蛇身爲4節長度

void Initializition() {
    initscr();//curses初始化

    int i;
    for (i = 3; i <= 6; i++) {//初始化蛇
        SnakeBody[6 - i].x = 4;
        SnakeBody[6 - i].y = i;
    }
    FoodProduce();
    int ret;
    ret = pthread_create(&id, NULL, waitForKey, NULL);//創建線程
    if (ret != 0) {
        exit(1);
    }

    for ( i = 0; i <= MAX_X; i+=2) {  //畫圍牆
        drawDot(i, 0,'*');
        drawDot(i, MAX_Y,'*');
    }

    for (i = 0; i <= MAX_Y; i++) {
        drawDot(0, i,'*');
        drawDot(MAX_X, i,'*');
    }

}

//蛇移動,依次從尾巴到頭賦值
void SnakeBodyMovement() {
    int i;
    for (i = Length - 1; i > 0; i--) {
        SnakeBody[i].x = SnakeBody[i - 1].x;
        SnakeBody[i].y = SnakeBody[i - 1].y;
    }

}


void SnakeHeadMovement() {

    clearDot(SnakeBody[Length - 1].x, SnakeBody[Length - 1].y);
    int directionX, directionY; /*定義原本蛇前進的方向,可通過蛇頭座標減去蛇的第二部分*/
    int newX, newY;
    newX = SnakeBody[0].x;
    newY = SnakeBody[0].y;

    directionX = SnakeBody[0].x - SnakeBody[1].x;
    directionY = SnakeBody[0].y - SnakeBody[1].y;
    

   

    if (input == 'w' && directionY<=0) //不走回頭路
        newY--;
    else if (input == 's' && directionY>=0 )
        newY++;
    else if (input == 'a' && directionX<=0)
        newX -= 2; /*因爲字符高是寬的兩倍*/
    else if (input == 'd' && directionX>=0)
        newX += 2;
    else {
        newX += directionX;
        newY += directionY;
    }
    FoodCheck(); 
    SnakeBodyMovement();
    SnakeBody[0].x = newX;
    SnakeBody[0].y = newY;

}
//判斷是否喫到食物,以及喫到後長度變長還有產生新的食物

void FoodCheck() {
    if (food.x == SnakeBody[0].x && food.y == SnakeBody[0].y) {
        Length = Length + 1;
        FoodProduce();
    }
}
//判斷是否死亡

void DeathCheck() {
    int i;
    if (SnakeBody[0].x <=1 || SnakeBody[0].x >= MAX_X  || SnakeBody[0].y <= 0 || SnakeBody[0].y >=MAX_Y)
        life = 0;
    for (i = 4; i < Length; i++)
        if (SnakeBody[0].x == SnakeBody[i].x && SnakeBody[0].y == SnakeBody[i].y)
            life = 0;
}

//排序和打印

void Paint() {
    int i = 0;

    drawDot(SnakeBody[i].x, SnakeBody[i].y,'@');
    for (i=1; i < Length; i++) {
        drawDot(SnakeBody[i].x, SnakeBody[i].y,'*');
    }
    drawDot(food.x, food.y,'$');
    clearDot(0, 0);
    refresh();//刷新畫布
}

void drawDot(int x, int y,char s) {
    move(y+CORNER_Y, x+CORNER_X);
    addch(s);
}

void clearDot(int x, int y) {
    move(y+CORNER_Y, x+CORNER_X);
    addch(' ');
}

 

編譯的時候的命令如下 gcc main.c -o main -lpthread -lcurses

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章