diff --git a/Ficdown.Console/Program.cs b/Ficdown.Console/Program.cs
index c8c035b..516ad34 100644
--- a/Ficdown.Console/Program.cs
+++ b/Ficdown.Console/Program.cs
@@ -1,6 +1,7 @@
namespace Ficdown.Console
{
using System;
+ using System.Linq;
using System.IO;
using Microsoft.SqlServer.Server;
using Parser;
@@ -115,6 +116,11 @@
var story = parser.ParseStory(storyText);
+ story.Orphans.ToList().ForEach(o =>
+ {
+ Console.Error.WriteLine("Warning (line {0}): {1} {2} is unreachable", o.LineNumber, o.Type, o.Name);
+ });
+
IRenderer rend;
switch (format)
{
diff --git a/Ficdown.Parser/FicDownParser.cs b/Ficdown.Parser/FicDownParser.cs
index fb67fc9..af106f2 100644
--- a/Ficdown.Parser/FicDownParser.cs
+++ b/Ficdown.Parser/FicDownParser.cs
@@ -4,6 +4,7 @@
namespace Ficdown.Parser
{
using System;
+ using System.Linq;
using System.Collections.Generic;
using Model.Parser;
using Parser;
@@ -38,7 +39,19 @@ namespace Ficdown.Parser
var blocks = BlockHandler.ExtractBlocks(lines);
var story = BlockHandler.ParseBlocks(blocks);
GameTraverser.Story = story;
- return StateResolver.Resolve(GameTraverser.Enumerate(), story);
+ var resolved = StateResolver.Resolve(GameTraverser.Enumerate(), story);
+ resolved.Orphans = GameTraverser.OrphanedScenes.Select(o => new Orphan
+ {
+ Type = "Scene",
+ Name = o.Name,
+ LineNumber = o.LineNumber
+ }).Union(GameTraverser.OrphanedActions.Select(o => new Orphan
+ {
+ Type = "Action",
+ Name = o.Toggle,
+ LineNumber = o.LineNumber
+ }));
+ return resolved;
}
}
}
diff --git a/Ficdown.Parser/Ficdown.Parser.csproj b/Ficdown.Parser/Ficdown.Parser.csproj
index 7a7a1ca..64f078a 100644
--- a/Ficdown.Parser/Ficdown.Parser.csproj
+++ b/Ficdown.Parser/Ficdown.Parser.csproj
@@ -84,6 +84,7 @@
+
@@ -109,4 +110,4 @@
-->
-
+
\ No newline at end of file
diff --git a/Ficdown.Parser/Model/Parser/Orphan.cs b/Ficdown.Parser/Model/Parser/Orphan.cs
new file mode 100644
index 0000000..dba8f5f
--- /dev/null
+++ b/Ficdown.Parser/Model/Parser/Orphan.cs
@@ -0,0 +1,9 @@
+namespace Ficdown.Parser.Model.Parser
+{
+ public class Orphan
+ {
+ public string Type { get; set; }
+ public string Name { get; set; }
+ public int LineNumber { get; set; }
+ }
+}
diff --git a/Ficdown.Parser/Model/Parser/ResolvedStory.cs b/Ficdown.Parser/Model/Parser/ResolvedStory.cs
index 1f34845..a36f0af 100644
--- a/Ficdown.Parser/Model/Parser/ResolvedStory.cs
+++ b/Ficdown.Parser/Model/Parser/ResolvedStory.cs
@@ -8,5 +8,6 @@
public string Description { get; set; }
public string FirstPage { get; set; }
public IEnumerable Pages { get; set; }
+ public IEnumerable Orphans { get; set; }
}
}
diff --git a/Ficdown.Parser/Model/Story/Action.cs b/Ficdown.Parser/Model/Story/Action.cs
index 04a8136..30dc720 100644
--- a/Ficdown.Parser/Model/Story/Action.cs
+++ b/Ficdown.Parser/Model/Story/Action.cs
@@ -6,5 +6,6 @@
public string Toggle { get; set; }
public string Description { get; set; }
public int LineNumber { get; set; }
+ public bool Visited { get; set; }
}
}
diff --git a/Ficdown.Parser/Model/Story/Scene.cs b/Ficdown.Parser/Model/Story/Scene.cs
index 14f02b7..f957c33 100644
--- a/Ficdown.Parser/Model/Story/Scene.cs
+++ b/Ficdown.Parser/Model/Story/Scene.cs
@@ -10,5 +10,6 @@
public string Description { get; set; }
public IDictionary Conditions { get; set; }
public int LineNumber { get; set; }
+ public bool Visited { get; set; }
}
}
diff --git a/Ficdown.Parser/Player/GameTraverser.cs b/Ficdown.Parser/Player/GameTraverser.cs
index cdd23ac..d4fdb36 100644
--- a/Ficdown.Parser/Player/GameTraverser.cs
+++ b/Ficdown.Parser/Player/GameTraverser.cs
@@ -1,10 +1,12 @@
namespace Ficdown.Parser.Player
{
+ using System;
using System.Collections.Generic;
using System.Linq;
using Model.Player;
using Model.Story;
using Parser;
+ using Action = Model.Story.Action;
internal class GameTraverser : IGameTraverser
{
@@ -13,6 +15,7 @@
private IDictionary _processed;
private IDictionary _compressed;
private IDictionary _actionMatrix;
+ private bool _wasRun = false;
private Story _story;
public Story Story
@@ -29,8 +32,29 @@
}
}
+ public IEnumerable OrphanedScenes
+ {
+ get
+ {
+ if(!_wasRun) throw new Exception("Call Enumerate() before getting orphans");
+ return _story.Scenes.SelectMany(l => l.Value, (l, s) => s).Where(s => !s.Visited);
+ }
+ }
+
+ public IEnumerable OrphanedActions
+ {
+ get
+ {
+ if(!_wasRun) throw new Exception("Call Enumerate() before getting orphans");
+ return _actionMatrix.Values.Where(a => !a.Visited);
+ }
+ }
+
public IEnumerable Enumerate()
{
+ if(_wasRun) throw new Exception("Can't call Enumerate() more than once");
+ _wasRun = true;
+
// generate comprehensive enumeration
var initial = _manager.InitialState;
@@ -97,11 +121,16 @@
private void ProcessState(StateQueueItem currentState)
{
+ currentState.Page.Scene.Visited = true;
+
var states = new HashSet();
var anchors = Utilities.GetInstance(currentState.Page.Scene.Name, currentState.Page.Scene.LineNumber).ParseAnchors(currentState.Page.Scene.Description).ToList();
foreach (var action in GetActionsForPage(currentState.Page))
+ {
+ action.Visited = true;
anchors.AddRange(Utilities.GetInstance(action.Toggle, action.LineNumber).ParseAnchors(action.Description));
+ }
var conditionals =
anchors.SelectMany(
a => a.Href.Conditions != null ? a.Href.Conditions.Select(c => c.Key) : new string[] {})
diff --git a/Ficdown.Parser/Player/IGameTraverser.cs b/Ficdown.Parser/Player/IGameTraverser.cs
index f390402..23c995d 100644
--- a/Ficdown.Parser/Player/IGameTraverser.cs
+++ b/Ficdown.Parser/Player/IGameTraverser.cs
@@ -8,5 +8,7 @@
{
Story Story { get; set; }
IEnumerable Enumerate();
+ IEnumerable OrphanedScenes { get; }
+ IEnumerable OrphanedActions { get; }
}
}