// AI logic private void AdvanceAI() { IComputer computer = null; bool cycle = false; AcquireGameStates currentState; // early out if (game == null || game.State == AcquireGameStates.GameSetup) { return; } // get the computer implementation (if this is a computer player) if (game.State == AcquireGameStates.TradeShares) { if (game.SharesToTrade.Player.IsComputer) { computer = GetComputer(game.SharesToTrade.Player); } } else if (game.State == AcquireGameStates.SellShares) { if (game.SharesToSell.Player.IsComputer) { computer = GetComputer(game.SharesToSell.Player); } } else if (game.CurrentPlayer.IsComputer) { computer = GetComputer(game.CurrentPlayer); } // not a computer player, so exit early if (computer == null) { // nothing lastComputer = null; return; } // guard against re-entrancy if (System.Threading.Interlocked.CompareExchange(ref oneThread, 1, 0) != 0) { return; } // rudimentry cycle detection, does not allow the same computer to be called twice cycle = (lastComputer == computer && lastState == game.State); currentState = game.State; // need to cache since state will change below // for cycle detection trade what has happened in the past cycleQueue.Add(computer.ID + " " + currentState); // plan next move switch (game.State) { case AcquireGameStates.ExitGame: // if there are only computers playing then Exit, else let the human player decide if (computers.Count == game.Players.Count) { EndGame(); } else { ContinueGame(); } break; case AcquireGameStates.Done: // if only the computers than repeat again if (computers.Count == game.Players.Count && repeatAgain) { StartGame(); } break; case AcquireGameStates.PlaceTile: // have the computer choose a piece if (cycle) { ShuffleTiles(); } else { SelectSquare(computer.SelectSquare(game.CurrentPlayer.Tiles)); } break; case AcquireGameStates.BuyShares: // have the current player buy shares if (cycle) { BuyShares(new CorpNames[0]); } else { BuyShares(computer.BuyShares(game.SharesToBuy)); } break; case AcquireGameStates.ChooseCorp: // have the current choose a corp if (cycle) { throw new ArgumentException("Cycle detected while choosing a corp"); } else { ChooseCorp(computer.ChooseCorp(game.AvailableCorporations)); } break; case AcquireGameStates.ChooseParentCorp: // have the current choose a parent corp if (cycle) { throw new ArgumentException("Cycle detected while choosing a parent corp"); } else { ChooseCorp(computer.ChooseParentCorp(game.ParentCorporations)); } break; case AcquireGameStates.NextTurn: // nothing break; case AcquireGameStates.SellShares: // have the 'sell' player choose how many shares to sell cycleQueue.Add(" - " + game.SharesToSell.Corporation + " " + game.SharesToSell.Price + " " + game.SharesToSell.Player.Name + " " + game.SharesToSell.Player.IsComputer); // TODO! cycle detection in selling will require saving the last trade and ensuring that it is not the same /*if (cycle) throw new ArgumentException("Cycle detected while selling shares"); * else */ SellShares(computer.SellShares(game.SharesToSell)); break; case AcquireGameStates.TradeShares: // have the 'trade' player choose how many shares to sell cycleQueue.Add(" - " + game.SharesToTrade.ParentCorp + "/" + game.SharesToTrade.MergedCorp + " " + game.SharesToTrade.Bonus + " " + game.SharesToTrade.Player.Name + " " + game.SharesToTrade.Player.IsComputer); // TODO! cycle detection in trading will require saving the last trade and ensuring that it is not the same /*if (cycle) throw new ArgumentException("Cycle detected while trading shares"); * else*/ TradeShares(computer.TradeShares(game.SharesToTrade, game[game.SharesToTrade.ParentCorp].Shares)); break; } // cycle detection lastState = currentState; // need to cache the state since it will change above lastComputer = computer; if (System.Threading.Interlocked.CompareExchange(ref oneThread, 0, 1) != 1) { throw new ArgumentException("Lock released more than once"); } }