1.井字棋

文章讲述了井字棋游戏的规则和一个编程题目的解决方案。题目要求根据给定的对局结束状态和先手信息判断获胜者。错误代码中由于在主函数内重新定义了棋盘数组,导致静态区的函数无法访问正确的数据。修正后的代码移除了主函数内的数组定义,确保所有函数都能访问同一棋盘状态。此外,文章强调了编程中的一些常见错误和良好编程习惯的重要性。
摘要由CSDN通过智能技术生成

【问题描述】

井字棋,是一种在3×3格子上进行的连珠游戏,和五子棋比较类似,由于棋盘一般不画边框,格线排成井字故得名。游戏需要的工具仅为纸和笔,然后由分别代表OX的两个游戏者轮流在格子里留下标记井字策略。任意三个标记形成一条直线,则为获胜。

Alice和Bob考完了期末考试,并获得了100分的好成绩,正觉无聊,于是开始玩起了井字棋。

给出 个3×3的字符数组,用于表示 次对局最终的标记情况。

由于总是一个人先手会使得游戏趣味性降低,每一局的先手者并不是固定的。

具体给出一个长度为 的字符串ss的第 个字符表示第 场对局的先手者是谁(0≤ <n),‘A’表示Alice先手,‘B’表示Bob先手。

先手者执“1”棋子,后手者执“2”棋子,无棋子处用“0”表示。

请分别判断这个 次对局的获胜者。

题目数据保证所有的局面都是合法且可判断唯一获胜者的。

【输入形式】

输入的第一行包含一个正整数 ( ≤300),表示对局的次数。

输入的第二行包含一个字符串s,表示各对局的先手情况。

接下来3 * 行,每行由一个长度为3的字符串组成,每3行共9个字符对应一个局面。

【输出形式】

输出共 行,每行输出A或B,表示每场对局的获胜者是谁。


【样例输入】

2
AB
120
112
201
222
101
010

【样例输出】

A
A


【样例说明】

第一场对局中棋子1在正对角线上三个相连,而Alice先手,所以Alice获胜

第二场对局中棋子2在第一行上三个相连,而Bob先手,Alice后手,所以Alice获胜

注:

此为CCF系列题解--2018年3月第四题 井字棋游戏 变体

代码思路参考该大佬(8条消息) CCF系列题解--2018年3月第四题 井字棋游戏_Jing Sir的博客-CSDN博客

先来说下该题思路:

首先:该题相较于原题难度大大降低,给定的最终棋局为一固定棋局,因此不需要考虑之后选手下的棋局,只需对现在已经确定的棋局进行判定即可。

其次:本题多了一个先手后手问题

且注意到  “题目数据保证所有的局面都是合法且可判断唯一获胜者的。” 因此可以换种思路,考虑棋盘上的棋子数以及先手问题,但本问不对此过多赘述。主要讲解一下本体在原题基础上的一个较为普遍的通解。(其实主要是想写下我的离谱错误.........)

先来看下错误代码

#include<cstring>
#include<iostream>
using namespace std;
char a[3][3];
bool hok(int h,int f)//判断行 
{
	return a[h][0]==(f+'0')&&a[h][1]==(f+'0')&&a[h][2]==(f+'0');
}
bool lok(int l,int f)//判断列 
{
	return a[0][l]==(f+'0')&&a[1][l]==(f+'0')&&a[2][l]==(f+'0');
}
int win(int f)//判断胜利 
{
	if(hok(0,f)||hok(1,f)||hok(2,f))
	return 1;
	if(lok(0,f)||lok(1,f)||lok(2,f))
	return 1;
	if(a[0][0]==(f+'0')&&a[1][1]==(f+'0')&&a[2][2]==(f+'0'))
	return 1;
	if(a[2][0]==(f+'0')&&a[1][1]==(f+'0')&&a[0][2]==(f+'0'))
	return 1;
	return 0;
}
int main()
{
	int n;
	cin>>n;
	string s;
	cin>>s;
	char a[3][3];
	for(int i=0;i<n;i++)//n个结果 
	{
		for(int j=0;j<3;j++)
		{
			string str;
			cin>>str;
			for(int k=0;k<3;k++)
			{
			     a[j][k]=str[k];
			}
		}
		int flag1=0;
		int flag2=0;
		if(s[i]=='A')
		{
			flag1=win(1);
			if(flag1==1)
			cout<<'A'<<endl;
			else 
			cout<<'B'<<endl;
		}
		else
		{
			flag2=win(1);
			if(flag2==1)
			cout<<'B'<<endl;
			else 
			cout<<'A'<<endl;
		}
	}
	return 0;
}

一眼看过去好像啥都没错,但是实际跑出来全是错误。而且即使一条条调用函数,跑出来的全是0,但将函数体直接扔到main里面却能得到对的返回值。博主百思不得其解(浪费 long time)

然后找老师盯了半天,发现一个很小但致命的错误。

注意注意:

静态区的函数里面需要调用棋盘数组,则必须在静态区开一个棋盘数组。(即此处如果不开,只在main函数里开,则函数会报错)。

但是这段错误的代码离谱的一个小错误在于 main函数里又把棋盘数组a[3][3]开了一遍。导致main函数里的操作只在main函数里生效,静态区的a[3][3]值没有传递过去。

尤其是main函数前面写了不少函数,然后检查代码时,查完几个函数就对自己开的数组没印象了。(虽然感觉也没几个会像我这样离谱,但还是记录一下,留个警示吧)

正确代码

#include<cstring>
#include<iostream>
using namespace std;
char a[3][3];
bool hok(int h,int f)//判断行 
{
	return a[h][0]==(f+'0')&&a[h][1]==(f+'0')&&a[h][2]==(f+'0');
}
bool lok(int l,int f)//判断列 
{
	return a[0][l]==(f+'0')&&a[1][l]==(f+'0')&&a[2][l]==(f+'0');
}
int win(int f)//判断胜利 
{
	if(hok(0,f)||hok(1,f)||hok(2,f))
	return 1;
	if(lok(0,f)||lok(1,f)||lok(2,f))
	return 1;
	if(a[0][0]==(f+'0')&&a[1][1]==(f+'0')&&a[2][2]==(f+'0'))
	return 1;
	if(a[2][0]==(f+'0')&&a[1][1]==(f+'0')&&a[0][2]==(f+'0'))
	return 1;
	return 0;
}
int main()
{
	int n;
	cin>>n;
	string s;
	cin>>s;
	for(int i=0;i<n;i++)//n个结果 
	{
		for(int j=0;j<3;j++)
		{
			string str;
			cin>>str;
			for(int k=0;k<3;k++)
			{
			     a[j][k]=str[k];
			}
		}
		int flag1=0;
		int flag2=0;
		if(s[i]=='A')
		{
			flag1=win(1);
			if(flag1==1)
			cout<<'A'<<endl;
			else 
			cout<<'B'<<endl;
		}
		else
		{
			flag2=win(1);
			if(flag2==1)
			cout<<'B'<<endl;
			else 
			cout<<'A'<<endl;
		}
	}
	return 0;
}

额外补充:

1.每个函数在任何情况下都要有对应返回值。void除外。(即 bool 函数不能只写返回true的,什么时候返回false也要写,以及main函数写return 0养成好习惯)

2.括号不要随便省略  a[i][j]!=b等价于 !(a[i][j]==b)!a[i][j]==b是错的

3.代码错了多角度思考思考,心平气和写(虽然不大可能),但是急起来确实越写越乱.....

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值