UVA - 220 Othello

/*
  这题实在是让人不由感慨一下,好的思路有多么重要!~
  起因:因为自己实在想不出来,于是百度题解。然而搜到的题解,要不看得艰难,要不一看就是200行以上的,就可能是畏难吧,于是我甚至看题解,看别人的代码都看不下去了...
  
  但是我又实在不想放弃,接着搜搜搜,居然在百度的比较靠后的页里,找到了一份对我而言,最简洁易懂的代码,马上就理解了,于是自己借用思路手敲了一次
  
  BTW,这个博主写的真心是好,毫无冗余,并且条理逻辑十分清晰,虽然注释不多,但还是让人一眼就看懂了,真的强烈推荐大家去瞻仰一下
  http://blog.csdn.net/fzl1941572592/article/details/75208834
  
  但是值得一提的是,如果用这种写法,对格式的控制必须十分精细,不得有丝毫错漏,否则很容易WA,建议先把所有输入数据赋值到一个txt里,观察格式,末尾有无空格,还是只是换行?合理运用getchar(),必要时可以用 cout / printf 输出来检验自己的输入格式,是否真的控制好了。
  
  还要说一下,如果选手在0和1间不断变换,可以用异或符号 ^=
  
  0826更新--
  今天我自己按照博主的思路敲了一次,才发现这题,黑白棋连子的判断和替换,选手的替换,这两个最大的难点,博主都用了十分简洁清晰的思路写出来了,真是十分佩服,要是我自己写,肯定得写得很长很长很麻烦
*/


#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
char chess[10][10];
typedef pair<int, int > p;
p store[50]; 
int dxy[8][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {-1, -1}, {-1, 1}, {1, -1}, {1, 1} };
//#define debug

void count()
{
	int s1 = 0, s2 = 0;
	for (int i = 1; i <= 8; i++)
	for (int j = 1; j <= 8; j++)
	{
		switch (chess[i][j])
		{
			case 'B': s1++; break;
			case 'W': s2++; break;
		}
	}
	printf("Black - %2d White - %2d\n", s1, s2);
}

int is_legal(char c)
{
	int res = 0;
	memset(store, 0, sizeof (store));
	
	for (int i = 1; i <= 8; i++)
	{
		for (int j = 1; j <= 8; j++)
		{
			bool flag = false;
			if (chess[i][j] == '-') //在此放己方棋子作为起点
			{
				for (int k = 0; k < 8; k++)
				{
					int xx = i + dxy[k][0], yy = j + dxy[k][1]; 
					if (xx >= 1&& xx <= 8 && yy >= 1 && yy <= 8 && chess[xx][yy] != c && chess[xx][yy] != '-') //只要该方向上距离 chess[i][j]最近的位置满足这个严苛的条件,就可以一直往这个方向循环,直到越界,或者因为不满足特定条件而break出来 
					{
						while (xx >= 1&& xx <= 8 && yy >= 1 && yy <= 8) //在此方向不断延伸,直到碰到己方棋子,或空位,
						{
							xx += dxy[k][0]; yy += dxy[k][1];
							
							if (chess[xx][yy] == '-') break; // 夹住对方棋子的条件:两端都是己方棋子,不能是空位
							if (chess[xx][yy] != c) continue; // 如果是对方棋子,继续循环
							
							flag = true; break; //如果是己方棋子,标记一下这个起点(i,j)可以放置,于是就可以退出了,将这个位置赋值pair数组
						}
					}
				}
			}
			
			if (flag)
			{
				res++;
				store[res].first = i; store[res].second = j;
			}
		}
	}
	return res;
}

void change (int x, int y, char c)
{
	chess[x][y] = c;
	for (int i = 0; i < 8; i++)
	{
		int xx = x + dxy[i][0], yy = y + dxy[i][1];
		bool flag = false;
		
		if (xx >= 1 && xx <= 8 && yy >= 1 && yy <= 8 && chess[xx][yy] != c && chess[xx][yy] != '-') //注意,有2个x的变量,有2个y的变量,不要写漏为1个了,我在这个地方WA了几次,找了很久,真的很难发现 
		{
			while (xx >= 1&& xx <= 8 && yy >= 1 && yy <= 8)
			{
				xx += dxy[i][0]; yy += dxy[i][1];
							
				if (chess[xx][yy] == '-') break;
				if (chess[xx][yy] != c) continue;
							
				flag = true; break; //确认当前方向的确可以替换己方棋子
			}
		}
		
		if (flag)
		{
			xx = x + dxy[i][0]; yy = y + dxy[i][1];
			while (xx >= 1&& xx <= 8 && yy >= 1 && yy <= 8)
			{
				chess[xx][yy] = c;
				xx += dxy[i][0]; yy += dxy[i][1];
				
				if (chess[xx][yy] == c) break; // 等到遇到己方棋子,该方向的替换也就结束了
			}
		}
		
	}
}

void showchess()
{
	for (int i = 1; i <= 8; i++)
	{
		for (int j = 1; j <= 8; j++) cout << chess[i][j];
		cout << endl;
	}
}

int main()
{	
	#ifdef debug
	freopen("E:\\in.txt", "r", stdin);
	freopen("E:\\out.txt", "w", stdout);
	#endif
	int t, kase = 0, s; //s表示当前棋局从谁开始下 
	char player[2] = { 'W', 'B' };
	char start, order; //起始选手,指令 
	cin >> t;
	getchar(); //处理末尾的回车符 
	while (t--)
	{
		if (kase++) cout << endl;
		for (int i = 1; i <= 8; i++)
		{
			for (int j = 1; j <= 8; j++)
			cin >> chess[i][j];
			getchar(); //处理末尾的回车符 
		}
		
		cin >> start; getchar(); //处理回车
		if (start == 'W')s = 0; else s = 1;
		
		while (cin >> order)
		{
			if (order == 'Q')
			{
				showchess();
				getchar();
				break;
			}
			else if (order == 'M')
			{
				int r, c, rc; // row, colunm
				cin >> rc;
				r = rc / 10;
				c = rc % 10;
				if (is_legal(player[s]))
				change(r, c, player[s]);
				else
				{
					s ^= 1;
					change(r, c, player[s]);
				}
				s ^= 1; //别忘了为M时,是真正的两人下棋的情况,一定要记得一人下完以后,更换选手了!!! 
				count();
			}
			else
			{
				int ans = is_legal(player[s]);
				
				if (!ans) cout << "No legal move." << endl;
				else
				{
					printf("(%d,%d)", store[1].first, store[1].second);
					
					for (int i = 2; i <= ans; i++)
					printf(" (%d,%d)", store[i].first, store[i].second);
					
					cout << endl;
				}
			}
			getchar();
		}			
	}	
	#ifdef debug
	fclose(stdin);
	fclose(stdout);
	#endif
	return 0;
}



posted @ 2017-08-27 07:57  mofushaohua  阅读(146)  评论(0编辑  收藏  举报