P&D 过河游戏智能帮助实现,程序具体要求:
- 实现状态图的自动生成
- 讲解图数据在程序中的表示方法
- 利用算法实现下一步的计算
游戏状态
游戏过程实际上是游戏状态之间的转换,状态记录的内容包括:
public class IState {
public int leftPriests;
public int leftDevils;
public int rightPriests;
public int rightDevils;
public bool boat;//船在左岸true或右案false
public IState parent;//上一个状态
}
-
初始状态
public static IState state = new IState(0, 0, 3, 3, false, null);
-
结束状态
public static IState endState = new IState(3, 3, 0, 0, true, null);
状态转换
游戏中我们可以通过点击移动人物和船来改变状态,一个状态向下一个状态的所有动作行为包括:
- 船在左岸
- 单人过河
- 牧师过河
- 魔鬼过河
- 双人过河
- 牧师 + 牧师过河
- 牧师 + 魔鬼过河
- 魔鬼 + 魔鬼过河
- 单人过河
- 船在右岸
- 单人过河
- 牧师过河
- 魔鬼过河
- 双人过河
- 牧师 + 牧师过河
- 牧师 + 魔鬼过河
- 魔鬼 + 魔鬼过河
- 单人过河
思路就是根据当前的状态和当前状态可能的下一个状态,找到能达到终点状态的一条路径。可以用BFS来实现:
-
当前状态进入队列。
-
队列不为空:
-
队头出队。
-
访问状态节点。
- 结束:回溯至开始状态输出
- 没有结束:计算下一个合法状态并压入队列。
-
public static IState bfs(IState start, IState end) {
Queue<IState> found = new Queue<IState>();
Queue<IState> visited = new Queue<IState>();
IState temp = new IState(start.leftPriests, start.leftDevils, start.rightPriests, start.rightDevils, start.boat, null);//当前开始状态
found.Enqueue(temp);//进入队列
while (found.Count > 0) {//队列不为空
temp = found.Peek();//队头出队
if (temp == end) {//结束,回溯到开始状态并返回
while (temp.parent != start) {
temp = temp.parent;
}
return temp;
}
found.Dequeue();
visited.Enqueue(temp);
//计算下一个合法状态
//在左岸
if (temp.boat) {
//移动一个牧师
if (temp.leftPriests > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = false;
next.leftPriests--;
next.rightPriests++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动一个魔鬼
if (temp.leftDevils > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = false;
next.leftDevils--;
next.rightDevils++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动1魔鬼1牧师
if (temp.leftDevils > 0 && temp.leftDevils > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = false;
next.leftPriests--;
next.leftDevils--;
next.rightPriests++;
next.rightDevils++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动两个魔鬼
if (temp.leftDevils > 1) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = false;
next.leftDevils -= 2;
next.rightDevils += 2;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动两个牧师
if (temp.leftPriests > 1) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = false;
next.leftPriests -= 2;
next.rightPriests += 2;
next.parent = new IState(temp);
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
} else {//在右岸
//移动一个牧师
if (temp.rightPriests > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = true;
next.rightPriests--;
next.leftPriests++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动一个魔鬼
if (temp.rightDevils > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = true;
next.rightDevils--;
next.leftDevils++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动1魔鬼1牧师
if (temp.rightDevils > 0 && temp.rightDevils > 0) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = true;
next.rightPriests--;
next.rightDevils--;
next.leftPriests++;
next.leftDevils++;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动两个魔鬼
if (temp.rightDevils > 1) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = true;
next.rightDevils -= 2;
next.leftDevils += 2;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
//移动两个牧师
if (temp.rightPriests > 1) {
IState next = new IState(temp);
next.parent = new IState(temp);
next.boat = true;
next.rightPriests -= 2;
next.leftPriests += 2;
if (next.valid() && !visited.Contains(next) && !found.Contains(next)) {
found.Enqueue(next);
}
}
}
}
return null;
}
获取游戏状态
最后在点击过河的时候获取当前游戏状态。
void OnMouseDown() {
if (gameObject.name == "boat") {
action.moveBoat ();
int from_priest = controller.fromCoast.getCharacterNum()[0];
int from_devil = controller.fromCoast.getCharacterNum()[1];
int to_priest = controller.toCoast.getCharacterNum()[0];
int to_devil = controller.toCoast.getCharacterNum()[1];
bool location = controller.boat.get_to_or_from() ==-1 ? true : false;
int[] boatCount = controller.boat.getCharacterNum ();
if (location) { // boat at toCoast
to_priest += boatCount[0];
to_devil += boatCount[1];
} else { // boat at fromCoast
from_priest += boatCount[0];
from_devil += boatCount[1];
}
state = new IState(to_priest, to_devil, from_priest, from_devil, location , null);
} else {
action.characterIsClicked (characterController);
}
}