ここに問題があります。AI ベースのゲームの戦闘シミュレーターに取り組んでいます。AI は、敵がすべての動きに対して最善の動きをしたときに、彼にとって最善の動きを計算する必要があります。
私のチームには 5 つの移動可能な X ユニットがあり、対戦相手には 5 つの移動可能な Y ユニットがあります。X と Y > 0 の場合、アルファ ベータ プルーニングを使用して、考えられる結果をそれぞれ生成し、最終的に最良のものを取り出します。問題は、各結果をシチュエーションに保存するという事実です。このシチュエーションにはリストが保存されますが、リストには保存されたオブジェクトへの参照が含まれているため、移動が同じシチュエーションに保存されます (1 ユニットの 5 つの移動すべて)。
私たちの 2 つのユニットと彼らのユニットの 1 つを想像してみてください。状況を作成し、それに 5 つの方向のいずれかを持つ 1 つのユニットを追加します。次に、2 番目のユニットに 1 つの方向を追加し、次に敵ユニットに追加します。これで、これを保存したい最終状況が得られました。次に、2 番目のユニット (つまり、敵ユニットなし) での状況から、敵の別の動きを状況に追加し、その新しい状況がより良い場合は保存します。しかし、C# はリストの参照を使用するため、この状況は他の敵の動きも含まれている状況です。
コードは少し大きいですが、私は本当にここで立ち往生しているので、これを修正するためのアイデアを手伝ってくれる時間があれば幸いです.
public Situation RecursiveMaxTree(List<SimAnt> undone, int index, bool[,] positions, Situation situation)
{
SimAnt front = undone[index];
int max = situation.Max;
List<SimAnt> bestmoves = new List<SimAnt>();
int frontY = front.position.Y;
int frontX = front.position.X;
if (!front.isEnemy() && undone[index + 1].isEnemy())//cutoff activated----------------------------------------------------------------------------
{
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
positions[newX, newY] = true;
List<SimAnt> newallAnts = situation.GetList;
Friend newant = new Friend(newX, newY);
newant.direction = direction;
newallAnts.Add(newant);
Situation current = RecursiveMinTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max > max)
{
max = current.Max;
bestmoves = current.GetList;
}
}
}
}
else //max-------------------------------------------------------------------------------------------------------------------------------------
{
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
positions[newX, newY] = true;
List<SimAnt> newallAnts = situation.GetList.Clone();
Friend newant = new Friend(newX, newY);
newant.direction = direction;
newallAnts.Add(newant);
Situation current = RecursiveMaxTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max > max)
{
max = current.Max;
bestmoves = current.GetList;
}
}
}
}
return new Situation(bestmoves, max);
}
Situation RecursiveMinTree(List<SimAnt> undone, int index, bool[,] positions, Situation situation)
{
SimAnt front = undone[index];
int max = situation.Max;
int frontY = front.position.Y;
int frontX = front.position.X;
int currentmin = 100;
foreach (Direction direction in directions)
{
int newX = GameState.WrapHorizonal(frontX + direction.toVector().X);
int newY = GameState.WrapVertical(frontY + direction.toVector().Y);
if (!positions[newX, newY] && map.isNotWater(newX, newY))
{
//add the updated ant to the new allAnts list
List<SimAnt> newallAnts = situation.GetList;
Foe newant = new Foe(newX, newY);
newallAnts.Add(newant);
if (index >= undone.Count - 1)
{
return new Situation(situation.GetList, CalculateBattleValue(situation.GetList));
}
else
{
positions[newX, newY] = true;
Situation current = RecursiveMinTree(undone, index + 1, positions, new Situation(newallAnts, max));//geeft min van alle enemy options
positions[newX, newY] = false;
if (current.Max < max)
return current;
else if (current.Max < currentmin)
{
currentmin = current.Max;
}
}
}
}
return new Situation(situation.GetList, currentmin);
}
class Situation
{
public Situation(List<SimAnt> ants, int max)
{
this.max = max;
this.ants = ants;
}
List<SimAnt> ants;
int max;
public List<SimAnt> GetList
{ get { return ants; } }
public int Max
{ get { return max; } }
}
よろしく、私