HNU程序设计训练——斯诺克台球

【问题描述】

斯诺克台球是一项古老而又时尚的运动,使用长方形球桌,台面四角以及两长边中心位置各有一个球袋,使用的球分为1个白球,15个红球和6个彩球共22个球。

其中母球(白球)1只,目标球21只。目标球中:红球15只各1分、黄球1只2分、绿球1只3分、咖啡球1只4分、蓝球1只5分、粉球1只6分、黑球1只7分。

djh.jpg

选手需要使用球杆撞击母球去击打目标球来完成得分,每局开始时总是先从红球开始。击球顺序为先打进红球(每次击打允许多个红球同时落袋),然后必须任意指定一个目标彩球击打,如果该彩球被打进(打进后需要再摆回),然后接着击打红球,直到红球全部落袋,然后以黄、绿、咖啡、蓝、粉红、黑的顺序逐个击球(不再摆回),最后以得分高者为胜。任何时候红球落袋都不再摆回,任何时候因犯规导致彩球落袋,彩球必须摆回。

斯诺克比赛由双方轮流击打,必须击打合规的目标球,打进则本方得到相应的分数并继续击打,未打进或犯规轮换为对方击打,未打进不得分,犯规将进行罚分处理。

犯规规则如下:

1.     当击打目标球时,如果先击打到或同时击打到一个或多个其他颜色的球,或者有其他颜色的球落袋,或者打空(未击打到任何球),则视为犯规。此时需要比较目标球的分值和与本犯规相关的其他颜色的球的分值,取其中最高的分值,如果该分值小于4,则对方加4分,否则对方加该分值。

2.     当击打红球落袋后,继续击打任意彩球时打空,即未打击到任何球,对方加4分。

相比正式的斯诺克比赛,本问题对规则进行了简化,任何时候都可以结束比赛并计算比赛结果,不考虑白球落袋的情况。

信息化时代的智能台球桌能自动记录实际比赛时的击打记录,并传送到后台,但该记录仅仅是流水记录,并且无参赛选手的任何信息,需要你编程计算每场比赛的比分,同时需要计算单杆100分及以上的情况(单杆得分是指选手一次连续击打所得分数之和)。

【输入形式】

输入第一行为正整数t (t≤100),表示有t组测试数据,每组数据代表一局比赛。

在输入中,球的颜色表示为:

               r-红色球 y-黄色球 g-绿色球 c-咖啡色球 b-蓝色球 p-粉红球 B-黑色球

接下来的每组数据包括若干行,每一行为一次击打的结果,为智能球桌记录下来的流水记录,每组数据最后一行为-1,表示每组数据的结束。

流水记录包含用空格分隔的2个部分:

首先撞到的球 落袋球及数量

第一部分“首先撞到的球”为一个字符串,可以是“rygcbpB”中1个或多个字符组合(可能有多个字符“r”),或为字符串“NULL”。为“NULL”时,第二部分必为空,表示该次击打未撞击到任何球也没有任何球落袋。当红球落袋后继续击打任意彩球时,该部分为“ygcbpB”中的任意单个字符时都认为是合规的目标球。

第二部分“落袋球及数量”为一个字符串,例如“r2gb”,代表本次击打有两个红球落袋,以及绿球和篮球落袋,红色球r后面有数字(大于0小于16),表示红球的落袋数,其他彩球后无数字。该部分可以为空,表示本次击打无球落袋。

比赛在A与B之间进行,每局比赛总是由A先开球。

【输出形式】

输出为t+1行,前t行每行输出用冒号分隔的两个整数,表示每局比赛A与B之间的比分;最后一行输出用冒号分隔的两个整数,表示t局比赛之后A与B之间获得的单杆100分及以上的次数之比(单杆得分是指选手一次连续击打所得分数之和)。

【样例输入】

3
r r1
B
r r2
c c
r r1
b g
-1
rp r1
r br2B
NULL
r r12
y y
g p
-1
rr r3
NULL
r r1
yg y
-1

【样例输出】

6:7

13:24

7:5

0:0

【样例说明】

第一局比赛:

A击打红球,打进1个红球,得1分,比分为 1:0

A继续击打任意彩球,打到黑球,未打进,不得分,比分为1:0

轮换为B击打红球,打进两个红球,得2分,比分为1:2

B继续击打任意彩球,打到咖啡球,打进咖啡球,咖啡球摆回,得4分,比分为1:6

B继续击打红球,打进一个红球,得1分,比分为1:7

B继续击打任意彩球,打到蓝球,打进绿球,犯规,取分值最大者蓝球,绿球摆回,对方加5分,比分为6:7

-1比赛结束

第二局比赛:

A击打红球,首先打到红球和粉球,犯规,打进1个红球和咖啡球,犯规,咖啡球摆回,取分值最大的粉球,对方加6分,比分为0:6

B击打红球,首先打到红球,打进蓝球、2个红球和黑球,犯规,蓝球和黑球摆回,取分值最大的黑球,对方加7分,比分为7:6

A击打红球,未打到任何球,犯规,对方加4分,比分为7:10

B击打红球,打到红球,打进12个红球,加12分,比分为7:22

B击打任意彩球,打到黄球,打进黄球,黄球摆回,得2分,比分为7:24

B击打黄球,打到绿球,打进粉球,犯规,粉球摆回,对方加6分,比分为13:24

-1比赛结束

第三局比赛:

A击打红球,打到2个红球,打进3个红球,加3分,比分为3:0

A击打任意彩球,打空,未打到任何球,对方加4分,比分为3:4

B击打红球,打到1个红球,打进1个红球,加1分,比分为3:5

B击打任意彩球,打到黄球和绿球,打进黄球,犯规,黄球摆回,取分值最高的绿球,绿球分值小于4,对方加4分,比分为7:5 

-1比赛结束

3局比赛中无人单杆得分过100,最后一行输出0:0

需要统计的变量和情况很多,很麻,特别麻

#include <iostream>
#include <string>
using namespace std;

int suma = 0, sumb = 0;//单杆得分过100的次数
int runa = 0, runb = 0;//ab当前连续得分数
int scorea = 0, scoreb = 0;//ab单场比赛得分
int rsum = 0, ysum = 0, gsum = 0, csum = 0, bsum = 0, psum = 0, Bsum = 0;//统计球进袋数
int flag = 1;//奇数代表a的球权,偶数为b球权
int FLAG = 1;//FLAG为奇数表示击打规定球,FLAG为偶数表示可击打任意彩球
//转换同球对应的得分
int conver1(char c)
{
	if (c == 'r') return 1;
	else if (c == 'y') return 2;
	else if (c == 'g') return 3;
	else if (c == 'c') return 4;
	else if (c == 'b') return 5;
	else if (c == 'p') return 6;
	//else if (c == 'B')
	return 7;
}
//处理犯规函数foul
void foul(int flag, int sum)
{
	if (sum < 4) sum = 4;
	if (flag % 2)//a犯规
		scoreb += sum;
	else
		scorea += sum;
}
//获取现在应该打什么球
char stipulate()
{
	if (rsum < 15) return 'r';
	else if (ysum == 0) return 'y';
	else if (gsum == 0) return 'g';
	else if (csum == 0) return 'c';
	else if (bsum == 0) return 'b';
	else if (psum == 0) return 'p';
	//else if (Bsum == 0) 
	return 'B';
}
void goal(char c, int sum = 1)//c颜色的球进了sum颗(书名默认为1)
{
	if (c == 'r') rsum += sum;
	else if (c == 'y') ysum++;
	else if (c == 'g') gsum++;
	else if (c == 'c') csum++;
	else if (c == 'b') bsum++;
	else if (c == 'p') psum++;
	else if (c == 'B') Bsum++;
}
//主处理函数
void fun(string s)
{
	int space = s.find(' ');//寻找s中的空格,没有找到就是没进球
	int foulflag = 0;//纪录犯规球的最高分
	bool foulFLAG = true;//纪录是否犯规
	int reflag = false;//目标球是否打进
	int resum = 0;//没有犯规且进球了应加的分
	bool rsumflag = false;//在击打规定球的回合判断红球是不是在本回合全部打入袋中。如果是下回合已经可以击打任意彩球
	if (FLAG%2)//应击打规定球,当红球全落袋后每次都按顺序击球
	{
		char re = stipulate();//确定应击打的球
		if (space != -1)
		{
			for (int i = 0; i < space; i++)
			{
				if (s[i] != re)//打到非目标球就是犯规
				{
					foulflag = max(foulflag, conver1(s[i]));
					foulFLAG = false;
				}
			}
			//space后
			for (unsigned int i = space + 1; i < s.length(); i++)
			{
				if (s[i] == re)
				{
					reflag = true;//目标球打进了
					if (re == 'r')
					{
						while (s[++i] >= '0' && s[i] <= '9')
							resum = resum*10 + s[i] - '0';
						i--;
						goal(re, resum);
						if (rsum == 15)
							rsumflag = true;//红色球是在本次回合全部进袋,下次依旧可以选择任意球打
					}
					else
					{
						resum = conver1(re);
						goal(re);
					}
				}
				else//别的球进了,犯规
				{
					foulFLAG = false;
					if (s[i] == 'r')
					{
						int rrsum = 0;
						while (s[++i] >= '0' && s[i] <= '9')
							rrsum = rrsum*10 + s[i] - '0';
						i--;
						if (rsum == 15)
							rsumflag = true;//红色球是在本次回合全部进袋,下次依旧可以选择任意球打
						goal(re, rrsum);
					}//红球任何时候进了都不放回
					else
						foulflag = max(foulflag, conver1(s[i]));
				}

			}
		}
		else//没有进球
		{
			for (unsigned int i = 0; i < s.length(); i++)
			{
				if (s[i] != re)//打到非目标球就是犯规
				{
					foulflag = max(foulflag, conver1(s[i]));
					foulFLAG = false;
				}
			}
		}

	}
	else//任意指定一个目标彩球击打
	{
		char re = s[0];//将第一个打到的球设为目标球
		foulflag = conver1(re);// 之后可能犯规,先将目标球设为犯规的最高分
		if (space != -1)
		{
			for (int i = 1; i < space; i++)
			{
				if (s[i] != re)//打到非目标球就是犯规
				{
					foulflag = max(foulflag, conver1(s[i]));
					foulFLAG = false;
				}
			}
			//space后
			for (unsigned int i = space + 1; i < s.length(); i++)
			{
				if (s[i] == re)
				{
					reflag = true;//目标球打进了
					if (re == 'r')
					{
						while (s[++i] >= '0' && s[i] <= '9')
							resum = resum*10 + s[i] - '0';
						i--;
						goal(re, resum);
					}
					else//不是打进的红球后续要拿出,无需统计进袋
						resum = conver1(re);
				}
				else//别的球进了,犯规
				{
					foulFLAG = false;
					if (s[i] == 'r')
					{
						int rrsum = 0;
						while (s[++i] >= '0' && s[i] <= '9')
							rrsum = rrsum*10 + s[i] - '0';
						i--;
						goal(re, rrsum);
					}//红球任何时候进了都不放回
					else
						foulflag = max(foulflag, conver1(s[i]));
				}
			}
		}
		else//没有进球
		{
			for (unsigned int i = 0; i < s.length(); i++)
			{
				if (s[i] != re)//打到非目标球就是犯规
				{
					foulflag = max(foulflag, conver1(s[i]));
					foulFLAG = false;
				}
			}
		}
	}
	if (!foulFLAG)//犯规了
		foul(flag, foulflag);
	else if (reflag)//没有犯规且打进目标球
	{
		if (flag % 2)//a的球权
			scorea += resum, runa += resum;
		else
			scoreb += resum, runb += resum;
		if (runa >= 100) suma++,runa=0;
		if (runb >= 100) sumb++,runb=0;//清零防止多次计算
		FLAG++;//改变下次应打的目标球
	}
	if (rsum == 15&&!rsumflag)
		FLAG = 1;//当红球全入袋且不是在本次指定击打红球时全部入袋后,每次都应击打规定球
	if (space == -1 || !foulFLAG)
	{
		flag++;//未进球或者犯规了则交换球权
		runa = 0, runb = 0;//连续得分清0
		FLAG = 1;//交换球权后一个先打指定球
	}
}
//单场比赛前参数初始化
void initialize() 
{
	FLAG = 1;//FLAG为0表示击打规定球,FLAG为1表示可击打任意彩球
	flag = 1;//球权初始为A
	runa = 0, runb = 0;//ab当前连续得分数
	scorea = 0, scoreb = 0;//ab单场比赛得分
	rsum = 0, ysum = 0, gsum = 0, csum = 0, bsum = 0, psum = 0, Bsum = 0;//统计球进袋数
}
int main()
{
	int t = 0;
	cin >> t;
	getchar();
	while (t--)
	{
		initialize();
		string s;
		while (getline(cin, s), s != "-1")
		{
			if (s == "NULL")
				foul(flag++, 4);//flag++ 交换球权
			else
			{
				fun(s);
			}
		}
		cout << scorea << ':' << scoreb << endl;
	}
	cout << suma << ':' << sumb;
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值