状态分析
- 首先列出可能的情况,即船上和其所靠岸上的Role,以PXDX形式表示,P代表牧师,其后面的X代表牧师的数量,D为恶魔,其后X同理
- 先排除不可能的情况,例如P0D0,因为船必须有Role在上面才能开动,而P0D0显然不合理;再比如P1D2,牧师少于恶魔则游戏结束,所以也不可能
- 综上,可以得到可能的情况有八种:
- P0D1
- P0D2
- P0D3
- P1D1
- P2D2
- P3D1
- P3D2
- P3D3
- 其中每种情况又分为在初始岸边和目的岸边,在不同的岸边下一步的选择也不同,根据上面八种情况,可以得到以下状态图
其中状态为船只停靠岸的Role情况,船的移动就是状态的转换,该图涵盖了所有可能情况,根据该图实现代码即可
代码实现
- 枚举五种输入(导致状态改变),其中End代表结束,INVALID表示当前输入非法
enum MoveStrategy { P1D0, P2D0, P1D1, P0D1, P0D2, END, INVALID}
- 根据当前状态得到下一步正确的输入,函数返回值为输入,即船上应该载的Role;当船在移动时该函数返回INVALID
MoveStrategy getNextMoveStratrgy() {
int[] boat_roles = boat.getRolesNum();
int[] total = new int[2]; //船和其停靠岸边一共有的角色
//在初始岸边
if (boat.getPos() == 0) {
int[] src_roles = src.getRolesNum();
for (int i = 0; i < 2; i++)
total[i] = boat_roles[i] + src_roles[i];
if (total[0] == 0 && total[1] == 1)
return MoveStrategy.P0D1;
else if (total[0] == 0 && total[1] == 2)
return MoveStrategy.P0D2;
else if (total[0] == 0 && total[1] == 3)
return MoveStrategy.P0D2;
else if (total[0] == 1 && total[1] == 1)
return MoveStrategy.P1D1;
else if (total[0] == 2 && total[1] == 2)
return MoveStrategy.P2D0;
else if (total[0] == 3 && total[1] == 1)
return MoveStrategy.P2D0;
else if (total[0] == 3 && total[1] == 2)
return MoveStrategy.P0D2;
else if (total[0] == 3 && total[1] == 3)
return MoveStrategy.P0D2;
else
return MoveStrategy.INVALID;
}
else if (boat.getPos() == 2) {
int[] dst_roles = dst.getRolesNum();
for (int i = 0; i < 2; i++)
total[i] = boat_roles[i] + dst_roles[i];
if (total[0] == 0 && total[1] == 1)
return MoveStrategy.P0D1;
else if (total[0] == 0 && total[1] == 2)
return MoveStrategy.P0D1;
else if (total[0] == 0 && total[1] == 3)
return MoveStrategy.P0D1;
else if (total[0] == 1 && total[1] == 1)
return MoveStrategy.P1D0;
else if (total[0] == 2 && total[1] == 2)
return MoveStrategy.P1D1;
else if (total[0] == 3 && total[1] == 1)
return MoveStrategy.P0D1;
else if (total[0] == 3 && total[1] == 2)
return MoveStrategy.P0D1;
else if (total[0] == 3 && total[1] == 3)
return MoveStrategy.END;
else
return MoveStrategy.INVALID;
}
else
return MoveStrategy.INVALID;
}
- 对得到的MoveStrategy数据类型进行处理,根据船上已有的Role对船上和岸上的Role进行移动
public void nextStep() {
MoveStrategy strategy = getNextMoveStratrgy();
int[] boat_roles = boat.getRolesNum();
int[] right_boat = new int[2];
if (strategy == MoveStrategy.P0D1) {
right_boat[0] = 0;
right_boat[1] = 1;
}
else if (strategy == MoveStrategy.P0D2) {
right_boat[0] = 0;
right_boat[1] = 2;
}
else if (strategy == MoveStrategy.P1D1) {
right_boat[0] = 1;
right_boat[1] = 1;
}
else if (strategy == MoveStrategy.P1D0) {
right_boat[0] = 1;
right_boat[1] = 0;
}
else if (strategy == MoveStrategy.P2D0) {
right_boat[0] = 2;
right_boat[1] = 0;
}
else if(strategy == MoveStrategy.END) {
right_boat[0] = 0;
right_boat[1] = 0;
}
else
return;
int need_p = right_boat[0] - boat_roles[0]; //船上还需要的牧师数量
int need_d = right_boat[1] - boat_roles[1]; //船上还需要的魔鬼数量
while(need_p < 0) {
MoveRole(boat.getRole(1));
need_p++;
}
while (need_d < 0) {
MoveRole(boat.getRole(2));
need_d++;
}
if (boat.getPos() == 0) {
while (need_p > 0) {
MoveRole(src.getRole(1));
need_p--;
}
while (need_d > 0) {
MoveRole(src.getRole(2));
need_d--;
}
}
else if (boat.getPos() == 2) {
while (need_p > 0) {
MoveRole(dst.getRole(1));
need_p--;
}
while (need_d > 0) {
MoveRole(dst.getRole(2));
need_d--;
}
}
}
- nextStep中的getRole函数是此次实验新添加的,其在BoatModel和CoastModel中定义,用于寻找所需类型的Role,其实现如下:
public RoleModel getRole(int flag) {
for (int i = 0; i < passenger.Length; i++) {
if (passenger[i] != null && passenger[i].getFlag() == flag)
return passenger[i];
}
return null;
}
public RoleModel getRole(int flag) {
for (int i = 0; i < empty.Length; i++) {
if (empty[i] != null && empty[i].getFlag() == flag)
return empty[i];
}
return null;
}