【题解】UVA1589 象棋
究极模拟题。
这是旧文章,当时写的时候还不会用静态数组模拟移动,导致代码写的很繁杂,看看就好。
大体思路:
用一个二维数组记录整个棋盘,一个二维数组记录棋盘上每个点能否被红方棋子吃掉。模拟每个棋子并记录下能吃掉的位置,最后模拟黑将移动判断有没有将死。
红将、车和炮的模拟可以相同,定义一个表示攻击状态的变量,红将和车一开始就是攻击状态,碰到红子后停止该方向的模拟。炮开始不是攻击状态,碰到红子后进入攻击状态,再碰到红子停止该方向模拟。
马单独一个模拟。
黑将单独一个模拟。
几个要注意的点:
- 棋子本身的位置是默认是不能被吃到的。
- 车和红将以及炮进入攻击状态后,碰到的红棋子的位置也要记录为可以吃到,碰到黑将则不理会继续记录本方向,因为黑将在该方向上移动仍会被将死。
- 炮在进入攻击状态前碰到红子,该红子位置不要被记录为可以吃到,如果碰到黑将则无需进入攻击状态,因为黑将能移动。
- 马写的时候要仔细,我写的时候错了一个符号,debug了好久...
附上代码:
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int maxn = 11;
char board[maxn][maxn];
bool is[maxn][maxn];
struct cmd //存储命令用的结构
{
char c;
int a;
int b;
} cmds[10];
void d(int x, int y, bool attack) //模拟车,炮,红将. attack表示攻击状态
{
bool attack1 = attack;
for (int i = x, j = y - 1; j != 0; j--) //left
if (board[i][j] != 0 && board[i][j] != 'E') //如果碰到红棋子
{
if (attack) //在攻击状态就设为可以吃到,并退出该方向
{
is[i][j] = true;
break;
}
else //不在攻击状态就进入攻击状态(炮)
attack = 1; //遇到的第一个棋子是黑将不进入攻击状态
}
else if (attack) //在攻击状态也没碰到棋子就设为可以吃到
is[i][j] = true;
attack = attack1; //重置攻击状态
for (int i = x, j = y + 1; j != 10; j++) //right
if (board[i][j] != 0 && board[i][j] != 'E')
{
if (attack)
{
is[i][j] = true;
break;
}
else
attack = 1;
}
else if (attack)
is[i][j] = true;
attack = attack1;
for (int i = x + 1, j = y; i != 11; i++) //down
if (board[i][j] != 0 && board[i][j] != 'E')
{
if (attack)
{
is[i][j] = true;
break;
}
else
attack = 1;
}
else if (attack)
is[i][j] = true;
attack = attack1;
for (int i = x - 1, j = y; i != 0; i--) //up
if (board[i][j] != 0 && board[i][j] != 'E')
{
if (attack)
{
is[i][j] = true;
break;
}
else
attack = 1;
}
else if (attack)
is[i][j] = true;
}
void h(int x, int y) //马
{
//马的代码都差不多,四个方向分别考虑,写好一个复制一下仔细改改就行,记得考虑蹩马腿
if (x >= 3 && board[x - 1][y] == 0) //up
{
if (y != 1)
is[x - 2][y - 1] = 1;
if (y != 9)
is[x - 2][y + 1] = 1;
}
if (x <= 8 && board[x + 1][y] == 0) //down
{
if (y != 1)
is[x + 2][y - 1] = 1;
if (y != 9)
is[x + 2][y + 1] = 1;
}
if (y >= 3 && board[x][y - 1] == 0) //left
{
if (x != 1)
is[x - 1][y - 2] = 1;
if (x != 10)
is[x + 1][y - 2] = 1;
}
if (y <= 7 && board[x][y + 1] == 0) //right
{
if (x != 1)
is[x - 1][y + 2] = 1;
if (x != 10)
is[x + 1][y + 2] = 1;
}
}
void m(const char type, int x, int y) //命令处理
{
if (type == 'R' || type == 'G')
d(x, y, true); //车和红将直接攻击状态
else if (type == 'C')
d(x, y, false); //炮先不是攻击状态
else if (type == 'H')
h(x, y);
}
bool t(int x, int y) //判断黑将是否将死
{
if (x == 1 || x == 2) //在1或2行判断能否向下走
if (is[x + 1][y] == false)
return 0;
if (x == 2 || x == 3) //在2或3行判断能否向上走
if (is[x - 1][y] == false)
return 0;
if (y == 4 || y == 5) //在4或5列判断能否向右走
if (is[x][y + 1] == false)
return 0;
if (y == 6 || y == 5) //在5或6列判断能否向左走
if (is[x][y - 1] == false)
return 0;
return 1;
}
int main()
{
int n, x, y;
char ch;
while (cin >> n >> x >> y && n)
{
memset(board, 0, sizeof(board));
memset(is, 0, sizeof(is)); //重置
board[x][y] = 'E'; //E代表黑将
int n1 = n, x1 = x, y1 = y; //复制一份信息备用
while (n--) //输入
{
cin >> ch >> x >> y;
cmds[n].c = ch;
cmds[n].a = x;
cmds[n].b = y;
board[x][y] = ch;
}
while (n1--)
m(cmds[n1].c, cmds[n1].a, cmds[n1].b); //执行每一个棋子
bool bo = t(x1, y1); //判断
if (bo)
cout << "YES\n";
else
cout << "NO\n";
}
return 0;
}