From bfa63f0e8f59e6bc0f8242cf8023100bdd25b91f Mon Sep 17 00:00:00 2001 From: Ashby Issac Date: Tue, 27 Jan 2026 20:55:55 +0530 Subject: [PATCH] Changes for bot logic. --- Assets/Scripts/Gameplay/GameplayManager.cs | 225 +++++++++++++++---- Assets/Scripts/Gameplay/Player/PlayerBase.cs | 14 ++ Assets/Scripts/Gameplay/Player/PlayerPawn.cs | 18 +- 3 files changed, 214 insertions(+), 43 deletions(-) diff --git a/Assets/Scripts/Gameplay/GameplayManager.cs b/Assets/Scripts/Gameplay/GameplayManager.cs index a985e36..4af877c 100644 --- a/Assets/Scripts/Gameplay/GameplayManager.cs +++ b/Assets/Scripts/Gameplay/GameplayManager.cs @@ -9,8 +9,7 @@ public enum PlayerType Player1 = 0, Player2 = 1, Player3 = 2, - Player4 = 3, - Bot + Player4 = 3 } [System.Serializable] @@ -20,17 +19,26 @@ public class PlayerGameData public int startIndex; public int endIndex; public Transform playersParent; - public List playerPawnsDict; + public Dictionary playerPawnsDict; public int totalPawnsFinished = 0; } [System.Serializable] public enum MatchType { - LAN, + PVP, Bot } +public enum BotMove +{ + FinishingPathMove = 0, + SafeMove = 1, + AttackMove = 2, + NormalMove = 3, + NoMoves = 4 +} + public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader { [SerializeField] private TextMeshProUGUI diceText; @@ -45,13 +53,17 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader private PlayerType currentPlayerTypeTurn; private int currentPlayerTurnIndex = 0; - private List playerTypes = new List(); + private List allPlayerTypes = new List(); + private List botTypesInGame = new List(); - public List PlayerTypesCollection => playerTypes; + public List PlayerTypesCollection => allPlayerTypes; // private Dictionary playerPawnsDict = new Dictionary>(); private Dictionary playerGameDatasDict = new Dictionary(); + // botRuntimeMovementData: where can the bot move if a particular dice value is thrown, and based on the value set the bot move for each using a predictive approach and select based on the the priority + private Dictionary> botRuntimeMovementData = new Dictionary>(); + private TilesManager tilesManager; private int diceRolledValue; @@ -74,53 +86,119 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader CanRollDice = true; // initialize the player list from UI. - InitPlayerTypesForLAN(null); + // InitPlayerTypesForLAN(null); + InitPlayerTypesForBotMatch(PlayerType.Player1, 1); } // TODO :: Call when the UI selection is made and game starts public void InitPlayerTypesForLAN(List types) { // TODO :: 2P, 3P, 4P - playerTypes = new List { PlayerType.Player1, PlayerType.Player2, PlayerType.Player3, PlayerType.Player4 }; + allPlayerTypes = new List { PlayerType.Player1, PlayerType.Player2, PlayerType.Player3, PlayerType.Player4 }; - playerBaseHandler.InitPlayerTypes(playerTypes); + playerBaseHandler.InitPlayerTypes(allPlayerTypes); InitCurrentGamePlayerInfo(); } public void InitPlayerTypesForBotMatch(PlayerType selectedPlayerType, int botCount) { - // test data + botTypesInGame.Clear(); + allPlayerTypes.Clear(); + AssignBotTypes(selectedPlayerType, botCount); + InitBotRuntimeData(); + + allPlayerTypes.Add(selectedPlayerType); + allPlayerTypes.AddRange(botTypesInGame); + + playerBaseHandler.InitPlayerTypes(allPlayerTypes); + InitCurrentGamePlayerInfo(); + AssignPlayerAndBotStates(selectedPlayerType); + } + + private void InitBotRuntimeData() + { + botRuntimeMovementData.Clear(); + + foreach (var botType in botTypesInGame) + { + PlayerGameData playerGameData = playerGameDatasDict[botType]; + if (!botRuntimeMovementData.ContainsKey(botType)) + { + botRuntimeMovementData.Add(botType, new Dictionary()); + } + + foreach (var pawn in playerGameData.playerPawnsDict) + { + botRuntimeMovementData[botType].Add(pawn.Value.PlayerId, BotMove.SafeMove); + } + } + } + + private void AssignPlayerAndBotStates(PlayerType selectedPlayerType) + { + PlayerBase playerBase = playerBaseHandler.GetPlayerBase(selectedPlayerType); + playerBase.AssignBotState(PawnType.User); + + foreach (PlayerType playerType in botTypesInGame) + { + playerBase = playerBaseHandler.GetPlayerBase(playerType); + playerBase.AssignBotState(PawnType.Bot); + } + } + + private void AssignBotTypes(PlayerType selectedPlayerType, int botCount) + { + int addedBots = 0; if (botCount == 1) { - var playerType = (PlayerType)((int)selectedPlayerType + 2 < Enum.GetValues(typeof(PlayerType)).Length ? + var playerType = (PlayerType)((int)selectedPlayerType + 2 < Enum.GetValues(typeof(PlayerType)).Length ? (int)selectedPlayerType + 2 : (int)selectedPlayerType - 2); - + botTypesInGame.Add(playerType); + } + else if (botCount == 2) + { + foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType))) + { + if (enumType == selectedPlayerType) continue; + + botTypesInGame.Add(enumType); + addedBots++; + + if (addedBots == botCount) break; + } } else { - + foreach (PlayerType enumType in Enum.GetValues(typeof(PlayerType))) + { + if (enumType == selectedPlayerType) continue; + + botTypesInGame.Add(enumType); + } } } // TODO :: Call based on 2P/3P/4P public void InitCurrentGamePlayerInfo() { - currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex]; + currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; // initialize the board based on the player types foreach (PlayerGameData playerGameData in playerGameDatas) { - if (!playerTypes.Contains(playerGameData.playerType)) + if (!allPlayerTypes.Contains(playerGameData.playerType)) continue; + Debug.Log($"playerGameData.playerType: {playerGameData.playerType}"); playerGameDatasDict.Add(playerGameData.playerType, playerGameData); - playerGameDatasDict[playerGameData.playerType].playerPawnsDict = new List(); + playerGameDatasDict[playerGameData.playerType].playerPawnsDict = new Dictionary(); foreach (Transform playerPawnChild in playerGameData.playersParent) { if (!playerPawnChild.gameObject.activeInHierarchy) continue; - playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Add(playerPawnChild.GetComponent()); + var pawn = playerPawnChild.GetComponent(); + playerGameDatasDict[playerGameData.playerType].playerPawnsDict.Add(pawn.PlayerId, pawn); } } } @@ -129,9 +207,9 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader { foreach (var playerPawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) { - if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath) continue; + if (playerPawn.Value.GetPlayerState() == PlayerState.InFinishingPath) continue; - playerPawn.SetPlayerSelectionState(state); + playerPawn.Value.SetPlayerSelectionState(state); } } @@ -149,23 +227,9 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader // provide option to select a pawn from the list // also play a simple animation before selecting EnablePlayerSelectionStates(true); - CanRollDiceAgain = true; - bool AreAllPawnsInFinishingPath = false; - foreach (var pawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) - { - if (pawn.GetPlayerState() == PlayerState.InFinishingPath && pawn.GetPlayerState() != PlayerState.HasFinished) - { - AreAllPawnsInFinishingPath = true; - continue; - } - - AreAllPawnsInFinishingPath = false; - break; - } - - if (AreAllPawnsInFinishingPath) + if (AreAllPawnsInFinishingPath()) CanRollDice = true; pointerMeshRend.material = selectMat; @@ -174,7 +238,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader else // if there are any other pawns that are in safe or moving state { // for player's logic - IEnumerable availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Select(pawn => pawn) + IEnumerable availPlayers = playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict.Values.Select(pawn => pawn) .Where(pawn => pawn.GetPlayerState() == PlayerState.InSafeZone || pawn.GetPlayerState() == PlayerState.Moving || pawn.GetPlayerState() == PlayerState.InFinishingPath); @@ -204,6 +268,7 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader Debug.Log($"CustomAvailablePlayers: {customAvailPlayers}"); if (customAvailPlayers < 1) { + // TODO :: Switch the player once the dice rolling has completed SwitchPlayer(); CanRollDice = true; } @@ -212,6 +277,24 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader } } + private bool AreAllPawnsInFinishingPath() + { + bool areAllPawnsInFinishingPath = false; + foreach (var pawn in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) + { + if (pawn.Value.GetPlayerState() == PlayerState.InFinishingPath && pawn.Value.GetPlayerState() != PlayerState.HasFinished) + { + areAllPawnsInFinishingPath = true; + continue; + } + + areAllPawnsInFinishingPath = false; + break; + } + + return areAllPawnsInFinishingPath; + } + public void OnPawnSelected(PlayerPawn playerPawn) { EnablePlayerSelectionStates(false); @@ -294,21 +377,21 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader Debug.Log($"currentPlayerTurn: {currentPlayerTypeTurn}"); Debug.Log($"currentPlayerTurnIndex: {currentPlayerTurnIndex}"); - if (playerTypes.Count == 1) + if (allPlayerTypes.Count == 1) { Debug.LogError($"GAME IS OVER"); return; } - if (currentPlayerTypeTurn == playerTypes[playerTypes.Count - 1]) + if (currentPlayerTypeTurn == allPlayerTypes[allPlayerTypes.Count - 1]) { currentPlayerTurnIndex = 0; - currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex]; + currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } else { currentPlayerTurnIndex++; - currentPlayerTypeTurn = playerTypes[currentPlayerTurnIndex]; + currentPlayerTypeTurn = allPlayerTypes[currentPlayerTurnIndex]; } diceText.text = $"{0}"; @@ -323,6 +406,64 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader if (playerPawn) playerPawn.SetPlayerState(tilesManager.RetrieveTileBasedOnIndex(playerPawn.CurrentTileIndex).IsSafeZone ? PlayerState.InSafeZone : PlayerState.Moving); + + Debug.Log($"botTypesInGame.Contains(currentPlayerTypeTurn): {botTypesInGame.Contains(currentPlayerTypeTurn)}"); + + if (!CanRollDiceAgain && botTypesInGame.Contains(currentPlayerTypeTurn)) // TODO :: Double check calling of the function + { + Invoke(nameof(RollDiceForBot), 1f); + } + } + + private void RollDiceForBot() + { + Debug.Log($"RollDiceForBot"); + + OnDiceRolled(UnityEngine.Random.Range(1, Ludo_3D_Constants.Max_Dice_Rolls + 1)); + } + + // TODO :: Call right after the dice is rolled with the animation + // What happens when you get a 6 + private void SelectPawnFromBotBase() + { + var botPawnsDict = botRuntimeMovementData[currentPlayerTypeTurn]; // set the data inside this dict + + // check the data from the playerGameDataDict + // change playerPawnsDict to list + + // only select the pawns that are active + // if no pawns have left the home select the first pawn inside the base + // + foreach (var keyValuePair in playerGameDatasDict[currentPlayerTypeTurn].playerPawnsDict) + { + var playerPawn = keyValuePair.Value; + var possibleLandingIndex = playerPawn.CurrentTileIndex + diceRolledValue; + + if (playerPawn.GetPlayerState() == PlayerState.HasFinished) + { + botPawnsDict.Remove(playerPawn.PlayerId); // TODO :: Double check logic + continue; + } + + Tile tileData = tilesManager.RetrieveTileBasedOnIndex(possibleLandingIndex); + if (playerPawn.GetPlayerState() == PlayerState.InFinishingPath || possibleLandingIndex > playerGameDatasDict[currentPlayerTypeTurn].endIndex) + { + botPawnsDict[playerPawn.PlayerId] = BotMove.FinishingPathMove; + continue; + } + else if (tileData.IsSafeZone || playerPawn.GetPlayerState() == PlayerState.InHome) + { + botPawnsDict[playerPawn.PlayerId] = BotMove.SafeMove; + } + else if (tileData.PlayerPawn != null) + { + botPawnsDict[playerPawn.PlayerId] = BotMove.AttackMove; + } + else + { + botPawnsDict[playerPawn.PlayerId] = BotMove.NormalMove; + } + } } private void MoveThroughTiles(PlayerPawn playerPawn, int index, int targetIndex) @@ -486,10 +627,10 @@ public class GameplayManager : MonoBehaviour, IBase, IBootLoader, IDataLoader CanRollDiceAgain = false; SwitchPlayer(); - if (playerTypes.Contains(currentPlayerTypeTurn)) - playerTypes.Remove(currentPlayerTypeTurn); + if (allPlayerTypes.Contains(currentPlayerTypeTurn)) + allPlayerTypes.Remove(currentPlayerTypeTurn); - Debug.Log($"PlayerTypes: {playerTypes.Count}"); + Debug.Log($"PlayerTypes: {allPlayerTypes.Count}"); } else { diff --git a/Assets/Scripts/Gameplay/Player/PlayerBase.cs b/Assets/Scripts/Gameplay/Player/PlayerBase.cs index 8676036..ea3939d 100644 --- a/Assets/Scripts/Gameplay/Player/PlayerBase.cs +++ b/Assets/Scripts/Gameplay/Player/PlayerBase.cs @@ -13,6 +13,11 @@ public class PlayerBase : MonoBehaviour [SerializeField] private BasePlacementData[] basePlacementDatas; [SerializeField] private PlayerPawn[] playerPawns; + public bool IsBotBase + { + get; private set; + } + public PlayerType GetPlayerType() => playerType; public void InitPlayerData() @@ -23,6 +28,15 @@ public class PlayerBase : MonoBehaviour } } + public void AssignBotState(PawnType pawnType) + { + IsBotBase = pawnType == PawnType.Bot; + for (int idx = 0; idx < playerPawns.Length; idx++) + { + playerPawns[idx].AssignBotPlayerState(IsBotBase); + } + } + public Transform GetBasePlacementDataPosition(int idx) { return basePlacementDatas[idx].placementTransform; diff --git a/Assets/Scripts/Gameplay/Player/PlayerPawn.cs b/Assets/Scripts/Gameplay/Player/PlayerPawn.cs index 66f60a6..677cd7a 100644 --- a/Assets/Scripts/Gameplay/Player/PlayerPawn.cs +++ b/Assets/Scripts/Gameplay/Player/PlayerPawn.cs @@ -11,6 +11,12 @@ public enum PlayerState HasFinished } +public enum PawnType +{ + User, + Bot +} + public class PlayerPawn : MonoBehaviour { [SerializeField] private PlayerState playerState; @@ -33,6 +39,16 @@ public class PlayerPawn : MonoBehaviour get; private set; } + public bool IsBotPlayer + { + get; private set; + } + + public void AssignBotPlayerState(bool state) + { + IsBotPlayer = state; + } + public void SetPlayerSelectionState(bool state) { canSelectPlayerFromHome = state; @@ -68,7 +84,7 @@ public class PlayerPawn : MonoBehaviour private void OnMouseDown() { - if (!canSelectPlayerFromHome) return; + if (IsBotPlayer || !canSelectPlayerFromHome) return; SetGameplayManager(); gameplayManager.OnPawnSelected(this);