前两个星期仔细学习了一下链表,然后发现双向链表用来写贪吃蛇还不错。(差点被CPP充满“健壮性”的链表教学劝退了)
具体实现起来还是有一点困难,看了一些博客,不过它们有些写的还不是很好(比如,不记录链表的tail项,每次都从head遍历至尾,这不就是CPP上“较慢的实现”吗 = =)。
我这个现在也有问题,比如在20来分之后,有时候就会吃到笑脸之后会卡顿一两秒 。。。还是too young。
游戏运行大概如下图:(感觉好丢人啊 = =)
有些东西是现拿的,比如隐藏光标:
1 // 隐藏光标 2 void gotoxy(int x, int y) { 3 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 4 COORD pos; 5 pos.X = x; 6 pos.Y = y; 7 SetConsoleCursorPosition(handle, pos); 8 } 9 void HideCursor() { 10 CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; 11 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); 12 }
我还不知道句柄是什么呢,= =。
讲不清,看代码吧。
Snake.h 头文件
1 #ifndef _SNAKE_H_ 2 #define _SNAKE_H_ 3 4 const int COL = 15; 5 const int ROW = 15; 6 7 typedef struct SnakeNode { 8 int x; 9 int y; 10 struct SnakeNode *pre; 11 struct SnakeNode *next; 12 }Node, *pNode; 13 typedef struct Food { 14 int x; 15 int y; 16 }Food, *pFood; 17 18 //一些全局变量 19 int score = 0; 20 int difficulty = 4; 21 pNode pTail = NULL; 22 23 // 隐藏光标 24 void gotoxy(int x, int y) { 25 HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); 26 COORD pos; 27 pos.X = x; 28 pos.Y = y; 29 SetConsoleCursorPosition(handle, pos); 30 } 31 void HideCursor() { 32 CONSOLE_CURSOR_INFO cursor_info = { 1, 0 }; 33 SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info); 34 } 35 36 pNode InitSnake(void) { 37 pNode pHead = (pNode)malloc(sizeof(Node)); 38 pHead->x = ROW / 2; 39 pHead->y = COL / 2; 40 pHead->next = pHead->pre = NULL; 41 pTail = pHead; 42 pTail->pre = pTail->next = NULL; 43 return pHead; 44 } 45 46 Food CreateFood(void) { 47 Food food; 48 srand((unsigned)time(NULL)); 49 food.x = rand() % ROW; 50 food.y = rand() % COL; 51 return food; 52 } 53 54 void AdjustDifficulty(int score) { 55 if (score == 5) 56 difficulty = 3; 57 else if (score == 10) 58 difficulty = 2; 59 else if (score == 20) 60 difficulty = 1; 61 } 62 63 bool SnakeDeath(pNode pHead) { 64 for (pNode pt = pHead->next; pt != NULL; pt = pt->next) { 65 if (pt->x == pHead->x&&pt->y == pHead->y) 66 return true; 67 } 68 return false; 69 } 70 71 bool FoodInSnake(pNode pHead,pFood pFood) { 72 for (pNode pt = pHead; pt != NULL; pt = pt->next) { 73 if (pFood->x == pt->x&&pFood->y == pt->y) 74 return true; 75 } 76 return false; 77 } 78 79 bool Move(pNode pHead, char key) { 80 bool game_over = false; 81 pNode pt = pTail; 82 while (pt != pHead) { // 每个节点依次向前完成蛇的移动 83 pt->x = pt->pre->x; 84 pt->y = pt->pre->y; 85 pt = pt->pre; 86 } 87 switch (key) { 88 case'd': { 89 pHead->x += 1; 90 if (pHead->x >= ROW) 91 pHead->x -= ROW; 92 break; 93 } 94 case'a': { 95 pHead->x -= 1; 96 if (pHead->x < 0) 97 pHead->x += ROW; 98 break; 99 } 100 case's': { 101 pHead->y += 1; 102 if (pHead->y >= COL) 103 pHead->y -= COL; 104 break; 105 } 106 case'w': { 107 pHead->y -= 1; 108 if (pHead->y < 0) 109 pHead->y += COL; 110 break; 111 } 112 } 113 if (SnakeDeath(pHead)) 114 game_over = true; 115 return game_over; 116 } 117 118 char CheckKey(char direct) { 119 char key; 120 if (kbhit()) { // kbhit函数检查是否有键盘端的输入 121 key = getch(); 122 if (direct != 'd'&& key == 'a') 123 direct = key; 124 else if (direct != 'a'&&key == 'd') 125 direct = key; 126 else if (direct != 'w'&&key == 's') 127 direct = key; 128 else if (direct != 's'&&key == 'w') 129 direct = key; 130 else if (key == 27) // 27是esc的ascII码 131 direct = key; 132 } 133 return direct; 134 } 135 136 pNode EatFood(pNode pHead, pFood pFood) { 137 pNode p_add = NULL, pt = NULL; 138 if (pFood->x == pHead->x&&pFood->y == pHead->y) { 139 p_add = (pNode)malloc(sizeof(Node)); 140 score++; 141 pTail->next = p_add; 142 p_add->pre = pTail; 143 p_add->next = NULL; 144 pTail = p_add; 145 // 检查食物是否出现在蛇身的位置上 146 do { 147 *pFood = CreateFood(); 148 }while (FoodInSnake(pHead, pFood)); 149 } 150 return pHead; 151 } 152 153 void Show(pNode pHead, Food food) { 154 int row = 0, col = 0, flag = 0; 155 pNode pt = NULL; 156 printf("---方向控制:上:w 下:s 左:a 右:d(Esc退出)---\n"); 157 printf("----------------------------------------\n"); 158 printf("当前分数为: %d \n",score); 159 printf("当前等级为: %d \n---", 5-difficulty); 160 for (row = 0; row < ROW; row++) 161 printf("—"); 162 putchar('\n'); 163 for (col = 0; col < COL; col++) { 164 printf(" |"); 165 for (row = 0; row < ROW; row++) { 166 pt = pHead; 167 flag = 0; 168 //打印出蛇 169 while (pt != NULL) { 170 if (row == pt->x && col == pt->y) { 171 if (pt == pHead) 172 printf("■"); 173 else 174 printf("□"); 175 flag = 1; 176 break; 177 } 178 pt = pt->next; 179 } 180 //打印出食物或两个空格 181 if (!flag) { 182 if (row == food.x && col == food.y) { 183 printf(":)"); 184 continue; 185 } 186 printf(" "); 187 } 188 } 189 printf("|\n"); 190 } 191 printf(" "); 192 for (row = 0; row < ROW; row++) 193 printf("—"); 194 putchar('\n'); 195 } 196 197 void ExitGame(pNode *ppHead) 198 { 199 pNode p_delete = NULL, p_save = NULL; 200 while (*ppHead != NULL) { 201 p_save = (*ppHead)->next; 202 if (p_save != NULL) 203 p_save->pre = NULL; 204 p_delete = *ppHead; 205 free(p_delete); 206 p_delete = NULL; 207 *ppHead = p_save; 208 } 209 } 210 #endif
Snake.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <time.h> 4 #include <conio.h> 5 #include <Windows.h> 6 #include <stdbool.h> 7 #include "rSnake.h" 8 9 int main(void) 10 { 11 bool game_over = false; 12 char direct = 'a', input; 13 Food food = CreateFood(); 14 pNode head = InitSnake(); 15 HideCursor(); 16 do{ 17 head = EatFood(head, &food); 18 input = CheckKey(direct); 19 if (27 == input){ 20 game_over = true; 21 break; 22 } 23 else 24 direct = input; 25 game_over = Move(head, direct); 26 system("cls"); 27 Show(head, food); 28 AdjustDifficulty(score); 29 Sleep(difficulty*50); 30 } while (game_over == false); 31 32 if (game_over){ 33 printf("游戏结束!\n"); 34 ExitGame(&head); 35 if (head==NULL) 36 printf("内存释放成功!\n"); 37 else 38 printf("内存释放失败!\n"); 39 } 40 getch(); 41 return 0; 42 }