Hello,
I am making a game like tiger and goats where goats target is to trap the tigers and restrict their movements, while tigers target is to capture 5 goats. I am trying to make AI for tiger for which i am trying to use minmax algorithm. I have done some research and implement the algorithm but it does not work as intended. here are some scripts to give you a better idea of what i am trying to do.
AIController.cs:
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
public class AIController : MonoBehaviour
{
[SerializeField] private GameObject EmptyTiger;
[SerializeField] private GameObject EmptyGoat;
[SerializeField] private GameManager _GameManager;
[SerializeField] private TurnManager _TurnManager;
[SerializeField] private Spawner _Spawner;
[SerializeField] public List<TigerController> AllSpanwedTigers = new List<TigerController>();
[SerializeField] private List<GoatMover> AllSpanwedGoats = new List<GoatMover>();
//MinMax Variables
public int Depth;
public SpawnPoint bestMove;
public void AddTiger(GameObject _tiger)
{
AllSpanwedTigers.Add(_tiger.GetComponent<TigerController>());
}
void Start()
{
_GameManager = FindObjectOfType<GameManager>();
_TurnManager = FindObjectOfType<TurnManager>();
}
public void PlayMove()
{
//_TurnManager.SwitchTurn();
// When Tiger is AI
if (_GameManager.PlayerMode == Modes.GOATS)
{
int Difficulty = PlayerPrefs.GetInt("difficulty", 0);
switch (Difficulty)
{
// case 0:
// {
// //AI is Tigers
// List<TigerController> NewTigerList = new List<TigerController>();
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// NewTigerList.Add(AllSpanwedTigers[i]);
// }
// int randomNumber = Random.Range(0, NewTigerList.Count);
// bool Moved = NewTigerList[randomNumber].AbleToMove();
// while (!Moved && NewTigerList.Count > 0)
// {
// NewTigerList.RemoveAt(randomNumber);
// randomNumber = Random.Range(0, NewTigerList.Count);
// Moved = NewTigerList[randomNumber].AbleToMove();
// }
// NewTigerList[randomNumber].MoveToPoint();
// break;
// }
// case 1:
// {
// //AI is Tigers
// List<TigerController> NewTigerList = new List<TigerController>();
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// NewTigerList.Add(AllSpanwedTigers[i]);
// }
// int randomNumber = Random.Range(0, NewTigerList.Count);
// bool Moved = NewTigerList[randomNumber].AbleToMove();
// while (!Moved && NewTigerList.Count > 0)
// {
// randomNumber = Random.Range(0, NewTigerList.Count);
// Moved = NewTigerList[randomNumber].AbleToMove();
// }
//
// NewTigerList[randomNumber].MoveToPoint();
// break;
// }
case 2:
{
Debug.Log("Hard Mode");
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// if (AllSpanwedTigers[i].CanKillGoat())
// {
// AllSpanwedTigers[i].MoveToPoint();
// return;
// }
// }
GoatsCaptured = _GameManager.CapturedGoats;
MinMax(true, 0, int.MinValue, int.MaxValue);
// MinMax(false, 0);
if (bestMove.connectedTiger != null)
{
bestMove.connectedTiger.CanDoMove(bestMove);
return;
}
Debug.Log("Connected Tiger is Empty");
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// if (AllSpanwedTigers[i].CanDoMove(bestMove))
// {
// Debug.Log("Moving Tiger");
// return;
// }
// }
Debug.Log("Cant Do Move");
// bool tigerFound = false;
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// if (AllSpanwedTigers[i].CanKillGoat())
// {
// AllSpanwedTigers[i].MoveToPoint();
// tigerFound = true;
// break;
// }
// }
//
// if (!tigerFound)
// {
// List<TigerController> NewTigerList = new List<TigerController>();
// for (int i = 0; i < AllSpanwedTigers.Count; i++)
// {
// NewTigerList.Add(AllSpanwedTigers[i]);
// }
// int randomNumber = Random.Range(0, NewTigerList.Count);
// bool Moved = NewTigerList[randomNumber].AbleToMove();
// while (!Moved && NewTigerList.Count > 0)
// {
// NewTigerList.RemoveAt(randomNumber);
// randomNumber = Random.Range(0, NewTigerList.Count);
// Moved = NewTigerList[randomNumber].AbleToMove();
// }
//
// NewTigerList[randomNumber].MoveToPoint();
//
// // if (!Moved && cycles >= AllSpanwedTigers.Count)
// // {
// // // Cant Move any Tigers
// // //Other Player Won
// // }
// }
//
//
//
// // GoatMover[] AllGoats = FindObjectsOfType<GoatMover>();
// // float MinimumDistance = Mathf.Infinity;
// // Transform NearestTiger = null;
// // List<TigerController> CopiedList = new List<TigerController>();
// // for (int i = 0; i < AllSpanwedTigers.Count; i++)
// // {
// // CopiedList.Add(AllSpanwedTigers[i]);
// // }
// // for (int i = 0; i < CopiedList.Count; i++)
// // {
// // for (int j = 0; j < AllGoats.Length; j++)
// // {
// // float distance = Vector3.Distance(CopiedList[i].transform.position,
// // AllGoats[j].transform.position);
// // if (distance < MinimumDistance)
// // {
// // NearestTiger = CopiedList[i].transform;
// // }
// // }
// // }
// //
// // int cycles = 1;
// // bool Moved;
// // // bool Moved = NearestTiger.GetComponent<TigerController>().MoveToPoint();
// // do
// // {
// // MinimumDistance = Mathf.Infinity;
// // Moved = NearestTiger.GetComponent<TigerController>().MoveToPoint();
// // CopiedList.Remove(NearestTiger.GetComponent<TigerController>());
// // for (int i = 0; i < CopiedList.Count; i++)
// // {
// // for (int j = 0; j < AllGoats.Length; j++)
// // {
// // float distance = Vector3.Distance(CopiedList[i].transform.position,
// // AllGoats[j].transform.position);
// // if (distance < MinimumDistance)
// // {
// // NearestTiger = CopiedList[i].transform;
// // }
// // }
// // }
// //
// // cycles++;
// // } while (!Moved && cycles < CopiedList.Count);
// //
// // if (!Moved && cycles >= AllSpanwedTigers.Count)
// // {
// // // Cant Move any Tigers
// // //Other Player Won
// // }
// //Move tigers
break;
}
}
}
else
{
int difficulty = PlayerPrefs.GetInt("difficulty", 0);
switch (difficulty)
{
case 0:
{
break;
}
case 1:
{
break;
}
case 2:
{
break;
}
}
//AI is Goats
if (_GameManager.CanSpawnGoats())
{
//SpawnNewGoat
_Spawner.SpawnGoatAtRandomPoint();
_GameManager.GoatSpawned();
}
else
{
List<GoatMover> AllGoatMovers = new List<GoatMover>();
Debug.Log("moving goats from AI");
for (int i = 0; i < _GameManager.SpawnedGoats.Count; i++)
{
AllGoatMovers.Add(_GameManager.SpawnedGoats[i].GetComponent<GoatMover>());
}
int randomNumber = Random.Range(0, AllGoatMovers.Count);
bool Moved = AllGoatMovers[randomNumber].MoveToPoint();
while (!Moved && AllGoatMovers.Count > 0)
{
AllGoatMovers.RemoveAt(randomNumber);
randomNumber = Random.Range(0, AllGoatMovers.Count);
Moved = AllGoatMovers[randomNumber].MoveToPoint();
}
//Move One Of the Goat
}
}
}
private int Evaluate(int depth = 0)
{
// Board.Player winner = board.Winner;
// if (winner == Board.Player.None)
// {
if (GoatsCaptured >= 5)
{
if (_GameManager.PlayerMode == Modes.GOATS)
{
return int.MaxValue;
}
else if (_GameManager.PlayerMode == Modes.TIGERS)
{
return int.MinValue;
}
}
int MovableTigers = 0;
TigerController[] AllTigers = FindObjectsOfType<TigerController>();
for (int i = 0; i < AllTigers.Length; i++)
{
if (AllTigers[i].AbleToMove())
{
MovableTigers++;
}
}
if (MovableTigers <= 0)
{
if (_GameManager.PlayerMode == Modes.GOATS)
{
return int.MinValue;
}else if (_GameManager.PlayerMode == Modes.TIGERS)
{
return int.MaxValue;
}
}
int NumberOfClosedSpaces = 0;
SpawnPoint[] AllSpawnPoints = FindObjectsOfType<SpawnPoint>();
for (int i = 0; i < AllSpawnPoints.Length; i++)
{
if (AllSpawnPoints[i].IsOccupied)
{
NumberOfClosedSpaces++;
}
}
return 300 * MovableTigers + 700 * GoatsCaptured/
- 700 * NumberOfClosedSpaces - depth;
//
// if (winner == Board.Player.Goat)
// {
// return -INF;
// }
// else if (winner == Board.Player.Tiger)
// {
// return INF;
// }
// return 0;
}
public int GoatsCaptured = 0;
private int MinMax(bool isMax, int depth, int alpha, int beta)
// private int MinMax(bool isMax, int depth)
{
// Debug.Log("Entered Minmax");
int score = Evaluate(depth);
// Debug.Log("Evaluation Complete");
if (depth == Depth || float.IsPositiveInfinity(Mathf.Abs(score)))
{
return score;
}
if (!isMax)
{
Debug.Log("In Goats Turn");
localTurn = Modes.GOATS;
int value = 100000000;
// List<SpawnPoint> LegalMoves = GenerateMovesList();
foreach (SpawnPoint move in GenerateMovesList())
{
MakeMove(move,"G");
int value_t = MinMax(true, depth + 1, alpha, beta);
// int value_t = MinMax(true, depth + 1);
//beta = Mathf.Min(beta, value_t);
if (value_t < value)
{
value = value_t;
//beta = Mathf.Min(beta, value);
if (depth == 0)
{
bestMove = move;
}
}
RevertMove(move,"G");
// if (alpha >= beta)
// {
// break;
// }
}
return value;
}
else
{
Debug.Log("In Tigers Turn");
localTurn = Modes.TIGERS;
int value = -100000000;
// List<SpawnPoint> LegalMoves = GenerateMovesList();
foreach (SpawnPoint move in GenerateMovesList())
{
MakeMove(move,"T");
int value_t = MinMax(false, depth + 1, alpha, beta);
// int value_t = MinMax(false, depth + 1);
if (value_t > value)
{
value = value_t;
//alpha = Mathf.Max(alpha, value);
if (depth == 0)
{
bestMove = move;
}
}
RevertMove(move,"T");
// if (alpha >= beta)
// {
// break;
// }
}
return value;
}
}
private void RevertMove(SpawnPoint move,string NameOfPlayer)
{
if (NameOfPlayer == "T")
{
move.connectedTiger.CurrentPoint.FreeSpace();
move.connectedTiger.CurrentPoint = move.connectedTiger.OldPoint;
move.connectedTiger.CurrentPoint.SpaceOccupied(move.connectedTiger.gameObject);
}
else
{
// Debug.Log("Calling Revert Move");
// move.connectedTiger.CurrentPoint = move.connectedTiger.OldPoint;
Destroy(move.OccupyingObject);
move.FreeSpace();
}
}
private void MakeMove(SpawnPoint move,string PlayerName)
{
move.IsOccupied = true;
if ("T" == PlayerName)
{
// GameObject temp = Instantiate(EmptyTiger, move.transform.position, Quaternion.identity);
// temp.GetComponent<TigerController>().AddCurrentPoint(move);
move.connectedTiger.OldPoint = move.connectedTiger.CurrentPoint;
move.connectedTiger.OldPoint.FreeSpace();
move.connectedTiger.CurrentPoint = move;
move.SpaceOccupied(move.connectedTiger.gameObject);
if (move.CapturePoint)
{
//Increase Number Of Captured Goats
Debug.Log("Capturing Goats");
GoatsCaptured++;
}
}
else if ("G" == PlayerName)
{
GameObject temp = Instantiate(EmptyGoat, move.transform.position, Quaternion.identity);
temp.GetComponent<GoatMover>().AddCurrentPoint(move);
move.SpaceOccupied(temp);
}
}
private Modes localTurn;
private List<SpawnPoint> GenerateMovesList()
{
List<SpawnPoint> LegalMoves = new List<SpawnPoint>();
if (localTurn == Modes.GOATS)
{
if (_GameManager.spawnedGoats < _GameManager.NumberOfStartingGoats)
{
SpawnPoint[] AllSpawnPoints = FindObjectsOfType<SpawnPoint>();
for (int i = 0; i < AllSpawnPoints.Length; i++)
{
if (!AllSpawnPoints[i].IsOccupied)
{
LegalMoves.Add(AllSpawnPoints[i]);
}
}
}
else
{
GoatMover[] AllGoatMovers = FindObjectsOfType<GoatMover>();
for (int i = 0; i < AllGoatMovers.Length; i++)
{
if (AllGoatMovers[i].AbleToMove())
{
for (int j = 0; j < AllGoatMovers[i].CurrentPoint.SupportedPoints.Count; j++)
{
LegalMoves.Add(AllGoatMovers[i].CurrentPoint.SupportedPoints[j]);
}
}
}
}
}
else
{
// List<TigerController> AllTigerControllers = FindObjectsOfType<TigerController>().ToList();
List<TigerController> AllTigerControllers = new List<TigerController>();
for (int i = 0; i < AllSpanwedTigers.Count; i++)
{
AllTigerControllers.Add(AllSpanwedTigers[i]);
}
Debug.Log($"All Tigers Are {AllTigerControllers.Count}");
for (int i = 0; i < AllTigerControllers.Count; i++)
{
if (AllTigerControllers[i].AbleToMove())
{
for (int j = 0; j < AllTigerControllers[i].CurrentPoint.SupportedPoints.Count; j++)
{
if (AllTigerControllers[i].CanKillGoat())
{
if (_Spawner.HaveGoat(AllTigerControllers[i].CurrentPoint.SupportedPoints[j]))
{
int[] values = AllTigerControllers[i]
.GetFinalValuesToKillGoat(AllTigerControllers[i].CurrentPoint.SupportedPoints[j]);
if (_Spawner.IsPointValid(values[0],values[1]))
{
LegalMoves.Add(_Spawner.GetPointAt(values[0],values[1]));
_Spawner.GetPointAt(values[0], values[1]).CapturePoint = true;
if (!AllTigerControllers[i].isEmpty)
{
_Spawner.GetPointAt(values[0], values[1]).connectedTiger = AllTigerControllers[i];
}
}
}
}
if (!AllTigerControllers[i].CurrentPoint.SupportedPoints[j].IsOccupied)
{
LegalMoves.Add(AllTigerControllers[i].CurrentPoint.SupportedPoints[j]);
if (!AllTigerControllers[i].isEmpty)
{
AllTigerControllers[i].CurrentPoint.SupportedPoints[j].connectedTiger = AllTigerControllers[i];
}
}
}
}
}
}
// LegalMoves.Shuffle();
return LegalMoves;
}
}
Can anyone see this and let me know what i am doing wrong in my code or a tutorial that someone can point me to will be great help.