1. 程式人生 > >C++控制檯迴圈連結串列實現貪吃蛇

C++控制檯迴圈連結串列實現貪吃蛇

-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;

}