puyopuyo(C++)

待施工

#include <iostream>
using namespace std;

struct tagInfo {
	int event;
	int dir;//旋转方向
	int col;//主块在第几列,主块用于控制旋转
	int val[2];//两个块的颜色
};
tagInfo tInfo;//当前要下落的块的信息

struct Point {
	int x;
	int y;
};

int map[50][50] = { 0 };//保存所有的块
int tail[50] = { 0 };//指向第i列为空的行
int mark[50][50];//被标记的块会在updatemap里进行删除

int board_width;//放置块的那个宽度,范围是0-board_width-1
int maxcol = -1;//最高列的块数,达到一定块数后game over

//用于深搜,查找是否有未消除的块
Point drop[10];
int drop_num;
int dfs_search_num;

//方向
int dir[4][2] = {
	0,1,
	0,-1,
	1,0,
	-1,0
};

//初始化宽度及每列
void init(int width) {
	board_width = width;

	for (int i = 0; i < board_width; i++) {
		tail[i] = 0;
	}
}

//设置普通块的信息,颜色可以不同
void newBlock(int block[]) {
	tInfo.event = 1;
	tInfo.dir = 0;
	tInfo.col = 1;
	tInfo.val[0] = block[0];
	tInfo.val[1] = block[1];
}

//旋转角度只有四种:0,90,180,270。
//在中间位置主块的列不会变化
//在右侧转到0度时,主块不贴墙,其余情况都贴墙
//在左侧转到180度时,主块不贴墙,其余情况都贴墙
//这里有点问题,移动后再旋转不行
void rotate(int angle) {
	tInfo.dir = (tInfo.dir + angle) % 4;
	if (tInfo.dir == 0 && tInfo.col == board_width - 1) {
		tInfo.col = board_width - 2;
	}
	if (tInfo.dir == 2 && tInfo.col == 0) {
		tInfo.col = 1;
	}
}

//移动:改变主块位置,再根据dir判断有没有越界
void move(int distance) {
	tInfo.col += distance;

	if (tInfo.col >= 1 && tInfo.col <= board_width - 2) return;//在中间不会越界
	
	if (tInfo.dir == 0 && tInfo.col >= board_width - 1) {//挪到右边界外边了,挪回来
		tInfo.col = board_width - 2;
		return;
	}
	if (tInfo.col > board_width - 1) {
		tInfo.col = board_width - 1;
		return;
	}
	if (tInfo.dir == 2 && tInfo.col <= 0) {//挪到左边界外边了,挪回来
		tInfo.dir = 1;
		return;
	}
	if (tInfo.col < 0) {
		tInfo.dir = 0;
		return;
	}
}

//设置特殊块,life直接设置为负数,mark后+1归0
void hinder(int count, int life) {
	tInfo.event = 2;
	for (int i = 0; i < count; i++) {
		map[i][tail[i]++] = -1 * life;
	}
}

//深搜找与map[x][y]颜色相同的块,记录下它的数目
//这里也有点冗余,用完的drop没有及时删除
void dfs(int x, int y) {
	if (map[x][y] == 0) return;
	mark[x][y] = 1;
	dfs_search_num++;

	for (int i = 0; i < 4; i++) {
		int nextx = x + dir[i][0];
		int nexty = y + dir[i][1];
		if (nextx < 0 || nextx >= board_width || nexty < 0 || nexty >= tail[nextx]) continue;
		if (mark[nextx][nexty] == 1) continue;
		if (map[x][y] == map[nextx][nexty])
			dfs(nextx, nexty);
	}
}

//清理mark
void clear(int x, int y) {
	if (map[x][y] == 0) return;
	mark[x][y] = 0;
	for (int i = 0; i < 4; i++) {
		int nextx = x + dir[i][0];
		int nexty = y + dir[i][1];
		if (nextx < 0 || nextx >= board_width || nexty < 0 || nexty >= tail[nextx]) continue;
		if (mark[nextx][nexty] == 0) continue;
		if (map[x][y] == map[nextx][nexty])
			clear(nextx, nexty);
	}
}

//检查map[i][j]周围是否有mark了的有颜色的块
int check(int i, int j) {
	for (int k = 0; k < 4; k++) {
		int x = i + dir[k][0];
		int y = j + dir[k][1];
		if (x < 0 || x >= board_width || y < 0 || y >= tail[x]) continue;
		if (mark[x][y] == 1 && map[x][y] > 0) return 1;
	}
	return 0;
}

void markhinder() {
	for (int i = 0; i < board_width; i++) {
		for (int j = 0; j < tail[i]; j++) {
			if (map[i][j] < 0) {//找到hinder,如果被炸了一下,改变数值,如果变成0,mark为1
				if (check(i, j) != 0) {
					map[i][j] += 1;
					mark[i][j] = map[i][j] == 0 ? 1 : 0;
				}
			}
		}
	}
}

//更新map,将mark的块删除,并记下新的要深搜的drop
void updatemap() {
	bool flag = false;
	for (int i = 0; i < board_width; i++) {
		int k = 0;
		for (int j = 0; j < tail[i]; j++) {
			if (mark[i][j] == 1) {
				mark[i][j] = 0;
				map[i][j] = 0;
				flag = true;
				continue;
			}
			map[i][k++] = map[i][j];

			if (flag && map[i][k-1] > 0) {//被炸之后掉下来的有颜色的块都有可能能继续消除
				drop[drop_num].x = i;
				drop[drop_num++].y = k - 1;
			}
		}
		tail[i] = k;
		flag = false;
	}
}

//找同颜色的块,多于四个就能消除
void solve(Point lhs, Point rhs) {
	drop_num = 2;
	drop[0] = lhs;
	drop[1] = rhs;
	while (drop_num != 0) {
		for (int i = drop_num - 1; i >= 0; i--) {
			if (mark[drop[i].x][drop[i].y] == 1) continue;
			dfs_search_num = 0;
			dfs(drop[i].x, drop[i].y);
			cout << "同颜色块数为:" << dfs_search_num << endl;
			if (dfs_search_num < 4) {
				drop_num--;
				clear(drop[i].x, drop[i].y);
			}
		}
		markhinder();
		updatemap();
	}
}

//让普通块落下,并计算最高列
int land() {
	Point pt1, pt2;
	if (tInfo.event == 1) {
		switch (tInfo.dir)//确定普通块的降落位置,加入map
		{
			case 0://水平方向
				pt1.x = tInfo.col;
				pt1.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[0];
				pt2.x = tInfo.col + 1;
				pt2.y = tail[tInfo.col + 1];
				map[tInfo.col + 1][tail[tInfo.col + 1]++] = tInfo.val[0];
				break;
			case 1:
				pt1.x = tInfo.col;
				pt1.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[1];
				pt2.x = tInfo.col;
				pt2.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[0];
				break;
			case 2:
				pt1.x = tInfo.col;
				pt1.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[0];
				pt2.x = tInfo.col - 1;
				pt2.y = tail[tInfo.col - 1];
				map[tInfo.col][tail[tInfo.col - 1]++] = tInfo.val[1];
				break;
			case 3:
				pt1.x = tInfo.col;
				pt1.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[0];
				pt2.x = tInfo.col;
				pt2.y = tail[tInfo.col];
				map[tInfo.col][tail[tInfo.col]++] = tInfo.val[1];
				break;
		}
		solve(pt1, pt2);//看看能不能消除
	}

	//找到最高列
	int max = 0;
	for (int i = 0; i < board_width; i++) {
		max = tail[i] > max ? tail[i] : max;
	}
	return max;
}


int main() {
	int width;
	cout << "请输入宽度" << endl;
	cin >> width;
	init(width);
	while (1) {
		cout << "创建普通块还是特殊块?" << endl;
		int key;
		cin >> key;
		switch (key)
		{
			case 1:
				cout << "输入普通块的两种颜色" << endl;
				int block[2];
				cin >> block[0] >> block[1];
				newBlock(block);
				cout << "旋转角度?" << endl;
				int angle;
				cin >> angle;
				rotate(angle);
				cout << "移动距离?" << endl;
				int distance;
				cin >> distance;
				move(distance);
				maxcol = land();
				break;
			case 2:
				cout << "输入块数和生命值" << endl;
				int count, life;
				cin >> count >> life;
				hinder(count, life);
				maxcol = land();
				break;
			default:
				break;
		}
		cout << "目前最高为:" << maxcol << endl;
		if (maxcol > 6) {
			cout << "游戏结束" << endl;
			break;
		}
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

河时有雨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值