C++控制台循环链表实现贪吃蛇

原创 2015年11月21日 14:46:51

-stdafx.h 为了简化程序定义一些宏和全局变量

#ifndef __STDAFX_H__
#define __STDAFX_H__

// ============上下左右=============
const int UP = 72;
const int DOWN = 80;
const int LEFT = 75;
const int RIGHT = 77;

// ==============宽高===============
#define HEIGHT 20
#define WIDTH 39

// ==============输出===============
#define cout_food std::cout<<"*"
#define cout_snake std::cout<<"■"
#define cout_space std::cout << " "
#define cout_snake_xy(x,y) SnakeUI::gotoXY(x,y);cout_snake
#define cout_food_xy(x,y) SnakeUI::gotoXY(x,y);cout_food
#define cout_space_xy(x,y) SnakeUI::gotoXY(x,y);cout_space

// =============结束?==============
#define OVER false
#define RUN true

#endif


-SnakeUI.h 

主要是初始化UI,初始化蛇,还有生产食物,判断食物和蛇有没有相撞,还有对界面的一些操作

#ifndef __SNAKE_UI_H__
#define __SNAKE_UI_H__

#include <iostream>
#include <Windows.h>
#include "Snake.h"

struct Food {
	int x;
	int y;
};

class SnakeUI {
public:
	static void initUI();
	static void initSnake();
	static void gotoXY(int x, int y);

	static void productFood(Snake& snake);
	static bool meetWithFood(int x, int y);
	
private:
	static Food food;

};


#endif

-SnakeUI.cpp

#include "stdafx.h"
#include "SnakeUI.h"
#include <ctime>
using namespace std;

Food SnakeUI::food = { 0, 0 };

// init UI
void SnakeUI::initUI() {
	cout << "┏";
	for (int i = 1; i < WIDTH; ++i) cout << "━"; 
	cout << "┓";
	gotoXY(0, HEIGHT);
	cout << "┗";
	for (int i = 1; i < WIDTH; ++i) cout << "━"; 
	cout << "┛";
	for (int y = 1; y < HEIGHT; ++y) {
		gotoXY(0, y); cout << "┃";
		gotoXY(WIDTH, y); cout << "┃";
	}
}

// init snake: three points
void SnakeUI::initSnake() {
	gotoXY(2, 10); cout_snake;
	gotoXY(3, 10); cout_snake;
	gotoXY(4, 10); cout_snake;
}

// goto point(x, y) in console
void SnakeUI::gotoXY(int x, int y) {
	COORD coord = { x * 2, y };
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

// random product food
void SnakeUI::productFood(Snake& snake) {
	srand((unsigned)time(NULL));
	int x, y;	// x from 1 to 38, y from 1 to 19
	bool productOK;
	for (;;) {
		productOK = true;
		x = rand() % 38 + 1;
		y = rand() % 19 + 1;
		// 不和蛇身碰撞1->检查身体和尾部
		for (SnakeNode* sn = snake.last; sn != snake.first; sn = sn->prev) {
			if (sn->x == x && sn->y == y) {
				productOK = false;
				break;
			}
		}
		// 不和蛇身碰撞2->检查头部
		if (x == snake.first->x && y == snake.first->y)
			productOK = false;

		if (productOK)
			break;
	}
	food.x = x; 
	food.y = y;
	cout_food_xy(food.x, food.y);
}

// is snake's head meet with food?
bool SnakeUI::meetWithFood(int x, int y) {
	return (food.x == x && food.y == y);
}

-Snake.h

蛇类,蛇的移动和状态

#ifndef __SNAKE_H__
#define __SNAKE_H__

struct SnakeNode {
	int x;
	int y;
	SnakeNode* prev;
	SnakeNode(int x_t, int y_t){ x = x_t; y = y_t; }
	SnakeNode(){}
};

class Snake {
	friend class SnakeUI;

public:
	Snake();
	~Snake();
	bool snakeMove(char& dir);

private:
	void getKey(char& dir);

private:
	SnakeNode* first;
	SnakeNode* last;
	char state;
};

#endif

-Snake.cpp

#include "stdafx.h"
#include "Snake.h"
#include "SnakeUI.h"

Snake::Snake() {
	// 状态:向右
	state = RIGHT;
	// 创建循环链表
	first = new SnakeNode(4, 10);
	last = new SnakeNode(2, 10);
	last->prev = new SnakeNode(3, 10);
	last->prev->prev = first;
	first->prev = last;
	// UI
	SnakeUI::initSnake();
	SnakeUI::productFood(*this);
}

Snake::~Snake() {
	SnakeNode* tmp = last;
	while (last != last) {
		last = last->prev;
		delete tmp;
		tmp = last;
	}
	delete last;
}

bool Snake::snakeMove(char& dir) {
	int x = first->x;
	int y = first->y;
	getKey(dir);
	// 撞墙->Game Over
	switch (state)
	{
	case UP: --y; if (y == 0) return OVER; break;
	case DOWN: ++y; if (y == HEIGHT) return OVER; break;
	case LEFT: --x; if (x == 0) return OVER; break;
	case RIGHT: ++x; if (x == WIDTH) return OVER; break;
	}

	// 撞到了自己
	SnakeNode* tmp = last;
	for (; tmp != first; tmp = tmp->prev) {
		if (first->x == tmp->x && first->y == tmp->y)
			return OVER;
	}

	// 吃食物
	if (SnakeUI::meetWithFood(x, y)) {
		SnakeNode* newHead = new SnakeNode(x, y);
		first->prev = newHead;
		newHead->prev = last;
		first = newHead;
		cout_snake_xy(x, y);
		SnakeUI::productFood(*this);
	}
	else {
		cout_space_xy(last->x, last->y);
		last->x = x;
		last->y = y;
		first = last;
		last = last->prev;
		cout_snake_xy(x, y);
	}

	return RUN;
}

void Snake::getKey(char& dir) {
	switch (dir)
	{
	case UP: if (state == LEFT || state == RIGHT) state = UP; return;
	case DOWN: if (state == LEFT || state == RIGHT) state = DOWN; return;
	case LEFT: if (state == UP || state == DOWN) state = LEFT; return;
	case RIGHT: if (state == UP || state == DOWN) state = RIGHT; return;
	}
}

-main.cpp

#include "stdafx.h"
#include "SnakeUI.h"
#include "Snake.h"
#include <iostream>
#include <conio.h>
using namespace std;

DWORD WINAPI ThreadProc1(LPVOID lpParameter);

char dir = RIGHT;

int main()
{
	SnakeUI::initUI();
	Snake snake;
	
	CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
	while (snake.snakeMove(dir)) Sleep(100);

	system("pause");
	return 0;
}


DWORD WINAPI ThreadProc1(LPVOID lpParameter)
{
	for (;;) {
		dir = _getch();
	}
	return 1;

}

版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

字符界面的贪吃蛇--链表--C++

前天看了下链表

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

完全用链表实现的贪吃蛇

完全用链表实现的贪吃蛇 分类: 杂感2011-09-18 14:08 5175人阅读 评论(25) 收藏 举报 structextensionlistrandomkill数据结构 ...
  • pi9nc
  • pi9nc
  • 2013年07月17日 14:17
  • 1785

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

c++经典项目控制台贪吃蛇小游戏详细教程

贪吃蛇GreedySnake本文将讲解如何使用c++面向对象方法编写控制台版贪吃蛇小游戏,项目github地址:silence1772/GreedySnake 游戏下载:GreedySnake 本...

贪吃蛇~~C++控制台实现!

刚学完了C语言,便尝试的写了贪吃蛇的代码,但是效果不佳,很多的bug,所以,这个学了C++,便重新的写了这个小游戏,用类来封装!~ 先是头文件: struct Snake { int x, y;...

队列的使用—WIN32控制台贪吃蛇(VS2010,C++语言)

VS2010平台C++开发的基于数组实现的贪吃蛇小程序
  • yaodix
  • yaodix
  • 2016年06月01日 20:21
  • 889

c/c++ 入门之控制台上实现贪吃蛇

分析贪吃蛇游戏,蛇的身体在吃到食物之后增长,因此可以用链表来储存蛇身体的节点。 // ConsoleApplication1.cpp : 定义控制台应用程序的入口点。 // #include "...

面向对象方法编一个简易的控制台版贪吃蛇(一)

今天,我们开始用面向对象的方法编写一个简易的控制台版的贪吃蛇。本人能力有限,若有纰漏还请及时指出,多多包涵。 在编写程序之前,我们得有一个较为清晰的思路,即:如何才能编出这个游戏。我想,可以遵循以下几...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C++控制台循环链表实现贪吃蛇
举报原因:
原因补充:

(最多只允许输入30个字)