C++贪吃蛇

C++贪吃蛇


C++贪吃蛇_第1张图片
// snake.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"

//打印
#include 

//键盘输入
#include 

//睡眠
#include 
#include 

#include 
#include 

//随机数
#include 

//数字转字符串
#include 

#include 

#include 

#define WIDTH  30
#define HEIGHT  20


enum DIRECTION {NONE_KEY=0,UP,DOWN,LEFT,RIGHT,STOP};
class Position {
public:
    int width;
    int height;

    Position() {

    }

    Position(const int& height, const int& width) :height(height),width(width)
    {

    }

    bool operator==(const Position& other) {
        return (this->width == other.width) && (this->height == other.height);
    }

};


template
class MyQueue {
public:
    std::array m_buff;
    int m_start = 0, m_end = 0;

    bool isExisted(const T& other) {
        //tail
        for (int i = m_end + 1; i <= m_end + size(); i++) {
            if (m_buff[i%Length] == other) {
                return true;
            }
        }

        return false;
    }

    bool isEmpty() {
        return m_start == m_end;
    }

    bool isFull() {
        return (m_start + 1) % Length == m_end;
    }

    int size() {
        return (m_start + Length - m_end) % Length;
    }

    int capacity() {
        return Length;
    }

    bool pop() {
        if (!isEmpty()) {
            m_end = (m_end + 1) % Length;
            return true;
        }
        else
            return false;
    }

    bool pushInFront(const T& elem) {
        if (isFull()) {
            return false;
        }
        else {
            m_start++;
            m_start %= Length;
            m_buff[m_start] = elem;
            return true;
        }
    }

    const Position& getElem(int i) {        
        return m_buff[(m_end + i + 1) % Length];
    }
};


class Snake {
private:
    MyQueue tailQ;
    Position head;
    DIRECTION currentDirection;
    Position m_fruit;
    char m_drawBuff[HEIGHT+1][WIDTH + 1];
    int point = 0;

private:
    bool collisionDetect() {
        if (tailQ.isExisted(head))
            return false;

        if (head.width == 0 || head.width == WIDTH || head.height == 0 || head.height == HEIGHT)
            return false;

        return true;
    }

    void getRandomFruit(Position& newPosition) {
        static std::default_random_engine width_e;
        static std::uniform_int_distribution width_u(1, WIDTH-1);
        static std::default_random_engine height_e;
        static std::uniform_int_distribution height_u(1, HEIGHT-1);

        //不知道为什么有时会超出范围,这里处理下。
        newPosition.width = width_u(width_e);
        newPosition.height = height_u(height_e);
    }

    void fillDrawBuff(const int& height, const int& width, const char& ch) {
        if (width > 0 && width < WIDTH&&height > 0 && height < HEIGHT) {
            m_drawBuff[height][width] = ch;
        }
        else {
            std::cout << "out of bound" << "x: " << width << "y:" << height << "ch:" << ch << std::endl;
        }
    }

public:
    Snake() : currentDirection(UP) ,head(HEIGHT / 2, WIDTH / 2) {
        getRandomFruit(m_fruit);
    }

    bool move(const DIRECTION& key) {
        Position lastHead = head;

        int step = 1;

        if (key != NONE_KEY  && key != STOP) {
            currentDirection = key;
        }

        switch(currentDirection){
            case UP:
                head.height -= step;
                break;

            case DOWN:
                head.height += step;
                break;

            case LEFT:
                head.width -= step;
                break;

            case RIGHT:
                head.width += step;
                break;
        }

        if (m_fruit == head) {
            tailQ.pushInFront(lastHead);
            getRandomFruit(m_fruit);
            point++;
        }
        else {
            if (tailQ.size() > 0) {
                tailQ.pop();
                tailQ.pushInFront(lastHead);
            }
        }

        return collisionDetect();
    }

    void display() {
        system("cls");
        int width, height;

        for (int i = 0; i <= HEIGHT; i++) {
            for (int j = 0; j <= WIDTH; j++) {
                m_drawBuff[i][j] = ' ';
            }
        }

        //上
        for (int i = 0; i <= WIDTH;i++) {
            m_drawBuff[0][i] = '#';
        }

        //下
        for (int i = 0; i <= WIDTH; i++) {
            m_drawBuff[HEIGHT][i] = '#';
        }

        //左
        for (int i = 0; i <= HEIGHT; i++) {
            m_drawBuff[i][0] = '#';
        }

        //右
        for (int i = 0; i <= HEIGHT; i++) {
            m_drawBuff[i][WIDTH] = '#';
        }

        //std::vector& myVector = tailQ.getAllElems();
        int n_elems = tailQ.size();
        for (int i = 0; i < n_elems; i++) {
            const Position& pos = tailQ.getElem(i);
            fillDrawBuff(pos.height, pos.width, 'o');
        }
        
        //head
        width = head.width;
        height = head.height;
        fillDrawBuff(height, width, 'O');

        //fruit
        width = m_fruit.width;
        height = m_fruit.height;
        fillDrawBuff(height, width, 'F');

        for (int i = 0; i < HEIGHT + 1; i++) {
            for (int j = 0; j < WIDTH + 1; j++) {
                std::cout << m_drawBuff[i][j];
            }
            std::cout  << std::endl;
        }

        std::cout << "point:" << point << std::endl;
        std::cout << "X:start/stop w:up s:down a:left d:right"  << std::endl;
    }
};


DIRECTION getKey() {
    if (_kbhit()) {
        switch (_getch()) {
            case 'w':
                return UP;

            case 's':
                return DOWN;

            case 'a':
                return LEFT;

            case 'd':
                return RIGHT;

            case 'x':
                return STOP;

            default:
                return NONE_KEY;
        }
    }
}


bool isDirectionKey(const DIRECTION& key) {
    if (key == UP || key == DOWN || key == LEFT || key == RIGHT) {
        return true;
    }
    else {
        return false;
    }
}


int main()
{
    const int interval_ms = 300;
    bool run = false;
    Snake snake;
    DIRECTION key = NONE_KEY, lastKey;
    bool isOK;
    int cnt = 0;

    snake.display();
    while (true) {
        lastKey = key;
        key = getKey();

        if (key == STOP) {
            run = !run;
            if (run) {
                cnt = 0;
            }
        }

        if (run ) {
            if ( isDirectionKey(key) || cnt == 0) {
                isOK = snake.move(key);
                if (!isOK) {
                    goto END;
                }
                snake.display();
            }

            cnt++;
            cnt %= interval_ms;
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(1));
    }

    END:
    system("pause");
    return 0;
}


你可能感兴趣的:(C++贪吃蛇)