麻将游戏(mahjong)题解

这篇博客介绍了一种使用宽度优先搜索(BFS)算法解决麻将游戏中的连接问题的方法。玩家需要找出所有可以通过特定路径相连的相同麻将牌,并移除它们。题目给出了详细的游戏规则和输入输出格式,并提供了一个示例输入和输出。博主分享了实现算法的思路,包括如何构建地图、如何进行宽度优先搜索以及处理特殊情况。最后,博主提供了完整的C++代码实现,用于计算连接两张牌所需的最小转弯次数,即路径长度。
摘要由CSDN通过智能技术生成

题目描述:

在一种"麻将"游戏中,游戏是在一个有w×h格子的矩形平板上进行的。每个格子可以放置一个麻将牌,也可以不放(如图所示)。玩家的目标是将平板上的所有可通过一条路径相连的两张相同的麻将牌,从平板上移去。最后如果能将所有牌移出平板,则算过关。

这个游戏中的一个关键问题是:两张牌之间是否可以被一条路径所连接,该路径满足以下两个特性:

1.它由若干条线段组成,每条线段要么是水平方向,要么是垂直方向。

2.这条路径不能横穿任何一个麻将牌 (但允许路径暂时离开平板)。

这是一个例子:

在(1,3)的牌和在(4, 4)的牌可以被连接。(2, 3)和(3, 4)不能被连接。

你的任务是编一个程序,检测两张牌是否能被一条符合以上规定的路径所连接。

输入格式:

输入文件的第一行有两个整数 w,h (1<=w,h<=75),表示平板的宽和高。接下来 h 行描述平板信息,每行包含 w 个字符,如果某格子有一张牌,则这个格子上有个'X',否则是一个空格。平板上最左上角格子的坐标为(1,1),最右下角格子的坐标为(w,h)。接下来的若干行,每行有四个数 x1, y1, x2, y2 ,且满足 1<=x1,x2<=w,1<=y1,y2<=h,表示两张牌的坐标(这两张牌的坐标总是不同的)。如果出现连续四个 0,则表示输入结束。

输出格式:

输出文件中,对于每一对牌输出占一行,为连接这一对牌的路径最少包含的线段数。如果不存在路径则输出 0。

【样例输入】(参照上图):

5 4 
XXXXX
X   X
XXX X
 XXX 
2 3 5 3 
1 3 4 4 
2 3 3 4 
0 0 0 0 

【样例输出】

4 
3 
0 

 思路

用宽搜求最小转弯数,往一个方向一直走,走到不能走为止,每次把队首取出,延伸出各个子节点;起点到该子节点的最小转弯数等于起点到父节点(队首)的最小转弯数+1,再将父节点可以到的所有子节点依次存入队列中,直到某个子节点为终点(有一条最短路径)

需要注意的细节

先输入的是列数,再是行数;

要把行数和列数后面的换行先消掉;

输入数据中包含空格,所以要用getline();

有时输入数据会用换行来代替整行空格,所以要加入判断语句   if(s.length()==0)continue(s为地图中的其中一行);

起点和终点需要提前解封;

地图周围需要加一圈可行区域,行数和列数都要+2;

起点终点坐标需要+1(因为地图扩宽之后,坐标也会发生变化);

每次队列和标记数组要清空;

找到最短路径后要把起点和终点重新还原;

线段数=转弯数+1;

代码

#include<bits/stdc++.h>
using namespace std;
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};//方向数组 
string s;
struct node{
	int x,y,sum; 
}num1,num2,nxt;
queue<node>q;
void cclear(queue<node>& q){//清空函数 
	while(!q.empty())q.pop();
}
int n,m,mapp[101][101]={0};
bool book[101][101];
int bfs(){ 
    cclear(q);
	memset(book,0,sizeof(book));    
	mapp[num1.x][num1.y]=0,mapp[num2.x][num2.y]=0;//起点终点解封 
	q.push(num1);//入队 
	q.front().sum=0;
	while(!q.empty()){        //队列不空 
		for(int i=0;i<4;i++){ //走四个方向
			nxt.x=q.front().x+dx[i];
			nxt.y=q.front().y+dy[i];
			while(nxt.x>=1&&nxt.x<=(n+2)&&nxt.y>=1&&nxt.y<=(m+2)&&mapp[nxt.x][nxt.y]==0){//是否越界、是否为障碍物 
				if(book[nxt.x][nxt.y]==0){//是否走过 
					if(nxt.x==num2.x&&nxt.y==num2.y){//到达终点 
						mapp[num1.x][num1.y]=1,mapp[num2.x][num2.y]=1;//重新封路 
						return q.front().sum+1;
					}
					book[nxt.x][nxt.y]=1;
					nxt.sum=q.front().sum+1;
					q.push(nxt);//入队 
				}
				nxt.x+=dx[i];
				nxt.y+=dy[i];
			}
		}
		q.pop();//出队 
	}		
	return 0;//无法走到终点 
}
int main(){
	cin>>m>>n;
	getline(cin,s);//消除换行 
	for(int i=2;i<=n+1;i++)
	{
		getline(cin,s);
		if(s.length()==0)continue;//特殊判定 
		for(int j=0;j<m;j++){
			if(s[j]=='X')mapp[i][j+2]=1;//构建地图 
			else mapp[i][j+2]=0;
		}
	}
	while(cin>>num1.y>>num1.x>>num2.y>>num2.x,num1.x!=0&&num1.y!=0&&num2.x!=0&&num2.y!=0){//是否有输入数据 
		num1.y++,num1.x++,num2.y++,num2.x++;//移动坐标 
	    cout<<bfs()<<endl;
    }
	return 0;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个麻将游戏的代码示例,使用Python语言编写: ```python import random # 麻将牌总数 MAHJONG_COUNT = 144 # 麻将牌的种类 MAHJONG_KINDS = ["万", "条", "饼", "风", "箭"] # 麻将牌的数字 MAHJONG_NUMS = ["一", "二", "三", "四", "五", "六", "七", "八", "九"] # 风牌的种类 MAHJONG_FENG_KINDS = ["东", "南", "西", "北"] # 箭牌的种类 MAHJONG_JIAN_KINDS = ["中", "发", "白"] # 玩家初始手牌数量 INIT_HAND_COUNT = 13 # 麻将牌的类 class Mahjong: def __init__(self, kind, num): self.kind = kind self.num = num def __str__(self): return self.num + self.kind # 麻将牌堆的类 class MahjongHeap: def __init__(self): self.heap = [] self.init_heap() self.shuffle() # 初始化麻将牌堆 def init_heap(self): for kind in MAHJONG_KINDS: if kind == "风": for feng in MAHJONG_FENG_KINDS: for i in range(4): self.heap.append(Mahjong(feng, "")) elif kind == "箭": for jian in MAHJONG_JIAN_KINDS: for i in range(4): self.heap.append(Mahjong(jian, "")) else: for num in MAHJONG_NUMS: for i in range(4): self.heap.append(Mahjong(kind, num)) # 洗牌 def shuffle(self): random.shuffle(self.heap) # 摸牌 def draw(self): if len(self.heap) > 0: return self.heap.pop() else: return None # 玩家类 class Player: def __init__(self, name): self.name = name self.hand = [] # 摸牌 def draw(self, mahjong): self.hand.append(mahjong) # 打牌 def discard(self, index): if index >= 0 and index < len(self.hand): return self.hand.pop(index) else: return None # 显示手牌 def show_hand(self): print(self.name + "的手牌:") for i, mahjong in enumerate(self.hand): print(str(i+1) + ": " + str(mahjong)) # 游戏类 class Game: def __init__(self): self.players = [] self.mahjong_heap = MahjongHeap() # 添加玩家 def add_player(self, player): self.players.append(player) # 开始游戏 def start(self): # 发牌 for i in range(INIT_HAND_COUNT): for player in self.players: player.draw(self.mahjong_heap.draw()) # 显示玩家手牌 for player in self.players: player.show_hand() # 主循环 while True: for player in self.players: # 玩家摸牌 mahjong = self.mahjong_heap.draw() player.draw(mahjong) print(player.name + "摸了一张牌:" + str(mahjong)) # 显示玩家手牌 player.show_hand() # 玩家打牌 while True: index = input(player.name + "打哪张牌?") if index.isdigit(): index = int(index) - 1 mahjong = player.discard(index) if mahjong is not None: print(player.name + "打出了:" + str(mahjong)) break else: print("无效的牌号!") else: print("无效的输入!") # 判断是否有人胡牌、和牌、杠牌、碰牌等等 # 判断是否有人胡牌 # 判断是否有人和牌 # 判断是否有人杠牌 # 判断是否有人碰牌 # 判断是否流局 # 结束游戏 def end(self): pass # 测试代码 if __name__ == "__main__": game = Game() game.add_player(Player("张三")) game.add_player(Player("李四")) game.add_player(Player("王五")) game.start() game.end() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值