• 字符界面的贪吃蛇--链表--C++


    前天看了下链表,由于平时对链表的使用不多,所以对链表的应用也没什么了解,所以想来想去,就想用链表实现一下贪吃蛇。

    下面言归正传,先看效果图,再看代码,其他没有了!

    图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...
    ");
       Sleep(5000);
       ShowTheCursor();
       SetColorAndBackground(15, 12);
       ConPrint("This is also a test...
    ", 23);
       SetColorAndBackground(1, 7);
       ConPrintAt(22, 15, "This is also a test...
    ", 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);
       }
    }
    


  • 相关阅读:
    selenium之css selector
    selenium之xpath
    selenium的一些概念
    HTML基础(四)JS
    HTML基础(三)DOM操作
    HTML基础(二)CSS
    HTML基础(一)HTML标签
    python学习笔记(六)发邮件、写日志、操作redis、导入模块
    python学习笔记(五)模块、第三方模块安装、模块导入
    python学习笔记(四)函数(下)、模块、集合
  • 原文地址:https://www.cnblogs.com/zhanghang-BadCoder/p/6476472.html
Copyright © 2020-2023  润新知