2018-08-28 19:37:51 再再再次更新
用STL库的deque(双端队列)重新实现了一下,代码减少了许多。
#include "stdafx.h" #include <iostream> #include <windows.h> #include <deque> #include <set> #include <time.h> typedef enum { U, D, L, R } Status; Status status = U; void SetPosition(short x, short y) { HANDLE winHandle; COORD pos = { x, y }; winHandle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(winHandle, pos); } bool IsCollised(std::deque<std::pair<int, int>> h, std::pair<int, int> f) { return h.front().first == f.first && h.front().second == f.second; } bool IsCollisSelf(std::deque<std::pair<int, int>> h) { std::deque<std::pair<int, int>> self = h; self.pop_front(); while (!self.empty()) { if (IsCollised(h, self.front())) return true; self.pop_front(); } return false; } void GenerateFood(std::deque<std::pair<int, int>> h, std::pair<int, int> & f) { srand((unsigned int)time(0)); int x = rand() % 67 + 1; int y = rand() % 28 + 1; f.first = x & 1 ? x + 1 : x; f.second = y; for (std::deque<std::pair<int, int>>::iterator self = h.begin(); self != h.end(); ++self) if (self->first == f.first && self->second == f.second) GenerateFood(h, f); SetPosition(f.first, f.second); std::cout << "■"; } void Init(std::deque<std::pair<int, int>> &h, std::pair<int, int> &f) { for (int i = 0; i <= 4; i++) { SetPosition(24, 8 + i); std::cout << "■"; h.push_back(std::pair<int, int>(24, 8 + i)); } GenerateFood(h, f); } void MoveUp(std::deque<std::pair<int, int>>&h, std::pair<int, int> &f) { h.push_front(std::pair <int, int>(h.front().first, h.front().second - 1)); if (h.front().second <= 0) h.front().second = 30; SetPosition(h.front().first, h.front().second); std::cout << "■"; if (!IsCollised(h, f)) { SetPosition(h.back().first, h.back().second); h.pop_back(); std::cout << " "; } else GenerateFood(h, f); } void MoveDown(std::deque<std::pair<int, int>>&h, std::pair<int, int> &f) { h.push_front(std::pair <int, int>(h.front().first, h.front().second + 1)); if (h.front().second >= 30) h.front().second = 0; SetPosition(h.front().first, h.front().second); std::cout << "■"; if (!IsCollised(h, f)) { SetPosition(h.back().first, h.back().second); h.pop_back(); std::cout << " "; } else GenerateFood(h, f); } void MoveLeft(std::deque<std::pair<int, int>>&h, std::pair<int, int> &f) { h.push_front(std::pair <int, int>(h.front().first - 2, h.front().second)); if (h.front().first <= 0) h.front().first = 70; SetPosition(h.front().first, h.front().second); std::cout << "■"; if (!IsCollised(h, f)) { SetPosition(h.back().first, h.back().second); h.pop_back(); std::cout << " "; } else GenerateFood(h, f); } void MoveRight(std::deque<std::pair<int, int>>&h, std::pair<int, int> &f) { h.push_front(std::pair <int, int>(h.front().first + 2, h.front().second)); if (h.front().first >= 70) h.front().first = 0; SetPosition(h.front().first, h.front().second); std::cout << "■"; if (!IsCollised(h, f)) { SetPosition(h.back().first, h.back().second); h.pop_back(); std::cout << " "; } else GenerateFood(h, f); } void Game(std::deque<std::pair<int, int>> &h, std::pair<int, int> &f) { while (1) { Sleep(200); if (GetAsyncKeyState(VK_UP) && status != D) status = U; else if (GetAsyncKeyState(VK_DOWN) && status != U) status = D; else if (GetAsyncKeyState(VK_LEFT) && status != R) status = L; else if (GetAsyncKeyState(VK_RIGHT) && status != L) status = R; else if (status == U) MoveUp(h, f); else if (status == D) MoveDown(h, f); else if (status == L) MoveLeft(h, f); else if (status == R) MoveRight(h, f); if (IsCollisSelf(h)) return; } } int main(int argc, char **argv) { std::deque<std::pair<int, int>> snake; std::pair<int, int> food; Init(snake, food); Game(snake, food); return 0; }
效果与前面的一样,就不贴图了。
2018-08-26 17:27:05 再再次更新
也了解一下关于贪吃蛇游戏的历史:https://en.wikipedia.org/wiki/Snake_(video_game_genre)
emm,又做了一点,增加了判断蛇是否咬到了自己,去除了食物的位置落在蛇身上的情况,对于随机生成食物位置的算法改进了一下。。。
效果:
源码:
#include "stdafx.h" #include <iostream> #include <windows.h> #include <time.h> typedef enum { U, D, L, R } Status; typedef struct Snake { char body[3]; int x, y; Snake*pre_node, *next_node; Snake() : body("■"), pre_node(nullptr), next_node(nullptr) {} Snake(int x1, int y1) : body("■"), x(x1), y(y1), pre_node(nullptr), next_node(nullptr) { } } SnakeBody; SnakeBody*head = nullptr; SnakeBody*tail = nullptr; SnakeBody*food = nullptr; Status status = U; void SetPosition(short x, short y) { HANDLE winHandle; COORD pos = { x, y }; winHandle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(winHandle, pos); } bool IsCollised(SnakeBody*h, SnakeBody*f) { if (!f) return false; return h->x == f->x && h->y == f->y; } bool IsCollisSelf(SnakeBody*h, SnakeBody*t) { SnakeBody*self = t; while (self->pre_node != h) { if (IsCollised(h, self)) return true; self = self->pre_node; } return false; } void GenerateFood(SnakeBody*t) { srand((unsigned int)time(0)); int x = rand() % 67 + 1; int y = rand() % 26 + 1; food = new Snake(x & 1 ? x + 1 : x, y); SnakeBody*self = t; while (self) { if (IsCollised(self, food)) { delete food; food = nullptr; GenerateFood(t); } self = self->pre_node; } SetPosition(food->x, food->y); printf("%s", food->body); } void Init() { head = new Snake(24, 8); SnakeBody*s_body = head; for (int i = 1; i <= 4; i++) { SnakeBody* cur_n = new Snake(head->x, head->y + i); cur_n->pre_node = s_body; s_body->next_node = cur_n; s_body = cur_n; } tail = s_body; s_body = head; while (s_body) { SetPosition(s_body->x, s_body->y); printf("%s", s_body->body); s_body = s_body->next_node; } } void MoveUp(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x, h->y - 1); if (n->y <= 0) n->y = 28; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; if (!IsCollised(h, food)) { SetPosition(t->x, t->y); printf(" "); t = t->pre_node; delete t->next_node; } else { delete food; food = nullptr; GenerateFood(tail); } } void MoveDown(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x, h->y + 1); if (n->y >= 28) n->y = 0; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; if (!IsCollised(h, food)) { SetPosition(t->x, t->y); printf(" "); t = t->pre_node; delete t->next_node; } else { delete food; food = nullptr; GenerateFood(tail); } } void MoveLeft(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x - 2, h->y); if (n->x <= 0) n->x = 68; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; if (!IsCollised(h, food)) { SetPosition(t->x, t->y); printf(" "); t = t->pre_node; delete t->next_node; } else { delete food; food = nullptr; GenerateFood(tail); } } void MoveRight(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x + 2, h->y); if (n->x >= 68) n->x = 0; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; if (!IsCollised(h, food)) { SetPosition(t->x, t->y); printf(" "); t = t->pre_node; delete t->next_node; } else { delete food; food = nullptr; GenerateFood(tail); } } void Game() { GenerateFood(tail); while (1) { Sleep(200); if (GetAsyncKeyState(VK_UP) && status != D) status = U; else if (GetAsyncKeyState(VK_DOWN) && status != U) status = D; else if (GetAsyncKeyState(VK_LEFT) && status != R) status = L; else if (GetAsyncKeyState(VK_RIGHT) && status != L) status = R; else if (status == U) MoveUp(head, tail); else if (status == D) MoveDown(head, tail); else if (status == L) MoveLeft(head, tail); else if (status == R) MoveRight(head, tail); if (IsCollisSelf(head, tail)) return; } } void DeleteSnake(SnakeBody*&h) { if (h) { DeleteSnake(h->next_node); delete h; h = nullptr; } } int main(int argc, char **argv) { Init(); Game(); DeleteSnake(head); return 0; }
2018-08-26 00:34:10 再次更新
本来不想做了,但找不到其他的事情做,于是增加了随机产生食物功能,蛇吃到食物就可以变长了。但有个bug,没有判断随机生成的食物的位置落在蛇身上。。。如果恰好落在蛇身上,就不能再随机生成食物了。。。
PS 这段代码删除了,因为与上一段代码差不多,但上一段更完整。
2018-08-24 21:49:51 更新
之前的代码中使用的数据结构是单链表,而我的算法是,每次改变位置都遍历一次链表,将节点的位置+1,然后再遍历链表打印出来,这样效率十分低下(可以想像如果蛇越来越长),而且只能看着蛇从上往下移动,于是这次改用了双向链表,并增加了控制功能,能控制蛇上下左右移动。
效果图:
代码:
#include <iostream> #include <windows.h> typedef enum { U, D, L, R } Status; typedef struct Snake { char body[3]; int x, y; Snake*pre_node, *next_node; Snake() : body("■"), pre_node(nullptr), next_node(nullptr) {} Snake(int x1, int y1) : body("■"), x(x1), y(y1), pre_node(nullptr), next_node(nullptr) { } } SnakeBody; SnakeBody*head = nullptr; SnakeBody*tail = nullptr; Status status = U; void SetPosition(short x, short y) { HANDLE winHandle; COORD pos = {x, y}; winHandle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(winHandle, pos); } void Init() { head = new Snake(24, 8); SnakeBody*s_body = head; for (int i = 1; i <= 4; i++) { SnakeBody* cur_n = new Snake(head->x, head->y + i); cur_n->pre_node = s_body; s_body->next_node = cur_n; s_body = cur_n; } tail = s_body; s_body = head; while (s_body) { SetPosition(s_body->x, s_body->y); printf("%s", s_body->body); s_body = s_body->next_node; } } void MoveUp(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x, h->y - 1); if (n->y <= 0) n->y = 28; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; SetPosition(t->x, t->y); printf(" "); t = t->pre_node; delete t->next_node; } void MoveDown(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x, h->y + 1); if (n->y >= 28) n->y = 0; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; SetPosition(t->x, t->y); printf(" "); n = t; t = t->pre_node; delete n; } void MoveLeft(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x - 2, h->y); if (n->x <= 0) n->x = 68; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; SetPosition(t->x, t->y); printf(" "); n = t; t = t->pre_node; delete n; } void MoveRight(SnakeBody*&h, SnakeBody*&t) { SnakeBody*n = new Snake(h->x + 2, h->y); if (n->x >= 68) n->x = 0; SetPosition(n->x, n->y); printf("%s", n->body); n->next_node = h; h->pre_node = n; h = n; SetPosition(t->x, t->y); printf(" "); n = t; t = t->pre_node; delete n; } void Game() { while(1) { Sleep(200); if (GetAsyncKeyState(VK_UP) && status != D) status = U; else if (GetAsyncKeyState(VK_DOWN) && status != U) status = D; else if (GetAsyncKeyState(VK_LEFT) && status != R) status = L; else if (GetAsyncKeyState(VK_RIGHT) && status != L) status = R; else if (status == U) MoveUp(head, tail); else if (status == D) MoveDown(head, tail); else if (status == L) MoveLeft(head, tail); else if (status == R) MoveRight(head, tail); } } void DeleteSnake(SnakeBody*h) { if (h) { DeleteSnake(h->next_node); delete h; } } int main(int argc, char **argv) { Init(); Game(); DeleteSnake(head); return 0; }
控制控制台光标位置以及键盘响应部分的代码和部分设计思路参考了以前在网上看到的一份贪吃蛇源码,但现在找不到在哪看到的了,只剩下源码了。
以下是原文:
无聊发现自己没写过贪吃蛇,于是做了一个简单的贪吃蛇,并不打算做完整版的(只能看到贪吃蛇不断的从上往下移动)。。
效果(截图软件的问题,会有前一帧的印记):
代码:
#include <iostream> #include <windows.h> typedef struct Snake { char body[3]; int x, y; Snake* n_node; Snake() : body("■"), n_node(nullptr) {} Snake(int x1, int y1) : body("■"), x(x1), y(y1), n_node(nullptr) { } } SnakeBody; void SetPosition(short x, short y) { HANDLE winHandle; COORD pos = {x, y}; winHandle = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(winHandle, pos); } SnakeBody*Init(SnakeBody*head) { head = new Snake(0, 0); SnakeBody*s_body = head; for (int i = 1; i <= 4; i++) { SnakeBody* cur_n = new Snake(head->x, head->y + i); s_body->n_node = cur_n; s_body = cur_n; } return head; } void PrintBody(SnakeBody*h) { SnakeBody*n = h; while (n) { SetPosition(n->x, n->y); printf("%s", n->body); n = n->n_node; } } SnakeBody*MoveDown(SnakeBody*h) { SnakeBody*n = h; while (n) { n->y += 1; if (n->y == 28) n->y = 0; n = n->n_node; } return h; } void Game(SnakeBody*head) { while(1) { PrintBody(head); SetPosition(head->x, head->y); printf(" "); head = MoveDown(head); Sleep(600); } } void DeleteSnake(SnakeBody*h) { if (h) { DeleteSnake(h->n_node); delete h; } } int main(int argc, char **argv) { SnakeBody*h = nullptr; h = Init(h); Game(h); DeleteSnake(h); return 0; }