字元介面的貪吃蛇--連結串列--C++
阿新 • • 發佈:2019-01-09
前天看了下連結串列,由於平時對連結串列的使用不多,所以對連結串列的應用也沒什麼瞭解,所以想來想去,就想用連結串列實現一下貪吃蛇。
下面言歸正傳,先看效果圖,再看程式碼,其他沒有了!
圖1:
圖2:
程式碼:
#include<iostream.h> //turbo c++ conio.h==控制控制檯相關函式的標頭檔案 #include<conio.h> #include<time.h> #include<stdlib.h> typedef char bool; //點 struct Point { int x; int y; }; //連結串列的一個節點 //蛇的一個身體 //每個節點包含位置資訊,pos:當前位置,lastpos:上一個位置 struct Node { Point lastpos; Point pos; Node* next; }; //圍牆 struct Wall { int UP_BOND; int RIGHT_BOND; int DOWN_BOND; int LEFT_BOND; int length; short offset; }; //蛇 struct Snake { Node* head;//蛇的頭 Node* tail;//蛇的尾 Node* atefood;//蛇吃下的食物資訊 Node* lastfood;//食物中最先被吃下的一個 int length;//蛇的長度 short direction;//蛇移動的方向 int timeperstep;//蛇的移動速度 Wall wall;//圍牆 }; //獲取當前蛇的尾巴節點 Node* getSnakeTail(Snake* snake) { Node* node; Node* lastnode; lastnode = snake->head; node = snake->head; while(NULL != node) { lastnode = node; node = node->next; } return lastnode; }; //初始化時新增蛇身 void addNode(Snake* snake,Node* node) { node->next = snake->head; snake->head = node; }; //隨機產生食物時,檢測食物是否在蛇的身上,即不合法 bool generateCheck(Point* pos,Snake* snake) { Node* node; node = snake->head; while(node!=NULL) { if(pos->x == node->pos.x&&pos->y == node->pos.y) { return 1; } node = node->next; } node = snake->atefood; while(NULL!=node) { if(pos->x == node->pos.x&&pos->y == node->pos.y) { return 1; } node = node->next; } return 0; }; //產生食物,位置隨機 Point* generateFood(Snake* snake) { Point* pos; pos = new Point; srand(time(NULL)); pos->x = rand()%snake->wall.length+snake->wall.offset+2; pos->y = rand()%snake->wall.length+snake->wall.offset+2; while(generateCheck(pos,snake)) { pos->x = rand()%50+2; pos->y = rand()%50+2; } return pos; }; //檢測蛇是否吃到食物 bool eateFood(Snake* snake,Point* food) { if(snake->head->pos.x == food->x && snake->head->pos.y == food->y) { return 1; } return 0; } //檢測蛇是否撞到圍牆或自己的身體 bool attackCheck(Snake* snake) { switch(snake->direction) { case 0://up if(snake->head->pos.y == snake->wall.UP_BOND) { return 1; } break; case 1://right if(snake->head->pos.x == snake->wall.RIGHT_BOND) { return 1; } break; case 2://down if(snake->head->pos.y == snake->wall.DOWN_BOND) { return 1; } break; case 3://left if(snake->head->pos.x == snake->wall.LEFT_BOND) { return 1; } break; } Node* node; node = snake->head->next; while(NULL != node) { if(snake->head->pos.x == node->pos.x && snake->head->pos.y == node->pos.y) return 1; node = node->next; } return 0; }; //向當前方向移動蛇 bool move(Snake* snake) { snake->head->lastpos.x = snake->head->pos.x; snake->head->lastpos.y = snake->head->pos.y; switch(snake->direction) { case 0://up snake->head->pos.y--; break; case 1://right snake->head->pos.x++; break; case 2://down snake->head->pos.y++; break; case 3://left snake->head->pos.x--; break; } Node* nodelast; Node* node; node = snake->head; //headmove gotoxy(node->pos.x,node->pos.y); cout<<'#'; nodelast = node; node = node->next; while(node!=NULL) { node->lastpos.x = node->pos.x; node->lastpos.y = node->pos.y; node->pos.x = nodelast->lastpos.x; node->pos.y = nodelast->lastpos.y; //move gotoxy(node->pos.x,node->pos.y); cout<<'*'; nodelast = node; node = node->next; } //lastpos //gotoxy(nodelast->lastpos.x,nodelast->lastpos.y); gotoxy(snake->tail->lastpos.x,snake->tail->lastpos.y); cout<<' '; if(1 == attackCheck(snake)) return 0; return 1; }; //初始化 Snake* init() { Snake* snake; snake = new Snake; snake->length = 0; snake->head = NULL; Node* node; int head_x; int head_y; head_x = 5; head_y = 5; for(int i=0;i<3;i++) { node = new Node; node->pos.x = head_x; node->pos.y = head_y; node->next = NULL; head_x++; snake->length++; addNode(snake,node); } snake->tail = getSnakeTail(snake); snake->lastfood = NULL; snake->atefood = NULL; snake->direction = 1; snake->timeperstep = 5; snake->wall.length = 20; snake->wall.offset = 0; snake->wall.UP_BOND = snake->wall.offset+1; snake->wall.RIGHT_BOND = snake->wall.length+snake->wall.offset+2; snake->wall.DOWN_BOND = snake->wall.length+snake->wall.offset+2; snake->wall.LEFT_BOND = snake->wall.offset+1; //draw wall int temp = snake->wall.length+2; for(i = 0;i < temp;i++) { //left wall gotoxy(1,i+1); cout<<'|'; //right wall gotoxy(temp,i+1); cout<<'|'; //up wall gotoxy(i+1,1); cout<<'-'; //down wall gotoxy(i+1,temp); cout<<'-'; } //draw snake //head gotoxy(snake->head->pos.x,snake->head->pos.y); cout<<'#'; //body node = snake->head->next; while(node!=NULL) { gotoxy(node->pos.x,node->pos.y); cout<<'*'; node = node->next; } //state gotoxy(snake->wall.RIGHT_BOND+10,snake->wall.UP_BOND+6); cout<<"SCORES:0"; return snake; }; //獲取蛇吃下的倒數第二個食物 Node* getLastSecFood(Snake* snake) { Node* node; Node* lastnode; lastnode = NULL; node = snake->atefood; while(NULL != node->next) { lastnode = node; node = node->next; } return lastnode; } //吃到一個食物 void addFood(Snake* snake,Node* node) { if(NULL == snake->atefood) snake->lastfood =node; node->next = snake->atefood; snake->atefood = node; }; //檢測食物是否消化,以增長蛇的長度 //當蛇吃下一個食物或多個食物時,食物的位置資訊會被儲存 //當蛇的尾部移動到相對最先被吃下的食物的位置時,將食物轉換為蛇的體長,及食物被消化。 void growSnake(Snake* snake) { if(NULL == snake->lastfood) return; Node* temp = getLastSecFood(snake); if(NULL == temp) { snake->lastfood = snake->atefood; } else { snake->lastfood = temp->next; } if(snake->lastfood ->pos.x == snake->tail->lastpos.x && snake->lastfood->pos.y == snake->tail->lastpos.y) { snake->tail->next = snake->lastfood; snake->tail = snake->lastfood; if(NULL == snake->atefood->next) { snake->lastfood = NULL; snake->atefood = NULL; } else { snake->lastfood = getLastSecFood(snake); snake->lastfood->next = NULL; } snake->length++; } } //清除連結串列的記憶體 void clean(Snake* snake) { Node* node; Node* temp; node = snake->head; while(NULL != node) { temp = node; node = node->next; delete temp; } node = snake->atefood; while(NULL!=node) { temp = node; node = node->next; delete temp; } delete snake; } //主函式 int main() { Snake* snake; clock_t start; bool flag; Point* food; Node* node; int score; short state; while(1)//外層:重新開始遊戲 { clrscr();//清屏 snake = init(); state = 0; score = 0; //產生第一個食物 food = generateFood(snake); gotoxy(food->x,food->y); cout<<'@'; while(1)//第二層:重新整理,移動蛇 { flag = 1; start = clock(); //while((flag = (clock()-start<=snake->timeperstep))&&!kbhit()); while(1) { //如果是時間間隔到達 if(clock() - start >= snake->timeperstep) { flag = 0; break; } //如果是有按鍵按下 if(kbhit()) break; }; //有按鍵按下時,根據按下的鍵改變方向 if(1==flag) { char temp = getch(); //cin.ignore(80); switch(temp) { case 'w': if(2!=snake->direction) snake->direction = 0; break; case 'd': if(3!=snake->direction) snake->direction = 1; break; case 's': if(0!=snake->direction) snake->direction = 2; break; case 'a': if(1!=snake->direction) snake->direction = 3; break; } } //如果移動失敗,碰到圍牆或自身 if(0==move(snake)) { gotoxy(snake->wall.RIGHT_BOND+10,snake->wall.UP_BOND+7); cout<<"game over!"; gotoxy(snake->wall.RIGHT_BOND+10,snake->wall.UP_BOND+8); cout<<"press 'q' to quit and others to continue!"; char temp; temp = getch(); if('q' == temp) { state = 1; } else { state = 2; } break; } //如果吃到了食物 if(1 == eateFood(snake,food)) { node = new Node; node->pos.x = food->x; node->pos.y = food->y; node->next = NULL; addFood(snake,node); food = generateFood(snake); gotoxy(food->x,food->y); cout<<'@'; score+=10; } //時刻檢測是否增長身體 growSnake(snake); gotoxy(snake->wall.RIGHT_BOND+10,snake->wall.UP_BOND+6); cout<<"SCORES:"<<score; } if(state == 1) break; clean(snake); } return 1; };
不能執行主要是clrscr和goto函式,參考:
#include <windows.h> #include <stdio.h> void ConPrint(char *CharBuffer, int len); void ConPrintAt(int x, int y, char *CharBuffer, int len); void gotoXY(int x, int y); void ClearConsole(void); void ClearConsoleToColors(int ForgC, int BackC); void SetColorAndBackground(int ForgC, int BackC); void SetColor(int ForgC); void HideTheCursor(void); void ShowTheCursor(void); int main(int argc, char* argv[]) { HideTheCursor(); ClearConsoleToColors(15, 1); ClearConsole(); gotoXY(1, 1); SetColor(14); printf("This is a test...\n"); Sleep(5000); ShowTheCursor(); SetColorAndBackground(15, 12); ConPrint("This is also a test...\n", 23); SetColorAndBackground(1, 7); ConPrintAt(22, 15, "This is also a test...\n", 23); gotoXY(0, 24); SetColorAndBackground(7, 1); return 0; } //This will clear the console while setting the forground and //background colors. void ClearConsoleToColors(int ForgC, int BackC) { WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F); //Get the handle to the current output buffer... HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); //This is used to reset the carat/cursor to the top left. COORD coord = {0, 0}; //A return value... indicating how many chars were written //not used but we need to capture this since it will be //written anyway (passing NULL causes an access violation). DWORD count; //This is a structure containing all of the console info // it is used here to find the size of the console. CONSOLE_SCREEN_BUFFER_INFO csbi; //Here we will set the current color SetConsoleTextAttribute(hStdOut, wColor); if(GetConsoleScreenBufferInfo(hStdOut, &csbi)) { //This fills the buffer with a given character (in this case 32=space). FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count); FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count); //This will set our cursor position for the next print statement. SetConsoleCursorPosition(hStdOut, coord); } } //This will clear the console. void ClearConsole() { //Get the handle to the current output buffer... HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); //This is used to reset the carat/cursor to the top left. COORD coord = {0, 0}; //A return value... indicating how many chars were written // not used but we need to capture this since it will be // written anyway (passing NULL causes an access violation). DWORD count; //This is a structure containing all of the console info // it is used here to find the size of the console. CONSOLE_SCREEN_BUFFER_INFO csbi; //Here we will set the current color if(GetConsoleScreenBufferInfo(hStdOut, &csbi)) { //This fills the buffer with a given character (in this case 32=space). FillConsoleOutputCharacter(hStdOut, (TCHAR) 32, csbi.dwSize.X * csbi.dwSize.Y, coord, &count); FillConsoleOutputAttribute(hStdOut, csbi.wAttributes, csbi.dwSize.X * csbi.dwSize.Y, coord, &count); //This will set our cursor position for the next print statement. SetConsoleCursorPosition(hStdOut, coord); } } //This will set the position of the cursor void gotoXY(int x, int y) { //Initialize the coordinates COORD coord = {x, y}; //Set the position SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord); } //This will set the forground color for printing in a console window. void SetColor(int ForgC) { WORD wColor; //We will need this handle to get the current background attribute HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO csbi; //We use csbi for the wAttributes word. if(GetConsoleScreenBufferInfo(hStdOut, &csbi)) { //Mask out all but the background attribute, and add in the forgournd color wColor = (csbi.wAttributes & 0xF0) + (ForgC & 0x0F); SetConsoleTextAttribute(hStdOut, wColor); } } //This will set the forground and background color for printing in a console window. void SetColorAndBackground(int ForgC, int BackC) { WORD wColor = ((BackC & 0x0F) << 4) + (ForgC & 0x0F);; SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), wColor); } //Direct console output void ConPrint(char *CharBuffer, int len) { DWORD count; WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), CharBuffer, len, &count, NULL); } //Direct Console output at a particular coordinate. void ConPrintAt(int x, int y, char *CharBuffer, int len) { DWORD count; COORD coord = {x, y}; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); SetConsoleCursorPosition(hStdOut, coord); WriteConsole(hStdOut, CharBuffer, len, &count, NULL); } //Hides the console cursor void HideTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = FALSE; SetConsoleCursorInfo(hStdOut, &cciCursor); } } //Shows the console cursor void ShowTheCursor() { CONSOLE_CURSOR_INFO cciCursor; HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); if(GetConsoleCursorInfo(hStdOut, &cciCursor)) { cciCursor.bVisible = TRUE; SetConsoleCursorInfo(hStdOut, &cciCursor); } }