C++贪吃蛇

// snake.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
//打印
#include <iostream>
//键盘输入
#include <conio.h>
//睡眠
#include <chrono>
#include <thread>
#include <array>
#include <algorithm>
//随机数
#include <random>
//数字转字符串
#include <sstream>
#include <vector>
#include <string>
#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<typename T,int Length>
class MyQueue {
public:
std::array<T, Length> 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<Position,100> 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<unsigned> width_u(1, WIDTH-1);
static std::default_random_engine height_e;
static std::uniform_int_distribution<unsigned> 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<Position>& 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;
}