internal void Initialize <TState>(ReduxStore <TState> store) where TState : class, new() { // Observe UI events UndoButton.Events().Click .Subscribe(_ => store.Undo()); RedoButton.Events().Click .Subscribe(_ => store.Redo()); ResetButton.Events().Click .Subscribe(_ => store.Reset()); PlayPauseButton.Events().Click .Subscribe(_ => _devToolsStore.Dispatch(new TogglePlayPauseAction())); Slider.Events().ValueChanged .Where(_ => Slider.FocusState != Windows.UI.Xaml.FocusState.Unfocused) .Select(e => (int)e.NewValue) .DistinctUntilChanged() .Subscribe(newPosition => { _devToolsStore.Dispatch(new MoveToPositionAction { Position = newPosition }); }); ReduxActionInfosListView.Events().ItemClick .Subscribe(e => { int index = ReduxActionInfosListView.Items.IndexOf(e.ClickedItem); _devToolsStore.Dispatch(new SelectPositionAction { Position = index }); }); // Observe changes on DevTools state Observable.CombineLatest( _devToolsStore.Select(SelectCurrentPosition), _devToolsStore.Select(SelectPlaySessionActive), _devToolsStore.Select(SelectMaxPosition), store.ObserveCanUndo(), store.ObserveCanRedo(), Tuple.Create ) .Subscribe(x => { var(currentPosition, playSessionActive, maxPosition, canUndo, canRedo) = x; Slider.Value = currentPosition; Slider.Maximum = maxPosition; if (playSessionActive) { UndoButton.IsEnabled = false; RedoButton.IsEnabled = false; ResetButton.IsEnabled = false; PlayPauseButton.IsEnabled = true; Slider.IsEnabled = false; PlayPauseButton.Content = "\xE769"; } else { UndoButton.IsEnabled = canUndo; RedoButton.IsEnabled = canRedo; ResetButton.IsEnabled = canUndo || canRedo; PlayPauseButton.IsEnabled = canRedo; Slider.IsEnabled = maxPosition > 0; PlayPauseButton.Content = "\xE768"; } }); _devToolsStore.Select( CombineSelectors(SelectCurrentActions, SelectSelectedActionPosition) ) .Subscribe(x => { var(actions, selectedPosition) = x; ReduxActionInfosListView.ItemsSource = actions; ReduxActionInfosListView.SelectedIndex = Math.Clamp(selectedPosition, -1, actions.Count - 1); }); _devToolsStore.Select(SelectSelectedReduxAction) .Subscribe(reduxActionOption => { reduxActionOption.Match() .Some().Do(reduxAction => { var serializerSettings = new JsonSerializerSettings { ContractResolver = SuccinctContractResolver.Instance, ReferenceLoopHandling = ReferenceLoopHandling.Ignore, Formatting = Formatting.Indented }; SelectedReduxActionDataTextBlock.Text = JsonConvert.SerializeObject( reduxAction.Data, serializerSettings ); SelectedStateTextBlock.Text = JsonConvert.SerializeObject( reduxAction.NextState, serializerSettings ); SelectedDiffStateTextBlock.Text = "This feature will be available soon..."; }) .None().Do(() => { SelectedReduxActionDataTextBlock.Text = string.Empty; SelectedStateTextBlock.Text = string.Empty; SelectedDiffStateTextBlock.Text = string.Empty; }) .Exec(); }); _devToolsStore.ObserveAction <MoveToPositionAction>() .WithLatestFrom( _devToolsStore.Select(SelectCurrentPosition), Tuple.Create ) .Subscribe(x => { var(action, currentPosition) = x; if (action.Position < currentPosition) { for (int i = 0; i < currentPosition - action.Position; i++) { store.Undo(); } } if (action.Position > currentPosition) { for (int i = 0; i < action.Position - currentPosition; i++) { store.Redo(); } } }); _devToolsStore.Select(SelectPlaySessionActive) .Select(playSessionActive => playSessionActive ? Observable.Interval(TimeSpan.FromSeconds(1)) : Observable.Empty <long>() ) .Switch() .ObserveOnDispatcher() .Subscribe(_ => { bool canRedo = store.Redo(); if (!canRedo) { _devToolsStore.Dispatch(new TogglePlayPauseAction()); } }); // Observe changes on listened state var storeHistoryAtInitialization = store.GetHistory(); store.ObserveHistory() .StartWith(storeHistoryAtInitialization) .Subscribe(historyInfos => { var mementosOrderedByDate = historyInfos.PreviousStates .OrderBy(reduxMemento => reduxMemento.Date) .ToList(); // Set list of current actions // Set list of future (undone) actions _devToolsStore.Dispatch(new HistoryUpdated { CurrentActions = mementosOrderedByDate .Select((reduxMemento, index) => { int nextIndex = index + 1; var nextState = nextIndex < mementosOrderedByDate.Count ? mementosOrderedByDate[nextIndex].PreviousState : store.State; return(new ReduxActionInfo { Date = reduxMemento.Date, Type = reduxMemento.Action.GetType(), Data = reduxMemento.Action, PreviousState = reduxMemento.PreviousState, NextState = nextState }); }) .ToImmutableList(), FutureActions = historyInfos.FutureActions .Select(action => { return(new ReduxActionInfo { Type = action.GetType(), Data = action }); }) .ToImmutableList() }); }); _devToolsStore.Dispatch( new SelectPositionAction { Position = storeHistoryAtInitialization.PreviousStates.Count - 1 } ); }
private static void PrintGameStats(this ReduxStore <GameState> store) { var game = store.State; Console.Write("ID: "); WriteColorLine(game.Identifier, ConsoleColor.Yellow); Console.Write("DAY: "); WriteColorLine(game.Day, ConsoleColor.Yellow); Console.WriteLine("PHS: " + game.Phase); Console.WriteLine("PLC: " + game.Players.Count); // Calculate votes. var votes = game.GetLynchCandidates(); string lynchDeterminant; if (votes.Length == 0) { lynchDeterminant = "No One Will Be Lynched"; } else if (votes.Length == 1) { lynchDeterminant = $"Currently {votes[0]} will be determined to be lynched at EOD"; } else { lynchDeterminant = "Currently there is a tie between "; foreach (var player in votes) { lynchDeterminant += player + ", "; } } Console.WriteLine($"\n-- {lynchDeterminant} --\n"); Console.WriteLine("\t=== Players ==="); foreach (var player in game.Players.Select(entry => entry.Value)) { var padding = 24; Console.Write($"\tID: {player.Identifier.PadRight(padding)} | "); WriteColor($"ROLE: [ {player.Role.ToString()?.PadRight(12)} ] ", GetTeamRole(player)); Console.Write("| "); if (player.Alive) { WriteColor("ALIVE", ConsoleColor.Green); } else { WriteColor($"ELIMINATED [{player.CauseOfDeath}]\n", ConsoleColor.Red); } if (player.Alive) { switch (player.Accusation.Type) { case VoteType.None: Console.WriteLine(); break; case VoteType.Lynch: Console.WriteLine($" (Lynch {player.Accusation.Identifier})"); break; case VoteType.NoLynch: Console.WriteLine(" (No Lynch)"); break; default: throw new ArgumentOutOfRangeException(); } } } var history = store.GetHistory().PreviousStates; Console.WriteLine("\n\t=== Last 10 Actions ==="); foreach (var a in history.Take(5)) { Console.WriteLine($"\tTYPE: {new DateTimeOffset(a.Date).ToUnixTimeMilliseconds()} :: {a.Action}"); } Console.WriteLine(); }