mingw编译的windows命令行贪吃蛇示例
mingw编译的windows命令行贪吃蛇示例
发布时间:2016-12-28 来源:查字典编辑
摘要:主线程:维护游戏逻辑,刷新画面。后台线程:监听按键(getch)暂时只支持Windows下的MinGW编译,本来用MinGW编译是想写成Li...

主线程:维护游戏逻辑,刷新画面。

后台线程:监听按键(getch)

暂时只支持Windows下的MinGW编译,本来用MinGW编译是想写成Linux下也能运行的。结果Linux下面没有直接提供getch()函数(Windows下的<conio.h>有)。

管他呢!纯属娱乐~

编译要加-lpthread

snake_cmd.cpp

复制代码 代码如下:

#include <limits.h> // for INT_MAX

#include <stdio.h>

#include <string.h>

#include <stdarg.h>

#include <pthread.h>

#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

};

struct PlayGround

{

int width;

int height;

bool border;

PlayGround() : width(0), height(0), border(true) {}

PlayGround(int w, int h, bool b) : width(w), height(h), border(b) { }

// x -- width, y -- height

bool inArea(int x, int y) {

if( border ) {

if( x < 1 || x >= width-1 ) return false;

if( y < 1 || y >= height-1 ) return false;

}

else { // no border

if( x < 0 || x >= width ) return false;

if( y < 0 || y >= height ) return false;

}

return true;

}

bool inArea(Point p) { return inArea(p.x, p.y); }

#ifdef DEBUG

void show() {

log("PlayGround_%p:n", this);

log("{n");

log(" width: %d,n", width);

log(" height: %d,n", height);

log(" border: %d,n", border);

log("}n");

}

#endif

};

enum GameState {

GS_UNKNOW,

GS_START,

GS_PAUSE,

GS_OVER,

GS_EXIT

};

class Game

{

Snake *snake;

PlayGround *ground;

char buffer[HEIGHT][WIDTH+2];

int foodCount;

Point *foodBuffer[MAX_FOOD_NUM];

int time;

GameState state;

std::stack<GameState> gsStack;

public:

Game() : snake(new Snake(RIGHT)),

ground(new PlayGround(WIDTH, HEIGHT, true)), foodCount(0) { init(); }

~Game() {

if(ground) delete ground;

if(snake) delete snake;

}

void setState(GameState gs) { state = gs; }

GameState getState() const { return state; }

void pause() {

if( state != GS_PAUSE ) {

state = GS_PAUSE;

gsStack.push(state);

log("state: %d, statck.size(): %dn", state, gsStack.size());

}

else {

state = gsStack.top();

gsStack.pop();

}

}

void init() {

memset(buffer, 0, sizeof(buffer));

memset(foodBuffer, 0, sizeof(foodBuffer));

Point ph(2, ground->height/3); // init head pos

snake->setHead(ph);

time = 0;

}

void syncGround() { // ground => buffer

for(int x=0; x<ground->width; x++) {

for(int y=0; y<ground->height; y++) {

if( ground->border

&& ( y == 0 || y == HEIGHT-1

|| x == 0 || x == WIDTH-1 )

){

buffer[y][x] = CH_BORDER;

}

else buffer[y][x] = CH_BLANK;

}

}

}

void syncSnake() { // snake => buffer

Point head = snake->getNode(0);

buffer[head.y][head.x] = CH_SNAKEH;

for(int i=1; i<snake->length()-1; i++) {

Point p = snake->getNode(i);

buffer[p.y][p.x] = CH_SNAKE;

}

if(snake->length() > 1) {

Point tail = snake->getNode(snake->length()-1);

buffer[tail.y][tail.x] = CH_SNAKET;

}

}

void syncFood() { // foodBuffer => buffer

for(int i=0; i<MAX_FOOD_NUM; i++) {

Point *p = foodBuffer[i];

if(NULL != p) {

buffer[p->y][p->x] = CH_FOOD;

}

}

}

void draw() { // buffer => console

// 0. clear last buffer

memset(buffer, 0, sizeof(buffer));

// 1. sync PlayGround

syncGround();

// 2. sync Snake

syncSnake();

// 3. draw food

syncFood();

// 4. draw to console

for(int i=0; i<HEIGHT; i++) {

puts(buffer[i]);

}

}

bool checkPos(Point p) const {

// check for border

if( ! ground->inArea(p) ) return false;

// check for snake

if( snake->isOnBody(p) ) return false;

// check for foods

for(int i=0; i<MAX_FOOD_NUM; i++) {

if(NULL != foodBuffer[i] && p == *foodBuffer[i]) {

return false;

}

}

return true;

}

void genFood() { // gen food => foodBuffer

log("Food generate...n");

if( foodCount < MAX_FOOD_NUM ) {

int x, y;

do {

x = rand() % WIDTH;

y = rand() % HEIGHT;

}while( ! checkPos(Point(x, y)) );

for(int i=0; i<MAX_FOOD_NUM; i++) {

if( NULL == foodBuffer[i] ) {

foodBuffer[i] = new Point(x, y);

break;

}

}

foodCount++;

// foodInfo();

}

}

void update() { // move snake once

++time;

Point nh = snake->nextHead();

// check for eating food

bool willEat = false;

int foodidx = -1;

for(int i=0; i<MAX_FOOD_NUM; i++) {

if(foodBuffer[i] && *foodBuffer[i] == nh ) {

willEat = true;

foodidx = i;

break;

}

}

if( willEat ) { // snake growth and food delete.

snake->growth();

// food delete.

delete foodBuffer[foodidx];

foodBuffer[foodidx] = NULL;

foodCount--;

// new food.

genFood();

}

else snake->move();

// check for wall collision

if( ground->border ) {

if( nh.x == 0 || nh.x == WIDTH-1

|| nh.y == 0 || nh.y == HEIGHT-1 ) {

state = GS_OVER;

}

}

else {

log("UNDEFINE...");

exit(-1);

}

// check for slef colision

if( snake->selfCollision() ) {

state = GS_OVER;

return;

}

}

void snakeTrun(Direction d) {

snake->changeDir(d);

}

void info() {

printf("Greedy Snake! length: %d time:%dn", snake->length(), time);

}

#ifdef DEBUG

void foodInfo() {

log("foodInfo: {n");

log(" foodCount: %d,n", foodCount);

log(" foodBuffer: [");

for(int i=0; i<MAX_FOOD_NUM; i++) {

Point *p = foodBuffer[i];

if( p ) log("(%d, %d)", p->x, p->y);

else log("null");

log("%s", i != MAX_FOOD_NUM-1 ? ", " : "");

}

log("]n}n");

}

void show() {

snake->show();

ground->show();

log("buffer:n");

#if 0

for(int i=0; i<HEIGHT; i++) {

for(int j=0; j<WIDTH; j++) {

log("%02X ", buffer[i][j]);

}

log("n");

}

#endif

}

#endif

};

/////////////////////////////////////////////////////////////////////////////

volatile int keyPressed = INT_MAX; // 按键缓冲(只记录一次)

volatile bool isDirKey = false;

Game *pGame = NULL;

pthread_t keyLisener;

pthread_mutex_t keyBufferLock;

void* keyListenFun(void *args)

{

while(1) {

keyPressed = getch(); // getch will bolck this thread.

// log("Pressed: %dn", keyPressed);

}

return NULL;

}

void init()

{

pGame = new Game();

// srand( time(NULL) );

pthread_mutex_init(&keyBufferLock, NULL);

pthread_create(&keyLisener, NULL, keyListenFun, NULL); // 创建按键侦听线程

}

void cleanup()

{

pthread_cancel(keyLisener);

pthread_mutex_destroy(&keyBufferLock);

delete pGame;

}

};

/////////////////////////////////////////////////////////////////////////////

int main(int argc, char *argv[])

{

using namespace game;

init();

// pGame->show();

for(int i=0; i<MAX_FOOD_NUM-1; i++)

pGame->genFood();

pGame->draw();

while(1) {

if( GS_PAUSE != pGame->getState() ) {

CLEAR_TERM

switch(keyPressed) {

case K_SPACE: pGame->setState(GS_PAUSE); break;

case K_UP:

case K_W: pGame->snakeTrun(UP); break;

case K_DOWN:

case K_S: pGame->snakeTrun(DOWN); break;

case K_LEFT:

case K_A: pGame->snakeTrun(LEFT); break;

case K_RIGHT:

case K_D: pGame->snakeTrun(RIGHT); break;

case K_ESC: pGame->setState(GS_EXIT); break;

}

pGame->info();

pGame->update();

pGame->draw();

}

else {

switch(keyPressed) {

case K_SPACE: pGame->setState(GS_START); break;

case K_ESC: pGame->setState(GS_EXIT); break;

}

}

if( pGame->getState() == GS_OVER ) {

puts("game over!");

break;

}

else if( pGame->getState() == GS_EXIT ) {

puts("exit!");

break;

}

keyPressed = INT_MAX;

msleep(GAME_CYCLE_MS);

}

cleanup();

return 0;

}

Makefile

复制代码 代码如下:

debug: snake_cmd.cpp

g++ snake_cmd.cpp -lpthread -DDEBUG -DDELAY=1000 -g -Wall

release: snake_cmd.cpp

g++ snake_cmd.cpp -lpthread -o snake -DDELAY=1000

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新C语言学习
热门C语言学习
编程开发子分类