started tracking info to help collapse full enumeration
This commit is contained in:
parent
1d0834e8ac
commit
bd99018ed1
7 changed files with 110 additions and 33 deletions
|
@ -1,8 +1,10 @@
|
|||
namespace Ficdown.Parser.Tests
|
||||
{
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Player;
|
||||
using ServiceStack.Text;
|
||||
using TestStories;
|
||||
using Xunit;
|
||||
|
||||
|
@ -20,6 +22,7 @@
|
|||
|
||||
var traverser = new GameTraverser(story);
|
||||
var test = traverser.Enumerate();
|
||||
Console.WriteLine(test.Take(10).Dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Model\Traverser\PageState.cs" />
|
||||
<Compile Include="Model\Traverser\State.cs" />
|
||||
<Compile Include="Model\Traverser\StateQueueItem.cs" />
|
||||
<Compile Include="Player\IRenderer.cs" />
|
||||
<Compile Include="Player\HtmlRenderer.cs" />
|
||||
<Compile Include="Parser\BlockHandler.cs" />
|
||||
|
|
|
@ -8,10 +8,9 @@
|
|||
internal class PageState
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public BitArray PlayerState { get; set; }
|
||||
public BitArray ScenesSeen { get; set; }
|
||||
public BitArray ActionsToShow { get; set; }
|
||||
public Scene Scene { get; set; }
|
||||
public State State { get; set; }
|
||||
public State AffectedState { get; set; }
|
||||
|
||||
public string Resolved { get; set; }
|
||||
public IDictionary<string, string> Links { get; set; }
|
||||
|
@ -23,10 +22,11 @@
|
|||
{
|
||||
if (_uniqueHash == null)
|
||||
{
|
||||
var combined = new bool[PlayerState.Count + ScenesSeen.Count + ActionsToShow.Count];
|
||||
PlayerState.CopyTo(combined, 0);
|
||||
ScenesSeen.CopyTo(combined, PlayerState.Count);
|
||||
ActionsToShow.CopyTo(combined, PlayerState.Count + ScenesSeen.Count);
|
||||
var combined =
|
||||
new bool[State.PlayerState.Count + State.ScenesSeen.Count + State.ActionsToShow.Count];
|
||||
State.PlayerState.CopyTo(combined, 0);
|
||||
State.ScenesSeen.CopyTo(combined, State.PlayerState.Count);
|
||||
State.ActionsToShow.CopyTo(combined, State.PlayerState.Count + State.ScenesSeen.Count);
|
||||
var ba = new BitArray(combined);
|
||||
var byteSize = (int) Math.Ceiling(combined.Length/8.0);
|
||||
var encoded = new byte[byteSize];
|
||||
|
|
11
Ficdown.Parser/Model/Traverser/State.cs
Normal file
11
Ficdown.Parser/Model/Traverser/State.cs
Normal file
|
@ -0,0 +1,11 @@
|
|||
namespace Ficdown.Parser.Model.Traverser
|
||||
{
|
||||
using System.Collections;
|
||||
|
||||
internal class State
|
||||
{
|
||||
public BitArray PlayerState { get; set; }
|
||||
public BitArray ScenesSeen { get; set; }
|
||||
public BitArray ActionsToShow { get; set; }
|
||||
}
|
||||
}
|
10
Ficdown.Parser/Model/Traverser/StateQueueItem.cs
Normal file
10
Ficdown.Parser/Model/Traverser/StateQueueItem.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
namespace Ficdown.Parser.Model.Traverser
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
|
||||
internal class StateQueueItem
|
||||
{
|
||||
public PageState Page { get; set; }
|
||||
public IList<State> AffectedStates { get; set; }
|
||||
}
|
||||
}
|
|
@ -9,13 +9,13 @@
|
|||
internal class GameTraverser
|
||||
{
|
||||
private readonly StateManager _manager;
|
||||
private readonly Queue<PageState> _processingQueue;
|
||||
private readonly Queue<StateQueueItem> _processingQueue;
|
||||
private readonly IDictionary<string, PageState> _processed;
|
||||
|
||||
public GameTraverser(Story story)
|
||||
{
|
||||
_manager = new StateManager(story);
|
||||
_processingQueue = new Queue<PageState>();
|
||||
_processingQueue = new Queue<StateQueueItem>();
|
||||
_processed = new Dictionary<string, PageState>();
|
||||
}
|
||||
|
||||
|
@ -23,13 +23,18 @@
|
|||
{
|
||||
// generate comprehensive enumeration
|
||||
|
||||
_processingQueue.Enqueue(_manager.InitialState);
|
||||
var initial = _manager.InitialState;
|
||||
_processingQueue.Enqueue(new StateQueueItem
|
||||
{
|
||||
Page = initial,
|
||||
AffectedStates = new List<State> {initial.AffectedState}
|
||||
});
|
||||
while (_processingQueue.Count > 0)
|
||||
{
|
||||
var state = _processingQueue.Dequeue();
|
||||
if (!_processed.ContainsKey(state.UniqueHash))
|
||||
if (!_processed.ContainsKey(state.Page.UniqueHash))
|
||||
{
|
||||
_processed.Add(state.UniqueHash, state);
|
||||
_processed.Add(state.Page.UniqueHash, state.Page);
|
||||
ProcessState(state);
|
||||
}
|
||||
}
|
||||
|
@ -40,21 +45,39 @@
|
|||
return _processed.Values;
|
||||
}
|
||||
|
||||
private void ProcessState(PageState currentState)
|
||||
private void ProcessState(StateQueueItem currentState)
|
||||
{
|
||||
var states = new HashSet<string>();
|
||||
foreach (
|
||||
var anchor in
|
||||
Utilities.ParseAnchors(currentState.Scene.Description)
|
||||
.Where(a => a.Href.Target != null || a.Href.Toggles != null))
|
||||
|
||||
var anchors = Utilities.ParseAnchors(currentState.Page.Scene.Description);
|
||||
var conditionals =
|
||||
anchors.SelectMany(
|
||||
a => a.Href.Conditions != null ? a.Href.Conditions.Select(c => c.Key) : new string[] {})
|
||||
.Distinct()
|
||||
.ToArray();
|
||||
var hasFirstSeen = RegexLib.BlockQuotes.IsMatch(currentState.Page.Scene.Description);
|
||||
|
||||
foreach (var affected in currentState.AffectedStates)
|
||||
{
|
||||
var newState = _manager.ResolveNewState(anchor, currentState);
|
||||
if (!currentState.Links.ContainsKey(anchor.Original))
|
||||
currentState.Links.Add(anchor.Original, newState.UniqueHash);
|
||||
// signal to previous scenes that this scene's used conditionals are important
|
||||
foreach (var conditional in conditionals) _manager.ToggleStateOn(affected, conditional);
|
||||
|
||||
// signal to previous scenes if this scene has first-seen text
|
||||
if (hasFirstSeen) _manager.ToggleSeenSceneOn(affected, currentState.Page.Scene.Id);
|
||||
}
|
||||
|
||||
foreach (var anchor in anchors.Where(a => a.Href.Target != null || a.Href.Toggles != null))
|
||||
{
|
||||
var newState = _manager.ResolveNewState(anchor, currentState.Page);
|
||||
if (!currentState.Page.Links.ContainsKey(anchor.Original))
|
||||
currentState.Page.Links.Add(anchor.Original, newState.UniqueHash);
|
||||
|
||||
if (!states.Contains(newState.UniqueHash) && !_processed.ContainsKey(newState.UniqueHash))
|
||||
{
|
||||
states.Add(newState.UniqueHash);
|
||||
_processingQueue.Enqueue(newState);
|
||||
var newAffected = new List<State>(currentState.AffectedStates);
|
||||
newAffected.Add(newState.AffectedState);
|
||||
_processingQueue.Enqueue(new StateQueueItem {Page = newState, AffectedStates = newAffected});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,9 +47,18 @@
|
|||
{
|
||||
Id = Guid.Empty,
|
||||
Links = new Dictionary<string, string>(),
|
||||
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
||||
ScenesSeen = new BitArray(_sceneCount),
|
||||
ActionsToShow = new BitArray(_actionCount),
|
||||
State = new State
|
||||
{
|
||||
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
||||
ScenesSeen = new BitArray(_sceneCount),
|
||||
ActionsToShow = new BitArray(_actionCount)
|
||||
},
|
||||
AffectedState = new State
|
||||
{
|
||||
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
||||
ScenesSeen = new BitArray(_sceneCount),
|
||||
ActionsToShow = new BitArray(_actionCount)
|
||||
},
|
||||
Scene = _story.Scenes[_story.FirstScene].Single(s => s.Conditions == null)
|
||||
};
|
||||
}
|
||||
|
@ -59,23 +68,33 @@
|
|||
{
|
||||
var target = anchor.Href.Target ?? current.Scene.Key;
|
||||
|
||||
var newState = CloneState(current);
|
||||
newState.ScenesSeen[current.Scene.Id - 1] = true;
|
||||
var newState = ClonePage(current);
|
||||
newState.State.ScenesSeen[current.Scene.Id - 1] = true;
|
||||
if (anchor.Href.Toggles != null)
|
||||
{
|
||||
foreach (var toggle in anchor.Href.Toggles)
|
||||
{
|
||||
if (_story.Actions.ContainsKey(toggle))
|
||||
{
|
||||
newState.ActionsToShow[_story.Actions[toggle].Id - 1] = true;
|
||||
newState.State.ActionsToShow[_story.Actions[toggle].Id - 1] = true;
|
||||
}
|
||||
newState.PlayerState[_stateMatrix[toggle]] = true;
|
||||
newState.State.PlayerState[_stateMatrix[toggle]] = true;
|
||||
}
|
||||
}
|
||||
newState.Scene = GetScene(target, newState.PlayerState);
|
||||
newState.Scene = GetScene(target, newState.State.PlayerState);
|
||||
return newState;
|
||||
}
|
||||
|
||||
public void ToggleStateOn(State state, string toggle)
|
||||
{
|
||||
state.PlayerState[_stateMatrix[toggle]] = true;
|
||||
}
|
||||
|
||||
public void ToggleSeenSceneOn(State state, int sceneId)
|
||||
{
|
||||
state.ScenesSeen[sceneId - 1] = true;
|
||||
}
|
||||
|
||||
private Scene GetScene(string target, BitArray playerState)
|
||||
{
|
||||
if (!_story.Scenes.ContainsKey(target))
|
||||
|
@ -102,15 +121,24 @@
|
|||
return scene.Conditions.All(c => playerState[_stateMatrix[c.Key]] == c.Value);
|
||||
}
|
||||
|
||||
private PageState CloneState(PageState state)
|
||||
private PageState ClonePage(PageState page)
|
||||
{
|
||||
return new PageState
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Links = new Dictionary<string, string>(),
|
||||
PlayerState = state.PlayerState.Clone() as BitArray,
|
||||
ScenesSeen = state.ScenesSeen.Clone() as BitArray,
|
||||
ActionsToShow = new BitArray(_actionCount)
|
||||
State = new State
|
||||
{
|
||||
PlayerState = page.State.PlayerState.Clone() as BitArray,
|
||||
ScenesSeen = page.State.ScenesSeen.Clone() as BitArray,
|
||||
ActionsToShow = new BitArray(_actionCount)
|
||||
},
|
||||
AffectedState = new State
|
||||
{
|
||||
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
||||
ScenesSeen = new BitArray(_sceneCount),
|
||||
ActionsToShow = new BitArray(_actionCount)
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue