Othello
Othello is a game played by two people on an 8 x 8 board, using disks that are white on one side and black on the other. One player places disks with the white side up and the other player places disks with the black side up. The players alternate placing one disk on an unoccupied space on the board.In placing a disk, the player must bracket at least one of the other color disks. Disks are bracketed if they are in a straight line horizontally, vertically, or diagonally, with a disk of the current player’s color at each end of the line. When a move is made, all the disks that were bracketed are changed to the color of the player making the move. (It is possible that disks will be bracketed across more than one line in a single move.)
On the left
Legal Moves for White
(2,3),(3,3),(3,5),(3,6)
(6,2),(7,3),(7,4),(7,5)
On the right
Board Configuration after
White Moves to (7,3)
Write a program to read a series of Othello games.
Input
The first line of the input is the number of games to be processed. Each game consists of a board
configuration followed by a list of commands. The board configuration consists of 9 lines. The first 8
specify the current state of the board. Each of these 8 lines contains 8 characters, and each of these
characters will be one of the following:
‘-’ indicating an unoccupied square
‘B’ indicating a square occupied by a black disk
‘W’ indicating a square occupied by a white disk
The ninth line is either a ‘B’ or a ‘W’ to indicate which is the current player. You may assume that
the data is legally formatted.
Then a set of commands follows. The commands are to list all possible moves for the current player,
make a move, or quit the current game. There is one command per line with no blanks in the input.
Output
The commands and the corresponding outputs are formatted as follows:
List all possible moves for the current player. The command is an ‘L’ in the first column of the
line. The program should go through the board and print all legal moves for the current player
in the format (x, y) where x represents the row of the legal move and y represents its column.
These moves should be printed in row major order which means:
- all legal moves in row number i will be printed before any legal move in row number j if j
is greater than i
and 2) if there is more than one legal move in row number i, the moves will be printed in ascending
order based on column number.
All legal moves should be put on one line. If there is no legal move because it is impossible for the
current player to bracket any pieces, the program should print the message ‘No legal move.’
Make a move. The command is an ‘M’ in the first column of the line, followed by 2 digits in the
second and third column of the line. The digits are the row and the column of the space to place
the piece of the current player’s color, unless the current player has no legal move. If the current
player has no legal move, the current player is first changed to the other player and the move
will be the move of the new current player. You may assume that the move is then legal. You
should record the changes to the board, including adding the new piece and changing the color
of all bracketed pieces. At the end of the move, print the number of pieces of each color on the
board in the format ‘Black - xx White - yy’ where xx is the number of black pieces on the
board and yy is the number of white pieces on the board. After a move, the current player will
be changed to the player that did not move.
Quit the current game. The command will be a ‘Q’ in the first column of the line. At this point,
print the final board configuration using the same format as was used in the input. This terminates
input for the current game.
You may assume that the commands will be syntactically correct. Put one blank line between
output from separate games and no blank lines anywhere else in the output.
Sample Input
2
--------
--------
--------
---WB---
---BW---
--------
--------
--------
W
L
M35
L
Q
WWWWB---
WWWB----
WWB-----
WB------
--------
--------
--------
--------
B
L
M25
L
Q
Sample Output
(3,5) (4,6) (5,3) (6,4)
Black - 1 White - 4
(3,4) (3,6) (5,6)
--------
--------
----W---
---WW---
---BW---
--------
--------
--------
No legal move.
Black - 3 White - 12
(3,5)
WWWWB---
WWWWW---
WWB-----
WB------
--------
--------
--------
--------
题目大意:有T组输入,每组给出一个8*8的棋盘,接着给出当前下棋的人,再接着给出一系列操作,这些操作分为三种:
1、L操作:
在棋盘上寻找所有合法的点。所谓合法,就是两个同色的棋子之间必须全都是对方颜色的棋子。
例如:当前下棋的人是白棋一方,那么就必须寻找到一个点,使得它能够跟另一个白棋(必须是在八个方向上,即同行或同列或同对角线)连成一条线,并且他们之间所有的都必须是黑棋,不能没有棋子。找到之后要把所有合法的点打印出来。
2、Mxy操作:
如果当前下棋的一方可以在(x,y)这个位置放上自己的棋子,也就是必须合法,那么就直接放上自己的棋子,并将所有对方被夹住的棋子变成自己的。
若当前下棋的一方不能在(x,y)这个位置上放自己的棋子,也就是不合法,那么就交换下棋人,下棋者变为对方,数据保证在交换后肯定会有一个合法位置。
在对棋盘进行改变之后,输出棋盘上黑棋和白棋的数量
不论Mxy操作过程中有没有交换下棋人,最后都要交换一次,变为对方发棋
3、Q操作:
打印棋盘,并结束对当前这组棋盘模拟的操作。
坑点:
1、Black - xx White - yy:这句话的意思是黑棋和白棋的数量要占两位,也就是%2d
2、…no blank lines anywhere else in the output. 这句话的意思是说在输出的时候,每组之间要有一个空行,但是最后一行不要有空行。
代码:
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef pair < int , int > PII;
const int dx[] = {1 , 0 , -1 , 0 , 1 , 1 , -1 , -1} , dy[] = {0 , 1 , 0 , -1 , 1 , -1 , 1 , -1};//八个方向
char g[10][10];//用来存储整个棋盘
char oper[10] , observer[10];
//用来储存当前发棋人和不发棋人,因为可能会有多余的空格,所以用char数组而不是char来保存发棋人,个人习惯
//至于为什么连不发棋人也要用数组,仅仅是因为强迫症,hhh。。。
void ChangeOper()//交换发棋人的,写成一个函数看起来直观一点
{
swap(oper[0] , observer[0]);
}
void Change(int x , int y)//改变在(x,y)这个位置上的棋子,将这个棋子变成对方的
{
if(g[x][y] == 'W') g[x][y] = 'B';
//这里是elseif 最后几次WA被这里坑惨了
else if(g[x][y] == 'B') g[x][y] = 'W';
}
bool judge(int x , int y)
{
//判断(x,y)这个坐标是否合法
return x >= 0 && x < 8 && y >= 0 && y < 8;
}
//从(x,y)这个位置向八个方向去找,返回值代表(x,y)这个位置是不是一个合法位置,isChange代表要不要改变对方的棋子
bool Find(int x , int y , int isChange)
{
bool isFind = false;
for(int i = 0 ; i < 8 ; ++ i)
{
int nx = x + dx[i] , ny = y + dy[i] , cnt = 0;
while(judge(nx , ny) && g[nx][ny] == observer[0]) cnt ++ , nx += dx[i] , ny += dy[i];
if(judge(nx , ny) && cnt && g[nx][ny] == oper[0])//这里cnt必须要大于0,否则有可能存在挨着的情况
{
isFind = true;
if(isChange)
{
//如果需要改变对方的棋子,就直接
for(int a = x + dx[i] , b = y + dy[i] ; a != nx || b != ny ; a += dx[i] , b += dy[i]) Change(a , b);
}
}
}
return isFind;
}
void FindAll()//L操作,寻找所有合法的位置
{
int idx = 0;//res数组下标,也代表有多少个合法位置
PII res[65];//用于储存所有合法位置
int vis[10][10];//标记数组,用于去重
memset(vis , 0 , sizeof vis);
for(int i = 0 ; i < 8 ; ++ i)
{
for(int j = 0 ; j < 8 ; ++ j)
{
if(g[i][j] != '-') continue;
if(Find(i , j , 0) && !vis[i][j])//如果当前这个位置是一个合法位置并且之前没有标记过
{
vis[i][j] = 1;
res[idx ++] = {i , j};
}
}
}
if(!idx)puts("No legal move.");//如果没有合法位置
else
{
sort(res , res + idx);
for(int i = 0 ; i < idx ; ++ i)
{
if(i) printf(" ");
printf("(%d,%d)",res[i].first + 1 , res[i].second + 1);
}
puts("");//换行
}
}
void Load(int x , int y)
{
if(!Find(x , y , 1))
{
ChangeOper();
Find(x , y , 1);
}
g[x][y] = oper[0];//把这个坐标放上当前发棋人的棋子
int wCnt = 0 , bCnt = 0;
for(int i = 0 ; i < 8 ; ++ i)
for(int j = 0 ; j < 8 ; ++ j)
{
if(g[i][j] == 'B') bCnt ++;
else if(g[i][j] == 'W') wCnt ++;
}
printf("Black - %2d White - %2d\n",bCnt , wCnt);//注意这里是2d
ChangeOper();//最后都要改变一次发棋人
}
int main(void)
{
int T;
cin >> T;
while(T --)
{
for(int i = 0 ; i < 8 ; ++ i) scanf("%s",g[i]);
scanf("%s",oper);//读入发棋人
if(oper[0] == 'W') observer[0] = 'B';
else observer[0] = 'W';
char op[10];//用来储存操作
while(scanf("%s",op) != EOF)
{
if(op[0] == 'L') FindAll();
else if(op[0] == 'M') Load(op[1] - '0' - 1 , op[2] - '0' - 1);//我的下标都是从0开始的,这里要注意一哈
else
{
for(int i = 0 ; i < 8 ; ++ i) printf("%s\n",g[i]);
if(T) puts("");
break;
}
}
}
return 0;
}