// public void OnChgDropdown(Dropdown ddobj, GamePenguin.PenguinColor col) { GamePenguin.PenguinColor col2; // Update which colors are selected, and player status // m_refSC.PlayersActiveStatus[col] = (GameManager.PlayerStatus)ddobj.value; // Repeatedly scan current selections until all inconsistencies are removed // while (true) { col2 = ValidateDropdown(col); if (col2 == GamePenguin.PenguinColor._None) { break; } m_refSC.PlayersActiveStatus[col2] = GameManager.PlayerStatus.Human; } // Update display after validation // UpdateDropdowns(); // Set status of play button, based on if two or more players are enabled // SetPlayBtn(); }
/// <summary> /// Get sequence of players taking turns for AI move evaluation (Also works backwards) /// </summary> /// <param name="prevPlayer">Player that just finsihed moving or being evaluated</param> /// <param name="direction">Move forward (1) or backward (-1) one player?</param> /// <remarks> /// CALLED BY: NextEvalPlayer(), PrevEvalPlayer(), AIBrain::Minimax**() /// </remarks> /// <returns></returns> /// public GamePenguin.PenguinColor GetPlayerIndex(GamePenguin.PenguinColor prevPlayer, int direction) { int newPlayerIndex = (int)prevPlayer; do { // Avoid underflow if going backwards // if (direction < 0 && newPlayerIndex == (int)GamePenguin.PenguinColor.Red) { newPlayerIndex = (int)GamePenguin.PenguinColor._None; } newPlayerIndex += direction; // Increment/Decrement to next/previous player // Wrap around from end of list to start // if (direction > 0 && newPlayerIndex == (int)GamePenguin.PenguinColor._None) { newPlayerIndex = (int)GamePenguin.PenguinColor.Red; } } while (!tablePlayerPenguins.ContainsKey((GamePenguin.PenguinColor)newPlayerIndex)); // Skip index values for inactive players (Not in list) return((GamePenguin.PenguinColor)newPlayerIndex); }
/// <summary> /// Verify values selected in dropdowns and remove inconsistencies (i.e. More than 1 "Youngest" or "AI") /// </summary> /// <param name="lastChanged"> /// The player color the user just changed. This is assumed to be the choice the user wants, and any /// previous selection of "AI" or "Youngest" is what gets changed. /// </param> /// <returns> /// Returns color value that is redundant ("AI" or "Youngest") and should be changed to "Human" (because we can have any number of human players) /// </returns> /// <remarks> /// (This requires its own method/loop because you cannot modify a container /// while it's being looped through -- So we have to break and restart whenever /// a problem is found.) /// </remarks> /// GamePenguin.PenguinColor ValidateDropdown(GamePenguin.PenguinColor lastChanged) { GamePenguin.PenguinColor lastAIFound = GamePenguin.PenguinColor._None; GamePenguin.PenguinColor lastYgFound = GamePenguin.PenguinColor._None; foreach (GamePenguin.PenguinColor c in m_refSC.PlayersActiveStatus.Keys) { if (m_refSC.PlayersActiveStatus[c] == GameManager.PlayerStatus.Youngest) { if (lastYgFound != GamePenguin.PenguinColor._None) // One was previously found { return((lastYgFound == lastChanged) ? c : lastYgFound); } else { lastYgFound = c; } } else if (m_refSC.PlayersActiveStatus[c] == GameManager.PlayerStatus.AI) { if (lastAIFound != GamePenguin.PenguinColor._None) // One was previously found { return((lastAIFound == lastChanged) ? c : lastAIFound); } else { lastAIFound = c; } } } return(GamePenguin.PenguinColor._None); // No issues -- Validation can end }
/// <summary> /// Build a list of moves from list a valid tiles from AIBoard /// </summary> /// <param name="player"></param> /// List <Command.GameMove> GetValidMoves(GamePenguin.PenguinColor player, VPenguin penguin) { // List of possible moves (Must be unique one for every node in MiniMax tree!) // List <Command.GameMove> possibleMoves = new List <Command.GameMove>(); // Get temporary list of tiles current penguin can move to // m_sourceTileList.Clear(); // m_refBoard.FetchLegalTiles(penguin.currTile, m_sourceTileList); possibleMoves.Clear(); // Ensure we have a clean slate // Build move object for every legal tile // foreach (string tileID in m_sourceTileList) { Command.MovePenguin move = new Command.MovePenguin(penguin, player, tileID, penguin.lastTile); possibleMoves.Add(move); } return(possibleMoves); }
/// <summary> /// Create physical Penguin game object and place him on input tile /// </summary> /// <param name="tile">Tile to place penguin</param> /// <param name="color">Color of penguin</param> /// <param name="bAI">Instantiate AI penguin?</param> /// <remarks> /// FLOW: State_Initialize::OnTileClicked() => Player::AddPenguin() => GameManager::CreatePenguin() /// </remarks> /// public GamePenguin CreatePenguin(GameTile tile, GamePenguin.PenguinColor color, bool bAI) { GameObject prefab = null; if (bAI) { prefab = PenguinAIPrefabs[(int)color]; // Choose the prefab for AI } else { prefab = PenguinPrefabs[(int)color]; // Choose the prefab for current player } Vector3 v3Pos = tile.transform.position; // Point to place the penguin at Vector3 v3Rot = new Vector3(0.0f, Random.Range(0.0f, 359.99f), 0.0f); // Random initial rotation // Instantiate a new penguin // GameObject gobNewPenguin = Instantiate(prefab, v3Pos, Quaternion.Euler(v3Rot)); GamePenguin newPenguin = gobNewPenguin.GetComponent <GamePenguin>(); // Initialize non-GameObject-related data // newPenguin.InitPenguinData(color, tile, bAI); // Link penguin to its tile // tile.PlacePenguin(newPenguin); return(newPenguin); }
public void AddPenguin(string tileID, GamePenguin.PenguinColor color) { List <VPenguin> penguinList; VTile tile = tileTable[tileID]; tile.IsPenguinHere = true; VPenguin newPenguin = ScriptableObject.CreateInstance <VPenguin>(); newPenguin.currTile = tileID; newPenguin.lastTile = tileID; newPenguin.numFish = 0; newPenguin.isActive = true; // Check that color already exists in table, if not, initialize it // if (!tablePlayerPenguins.ContainsKey(color)) { penguinList = new List <VPenguin>(); tablePlayerPenguins.Add(color, penguinList); } else { penguinList = tablePlayerPenguins[color]; } // Add new penguin to list for player // penguinList.Add(newPenguin); }
public MovePenguin(VPenguin pen, GamePenguin.PenguinColor player, string destTile, string priorTile) { playerColor = player; penguin = pen; toTile = destTile; prevTile = priorTile; fromTile = pen.currTile; }
/// <summary> /// Does this player have a penguin on the designated tile? /// </summary> /// <param name="color">Player's color</param> /// <param name="tile">Tile we're checking for a penguin</param> /// <returns>Return the penguin if it's there</returns> /// public VPenguin GetPenguinOn(GamePenguin.PenguinColor color, GameTile tile) { List <VPenguin> penguins = m_refAIBoard.tablePlayerPenguins[color]; foreach (VPenguin pen in penguins) { if (pen.currTile == tile.tileID) { return(pen); } } return(null); // No penguin of correct color found }
public void SetScoreDisplay(GamePenguin.PenguinColor color, int score) { Text guiText = null; if (m_scoreGUIMap.ContainsKey(color)) { guiText = m_scoreGUIMap[color]; } if (guiText) { guiText.text = score.ToString(); } }
/// <summary> /// After player's last penguin is removed from game and casn no longer move. /// indicate this by "ghosting out" the score display. /// </summary> /// <param name="color">Player no longer playing</param> /// void GhostScorePanel(GamePenguin.PenguinColor color) { GameObject panel = GetScorePanel(color); Text[] texts = panel.GetComponentsInChildren <Text>(); foreach (Text txt in texts) { txt.color = Color.gray; // Grayed-out txt.fontStyle = FontStyle.Italic; // Just to emphasize the point } UpdateScore(); // Update the display }
public Text textScores; // List of their scores /// <summary> /// Populate screen with final results /// </summary> /// public void DisplayScores() { int highestScore = 0; bool bTie = false; GamePenguin.PenguinColor winningColor = GamePenguin.PenguinColor._None; textWon.text = ""; textColors.text = ""; textScores.text = ""; for (GamePenguin.PenguinColor color = GamePenguin.PenguinColor.Red; color < GamePenguin.PenguinColor._None; color++) { if (m_refSC.AllPlayerScores.ContainsKey(color)) // Ignore colors not playing this session { int score = m_refSC.AllPlayerScores[color]; textColors.text += color.ToString() + ":\n"; textScores.text += score.ToString() + "\n"; // Determine who got the most fish // if (score > highestScore) { highestScore = score; winningColor = color; bTie = false; } else if (score == highestScore) { bTie = true; } } } // If this game ended in a tie for first place // (TODO: To be entirely "According to Hoyle", if there's a tie in fish score, // the win should go to who won the most tiles.) // if (bTie) { textWon.text = "This Game is a Draw!"; } else { textWon.text = winningColor.ToString() + " Won!"; } }
/// <summary> /// Build a list of all possible moves for current player /// </summary> /// <param name="currPlayer"></param> /// <returns></returns> /// public List <Command.GameMove> BuildMoveList(GamePenguin.PenguinColor currPlayer) { List <Command.GameMove> allPossibleMoves = new List <Command.GameMove>(); List <VPenguin> penguins = m_refBoard.tablePlayerPenguins[currPlayer]; // Accumulate all moves this player can make with any of their penguins // foreach (VPenguin pen in penguins) { // Get all of current player's legal moves (Placed in possibleMoves) // List <Command.GameMove> thisPensPossibleMoves = GetValidMoves(currPlayer, pen); allPossibleMoves.AddRange(thisPensPossibleMoves); } return(allPossibleMoves); }
/// <summary> /// Add a player to game /// </summary> /// <param name="color">Player's penguin color</param> /// <param name="bFirstPlayer">Will this be the first player to move?</param> /// <param name="bAIPlayer">Should this player be controlled by the computer? (otherwise, human player)</param> /// public void CreatePlayer(GamePenguin.PenguinColor color, bool bFirstPlayer, bool bAIPlayer) { Player newPlayer; if (bAIPlayer) { newPlayer = ScriptableObject.CreateInstance <PlayerAI>(); } // else { newPlayer = ScriptableObject.CreateInstance <PlayerHuman>(); } newPlayer.Color = color; newPlayer.IsStartingPlayer = bFirstPlayer; m_players.Add(newPlayer); // Player is now in game m_allPlayerScores.Add(color, 0); // Start keeping score m_numActivePlayers++; }
/// <summary> /// Accept move just made by human player and apply it to AI board /// </summary> /// <param name=""></param> /// <param name=""></param> /// public void UpdateAIBoard(GamePenguin.PenguinColor playerColor, Command.GameMove move) { Debug.Assert(playerColor == colorCurrentPlayer); // Board should be on current player ApplyMove(move); // Apply move to AI board ("move" object is polymorphic) }
/// <summary> /// Fetch the GUI panel for input player color's score /// </summary> /// <param name="color">Player Color</param> /// <returns>UI Panel</returns> /// GameObject GetScorePanel(GamePenguin.PenguinColor color) { return(scorePanels[(int)color]); }
} // Check for "island" removal, or just tile penguin is standing on? public RemovePenguin(VPenguin pen, GamePenguin.PenguinColor player) { playerColor = player; penguin = pen; }
// Get list of active penguins a player has // List <VPenguin> GetPlayerPenguins(GamePenguin.PenguinColor player) { return(tablePlayerPenguins[player]); }
/// <summary> /// MiniMax with alpha-beta pruning /// </summary> /// <param name="depth"></param> /// <param name="currPlayer"></param> /// <returns></returns> /// public float MinimaxAB(int depth, GamePenguin.PenguinColor currPlayer, List <Command.GameMove> allPossibleMoves, float alpha, float beta) { float bestHeuristicScore, currHeuristicScore = 0.0f; Command.GameMove lastMove; if (depth == 0) { return(m_refBoard.GetHeuristicScore()); // This is a "leaf node" -- Return its heuristic value } // Find all valid possible moves (Initial call hands current allPossibleMoves for AI, so does // not to be found again on first iteration) // if (allPossibleMoves == null) { allPossibleMoves = BuildMoveList(currPlayer); } // Evaluate list of moves // if (currPlayer == m_me) // AI's Turn (Maximizing Player) { bestHeuristicScore = Mathf.NegativeInfinity; foreach (Command.GameMove testMove in allPossibleMoves) { m_refBoard.PushMove(testMove); // "Try out" this move on AI Board // Get to next node // currHeuristicScore = MinimaxAB(depth - 1, m_refBoard.GetPlayerIndex(currPlayer, 1), null, alpha, beta); // Print info only at uppermost level... // if (depth == m_depthInPlys) { MiniMaxDebugInfo(testMove, currHeuristicScore); } // Undo move when test on this branch is done // lastMove = m_refBoard.PopMove(); // Test heuristic result of this position // if (currHeuristicScore > alpha) { // Print info only at uppermost level... // if (depth == m_depthInPlys) { if (_debugMode) { Debug.Log("New best move..."); } MiniMaxDebugInfo(lastMove, currHeuristicScore); m_refBoard.pendingMove = lastMove; } alpha = bestHeuristicScore = currHeuristicScore; } if (alpha >= beta) { break; // Prune the tree } } return(bestHeuristicScore); } else // Human player's Turn (Minimizing Players) { bestHeuristicScore = Mathf.Infinity; foreach (Command.GameMove testMove in allPossibleMoves) { m_refBoard.PushMove(testMove); currHeuristicScore = MinimaxAB(depth - 1, m_refBoard.GetPlayerIndex(currPlayer, 1), null, alpha, beta); // MiniMaxDebugInfo(testMove, currHeuristicScore); m_refBoard.PopMove(); if (currHeuristicScore < beta) { beta = bestHeuristicScore = currHeuristicScore; } if (alpha >= beta) { break; // Prune the tree } } return(bestHeuristicScore); } }