示例#1
0
 public static void DispatchAllActions <T>(ReduxStore <T> store) where T : class, new()
 {
     DispatchAddTodoItemAction(store, 1, "Create unit tests");
     DispatchSwitchUserAction(store, "Emily");
     DispatchAddTodoItemAction(store, 2, "Create Models");
     DispatchAddTodoItemAction(store, 3, "Refactor tests");
 }
示例#2
0
 public static void DispatchSwitchUserAction <T>(ReduxStore <T> store, string newUser) where T : class, new()
 {
     store.Dispatch(new SwitchUserAction
     {
         NewUser = newUser
     });
 }
示例#3
0
 public static void DispatchAddTodoItemAction <T>(ReduxStore <T> store, int id, string title) where T : class, new()
 {
     store.Dispatch(new AddTodoItemAction
     {
         TodoItem = new TodoItem
         {
             Id    = id,
             Title = title
         }
     });
 }
示例#4
0
        public void CanCreateAStoreWithEmptyState()
        {
            // Arrange
            var store = new ReduxStore <EmptyState>(
                Setup.EmptyStore.Reducers.CreateReducers()
                );

            // Act

            // Assert
            Assert.NotNull(store.State);
        }
        public static IServiceCollection AddRedux(this IServiceCollection services)
        {
            services.AddScoped(sp =>
            {
                var store   = new ReduxStore <MovieSearchState>(MovieSearchReducers.CreateReducers());
                var effects = new MovieSearchEffects(store, sp.GetService <IOmdbMovieService>());
                store.RegisterEffects(effects.SearchMovies);

                return(store);
            });

            return(services);
        }
示例#6
0
        public void CanCreateAStoreWithDefaultState()
        {
            // Arrange
            var initialState = CreateInitialTodoListState();
            var store        = new ReduxStore <TodoListState>(
                Setup.TodoListStore.Reducers.CreateReducers(),
                initialState
                );

            // Act

            // Assert
            Assert.Empty(store.State.TodoList);
        }
示例#7
0
            public async Task Handle(CustomerCreated notification, CancellationToken cancellationToken)
            {
                var @event = await _eventStore.GetEvent(notification.EventId);

                var entity = new Customer
                {
                    Id      = notification.AggregateId,
                    Created = @event.TimeStamp
                };
                var redux = new ReduxStore <Customer>(Customer.Reducer, entity);

                redux.Dispatch(notification.Action);

                await _context.Customers.AddAsync(entity, cancellationToken);

                await _context.SaveChangesAsync(cancellationToken);
            }
            public async Task Handle(CustomerUpdated notification, CancellationToken cancellationToken)
            {
                var entity = await _context.Customers.FindAsync(notification.AggregateId);

                if (entity == null)
                {
                    throw new NotFoundException(nameof(Customer), notification.AggregateId);
                }

                var redux = new ReduxStore <Customer>(Customer.Reducer, entity);

                foreach (var action in notification.Actions)
                {
                    redux.Dispatch(action);
                }

                await _context.SaveChangesAsync(cancellationToken);
            }
示例#9
0
        /// <summary>
        /// Open Store DevTools in a separate window.
        /// </summary>
        /// <typeparam name="TState">Type of the state.</typeparam>
        /// <param name="store">Store to display information about.</param>
        /// <returns>True if the Store DevTools has been shown.</returns>
        public static async Task <bool> OpenDevToolsAsync <TState>(this ReduxStore <TState> store)
            where TState : class, new()
        {
            if (store == null || !store.TimeTravelEnabled)
            {
                return(false);
            }

            var appWindow = await AppWindow.TryCreateAsync();

            var appWindowContentFrame = new Frame();

            appWindowContentFrame.Navigate(typeof(DevToolsComponent));

            var devToolsComponent = appWindowContentFrame.Content as DevToolsComponent;

            devToolsComponent.Initialize(store);

            // TODO : Set as options
            // Extend view into title bar
            appWindow.TitleBar.ExtendsContentIntoTitleBar = true;

            // TODO : Set as options
            // Set TitleBar properties (colors)
            appWindow.TitleBar.ButtonBackgroundColor         = Colors.Transparent;
            appWindow.TitleBar.ButtonInactiveBackgroundColor = Colors.Transparent;
            appWindow.TitleBar.ButtonHoverBackgroundColor    = Color.FromArgb(255, 72, 42, 203);
            appWindow.TitleBar.ButtonPressedBackgroundColor  = Color.FromArgb(200, 72, 42, 203);
            appWindow.TitleBar.ButtonForegroundColor         = Colors.Black;

            ElementCompositionPreview.SetAppWindowContent(appWindow, appWindowContentFrame);

            bool result = await appWindow.TryShowAsync();

            appWindow.Closed += delegate
            {
                appWindowContentFrame.Content = null;
                appWindow = null;
            };

            return(result);
        }
示例#10
0
        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
            }
                );
        }
示例#11
0
 public ManagerWithStore()
 {
     Store = new ReduxStore <TState>();
 }
 public ReduxMiddlewareTests()
 {
     _incrementingReducer = new FakeReducer <int>(Incrementer);
     _store = new ReduxStore <int>(_incrementingReducer, stateFactory);
 }
示例#13
0
        public async Task CreateSnapshots()
        {
            var customerSnapshotDeltas = await _eventStore.QuerySnapshotDeltas(AggregateType);

            foreach (var delta in customerSnapshotDeltas)
            {
                Customer customer = null;
                if (delta.LastSnapshotVersion > 0)
                {
                    var snapShot = await _eventStore.GetSnapshot(delta.AggregateId, delta.LastSnapshotVersion);

                    customer = JsonConvert.DeserializeObject <Customer>(snapShot.SerializedData);
                }
                else
                {
                    customer = new Customer {
                        Id = delta.AggregateId
                    };
                }
                var redux = new ReduxStore <Customer>(Customer.Reducer, customer);

                var @events = await _eventStore.GetEvents(delta.AggregateId,
                                                          delta.LastSnapshotVersion, delta.CurrentVersion);

                foreach (var @event in @events)
                {
                    switch (@event.Name)
                    {
                    case "CustomerCreated":
                        customer.Created = @event.TimeStamp;
                        redux.Dispatch(JsonConvert.DeserializeObject <CreateCustomer>(@event.Data));
                        break;

                    case "CustomersFirstNameUpdated":
                        redux.Dispatch(JsonConvert.DeserializeObject <UpdateCustomersFirstName>(@event.Data));
                        break;

                    case "CustomersLastNameUpdated":
                        redux.Dispatch(JsonConvert.DeserializeObject <UpdateCustomersLastName>(@event.Data));
                        break;

                    case "CustomersPrefixUpdated":
                        redux.Dispatch(JsonConvert.DeserializeObject <UpdateCustomersPrefix>(@event.Data));
                        break;

                    case "CustomersTitleUpdated":
                        redux.Dispatch(JsonConvert.DeserializeObject <UpdateCustomersTitle>(@event.Data));
                        break;

                    default:
                        break;
                    }
                }
                await _eventStore.SaveSnapshot(new Snapshot
                {
                    AggregateId    = delta.AggregateId,
                    SerializedData = JsonConvert.SerializeObject(redux.State),
                    Version        = delta.CurrentVersion
                });
            }
        }
 public MovieSearchEffects(ReduxStore <MovieSearchState> store, IOmdbMovieService omdbMovieService)
 {
     _store            = store;
     _omdbMovieService = omdbMovieService;
 }
示例#15
0
        /// <summary>
        /// Enable the router feature to the specified store.
        /// </summary>
        /// <typeparam name="TState">Type of the state.</typeparam>
        /// <param name="store">Store used to store router information.</param>
        /// <param name="rootFrame">The root frame of the UWP application.</param>
        public static void EnableRouterFeature <TState>(this ReduxStore <TState> store, Frame rootFrame)
            where TState : class, IBaseRouterState, new()
        {
            // TODO : Find children frame in the current one for multi-layer navigation?

            // Add router navigation reducers
            var routerReducers = new[]
            {
                On <RouterNavigatingAction, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterNavigatedAction, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterErrorAction, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterCancelAction, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    )
            };

            var reducers = CreateSubReducers <TState, RouterState>(routerReducers, SelectRouter);

            store.AddReducers(reducers);

            // Listen to router events
            var navigatingEffect = CreateEffect <TState>(
                () => rootFrame.Events().Navigating
                .Select(@event =>
            {
                return(new RouterNavigatingAction
                {
                    Event = new RouterNavigatingEvent
                    {
                        Cancel = @event.Cancel,
                        NavigationMode = @event.NavigationMode,
                        Parameter = @event.Parameter,
                        SourcePageType = @event.SourcePageType
                    }
                });
            }),
                true
                );
            var navigatedEffect = CreateEffect <TState>(
                () => rootFrame.Events().Navigated
                .Select(@event =>
            {
                return(new RouterNavigatedAction
                {
                    Event = new RouterNavigatedEvent
                    {
                        ContentType = @event.Content?.GetType(),
                        SourcePageType = @event.SourcePageType,
                        NavigationMode = @event.NavigationMode,
                        Parameter = @event.Parameter,
                        Uri = @event.Uri
                    }
                });
            }),
                true
                );
            var navigationFailedEffect = CreateEffect <TState>(
                () => rootFrame.Events().NavigationFailed
                .Select(@event =>
            {
                return(new RouterErrorAction
                {
                    Event = new RouterErrorEvent
                    {
                        Exception = @event.Exception,
                        Handled = @event.Handled,
                        SourcePageType = @event.SourcePageType
                    }
                });
            }),
                true
                );
            var navigationStoppedEffect = CreateEffect <TState>(
                () => rootFrame.Events().NavigationStopped
                .Select(@event =>
            {
                return(new RouterCancelAction
                {
                    Event = new RouterCancelEvent
                    {
                        ContentType = @event.Content?.GetType(),
                        SourcePageType = @event.SourcePageType,
                        NavigationMode = @event.NavigationMode,
                        Parameter = @event.Parameter,
                        Uri = @event.Uri
                    }
                });
            }),
                true
                );

            // Add router navigation effects
            store.RegisterEffects(
                navigatingEffect,
                navigatedEffect,
                navigationFailedEffect,
                navigationStoppedEffect
                );
        }
示例#16
0
        public MovieListViewModel(
            NavigationManager navigationManager,
            ILocalStorageService localStorageService,
            ReduxStore <MovieSearchState> movieSearchStore)
        {
            _navigationManager   = navigationManager;
            _localStorageService = localStorageService;

            // Set initial value
            SearchText = movieSearchStore.State.SearchText;

            var source = new SourceCache <OmdbMovieSearchDto, string>(x => x.ImdbId)
                         .DisposeWith(CleanUp);

            source.Connect()
            .Sort(SortExpressionComparer <OmdbMovieSearchDto> .Ascending(p => p.Title), SortOptimisations.ComparesImmutableValuesOnly)
            .Bind(Movies)
            .Subscribe(_ => UpdateState())
            .DisposeWith(CleanUp);

            source.CountChanged
            .StartWith(0)
            .Select(x => x == 0)
            .ToPropertyEx(this, x => x.IsSourceEmpty)
            .DisposeWith(CleanUp);

            var searchTextObservable = this.WhenAnyValue(x => x.SearchText)
                                       .Skip(1)
                                       // Use throttle to prevent over requesting data
                                       .Throttle(TimeSpan.FromMilliseconds(250))
                                       .Publish();

            searchTextObservable
            .Where(string.IsNullOrEmpty)
            .Subscribe(_ => movieSearchStore.Dispatch(new ResetMovieSearchAction()))
            .DisposeWith(CleanUp);

            searchTextObservable
            .Where(x => !string.IsNullOrEmpty(x))
            .Subscribe(x => movieSearchStore.Dispatch(new PerformMovieSearchAction(x)))
            .DisposeWith(CleanUp);

            searchTextObservable.Connect();

            movieSearchStore
            .Select(MovieSearchSelectors.SelectIsSearching)
            .ToPropertyEx(this, x => x.IsSearching)
            .DisposeWith(CleanUp);

            movieSearchStore
            .Select(MovieSearchSelectors.SelectMovies)
            .Subscribe(x => source.Edit(list =>
            {
                list.Clear();
                list.AddOrUpdate(x);
            }))
            .DisposeWith(CleanUp);

            movieSearchStore
            .Select(MovieSearchSelectors.SelectSearchText)
            .Skip(1)
            .SelectMany(async x =>
            {
                await SaveSearchTextsAsync(x)
                .ConfigureAwait(false);

                return(Unit.Default);
            })
            .Subscribe()
            .DisposeWith(CleanUp);
        }
示例#17
0
 public static void DispatchResetAction <T>(ReduxStore <T> store) where T : class, new()
 {
     store.Dispatch(new ResetStateAction());
 }
示例#18
0
        private static void Main()
        {
            var store = new ReduxStore <GameState>(RootReducer.CreateReducers(), true);

            store.ObserveAction().Subscribe(_ =>
            {
                // Console.Clear();
                PrintGameStats(store);
            });

            #region Players Added
            const string Phar          = "Phar";
            const string Cainsith      = "cainsith";
            const string Jaxico        = "Jaxico";
            const string Sinsorium     = "Sinsorium";
            const string RarefiedLuck  = "RarefiedLuck";
            const string Psyberia      = "Psyberia!";
            const string SirSaltimus   = "SirSaltimus";
            const string Breadly       = "Breadly";
            const string DarkFalz      = "DarkFalz";
            const string iDrop         = "iDrop";
            const string SefiCompacto  = "SefiCompacto";
            const string Bullied       = "Gets Bullied By Dori";
            const string Cheez         = "cheezburg";
            const string Tzoonami      = "tzoonami";
            const string Dori          = "ElsalvaDorian";
            const string SaberRider    = "SaberRider";
            const string JaggerGascar  = "JaggerGascar";
            const string Vascosta      = "Vascosta Rica";
            const string Nub           = "nub";
            const string NetGlowGillie = "NetGlowGillie";
            const string WolfGirl      = "Wolfgirl1477";
            const string KillJoy       = "Kill Joy";
            const string Canadian      = "TheCanadian";
            #endregion

            store.Dispatch(new SetIdentifierAction {
                Identifier = "EXAMPLE GAME"
            });

            // Players Join
            #region Players Joined
            store.Dispatch(new AddPlayerAction {
                Identifier = Phar
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Cainsith
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Jaxico
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Sinsorium
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = RarefiedLuck
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Psyberia
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = SirSaltimus
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Breadly
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = DarkFalz
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = iDrop
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = SefiCompacto
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Bullied
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Cheez
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Tzoonami
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Dori
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = "TEST PLAYER"
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = SaberRider
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = JaggerGascar
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Vascosta
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Nub
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = NetGlowGillie
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = WolfGirl
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = KillJoy
            });
            store.Dispatch(new AddPlayerAction {
                Identifier = Canadian
            });
            #endregion

            // Player Leaves
            store.Dispatch(new RemovePlayerAction {
                Identifier = "TEST PLAYER"
            });

            // Assign Roles
            #region Player Assigns
            store.Dispatch(new AssignRoleAction {
                Identifier = Phar, RoleToAssign = new Bodyguard()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Sinsorium, RoleToAssign = new Hunter()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = RarefiedLuck, RoleToAssign = new Werewolf()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Psyberia, RoleToAssign = new Witch()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = SirSaltimus, RoleToAssign = new Sorceress()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Breadly, RoleToAssign = new Werewolf()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = iDrop, RoleToAssign = new Seer()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Cheez, RoleToAssign = new Mayor()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Tzoonami, RoleToAssign = new Werewolf()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Dori, RoleToAssign = new Mason()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = SaberRider, RoleToAssign = new Werewolf()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Vascosta, RoleToAssign = new Mason()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = Nub, RoleToAssign = new Lycan()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = NetGlowGillie, RoleToAssign = new Werewolf()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = WolfGirl, RoleToAssign = new Mason()
            });
            store.Dispatch(new AssignRoleAction {
                Identifier = KillJoy, RoleToAssign = new Prince()
            });
            #endregion

            // Night 1
            store.Dispatch(new SetNightAction());

            // Day 1
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Phar, Accusing = NetGlowGillie
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Phar
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Phar
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Bullied
            });

            // Night 2
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = SirSaltimus, Reason = EliminationCause.Werewolves
            });

            // Day 2
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Phar, Accusing = Cheez
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Cheez
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Phar, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Sinsorium, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Breadly, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = iDrop, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = NetGlowGillie, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Tzoonami, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = RarefiedLuck, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = WolfGirl
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SaberRider, Accusing = Jaxico
            });
            store.Dispatch(new EliminateAction {
                Identifier = WolfGirl, Reason = EliminationCause.LeftGame
            });

            // Night 3
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = Cainsith, Reason = EliminationCause.Werewolves
            });

            // Day 3
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Nub
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = iDrop
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = iDrop, Accusing = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Dori, Accusing = Jaxico
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = iDrop
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Jaxico
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Phar, Accusing = Sinsorium
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Phar
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Phar, Accusing = Vascosta
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Bullied, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Canadian, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = NetGlowGillie, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Tzoonami, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Dori, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Cheez, Accusing = Bullied
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Breadly, Accusing = Bullied
            });
            store.Dispatch(new EliminateAction {
                Identifier = Bullied, Reason = EliminationCause.Lynching
            });

            // Night 4
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = Phar, Reason = EliminationCause.Werewolves
            });

            // Day 4
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = Jaxico
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Canadian
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = Canadian
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = Canadian
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Breadly, Accusing = Canadian
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = JaggerGascar, Accusing = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = JaggerGascar
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Breadly
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Canadian, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = DarkFalz, Accusing = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = iDrop, Accusing = Canadian
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Cheez, Accusing = SefiCompacto
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = SefiCompacto
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Dori, Accusing = Canadian
            });
            store.Dispatch(new EliminateAction {
                Identifier = Canadian, Reason = EliminationCause.Lynching
            });

            // Night 5
            store.Dispatch(new SetNightAction());

            // Day 5
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = Cheez
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Cheez
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = KillJoy
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SaberRider, Accusing = KillJoy
            });
            store.Dispatch(new ClearVoteAction {
                Identifier = Jaxico
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Breadly, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Dori, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = JaggerGascar, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = DarkFalz, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = Dori
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = SaberRider
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Tzoonami, Accusing = SaberRider
            });
            store.Dispatch(new EliminateAction {
                Identifier = SaberRider, Reason = EliminationCause.Lynching
            });

            // Night 6
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = RarefiedLuck, Reason = EliminationCause.Witch
            });
            store.Dispatch(new EliminateAction {
                Identifier = Dori, Reason = EliminationCause.Werewolves
            });

            // Day 6
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Sinsorium, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = DarkFalz, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Cheez, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = JaggerGascar, Accusing = Breadly
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Tzoonami, Accusing = Breadly
            });
            store.Dispatch(new EliminateAction {
                Identifier = Breadly, Reason = EliminationCause.Lynching
            });

            // Night 7
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = DarkFalz, Reason = EliminationCause.Werewolves
            });

            // Day 7
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Sinsorium, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = KillJoy, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = NetGlowGillie, Accusing = Tzoonami
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = JaggerGascar, Accusing = Tzoonami
            });
            store.Dispatch(new EliminateAction {
                Identifier = Tzoonami, Reason = EliminationCause.Lynching
            });

            // Night 8
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EliminateAction {
                Identifier = KillJoy, Reason = EliminationCause.Werewolves
            });

            // Day 8
            store.Dispatch(new SetDayAction());
            store.Dispatch(new VoteLynchAction {
                Identifier = SefiCompacto, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = iDrop, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Sinsorium, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Vascosta, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Nub, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Jaxico, Accusing = NetGlowGillie
            });
            store.Dispatch(new VoteLynchAction {
                Identifier = Psyberia, Accusing = NetGlowGillie
            });
            store.Dispatch(new EliminateAction {
                Identifier = NetGlowGillie, Reason = EliminationCause.Lynching
            });

            // End Game
            store.Dispatch(new SetNightAction());
            store.Dispatch(new EndGameAction());
        }
示例#19
0
        public void ConnectToStore <T>(ReduxStore <T> store)
            where T : class, IImmutable, new()
        {
            var rootSelector = Selectors.CreateSelector((T state) => state);

            var onHistory = store.ObserveHistory()
                            .WithLatestFrom(store.Select(rootSelector), (history, state) => (history, state))
                            .Select(pair => _selectHistoryRecords(pair.history, pair.state));

            var onLatestEnsureHistory = EnsureManager
                                        .GetHistory()
                                        .Select(history => history.ToImmutableDictionary(session => session.Action));

            onLatestEnsureHistory
            .Subscribe(val => _ensureSessions = val)
            .DisposedBy(this);

            MvvmRx.ApplyOnCollection(onHistory, this, Records,
                                     factory: Resolver.Resolve <HistoryRecordVm>,
                                     syncer: (model, vm) => vm.ReadModel(model, _ensureSessions),
                                     onRemove: vm => vm.Dispose());

            var onCurrentHistoryRecord = Observable.CombineLatest(
                onHistory,
                MvvmRx.ObservePropertyValues(this, x => x.SelectedItem),
                (records, index) => (records, index))
                                         .Select(pair => _pure_getSelectedHistoryRecord(pair.records, pair.index))
                                         .Where(record => record != null);

            onCurrentHistoryRecord
            .Select(record => _pure_createJsonHierarchy(record.Action))
            .ApplyOnProperty(this, x => x.Action);

            onCurrentHistoryRecord
            .Select(record => _pure_createJsonHierarchy(record.NextState))
            .ApplyOnProperty(this, x => x.State);

            onCurrentHistoryRecord
            .Subscribe(record => Differ.ReadModel(record.PreviousState.ToJson(), record.NextState.ToJson()))
            .DisposedBy(this);

            var onEnsureSession = Observable.CombineLatest(onLatestEnsureHistory, onCurrentHistoryRecord,
                                                           (history, record) => _pure_getEnsureSessionHistory(record, history));

            onEnsureSession
            .Select(session => session?.Items
                    ?.Select(item => Resolver.Resolve <EnsureItemVm>().ReadModel(item))
                    ?.ToObservableCollection()
                    ?? new ObservableCollection <EnsureItemVm>()
                    )
            .ApplyOnProperty(this, x => x.EnsureItems);

            var onEnsureItem = Observable.CombineLatest(
                onEnsureSession,
                MvvmRx.ObservePropertyValues(this, x => x.SelectedEnsureItem),
                (session, index) => (session, index))
                               .Select(pair => _pure_getSelectedEnsureItem(pair.session, pair.index));

            onEnsureItem.Select(item => _pure_createJsonHierarchy(item?.Context.Entity))
            .ApplyOnProperty(this, x => x.EnsureItemState);

            onEnsureItem
            .Subscribe(item => EnsureDiffer.ReadModel(item?.Before.ToJson(), item?.After.ToJson()))
            .DisposedBy(this);
        }
示例#20
0
        public static void EnableRouterFeature <TState>(this ReduxStore <TState> store, Frame rootFrame)
            where TState : class, IBaseRouterState, new()
        {
            // TODO : Find children frame in the current one for multi-layer navigation?

            // Add router navigation reducers
            var routerReducers = new[]
            {
                On <RouterNavigating, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterNavigated, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterError, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    ),
                On <RouterCancel, RouterState>(
                    (state, action) => state.With(new
                {
                    rootFrame.CanGoBack,
                    rootFrame.CanGoForward,
                })
                    )
            };

            var reducers = CreateSubReducers <TState, RouterState>(routerReducers, SelectRouter);

            store.AddReducers(reducers);

            // Listen to router events
            var navigatingEffect = CreateEffect <TState>(
                () => rootFrame.Events().Navigating
                .Select(@event =>
            {
                return(new RouterNavigating
                {
                    Event = @event
                });
            }),
                true
                );
            var navigatedEffect = CreateEffect <TState>(
                () => rootFrame.Events().Navigated
                .Select(@event =>
            {
                return(new RouterNavigated
                {
                    Event = @event
                });
            }),
                true
                );
            var navigationFailedEffect = CreateEffect <TState>(
                () => rootFrame.Events().NavigationFailed
                .Select(@event =>
            {
                return(new RouterError
                {
                    Event = @event
                });
            }),
                true
                );
            var navigationStoppedEffect = CreateEffect <TState>(
                () => rootFrame.Events().NavigationStopped
                .Select(@event =>
            {
                return(new RouterCancel
                {
                    Event = @event
                });
            }),
                true
                );

            // Add router navigation effects
            store.RegisterEffects(
                navigatingEffect,
                navigatedEffect,
                navigationFailedEffect,
                navigationStoppedEffect
                );
        }
        public void Initialize <TState>(ReduxStore <TState> store) where TState : class, new()
        {
            if (store.TimeTravelEnabled)
            {
                // TODO : Cannot activate History component
            }

            // 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(_ => _internalStore.Dispatch(new TogglePlayPauseAction()));

            Slider.Events().ValueChanged
            .Where(_ => Slider.FocusState != FocusState.Unfocused)
            .Subscribe(e =>
            {
                int newPosition = (int)e.NewValue;
                _internalStore.Dispatch(new MoveToPositionAction {
                    Position = newPosition
                });
            });

            // Observe changes on internal state
            _internalStore.Select(state => state.MaxPosition)
            .Subscribe(maxPosition =>
            {
                Slider.Maximum = maxPosition;
            });

            Observable.CombineLatest(
                _internalStore.Select(state => state.CurrentPosition),
                _internalStore.Select(state => state.PlaySessionActive),
                _internalStore.Select(state => state.MaxPosition),
                store.ObserveCanUndo(),
                store.ObserveCanRedo(),
                Tuple.Create
                )
            .ObserveOnDispatcher()
            .Subscribe(x =>
            {
                var(currentPosition, playSessionActive, maxPosition, canUndo, canRedo) = x;

                Slider.Value = currentPosition;

                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";
                }
            });

            _internalStore.ObserveAction <MoveToPositionAction>()
            .Subscribe(a =>
            {
                if (a.Position < _internalStore.State.CurrentPosition)
                {
                    for (int i = 0; i < _internalStore.State.CurrentPosition - a.Position; i++)
                    {
                        store.Undo();
                    }
                }
                if (a.Position > _internalStore.State.CurrentPosition)
                {
                    for (int i = 0; i < a.Position - _internalStore.State.CurrentPosition; i++)
                    {
                        store.Redo();
                    }
                }
            });

            // Observe changes on listened state
            var goForwardNormalActionOrigin = store.ObserveAction()
                                              .Select(action => new { Action = action, BreaksTimeline = true });
            var goForwardRedoneActionOrigin = store.ObserveAction(ActionOriginFilter.Redone)
                                              .Select(action => new { Action = action, BreaksTimeline = false });

            goForwardNormalActionOrigin.Merge(goForwardRedoneActionOrigin)
            .ObserveOnDispatcher()
            .Subscribe(x =>
            {
                _internalStore.Dispatch(new GoForwardAction {
                    Action = x.Action, BreaksTimeline = x.BreaksTimeline
                });
                if (_internalStore.State.PlaySessionActive && !store.CanRedo)
                {
                    _internalStore.Dispatch(new TogglePlayPauseAction());
                }
            });

            store.ObserveUndoneAction()
            .ObserveOnDispatcher()
            .Subscribe(_ => _internalStore.Dispatch(new GoBackAction()));

            store.ObserveReset()
            .ObserveOnDispatcher()
            .Subscribe(_ => _internalStore.Dispatch(new ResetAction()));

            _internalStore.Select(state => state.PlaySessionActive)
            .Select(playSessionActive =>
                    playSessionActive ? Observable.Interval(TimeSpan.FromSeconds(1)) : Observable.Empty <long>()
                    )
            .Switch()
            .ObserveOnDispatcher()
            .Subscribe(_ =>
            {
                bool canRedo = store.Redo();
                if (!canRedo)
                {
                    _internalStore.Dispatch(new TogglePlayPauseAction());
                }
            });

            // Track redux actions
            _internalStore.ObserveAction()
            .Subscribe(action =>
            {
                TrackReduxAction(action);
            });
        }
示例#22
0
        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();
        }