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; }