MinGW compiled Windows command line greedy Snake sample _c language

Source: Internet
Author: User
Tags rand volatile

Main thread: Maintain the game logic, refresh the picture.
Background Thread: Monitor key (Getch)

Temporarily only supports the MinGW compilation under Windows, originally uses the MINGW compilation to want to write under the Linux also to be able to run. As a result, Linux does not directly provide the Getch () function (<conio.h> under Windows).

Don't care! Pure Entertainment

Compile to add-lpthread

Snake_cmd.cpp

Copy Code code as follows:

#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; Forward direction
Point Body[max_body_len]; Body position
Body_type body; Body position

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 ():%d\n", 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-&GT;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-&GT;Y][P-&GT;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; iPuts (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:%d\n ", 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; ifor (int j=0; j<width; j) {
Log ("%02x", Buffer[i][j]);
}
Log ("\ n");
}
#endif
}
#endif
};

/////////////////////////////////////////////////////////////////////////////
volatile int keypressed = Int_max; Key buffer (only once)
volatile bool Isdirkey = false;
Game *pgame = NULL;

pthread_t Keylisener;
pthread_mutex_t Keybufferlock;

void* keylistenfun (void *args)
{
while (1) {
keypressed = Getch (); Getch'll bolck this thread.
Log ("Pressed:%d\n", keypressed);
}
return NULL;
}

void Init ()
{
Pgame = new Game ();
Srand (Time (NULL));
Pthread_mutex_init (&keybufferlock, NULL);
Pthread_create (&keylisener, NULL, keylistenfun, NULL); Creating a key listener thread
}

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

Copy Code code as follows:

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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.