/// <summary> /// Updates the opponent's history of played cards and returns the last played cards of the opponent. /// This cards will be used for the prediction. /// </summary /// <param name="decayFactor">the decay factor by which the probability will be decrease</param> /// <param name="opponent">the controller of the opponent</param> /// <returns>the last played cards</returns> private PlayedCards updateTasks(double decayFactor, Controller opponent) { double initValue = 1; // add cards which were in the opponent's board and weren't played Minion[] oppBoard = opponent.BoardZone.GetAll(); oppBoard.Select(b => b.Card) .Where(c => !_oppBoardCards.Cards.Contains(c)).ToList() .ForEach(c => { _oppBoardCards.Add(c, initValue); }); List <PlayHistoryEntry> history = opponent.PlayHistory; history.Where(h => !_oppHistory.Contains(h)).ToList() .Select(h => h.SourceCard) .Where(c => !_oppBoardCards.Cards.Contains(c)).ToList() .ForEach(c => { _oppBoardCards.Add(c, initValue); }); PlayHistoryEntry[] copyHistory = new PlayHistoryEntry[history.Count]; history.CopyTo(copyHistory); _oppHistory = copyHistory.ToList(); return(_oppBoardCards); }
public void Initialize(POGame game) { if (_oppHistory == null) { List <PlayHistoryEntry> history = game.CurrentOpponent.PlayHistory; var copyHistory = new PlayHistoryEntry[history.Count]; history.CopyTo(copyHistory); _oppHistory = copyHistory.ToList(); } }
private async Task PlayMusic(IVoiceChannel channel, Playlist playlist) { var token = tokenSource.Token; PlayerState = PlayerState.Idle; VoiceChannel = channel; Playlist = playlist; playedSongs.Clear(); var logTag = $"[Music {VoiceChannel.GuildId}] "; logger.LogInformation($"{logTag}Starting music player in guild {Guild.Name}, channel {VoiceChannel.Name}"); ConnectionState = ConnectionState.Connecting; IAudioClient audioClient = null; AudioOutStream discordStream = null; try { audioClient = await VoiceChannel.ConnectAsync(); discordStream = audioClient.CreateOpusStream(); logger.LogDebug($"{logTag}Connected"); ConnectionState = ConnectionState.Connected; while (!token.IsCancellationRequested) { var songId = playlist.GetNextSong(); if (songId == null) { break; } logger.LogDebug($"{logTag}Playing next song (Id: {songId})"); var song = await musicService.GetSong(songId); if (song == null) { logger.LogWarning($"{logTag}Failed to get data for song id {songId}"); continue; } var playHistoryEntry = new PlayHistoryEntry { song = song, state = SongState.Playing }; var oggStream = await song.GetOggStream(); if (oggStream == null) { logger.LogWarning($"{logTag}Failed to get ogg stream for current song (Id: {songId})"); playHistoryEntry.state = SongState.Error; playedSongs.Add(playHistoryEntry); continue; } playedSongs.Add(playHistoryEntry); try { var opusStream = new OpusOggReadStream(null, oggStream); PlayerState = PlayerState.Playing; while (opusStream.HasNextPacket && !token.IsCancellationRequested) { var packet = opusStream.RetrieveNextPacket(); if (packet == null) { break; } await discordStream.WriteAsync(packet, 0, packet.Length); } playHistoryEntry.state = SongState.Finished; playedSongs[playedSongs.Count - 1] = playHistoryEntry; } catch (Exception ex) { logger.LogError(ex, $"{logTag}Exception while playing, skipping to next track"); playHistoryEntry.state = SongState.Error; playedSongs[playedSongs.Count - 1] = playHistoryEntry; } finally { oggStream.Dispose(); await discordStream.FlushAsync(); } PlayerState = PlayerState.Idle; } } catch (Exception ex) { logger.LogError(ex, $"{logTag}Exception in music player"); } finally { logger.LogInformation($"{logTag}Stopping music player"); VoiceChannel = null; Playlist = null; ConnectionState = ConnectionState.Disconnecting; discordStream?.Dispose(); if (audioClient != null) { audioClient.Disconnected -= ClientDisconnected; audioClient.Dispose(); } ConnectionState = ConnectionState.Disconnected; PlayerState = PlayerState.Disconnected; logger.LogDebug($"{logTag}Stopped music player"); } Task ClientDisconnected(Exception ex) { return(Task.Run(() => { if (ex != null) { logger.LogError(ex, "Audio client disconnected with exception"); } tokenSource.Cancel(); })); } }
/// <summary> /// TODO: API /// </summary> /// <param name="game"></param> /// <returns></returns> public override MCTSNode simulate(POGame.POGame game) { POGame.POGame gameCopy = game.getCopy(); // initials root node var initLeafs = new List <MCTSNode>(); var root = new MCTSNode(_playerId, new List <MCTSNode.ScoreExt> { new MCTSNode.ScoreExt(1.0, _scoring) }, gameCopy, null, null); // simulate MCTSNode bestNode = simulate(_deltaTime, root, ref initLeafs); // initials opponent's history if (_oppHistory == null) { List <PlayHistoryEntry> history = gameCopy.CurrentOpponent.PlayHistory; PlayHistoryEntry[] copyHistory = new PlayHistoryEntry[history.Count]; history.CopyTo(copyHistory); _oppHistory = copyHistory.ToList(); } var simulationQueue = new Queue <KeyValuePair <POGame.POGame, List <MCTSNode> > >(); simulationQueue.Enqueue(new KeyValuePair <POGame.POGame, List <MCTSNode> >(gameCopy, initLeafs)); int i = 0; while (i < _predictionParameters.SimulationDepth && simulationQueue.Count > 0) { // calculate the lower and upper time bound of the current depth double lowerSimulationTimeBound = _deltaTime + i * (2 * _deltaTime); KeyValuePair <POGame.POGame, List <MCTSNode> > simulation = simulationQueue.Dequeue(); POGame.POGame simulationGame = simulation.Key; List <MCTSNode> leafs = simulation.Value; leafs = leafs.Where(l => l.Game != null) .OrderByDescending(l => l.Score) .Take((leafs.Count > _predictionParameters.LeafCount) ? _predictionParameters.LeafCount : leafs.Count) .ToList(); if (leafs.Count() < 0) { return(bestNode); } Controller opponent = getOpponent(simulationGame); List <Prediction> predicitionMap = getPredictionMap(simulationGame, opponent); var oldSimulations = new Dictionary <POGame.POGame, List <MCTSNode> >(); // the simulation time for one leaf double timePerLeaf = (2 * _deltaTime) / leafs.Count; // get all games from all leaf nodes for (int j = 0; j < leafs.Count; j++) { // calculate the lower time bound of the current leaf double lowerLeafTimeBound = lowerSimulationTimeBound + j * timePerLeaf; MCTSNode leafNode = leafs[j]; POGame.POGame oppGame = leafNode.Game; double leafScore; // XXX: game can be null leafScore = simulateOpponentWithPrediction(lowerLeafTimeBound, timePerLeaf, oppGame, opponent, predicitionMap, ref oldSimulations); // back-propagate score backpropagate(leafNode, leafScore); } var newSimulations = new Dictionary <POGame.POGame, List <MCTSNode> >(); oldSimulations.ToList() .OrderByDescending(s => s.Value.Sum(l => l.TotalScore)) .Take((leafs.Count > _predictionParameters.OverallLeafCount) ? _predictionParameters.OverallLeafCount : leafs.Count) .ToList() .ForEach(l => newSimulations.Add(l.Key, l.Value)); // add new simulations foreach (KeyValuePair <POGame.POGame, List <MCTSNode> > sim in oldSimulations) { simulationQueue.Enqueue(sim); } i++; } return(root.Children .OrderByDescending(c => c.TotalScore) .First()); }