主线程:维护游戏逻辑,刷新画面。
后台线程:监听按键(getch)
暂时只支持Windows下的MinGW编译,本来用MinGW编译是想写成Linux下也能运行的。结果Linux下面没有直接提供getch()函数(Windows下的<conio.h>有)。
管他呢!纯属娱乐~
编译要加-lpthread
snake_cmd.cpp
#include <list>
#include <stack>
#include <vector>
#include <algorithm>
#ifdef WIN32
#include <windows.h>
#include <conio.h> // for console I/O
#define sleep(x) Sleep(1000 * (x))
#define msleep(x) Sleep(x)
#define CLEAR_TERM system("CLS");
#else
#include <unistd.h>
#define msleep(x) usleep(1000 * (x))
#define CLEAR_TERM system("clear");
#endif
namespace game {
// using namespace std;
/////////////////////////////////////////////////////////////////////////////
// for debug
#ifdef DEBUG
struct Logger {
FILE* out;
Logger(FILE *pf) : out(pf) {}
void operator()(const char *format, ...) {
va_list args;
va_start(args, format);
vfprintf(out, format, args);
va_end(args);
}
};
Logger outLogger(stdout);
Logger errLogger(stderr);
#define log outLogger
#define err errLogger
// void logger(const char *format, ...)
// {
// va_list args;
// va_start(args, format);
// vprintf(format, args);
// va_end(args);
// }
#else
#define logger(fmt, ...) fmt
#define log logger
#define err logger
#endif
// #define log logger
// #define log outLogger
/////////////////////////////////////////////////////////////////////////////
// key values:
#define K_SPACE 32
#define K_ESC 27
#define K_W 119
#define K_S 115
#define K_A 97
#define K_D 100
// up, down, left, right Pressed 1 key Return 2 value
#define K_DIR 224 // ignore this
#define K_UP 72
#define K_DOWN 80
#define K_LEFT 75
#define K_RIGHT 77
// common constants:
#ifndef DELAY
#define GAME_CYCLE_MS 1000
#else
#define GAME_CYCLE_MS DELAY
#endif
#define MAX_BODY_LEN 128
#define MAX_FOOD_NUM 8
#define WIDTH 64
#define HEIGHT 24
// char constants:
#define CH_BORDER '#'
#define CH_BLANK ' '
#define CH_SNAKE '*'
#define CH_SNAKEH '@'
#define CH_SNAKET '+'
#define CH_FOOD '$'
#define CH_MINE '#'
/////////////////////////////////////////////////////////////////////////////
enum Direction
{
UNKNOW, UP, DOWN, LEFT, RIGHT
};
struct Point
{
int x;
int y;
Point() : x(0), y(0) {}
Point(int xx, int yy) : x(xx), y(yy) {}
bool operator==(const Point &rhs) const {
return x == rhs.x && y == rhs.y;
}
Point& operator+=(const Point &rhs) {
x += rhs.x;
y += rhs.y;
return *this;
}
Point operator+(const Point &rhs) const {
Point res(rhs);
res.x += x;
res.y += y;
return res;
}
#ifdef DEBUG
void show() {
log("Point_%p:(%d, %d)\n", this, x, y);
}
#endif
};
/////////////////////////////////////////////////////////////////////////////
/*
dimension:
0---x+
|
y
+
*/
Point operator+(const Point &point, const Direction &dir)
{
Point pt(point);
switch(dir) {
case UP:
pt.y--; break;
case DOWN:
pt.y++; break;
case LEFT:
pt.x--; break;
case RIGHT:
pt.x++; break;
default:
err("ERROR: Point + Direction Error!\n");
break;
}
return pt;
}
/////////////////////////////////////////////////////////////////////////////
class Snake
{
typedef std::vector<Point> body_type;
typedef body_type::iterator body_iter;
typedef body_type::const_iterator body_citer;
Direction dir; // 前进方向
// Point body[MAX_BODY_LEN]; // 身体位置
body_type body; // 身体位置
public:
Snake(): dir(UNKNOW) {}
Snake(Direction d) : dir(d) {}
void setDir(Direction dir) {
this->dir = dir;
}
void setHead(Point p) {
log("setHead...\n");
// p.show();
if(body.size() == 0) {
body.insert(body.begin(), p);
}
}
int length() const { return body.size(); }
Point getNode(int ino) const { return body[ino]; }
Point getHead() const {
return *body.begin();
}
Point nextHead() const {
return getHead() + dir;
}
bool isOnBody(Point pt) const {
for( body_citer it = body.begin(); it != body.end(); ++it ) {
if( *it == pt ) return true;
}
return false;
}
bool checkDir(Direction newDir) const {
if( dir == UP && newDir == DOWN
|| dir == DOWN && newDir == UP
|| dir == LEFT && newDir == RIGHT
|| dir == RIGHT && newDir == LEFT)
return false;
return true;
}
bool selfCollision() const {
Point h = getHead(); // next time head position
// if( length() > 1 && isOnBody(h) ) return true;
body_citer it = body.begin();
for( ++it; it != body.end(); ++it ) {
if( *it == h ) return true;
}
return false;
}
bool changeDir(Direction newDir) {
if( checkDir(newDir) ) {
setDir(newDir);
return true;
}
else {
return false;
}
}
void move() {
if( ! selfCollision() ) {
Point nh = nextHead();
body.insert(body.begin(), nh);
body.erase(body.end());
}
else {
err("ERROR: move failed! direction incorrect!\n");
}
}
void growth() {
Point nh = nextHead();
body.insert(body.begin(), nh);
}
// void putTo(Point axis) {
// for(body_iter it=body.begin(); it!=body.end(); ++it) {
// *it += axis;
// }
// }
#ifdef DEBUG
void show() {
log("Snake_%p:\n", this);
log("{\n");
log(" dir: %d,\n", dir);
log(" body: [");
for(body_citer it = body.begin(); it != body.end(); ++it) {
log("(%d, %d), ", it->x, it->y);
}
log("]\n}\n");
}
#endif
};
struc