消消乐小游戏

游戏展示


界面展示

  1. 启动界面

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7GXnwMG1-1587000817034)(I:\作业\消消乐\QQ截图20200416075409.png)]

  2. 选择界面

在这里插入图片描述

  1. 开始游戏

在这里插入图片描述

  1. 炮弹为空

    在这里插入图片描述

  2. 游戏胜利

在这里插入图片描述

  1. 游戏失败

在这里插入图片描述

  1. 退出游戏

在这里插入图片描述

游戏中过程解析

  • 游戏每秒进行的操作

    • 队头元素入队尾
    • 队头出队
    • 从右上角开始顺时针展示队列 元素较少时会居中展示
    • 清除屏幕 显示下一帧
    • 获取键盘数据
  • 按下s / S

    • 子弹入栈
    • 判断是否有三个重复元素 是 删除
  • 按下w / W

    • 子弹出栈
    • 队列中目标位置插入数据
    • 判断是否有三个重复元素 是 删除
  • 队列元素小于等于三

    • 胜利游戏 游戏结束
  • 队列元素大于等于一圈的元素数量

    • 游戏失败 游戏结束

数据结构

​ - -(为游戏服务有些地方未通用化)

  • //构造栈 
    typedef struct stack {
    	char  st[maxn];
    	int len = 0;
    	void push(char q) {
    		if (len >= maxn) {
    			printf("子弹装满了哦!!!");
    			exit(1);
    		}
    		else {
    			st[++len] = q;
    		}
    	}
    	void pop() {
    		if (len == 0) {
    			printf("没有子弹哦!!!");
    			exit(1);
    		}
    		else {
    			len--;
    		}
    	}
    	char top() {
    		if (len == 0) {
    			printf("没有子弹哦!!!");
    			return NULL;
    		}
    		else {
    			return st[len];
    		}
    	}
    	bool empty() {
    		if (len == 0) return true;
    		else {
    			return false;
    		}
    	}
    
    };
    
    
  • 链表

    //节点
    typedef struct node {
    	char date;
    	node* next;
    }node;
    
    
    
    //构造链表       
    typedef struct list {
    	int size;
    	node* elem;
    	void initlist() {
    		list* p = (list*)malloc(sizeof(list));
    		node* q = (node*)malloc(sizeof(node));
    		q->next = NULL;
    		p->elem = q;
    		p->size = 0;
    		*this = *p;
    	}
    	node* creatlist(int n, int alrank) {
    		node* t = elem;
    		size = n;
    		srand(time(NULL));
    		for (int i = 1; i <= n; i++) {
    			node* q = (node*)malloc(sizeof(node));
    			q->next = NULL;
    			q->date = (rand() % alrank) + 'A';
    			t->next = q;
    			t = q;
    		}
    		return t;
    	}
    	//直接插入无需循环
    	bool insertlist(node* p, char date) {
    		if(p== (node*)0xCCCCCCCC) return false;
    		size++;
    		node* q = (node*)malloc(sizeof(node));
    		q->date = date;
    		q->next = p->next;
    		//
    		p->next = q;
    		return true;
    	}
    	bool deletlist(node* p) {
    		size--;
    		node* q = p->next;
    		if (p->next != (node*)0xDDDDDDDD) {
    			p->next = q->next;
    			free(q);
    			return true;
    		}
            return false;
    
    	}
    	//仅测试时使用
    	bool showlist() {
    		node* p = elem->next;
    		printf("长为%d的表为:\n", size);
    		while (p) {
    			printf("%c ", p->date);
    			p = p->next;
    		}
    		putchar('\n');
    		return true;
    	}
    }list;
    
    
  • 队列

    //游戏用到大量的插入删除故使用链表队列
    typedef struct queue {
    	list k;
    	int len = 0;
    	//front 指向头结点
    	node* front, * rear;
    	void innit(int n, int alrank) {
    		k.initlist();
    		rear = k.creatlist(n, alrank);
    		//	rear = prerear->next;
    		len = k.size;
    		front = k.elem;
    	}
    	char gethead() {
    		return front->next->date;
    	}
    	char getrear() {
    		return rear->date;
    	}
    	void in() {
    		if (len) {
    			k.insertlist(rear, gethead());
    			rear = rear->next;
    			len = k.size;
    		}
    		else {
    			printf("队列空");
    		}
    		
    
    	}
    	void out() {
    		k.deletlist(front);
    		len = k.size;
    	}
    	void show() {
    		k.showlist();
    	}
    	void insert(node* p, char a) {
    		k.insertlist(p, a);
    	}
    	bool empty() {
    		if (len == 0) return true;
    		else {
    			return false;
    		}
    	}
    
    }queue;
    
    
  • 游戏对象

    typedef struct game {
    	//标记游戏结束
    	int flag = 0;
    	//当前点击
    	char click = ' ';
    	//等级规则 用于计算字母个数
    	int rule = 7;
    	//存放目标
    	queue k;
    	//存放子弹
    	stack bullets;
    	//字母种类难度等级
    	int alrank = 5;
    	//字母数量难度等级
    	int rank;
    	//速度难度等级 
    	int speedrk;
    	//子弹打入位置--插入位置的前一位置
    	node* insertposition;
    	//游戏界面
    	char gra[200][200] = {};
    	//界面与左边框距离 dx 个空格 上边距 dy 个空格
    	int dx = 10, dy = 8;
    	//炮台
    	char pt[7][13] = {
    					 "    | |    ",
    					 "    | |    ",
    					 "    | |    ",
    					 "   #| |#   ",
    					 "  ##| |##  ",
    					 " ###| |### ",
    					 "<<<<< >>>>>",
    	};
    	//将难度等级转化为字母个数
    	int getcnt() {
    		return 3 * rank * rule - 2;
    	}
    
    
    	void innit(int n) {
    		srand(time(NULL));
    		rank = n;
    		k.innit(getcnt(), alrank);
    		//创建线程
    		pthread_t as;
    		pthread_create(&as, NULL, getMsg, this);
    	}
    	//bullet : 子弹
    	void getbullet() {
    		bullets.push(rand() % alrank + 'A');
    	}
    	//消除三个相同的
    	void ck() {
    		node* o = k.front;
    		while (k.len>=3&&o->next) {
    			if (!o->next->next) break;
    			if (!o->next->next->next) break;
    			if (o->next->date == o->next->next->date && o->next->date == o->next->next->next->date) {
    				node* a = o, * b = o->next, * c = o->next->next;
    				k.k.deletlist(c);
    				k.k.deletlist(b);
    				k.k.deletlist(a);
    				k.len = k.k.size;
    			}
    			o = o->next;
    		}
    	}
    	//开火
    	void fire() {
    		char b;
    		if (!bullets.empty()) {
    			b = bullets.top();
    			bullets.pop();
    			k.insert(insertposition, b);
    		}
    		else {
    			printf("请先装填子弹哦!!!");
    		}
    		ck();
    		
    	}
    
    	bool win() {
    		if (k.len <= 3) return true;
    		else {
    			return false;
    		}
    	}
    	bool lost() {
    		if (k.len >= getcnt() + 2 * rule  && !win())
    		{
    			return true;
    		
    		}
    		else {
    			return false;
    		}
    	}
    	//测试
    	void delt() {
    		node* o = k.front;
    		node* a = o;
    		k.k.deletlist(a);
    		k.len = k.k.size;
    	}
    	//显示界面
    	void next() {
    		k.in(); 
    		k.out();
    	}
    	void show() {
    		printf("游戏规则:\n     1 w发射 s压弹\n     2 当字母数量小于等于3时获胜\n     3 当个数占满一圈时失败\n     4 当且仅当有三个连续字母相同时会消去\n");
    		for (int i = 0; i < 200; i++) {
    			for (int j = 0; j < 200; j++) {
    				if (j == dx + 2 * (rule - 1) + 4 * (rule - rule / 2) + 2) {
    					gra[i][j] = '\0';
    					break;
    				}
    				else {
    					gra[i][j] = ' ';
    				}
    			}
    		}
    		node* p = k.front->next;
    		//居中
    		int dp = (getcnt() - k.len) / 2 ;
    		dp = (getcnt() - k.len) / 2;
    		
    		//射击位置
    		int mid = dx + 1 + rule - 1 + 2 * (rule - rule / 2);
    		{
    			
    			//绘制右边框
    			for (int i = dy; p && i <= rule / 2 + dy - 1; i++) {
    				if (dp-- > 0) {
    					continue;
    				}
    				gra[i][dx + 2 * (rule - 1) + 4 * (rule - rule / 2) + 1] = p->date;
    				p = p->next;
    			}
    			//绘制下边框
    			for (int i = dx + 2 * (rule - 1) + 4 * (rule - rule / 2); p && i >= dx + 3; i -= 2) {
    				if (dp-- > 0) {
    					continue;
    				}
    				if (i - 1 == mid) {
    					insertposition = p;
    				}
    				gra[rule / 2 + dy - 1][i - 1] = p->date;
    				p = p->next;
    			}
    			//绘制左边框
    			for (int i = rule / 2 + dy - 1; p && i >= dy; i--) {
    				gra[i][dx + 1] = p->date;
    				p = p->next;
    			}
    			//绘制上边框
    			for (int i = dx + 3; p && i <= dx + 2 * (rule - 1) + 4 * (rule - rule / 2); i += 2) {
    				gra[dy][i] = p->date;
    				p = p->next;
    			}
    		}
    
    		//绘制炮台
    		{
    			gra[rule / 2 + dy][mid - 1] = '|';
    			gra[rule / 2 + dy][mid + 1] = '|';
    			int dypt = 5;
    			//显示炮弹位次
    			int ct = bullets.len;
    			for (int i = rule / 2 + dy + dypt; i < rule / 2 + dy + dypt + 7; i++) {
    				for (int j = mid - 5; j <= mid + 6; j++) {
    
    					if (j == mid && ct > 0) {
    						gra[i][j] = bullets.st[ct--];
    					}
    					else {
    						gra[i][j] = pt[i - rule / 2 - dy - dypt][j - mid + 5];
    					}
    				}
    			}
    		}
    
    		for (int i = 0; i < dy + rule + 7; i++) {
    			puts(gra[i]);
    		}
    	}
    }game;
    

特色

  • 游戏函数全部封装进结构体 调用方便

  • 代码清晰

  • 大量使用插入删除 使用链表进行辅助操作

  • 使用多线程 使键盘输入与程序运行相分离完成游戏操作

  • 界面优化 选择界面 启动界面

原代码

/*
	Name: 消消乐小游戏
	Copyright: 1913041130
	Author: 张文涛
	Date: 13/04/21 11:59
	Description:

*/
#pragma warning( disable:4996)
#include"stdio.h"
#include"malloc.h"
#include"stdlib.h"
#include "time.h"
#include "string.h"
#include "windows.h"
#include "conio.h"
#include "iostream"
#include "pthread.h"
#include"unistd.h"
const int maxn = 1e3;
//获取当前点击
void* getMsg(void* f);


//构造栈 
typedef struct stack {
	char  st[maxn];
	int len = 0;
	void push(char q) {
		if (len >= maxn) {
			printf("子弹装满了哦!!!");
			exit(1);
		}
		else {
			st[++len] = q;
		}
	}
	void pop() {
		if (len == 0) {
			printf("没有子弹哦!!!");
			exit(1);
		}
		else {
			len--;
		}
	}
	char top() {
		if (len == 0) {
			printf("没有子弹哦!!!");
			return NULL;
		}
		else {
			return st[len];
		}
	}
	bool empty() {
		if (len == 0) return true;
		else {
			return false;
		}
	}

};



//节点
typedef struct node {
	char date;
	node* next;
}node;



//构造链表       
typedef struct list {
	int size;
	node* elem;
	void initlist() {
		list* p = (list*)malloc(sizeof(list));
		node* q = (node*)malloc(sizeof(node));
		q->next = NULL;
		p->elem = q;
		p->size = 0;
		*this = *p;
	}
	node* creatlist(int n, int alrank) {
		node* t = elem;
		size = n;
		srand(time(NULL));
		for (int i = 1; i <= n; i++) {
			node* q = (node*)malloc(sizeof(node));
			q->next = NULL;
			q->date = (rand() % alrank) + 'A';
			t->next = q;
			t = q;
		}
		return t;
	}
	//直接插入无需循环
	bool insertlist(node* p, char date) {
		if(p== (node*)0xCCCCCCCC) return false;
		size++;
		node* q = (node*)malloc(sizeof(node));
		q->date = date;
		q->next = p->next;
		//
		p->next = q;
		return true;
	}
	bool deletlist(node* p) {
		size--;
		node* q = p->next;
		if (p->next != (node*)0xDDDDDDDD) {
			p->next = q->next;
			free(q);
			return true;
		}

	}
	//仅测试时使用
	bool showlist() {
		node* p = elem->next;
		printf("长为%d的表为:\n", size);
		while (p) {
			printf("%c ", p->date);
			p = p->next;
		}
		putchar('\n');
		return true;
	}
}list;



//游戏用到大量的插入删除故使用链表队列
typedef struct queue {
	list k;
	int len = 0;
	//front 指向头结点
	node* front, * rear;
	void innit(int n, int alrank) {
		k.initlist();
		rear = k.creatlist(n, alrank);
		//	rear = prerear->next;
		len = k.size;
		front = k.elem;
	}
	char gethead() {
		return front->next->date;
	}
	char getrear() {
		return rear->date;
	}
	void in() {
		if (len) {
			k.insertlist(rear, gethead());
			rear = rear->next;
			len = k.size;
		}
		else {
			printf("队列空");
		}
		

	}
	void out() {
		k.deletlist(front);
		len = k.size;
	}
	void show() {
		k.showlist();
	}
	void insert(node* p, char a) {
		k.insertlist(p, a);
	}
	bool empty() {
		if (len == 0) return true;
		else {
			return false;
		}
	}

}queue;



typedef struct game {
	//标记游戏结束
	int flag = 0;
	//当前点击
	char click = ' ';
	//等级规则 用于计算字母个数
	int rule = 7;
	//存放目标
	queue k;
	//存放子弹
	stack bullets;
	//字母种类难度等级
	int alrank = 5;
	//字母数量难度等级
	int rank;
	//速度难度等级 
	int speedrk;
	//子弹打入位置--插入位置的前一位置
	node* insertposition;
	//游戏界面
	char gra[200][200] = {};
	//界面与左边框距离 dx 个空格 上边距 dy 个空格
	int dx = 10, dy = 8;
	//炮台
	char pt[7][13] = {
					 "    | |    ",
					 "    | |    ",
					 "    | |    ",
					 "   #| |#   ",
					 "  ##| |##  ",
					 " ###| |### ",
					 "<<<<< >>>>>",
	};
	//将难度等级转化为字母个数
	int getcnt() {
		return 3 * rank * rule - 2;
	}


	void innit(int n) {
		srand(time(NULL));
		rank = n;
		k.innit(getcnt(), alrank);
		//创建线程
		pthread_t as;
		pthread_create(&as, NULL, getMsg, this);
	}
	//bullet : 子弹
	void getbullet() {
		bullets.push(rand() % alrank + 'A');
	}
	//消除三个相同的
	void ck() {
		node* o = k.front;
		while (k.len>=3&&o->next) {
			if (!o->next->next) break;
			if (!o->next->next->next) break;
			if (o->next->date == o->next->next->date && o->next->date == o->next->next->next->date) {
				node* a = o, * b = o->next, * c = o->next->next;
				k.k.deletlist(c);
				k.k.deletlist(b);
				k.k.deletlist(a);
				k.len = k.k.size;
			}
			o = o->next;
		}
	}
	//开火
	void fire() {
		char b;
		if (!bullets.empty()) {
			b = bullets.top();
			bullets.pop();
			k.insert(insertposition, b);
		}
		else {
			printf("请先装填子弹哦!!!");
		}
		ck();
		
	}

	bool win() {
		if (k.len <= 3) return true;
		else {
			return false;
		}
	}
	bool lost() {
		if (k.len >= getcnt() + 2 * rule  && !win())
		{
			return true;
		
		}
		else {
			return false;
		}
	}
	//测试
	void delt() {
		node* o = k.front;
		node* a = o;
		k.k.deletlist(a);
		k.len = k.k.size;
	}
	//显示界面
	void next() {
		k.in(); 
		k.out();
	}
	void show() {
		printf("游戏规则:\n     1 w发射 s压弹\n     2 当字母数量小于等于3时获胜\n     3 当个数占满一圈时失败\n     4 当且仅当有三个连续字母相同时会消去\n");
		for (int i = 0; i < 200; i++) {
			for (int j = 0; j < 200; j++) {
				if (j == dx + 2 * (rule - 1) + 4 * (rule - rule / 2) + 2) {
					gra[i][j] = '\0';
					break;
				}
				else {
					gra[i][j] = ' ';
				}
			}
		}
		node* p = k.front->next;
		//居中
		int dp = (getcnt() - k.len) / 2 ;
		dp = (getcnt() - k.len) / 2;
		
		//射击位置
		int mid = dx + 1 + rule - 1 + 2 * (rule - rule / 2);
		{
			
			//绘制右边框
			for (int i = dy; p && i <= rule / 2 + dy - 1; i++) {
				if (dp-- > 0) {
					continue;
				}
				gra[i][dx + 2 * (rule - 1) + 4 * (rule - rule / 2) + 1] = p->date;
				p = p->next;
			}
			//绘制下边框
			for (int i = dx + 2 * (rule - 1) + 4 * (rule - rule / 2); p && i >= dx + 3; i -= 2) {
				if (dp-- > 0) {
					continue;
				}
				if (i - 1 == mid) {
					insertposition = p;
				}
				gra[rule / 2 + dy - 1][i - 1] = p->date;
				p = p->next;
			}
			//绘制左边框
			for (int i = rule / 2 + dy - 1; p && i >= dy; i--) {
				gra[i][dx + 1] = p->date;
				p = p->next;
			}
			//绘制上边框
			for (int i = dx + 3; p && i <= dx + 2 * (rule - 1) + 4 * (rule - rule / 2); i += 2) {
				gra[dy][i] = p->date;
				p = p->next;
			}
		}

		//绘制炮台
		{
			gra[rule / 2 + dy][mid - 1] = '|';
			gra[rule / 2 + dy][mid + 1] = '|';
			int dypt = 5;
			//显示炮弹位次
			int ct = bullets.len;
			for (int i = rule / 2 + dy + dypt; i < rule / 2 + dy + dypt + 7; i++) {
				for (int j = mid - 5; j <= mid + 6; j++) {

					if (j == mid && ct > 0) {
						gra[i][j] = bullets.st[ct--];
					}
					else {
						gra[i][j] = pt[i - rule / 2 - dy - dypt][j - mid + 5];
					}
				}
			}
		}

		for (int i = 0; i < dy + rule + 7; i++) {
			puts(gra[i]);
		}
	}
}game;



void* getMsg(void* f) {
	game* t = (game*)f;
	while (1) {
		char click = '#';
		t->ck();
		click = getch();
		t->click = click;
		if (click == ' ') {
			t->delt();
		}
		if (click == 'w' || click == 'W') {
			t->fire();
		}
		if (click == 's' || click == 'S') {
			t->getbullet();
		}
		if (t->win()) {
			printf("恭喜你赢了!!!");
			t->flag = 1;
			break;
		}
		if (t->lost()) {
			printf("别灰心再来一次!!!");
			t->flag = 1;
			break;
		}
	}
	return NULL;
}



int main() {
    begin:;
	game s;
	system("color 57");
	int tt = 5;
	char meau[12][35] = {
		 "*|******************************|*",
		 "*|                              |*",
		 "*|                              |*",
		 "*|                              |*",
		 "*|            开始游戏          |*",//4
		 "*|                              |*",
		 "*|                              |*",
		 "*|            退出游戏          |*",//7
		 "*|                              |*",
		 "*|                (w s选择a选中)|*",
		 "*|                              |*",
		 "*|******************************|*",
	};           
	int choose = 0;
	char choos1[2][35] = { "*| >>>>>>>>>开始游戏<<<<<<<<<<  |*" , "*|          开始游戏            |*" },
		choos2[2][35] = {  "*| >>>>>>>>>退出游戏<<<<<<<<<<  |*", "*|          退出游戏            |*" };
    char ch = ' ';
	while (1) {
		if (ch == 'a'|| ch == 'A') break;
		if (ch == 'w' || ch == 'W'|| ch == 's' || ch == 'S') {
			choose ^= 1;
		}
		system("cls");
		if (choose == 0) {
			strcpy(meau[4],choos1[0]);
			strcpy(meau[7],choos2[1]);
		} 
		else {
			strcpy(meau[4], choos1[1]);
			strcpy(meau[7], choos2[0]);
		}
		for (int i = 0; i <= 11; i++) {
			puts(meau[i]);
		}
		ch = getch();
	}
	if (choose == 1) goto end;
	s.innit(1);
	while (tt--) {
		system("cls");
		printf("\n\n\n\n\n          全屏游戏更爽哦  \n        游戏将在 %d 秒后开始",tt);
		Sleep(1000);
	}
	printf("\n\n\n\n\n《《《《《《《游戏开始》》》》》》》");
	Sleep(1000);
	//s.show();
	for (int i = 0;; i++) {
		//单位毫秒
		Sleep(1000);
		if (s.flag) {
			break;
		}
		system("cls");
		                                                                 
		s.next();
		s.show();
		s.k.show();
		if (s.win()) {
			printf("恭喜你赢了!!!");
			s.flag = 1;
			break;
		}
		if (s.lost()) {
			printf("别灰心再来一次!!!");
			s.flag = 1;
			break;
		}
	}

    end:;
	printf("游戏结束!!!");
	Sleep(5000);

}

附:

游戏中或许有些 bug 还请帮忙更正

发布了49 篇原创文章 · 获赞 0 · 访问量 660

猜你喜欢

转载自blog.csdn.net/qq_14989799/article/details/105550556