题目
3、P&D 过河游戏智能帮助实现,程序具体要求:
- 实现状态图的自动生成
- 讲解图数据在程序中的表示方法
- 利用算法实现下一步的计算
- 参考:P&D 过河游戏智能帮助实现
实现
状态图
表示方法
该图在游戏中以矩阵的形式表示,使用数字编码对游戏数据进行设置,以3P3D为例,计算公式为:Pnum * 4 + Dnum。其中,P与D均为左岸数据。
而图书局的生成依靠如下代码:
遍历所有的点,如果该点是合法的,那么说明可以计算该点到其他点的关系。否则跳过。
for (int i = 0; i < 32; i++)
{
int P = getP(i);
int D = getD(i);
bool side = getSide(i);
if ((P < D && P != 0) || (P > D && P != MAXP) || (P == MAXP && D == MAXD && !side))
{
continue;
}
else
{
Stack<int> temp = getNextNum(i);
while (temp.Count != 0)
{
matrix[i, temp.Peek()] = 1;
temp.Pop();
}
}
}
计算时,使用函数来计算,分别模拟5种情况,判断是否能够完成该情况,如果能够,就将该操作的结果插入存储器,最终返回存储器。
生成矩阵
判断如下
判断的代码如下:
public Stack<int> getNextNum(int now)
{
Stack<int> temp = new Stack<int>();
int P = getP(now);
int D = getD(now);
// 1
if (getSide(now))
{
if ((D == 2 && P == 0) || (P == MAXP - 2 && D == MAXD - 2))
{
temp.Push((P * 4 + D + 8));
}
}
else
{
if ((P == 2 && D == 2) || (P == MAXP && D == MAXD - 2))
{
temp.Push(P * 4 + D - 8 + 16);
}
}
// 2
if (getSide(now))
{
if (MAXD - D >= 2 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D + 2);
}
}
else
{
if (D >= 2 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D - 2 + 16);
}
}
// 3
if (getSide(now))
{
if (P == D && MAXD > P)
{
temp.Push(P * 4 + D + 5);
}
}
else
{
if (P == D && P > 0)
{
temp.Push(P * 4 + D - 5 + 16);
}
}
// 4
if (getSide(now))
{
if ((MAXP - P == 1 && MAXD - D == 1) || (D == 1 && P == 0))
{
temp.Push(P * 4 + D + 4);
}
}
else
{
if ((P == 1 && D == 1) || (MAXD - D == 1 && P == MAXP))
{
temp.Push(P * 4 + D - 4 + 16);
}
}
// 5
if (getSide(now))
{
if (MAXD - D > 0 && (P == MAXP || P == 0))
{
temp.Push(P * 4 + D + 1);
}
}
else
{
if (D > 0 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D - 1 + 16);
}
}
return temp;
}
计算时,使用了DFS算法,递归实现,实现较为简单,其中设置终点。代码如下:
public Stack<int> Tips(int start, int end)
{
Stack<int> temp = new Stack<int>();
bool[] dfs = new bool[32];
for (int i = 0; i < 32; i++)
{
dfs[i] = false;
}
bool flag = false;
DFS(dfs, start, temp, end, flag);
return temp;
}
public void DFS(bool[] dfs, int pos, Stack<int> temp, int end, bool flag)
{
dfs[pos] = true;
for (int i = 0; i < 32; i++)
{
if (matrix[pos, i] != -1 && !dfs[i]) {
if (!flag)
{
temp.Push(i);
}
if (i != end)
{
DFS(dfs, i, temp, end, flag);
}
else
{
flag = true;
}
}
}
}
## 其他实现:
使用了一个新的按钮,当点击这个按钮的时候,会进行计算,计算后返回存储了int的存储器,需要进行解析,并输出。
while (newStack.Count != 0)
{
int tempi = newStack.Peek();
newStack.Pop();
bool tempS = (tempi > 16) ? true : false;
int tempP = (tempi % 16) / 4;
int tempD = (tempi % 16) % 4;
if (tempS)
{
Debug.Log("前往右岸,使左岸有" + tempP + "牧师和" + tempD + "魔鬼\n");
}
else
{
Debug.Log("前往左岸,使左岸有" + tempP + "牧师和" + tempD + "魔鬼\n");
}
}
完整代码
其他代码与之前相同,只贴上新的控制类与计算路径类
graph
public class Graph
{
public int MAXP = 3;
public int MAXD = 3;
public int priestNum;
public int demonNum;
public bool boatSide;
int[,] matrix = new int[32, 32];
public Graph()
{
priestNum = 0;
demonNum = 0;
boatSide = false;
for (int i = 0; i < 32; i++)
{
for (int j = 0; j < 32; j++)
{
matrix[i, j] = -1;
}
}
for (int i = 0; i < 32; i++)
{
int P = getP(i);
int D = getD(i);
bool side = getSide(i);
if ((P < D && P != 0) || (P > D && P != MAXP) || (P == MAXP && D == MAXD && !side))
{
continue;
}
else
{
Stack<int> temp = getNextNum(i);
while (temp.Count != 0)
{
matrix[i, temp.Peek()] = 1;
temp.Pop();
}
}
}
}
public Stack<int> Tips(int start, int end)
{
Stack<int> temp = new Stack<int>();
bool[] dfs = new bool[32];
for (int i = 0; i < 32; i++)
{
dfs[i] = false;
}
bool flag = false;
DFS(dfs, start, temp, end, flag);
return temp;
}
public void DFS(bool[] dfs, int pos, Stack<int> temp, int end, bool flag)
{
dfs[pos] = true;
for (int i = 0; i < 32; i++)
{
if (matrix[pos, i] != -1 && !dfs[i]) {
if (!flag)
{
temp.Push(i);
}
if (i != end)
{
DFS(dfs, i, temp, end, flag);
}
else
{
flag = true;
}
}
}
}
public int getP(int num)
{
num = num % 16;
return num / 4;
}
public int getD(int num)
{
num = num % 16;
return num % 4;
}
public bool getSide(int num)
{
if (num >= 16)
{
return true;
}
else
{
return false;
}
}
//1 = 2P; 2 = 2D; 3 = 1P1D; 4 = 1P; 5 = 1D
public Stack<int> getNextNum(int now)
{
Stack<int> temp = new Stack<int>();
int P = getP(now);
int D = getD(now);
// 1
if (getSide(now))
{
if ((D == 2 && P == 0) || (P == MAXP - 2 && D == MAXD - 2))
{
temp.Push((P * 4 + D + 8));
}
}
else
{
if ((P == 2 && D == 2) || (P == MAXP && D == MAXD - 2))
{
temp.Push(P * 4 + D - 8 + 16);
}
}
// 2
if (getSide(now))
{
if (MAXD - D >= 2 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D + 2);
}
}
else
{
if (D >= 2 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D - 2 + 16);
}
}
// 3
if (getSide(now))
{
if (P == D && MAXD > P)
{
temp.Push(P * 4 + D + 5);
}
}
else
{
if (P == D && P > 0)
{
temp.Push(P * 4 + D - 5 + 16);
}
}
// 4
if (getSide(now))
{
if ((MAXP - P == 1 && MAXD - D == 1) || (D == 1 && P == 0))
{
temp.Push(P * 4 + D + 4);
}
}
else
{
if ((P == 1 && D == 1) || (MAXD - D == 1 && P == MAXP))
{
temp.Push(P * 4 + D - 4 + 16);
}
}
// 5
if (getSide(now))
{
if (MAXD - D > 0 && (P == MAXP || P == 0))
{
temp.Push(P * 4 + D + 1);
}
}
else
{
if (D > 0 && (P == 0 || P == MAXP))
{
temp.Push(P * 4 + D - 1 + 16);
}
}
return temp;
}
}
controller
public class Controller : MonoBehaviour
{
Data instance; //数据块
GameState states; //当前游戏状态
DemonAndPriest.Action act; //动作管理器
bool toBoat; //判断上船动作是否完成,若完成则改变Data中的状态,下同
bool turnBack; //是否船已到达对岸,需要掉头
bool toShore; //是否需要对象上岸
Graph graph;
//初始化
public void Start()
{
instance = gameObject.AddComponent<Data>() as Data;
act = gameObject.AddComponent<DemonAndPriest.Action>() as DemonAndPriest.Action;
graph = new Graph();
states = GameState.Waiting;
toBoat = false;
turnBack = false;
toShore = false;
}
//交互
public void OnGUI()
{
//显示界面
instance.SetView();
//调整当前状态,查看是否有已完成动作但未和Data同步
if (!act.Run())
{
states = GameState.Waiting;
if (toBoat)
{
instance.MoveToBoat();
toBoat = false;
} else if(toShore)
{
instance.MoveToShore();
toShore = false;
} else if (turnBack)
{
instance.SetPosition();
turnBack = false;
}
}
//判断当前游戏是否结束
if (states == GameState.Waiting)
{
states = instance.Charge();
}
//游戏进行中
if (states == GameState.Waiting || states == GameState.Moving)
{
if (states == GameState.Waiting)
{
if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 2f, 100, 30), "提示"))
{
int now = 0;
if (instance.getBoatPosition())
{
now = (3 - instance.GetPriestCount()) * 4 + (3 - instance.GetDemonCount()) + 16;
}
else
{
now = instance.GetPriestCount() * 4 + instance.GetDemonCount();
}
Debug.Log(now);
Stack<int> next = graph.Tips(now , 15);
Stack<int> newStack = new Stack<int>();
while (next.Peek() != 15)
{
next.Pop();
}
while (next.Count != 0)
{
int tempi = next.Peek();
newStack.Push(tempi);
next.Pop();
}
while (newStack.Count != 0)
{
int tempi = newStack.Peek();
newStack.Pop();
bool tempS = (tempi > 16) ? true : false;
int tempP = (tempi % 16) / 4;
int tempD = (tempi % 16) % 4;
if (tempS)
{
Debug.Log("前往右岸,使其有" + tempP + "牧师和" + tempD + "魔鬼\n");
}
else
{
Debug.Log("前往左岸,使其有" + tempP + "牧师和" + tempD + "魔鬼\n");
}
}
}
}
if (GUI.Button(new Rect (Screen.width / 10 * 3.4f, Screen.height / 10 * 2f, 100, 30), "牧师上船"))
{
if (states == GameState.Waiting)
{
if (instance.BoatCount() == 2 || instance.GetPriestCount() == 0)
{
return;
}
instance.PriestOnBoat();
act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), false);
states = GameState.Moving;
toBoat = true;
}
}
if (GUI.Button(new Rect(Screen.width / 10 * 6, Screen.height / 10 * 2f, 100, 30), "恶魔上船"))
{
if (states == GameState.Waiting)
{
if (instance.BoatCount() == 2 || instance.GetDemonCount() == 0)
{
return;
}
instance.DemonOnBoat();
act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), false);
states = GameState.Moving;
toBoat = true;
}
}
if (GUI.Button(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3.5f, 100, 30), "启程"))
{
if (states == GameState.Moving || instance.BoatCount() == 0)
{
return;
}
act.Act(instance.GetBoat(), instance.getBoatPosition(), instance.BoatCount(), true);
states = GameState.Moving;
turnBack = true;
}
if (GUI.Button(new Rect (Screen.width / 2 - 50, Screen.height / 10 * 4.5f, 100, 30), "下船"))
{
if(states != GameState.Waiting)
{
return;
}
if (instance.BoatCount() != 0)
{
instance.DownBoat();
act.Act(instance.getMoving(), instance.getBoatPosition(), instance.BoatCount(), true);
states = GameState.Moving;
toShore = true;
}
}
if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始"))
{
instance.Reload();
states = GameState.Waiting;
}
}
//胜利
else if (states == GameState.Win)
{
GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3f, 100, 30), "胜利");
if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始")) {
states = GameState.Waiting;
instance.Reload();
}
}
//游戏结束
else if (states == GameState.GameOver)
{
GUI.Label(new Rect(Screen.width / 2 - 50, Screen.height / 10 * 3f, 100, 30), "牧师死亡");
if (GUI.Button(new Rect(Screen.width / 4 * 3, Screen.height / 10 * 8f, 100, 30), "重新开始"))
{
states = GameState.Waiting;
instance.Reload();
}
}
}
}