贪吃蛇

实现贪吃蛇功能:

1.蛇节点成员:


class SnakeNode
{
public:
	SnakeNode(Point data = Point{ INVALID, INVALID }, SnakeNode* pred = nullptr, SnakeNode* succ = nullptr)
		: position(data), pred(pred), succ(succ) {}

	~SnakeNode();

	Point position;
	SnakeNode* pred;
	SnakeNode* succ;

	SnakeNode* insertAsPred(Point const& data);
	SnakeNode* insertAsPred(SnakeNode* node);
	SnakeNode* insertAsSucc(Point const& data);
	SnakeNode* insertAsSucc(SnakeNode* node);
	SnakeNode* popPred();
	SnakeNode* popSucc();

	Point getUp() const;
	Point getDown() const;
	Point getLeft() const;
	Point getRight() const;

	void draw(HDC& hdc);
};

2.蛇的所包含的成员:

class SnakeNode;
class Snake
{
private:
	int _len;				// 蛇长度
	SnakeNode* header;		// 头哨兵
	SnakeNode* trailer;		// 尾哨兵
	Direction direction;
	LPRECT rect;

protected:
	// 蛇的初始化
	void init();
	// 删除所有蛇节点
	int clear();
	//删除合法位置p处的节点,返回被删除节点
	Point remove(SnakeNode* node);

	SnakeNode* insertAsBegin();

	SnakeNode* insertAsBegin(SnakeNode* node);

	Point getMoveNextPoint() const;

	SnakeNode* popEnd();

	SnakeNode* popBegin();

	SnakeNode* begin() const;

public:
	Snake(HWND& hWnd);
	~Snake();
	// 蛇的移动
	void move();
	// 画蛇
	void draw(HDC& hdc);
};

3.将贪吃蛇设置成链表的形式

将贪吃蛇设置成双向链表,初始化时设置一个头哨兵与尾哨兵,不包含任何数据,并随机生成一个节点,表示游戏开始时,贪吃蛇的位置
 

Snake::Snake(HWND& hWnd)
	: _len(0)
	, header(nullptr)
	, trailer(nullptr)
	, direction(UNKNOWN)
	, rect(nullptr)
{
	init();
	rect = new tagRECT;
	GetClientRect(hWnd, rect);

	int x = rand() % ((rect->right - rect->left) / 10);
	int y = rand() % ((rect->bottom - rect->top) / 10);
	header->insertAsSucc(Point(x * 10, y * 10));
}

void Snake::init()
{
	header = new SnakeNode;
	trailer = new SnakeNode;
	header->succ = trailer;
	trailer->pred = header;
	_len = 0;
}

4.移动时,贪吃蛇的移动方法(采用滚动的形式):

将尾节点从链表中pop,并insert到链表的首节点

具体实现:采用滚动的形式,通过尾哨兵获取末尾节点end,并从链表中去掉,根据蛇的运动方向,获取下一步所经过的屏幕的position,将end的position设置成蛇运动下一步所经过的屏幕的position,插入作为到整个蛇链表的首节点的前驱

void Snake::move()
{
	Point begin = getMoveNextPoint();
	SnakeNode* node = popEnd();
	node->position = begin;
	insertAsBegin(node);
}

SnakeNode* Snake::popEnd()
{
	SnakeNode* node = trailer->popPred();
	_len--;
	return node;
}

Point Snake::getMoveNextPoint() const
{
	if (begin()->position == Point(INVALID, INVALID))
		return Point(INVALID, INVALID);

	switch (direction)
	{
	case UP:
		return begin()->getUp();
	case DOWN:
		return begin()->getDown();
	case LEFT:
		return begin()->getLeft();
	case RIGHT:
		return begin()->getRight();
	default:
		return Point(INVALID, INVALID);
	}
}

5.当蛇吃到食物时:

吃到食物的位置,根据下一步蛇移动的屏幕位置,插入到首节点之前,,此时,蛇不移动,只是增长一个节点,再下一时刻才移动
 

// 当吃到食物时,在begin插入节点
SnakeNode* Snake::insertAsBegin()
{
	Point p = getMoveNextPoint();
	if (p == Point(INVALID, INVALID))
		return nullptr;

	SnakeNode* node = header->insertAsSucc(p);
	_len++;
	return node;
}

总结:

通过此次学习,让我在实际应用问题中使用数据结构更加熟练,形成了学习到应用的转化。不再像此前思维固化,只知道蛮力求解问题,让我的思维更加灵活和懂得变通

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值