public static void LogAIError(Exception ex, databaseCache cache) { //Save the cache for later checking and try again WebLogging.AddLog("GPA", WebLogging.LogCategory.AIError, "AI error logged - " + ex.ToString()); string errorFileName = "pokerAIError " + DateTime.Now.Hour.ToString() + "." + DateTime.Now.Minute.ToString() + "." + DateTime.Now.Second.ToString() + "." + DateTime.Now.Millisecond.ToString() + " " + DateTime.Now.ToString("dd-MM-yyyy"); using (System.IO.StreamWriter sw = new System.IO.StreamWriter(errorFileName + ".log", false)) { sw.WriteLine("Hand Id: " + cache.getCurrentHandId().ToString() + " Player Id: " + cache.getPlayerId(cache.getCurrentActiveTablePosition()).ToString()); if (ex.GetBaseException() != null) { sw.WriteLine("Base Exception Type: " + ex.GetBaseException().ToString()); } if (ex.InnerException != null) { sw.WriteLine("Inner Exception Type: " + ex.InnerException.ToString()); } if (ex.StackTrace != null) { sw.WriteLine(""); sw.WriteLine("Stack Trace: " + ex.StackTrace.ToString()); } File.WriteAllBytes(errorFileName + ".FBPcache", cache.Serialise()); sw.Close(); } }
/// <summary> /// Creates a new update item and creates a NEW COPY of the passed cache /// Can we quite slow ~ 1ms. /// </summary> /// <param name="cache"></param> public UpdateItem(databaseCache cache) { currentHandId = cache.getCurrentHandId(); playerIds = cache.getSatInPlayerIds(); tableId = cache.TableId; cache = databaseCache.DeSerialise(cache.Serialise()); }
private void PreDecisionErrorChecking(long playerId, databaseCache genericGameCache) { if (runInSafeMode) { #region Basic Error Checking if (!(genericGameCache.getCurrentHandId() > 0)) { throw new Exception("getCurrentHandId() returns an invalid value."); } byte[] positionsLeftToAct = genericGameCache.getActivePositionsLeftToAct(); if (positionsLeftToAct.Length == 0) { throw new Exception("Positions left to act contains no elements."); } if (positionsLeftToAct[0] != genericGameCache.getPlayerPosition(playerId)) { throw new Exception("First position left to act should always be the specified player - otherwise why are we trying to determine an action yet."); } if (!genericGameCache.getPlayerDetails(playerId).isBot) { throw new Exception("Decision requested for player who is not marked as a bot."); } if (genericGameCache.TableId == 0) { throw new Exception("Cache Table Id is 0 which cannot be correct!"); } #endregion } }
public void Update(long playerId, databaseCache currentCache) { if (maintainRecentCacheHistory) { lock (updateQueue) updateQueue.Enqueue(new UpdateItem(currentCache)); } else { //We need to guarantee the table is in the cacheTracker for the winRatio provider before this method returns lock (locker) { if (tableCaches.ContainsKey(currentCache.TableId)) { tableCaches[currentCache.TableId].Refresh(); } else { tableCaches.Add(currentCache.TableId, new tableCache(currentCache.TableId, currentCache)); } } lock (updateQueue) updateQueue.Enqueue(new UpdateItem(currentCache.getSatInPlayerIds(), currentCache.TableId, currentCache.getCurrentHandId())); } }
/// <summary> /// Initiaties a decision but overrides the player config using the specified serverType and configStr /// </summary> /// <param name="handId"></param> /// <param name="playerId"></param> /// <param name="genericGameCache"></param> /// <returns></returns> public Play GetDecision(long playerId, databaseCache genericGameCache, AIGeneration serverType, string aiConfigStr) { try { //AIGeneration serverType; //string aiConfigStr; int selectedInstanceIndex; //Check for any simple errors PreDecisionErrorChecking(playerId, genericGameCache); //Determine which instance to use selectedInstanceIndex = DetermineAvailableInstance(); //Enter the correct lock lock (instanceLocks[selectedInstanceIndex]) { //Update the infostore //If anything in the InfoStore throws any error it will be caught by the catch //in this method, and thus logged correctly. UpdateInfoStore(playerId, genericGameCache, infoStoreCollection[selectedInstanceIndex], infoProviderCollection[selectedInstanceIndex]); //Get the correct AI version and configuration for this player if (serverType == AIGeneration.Undefined || aiConfigStr == null) { cacheTracker.playerAiConfig(playerId, genericGameCache.TableId, out serverType, out aiConfigStr); } //Pick that aiServer from the available list var aiServer = from server in aiCollection[selectedInstanceIndex] where server.AiType == serverType select server; if (aiServer.Count() != 1) { throw new Exception("Unable to select correct AI from those avaialble."); } //Get the ai decision Play aiAction = aiServer.First().GetDecision(playerId, aiConfigStr, genericGameCache, infoStoreCollection[selectedInstanceIndex]); aiAction = SetDecisionTime(ValidatePlayerDecision(aiAction, genericGameCache)); //Signal this decision as finished and let another one through. lock (idlelocker) { instancesIdle = instancesIdle | (1 << selectedInstanceIndex); //aiAvailableEvent.Set(); } return(aiAction); } } catch (Exception ex) { //Reset idle instances (the locks will protected and potential multithreading problems). instancesIdle = 0; for (int i = 0; i < numInstances; i++) { instancesIdle = instancesIdle | (1 << i); } genericGameCache.readLockCounter = 0; LogAIError(ex, genericGameCache); return(new Play(PokerAction.GeneralAIError, 0, 0, genericGameCache.getCurrentHandId(), playerId, ex.ToString(), 3)); } throw new Exception("Should never get here!"); }
public void UpdatePlayerModels(databaseCache cache) { //First get hand details var handDetails = cache.getCurrentHandDetails(); //If hand id has changed since last time then some reseting is needed if (cache.getCurrentHandId() != lastHandIdConsidered) { //reset variables lastHandIdConsidered = cache.getCurrentHandId(); wasRaisedPot = false; wasHandState = HandState.PreFlop; lastActionIdConsidered = -1; //get keys in players dictionary and players in cache who are sat in //long[] keys = playersOld.Keys.ToArray(); long[] satInPlayerIds = cache.getSatInPlayerIds(); lastNumberActivePlayers = cache.PlayerIdsStartedHand().Length; //Remove from players all items that don't correspond to sat in players //long[] toRemove = keys.Except(satInPlayerIds).ToArray(); //for (byte i = 0; i < toRemove.Length; i++) // playersOld.Remove(toRemove[i]); //Go through each seat //for (int i = 0; i < satInPlayerIds.Length; i++) //{ // //Get player id for person in seat // long pid = satInPlayerIds[i]; // //and the player is not in dictionary add them, otherwise reset their entry // if (!playersOld.ContainsKey(pid)) // playersOld.Add(pid, new PlayerModel(tableId, lastHandIdConsidered, pid, wrProv)); // else // playersOld[pid].ResetProbsToDefault(lastHandIdConsidered); // playersOld[pid].UpdateCardsWinPercentages(new Card[] { }, lastNumberActivePlayers); //} //get keys in players dictionary and players in cache who are sat in long[] keys = playersNew.Keys.ToArray(); //Remove from players all items that don't correspond to sat in players long[] toRemove = keys.Except(satInPlayerIds).ToArray(); for (byte i = 0; i < toRemove.Length; i++) { playersNew.Remove(toRemove[i]); } //Go through each seat for (int i = 0; i < satInPlayerIds.Length; i++) { //Get player id for person in seat long pid = satInPlayerIds[i]; //and the player is not in dictionary add them, otherwise reset their entry if (!playersNew.ContainsKey(pid)) { playersNew.Add(pid, new PlayerModelFixed(tableId, cache.BigBlind, lastHandIdConsidered, pid, wrProv)); } else { playersNew[pid].ResetProbsToDefault(lastHandIdConsidered); } playersNew[pid].UpdateCardsWinPercentages(new Card[] { }, lastNumberActivePlayers); } } //Setup cards array based on cards that were present at end of last update Card[] cards = new Card[0]; switch (wasHandState) { case HandState.Flop: cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3) }; break; case HandState.Turn: cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3), (Card)(handDetails.tableCard4) }; break; case HandState.River: cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3), (Card)(handDetails.tableCard4), (Card)(handDetails.tableCard5) }; break; } //Get all dealer and betting actions since last update var handActions = cache.getHandActions(lastHandIdConsidered); handActions = (from a in handActions where a.localIndex > lastActionIdConsidered && (a.actionType == PokerAction.Check || a.actionType == PokerAction.Call || a.actionType == PokerAction.Raise || a.actionType == PokerAction.Fold || a.actionType == PokerAction.DealFlop || a.actionType == PokerAction.DealTurn || a.actionType == PokerAction.DealRiver) orderby a.localIndex select a).ToArray(); //Get a list of active players by the end of the hand actions above var activePlayers = cache.getActivePlayerIds(); //Now go through each new hand action foreach (var handAction in handActions) { //if the action is a dealer action then update hand state, change raised pot flag and for each active player update card probs change after deal if (handAction.actionType == PokerAction.DealFlop) { wasHandState = HandState.Flop; wasRaisedPot = false; cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3) }; foreach (var player in activePlayers) { //playersOld[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard1)); //playersOld[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard2)); //playersOld[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard3)); playersNew[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard1)); playersNew[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard2)); playersNew[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard3)); } continue; } else if (handAction.actionType == PokerAction.DealTurn) { wasHandState = HandState.Turn; wasRaisedPot = false; cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3), (Card)(handDetails.tableCard4) }; foreach (var player in activePlayers) { //playersOld[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard4)); playersNew[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard4)); } continue; } else if (handAction.actionType == PokerAction.DealRiver) { wasHandState = HandState.River; wasRaisedPot = false; cards = new Card[] { (Card)(handDetails.tableCard1), (Card)(handDetails.tableCard2), (Card)(handDetails.tableCard3), (Card)(handDetails.tableCard4), (Card)(handDetails.tableCard5) }; foreach (var player in activePlayers) { //playersOld[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard5)); playersNew[player].UpdateProbsAfterCardDealt((Card)(handDetails.tableCard5)); } continue; } else if (handAction.actionType == PokerAction.Fold) { //if a player has folded set all their probabilities of having cards to zero and reduce number of active players //if (playersOld.ContainsKey(handAction.playerId)) // playersOld[handAction.playerId].SetAllProbsToZeroOnFold(); if (playersNew.ContainsKey(handAction.playerId)) { playersNew[handAction.playerId].SetAllProbsToZeroOnFold(); } lastNumberActivePlayers--; continue; } //otherwise we're dealing with a betting action so they should be in active players if (activePlayers.Contains(handAction.playerId)) { //Update win percentages and indices in player model and update card probs based on action //playersOld[handAction.playerId].UpdateCardsWinPercentages(cards, lastNumberActivePlayers); playersNew[handAction.playerId].UpdateCardsWinPercentages(cards, lastNumberActivePlayers); decimal ra = 0, ca = 0, pa = 0; double dd; if (handAction.actionType == PokerAction.Raise) { ra = cache.getCurrentRoundLastRaiseAmount(handAction.localIndex + 1L); } if (wasRaisedPot) { ca = cache.getMinimumPlayAmount(handAction.localIndex) - cache.getPlayerCurrentRoundBetAmount(handAction.playerId, handAction.localIndex); } pa = cache.getPotUpToActionId(handAction.localIndex); dd = (cache.getActivePlayerDistanceToDealer(handAction.playerId, handAction.localIndex) - 1.0) / (cache.getActivePositions(handAction.localIndex).Length - 1.0); //playersOld[handAction.playerId].UpdateCardProbsBasedOnAction(handAction.actionType, wasHandState, ca, ra, pa, wasRaisedPot, dd < 0.5); playersNew[handAction.playerId].UpdateCardProbsBasedOnAction(handAction.actionType, wasHandState, ca, ra, pa, wasRaisedPot, dd < 0.5); } //Finally if the action was a raise we now have a raised pot if (handAction.actionType == PokerAction.Raise) { wasRaisedPot = true; } } //for (int i = 0; i < activePlayers.Length; i++) // playersOld[activePlayers[i]].UpdateCardsWinPercentages(cards, activePlayers.Length); for (int i = 0; i < activePlayers.Length; i++) { playersNew[activePlayers[i]].UpdateCardsWinPercentages(cards, activePlayers.Length); } //finally update last action considered and last number players if (handActions.Count() > 0) { lastActionIdConsidered = handActions.Last().localIndex; } lastNumberActivePlayers = activePlayers.Length; }
public TableModel(databaseCache cache, WinRatioProvider wrProv, bool useAllPlayersCards) { this.tableId = cache.TableId; this.numPlayers = cache.NumSeats; this.wrProv = wrProv; //playersOld = new Dictionary<long, PlayerModel>(numPlayers); playersNew = new Dictionary <long, PlayerModelFixed>(numPlayers); var satDownPositions = cache.getSatDownPositions(); for (byte i = 0; i < numPlayers; i++) { if (satDownPositions.Contains(i)) { //playersOld.Add(cache.getPlayerId(i), new PlayerModel(tableId, cache.getCurrentHandId(), cache.getPlayerId(i), wrProv)); playersNew.Add(cache.getPlayerId(i), new PlayerModelFixed(tableId, cache.BigBlind, cache.getCurrentHandId(), cache.getPlayerId(i), wrProv)); } } }
/// <summary> /// Initiaties a decision but overrides the player config using the specified serverType and configStr /// </summary> /// <param name="handId"></param> /// <param name="playerId"></param> /// <param name="genericGameCache"></param> /// <returns></returns> public Play GetDecision(long playerId, databaseCache genericGameCache, AIGeneration serverType, string aiConfigStr) { try { //Sort out the cacheTracker CacheTracker.Instance.Update(playerId, genericGameCache); if (serverType == AIGeneration.Undefined || aiConfigStr == null) { CacheTracker.Instance.PlayerAiConfig(playerId, genericGameCache.TableId, out serverType, out aiConfigStr); } DecisionRequest newRequest = new DecisionRequest(playerId, genericGameCache, serverType, aiConfigStr, AIManager.RunInSafeMode); PreDecisionErrorChecking(newRequest.PlayerId, newRequest.Cache); //For now we will just use the old method //Determine an available AIInstance int selectedInstanceIndex = DetermineAvailableInstance(newRequest); //This could be done in a seperate thread if (selectedInstanceIndex == -1) { //There were no available instances so we join the queue and wait newRequest.WaitForDecision(); } else { if (ConcurrencyMode.Concurrency == ConcurrencyMode.ConcurencyModel.MultiCore) { Task t = Task.Factory.StartNew(aiInstanceList[selectedInstanceIndex].HandleDecisionRequest, newRequest); t.Wait(); } else { aiInstanceList[selectedInstanceIndex].HandleDecisionRequest(newRequest); } } Play aiAction = newRequest.DecisionPlay; aiAction = SetDecisionTime(ValidatePlayerDecision(aiAction, newRequest.Cache)); return(aiAction); } catch (Exception ex) { instanceSelector.instancesIdle = 0; for (int i = 0; i < aiInstanceList.Count; i++) { instanceSelector.instancesIdle = instanceSelector.instancesIdle | (1 << i); } genericGameCache.readLockCounter = 0; string fileName = LogError.Log(ex, "PokerAIError"); genericGameCache.SaveToDisk("", fileName); return(new Play(PokerAction.GeneralAIError, 0, 0, genericGameCache.getCurrentHandId(), playerId, ex.ToString(), 3)); } throw new Exception("This point should never be reached."); }