starting scene expansion
This commit is contained in:
parent
4538edd9a3
commit
12ac1cfadc
|
@ -1,29 +1,6 @@
|
||||||
namespace Ficdown.Parser.Tests
|
namespace Ficdown.Parser.Tests
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Text;
|
|
||||||
using Engine;
|
|
||||||
using Model.Parser;
|
|
||||||
using Model.Story;
|
|
||||||
using ServiceStack.Text;
|
|
||||||
using TestStories;
|
|
||||||
using Xunit;
|
|
||||||
|
|
||||||
public class BlockHandlerTests
|
public class BlockHandlerTests
|
||||||
{
|
{
|
||||||
[Fact]
|
|
||||||
public void GoodTestStoryShouldParse()
|
|
||||||
{
|
|
||||||
var lines = Encoding.UTF8.GetString(Resources.the_robot_king).Split(new[] {'\r', '\n'});
|
|
||||||
var handler = new BlockHandler();
|
|
||||||
IEnumerable<Block> blocks = null;
|
|
||||||
Story story = null;
|
|
||||||
Assert.DoesNotThrow(() => blocks = handler.ExtractBlocks(lines));
|
|
||||||
Assert.DoesNotThrow(() => story = handler.ParseBlocks(blocks));
|
|
||||||
Assert.NotNull(story);
|
|
||||||
|
|
||||||
Console.WriteLine(story.Dump());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,21 @@
|
||||||
using System;
|
namespace Ficdown.Parser.Tests
|
||||||
using System.Collections.Generic;
|
{
|
||||||
using System.Linq;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using ServiceStack.Text;
|
||||||
|
using TestStories;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
namespace Ficdown.Parser.Tests
|
public class IntegrationTests
|
||||||
{
|
{
|
||||||
class IntegrationTests
|
[Fact]
|
||||||
|
public void CanParseValidStoryFile()
|
||||||
{
|
{
|
||||||
|
var parser = new FicdownParser();
|
||||||
|
var storyText = Encoding.UTF8.GetString(Resources.the_robot_king);
|
||||||
|
var story = parser.ParseStory(storyText);
|
||||||
|
Assert.NotNull(story);
|
||||||
|
Console.WriteLine(story.Dump());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,12 +74,7 @@
|
||||||
|
|
||||||
if (!story.Scenes.ContainsKey(storyTarget))
|
if (!story.Scenes.ContainsKey(storyTarget))
|
||||||
throw new FormatException(string.Format("Story targets non-existent scene: {0}", storyTarget));
|
throw new FormatException(string.Format("Story targets non-existent scene: {0}", storyTarget));
|
||||||
story.FirstScene =
|
story.FirstScene = storyTarget;
|
||||||
story.Scenes[storyTarget].SingleOrDefault(
|
|
||||||
s => s.Conditions == null || s.Conditions.All(c => c.StartsWith("!")));
|
|
||||||
if (story.FirstScene == null)
|
|
||||||
throw new FormatException(string.Format("Story targets scene with no unconditional definition: {0}",
|
|
||||||
storyTarget));
|
|
||||||
|
|
||||||
return story;
|
return story;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
namespace Ficdown.Parser.Engine
|
namespace Ficdown.Parser.Engine
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Model.Story;
|
using Model.Story;
|
||||||
|
using Model.Story.Extensions;
|
||||||
|
|
||||||
public class SceneLinker : ISceneLinker
|
public class SceneLinker : ISceneLinker
|
||||||
{
|
{
|
||||||
|
|
||||||
public void ExpandScenes(Story story)
|
public void ExpandScenes(Story story)
|
||||||
{
|
{
|
||||||
|
VerifySanity(story);
|
||||||
|
|
||||||
var newScenes = new Dictionary<string, IList<Scene>>();
|
var newScenes = new Dictionary<string, IList<Scene>>();
|
||||||
foreach(var key in story.Scenes.Keys)
|
foreach(var key in story.Scenes.Keys)
|
||||||
{
|
{
|
||||||
|
@ -15,14 +20,72 @@
|
||||||
foreach (var scene in story.Scenes[key])
|
foreach (var scene in story.Scenes[key])
|
||||||
{
|
{
|
||||||
var anchors = RegexLib.Anchors.Matches(scene.Description);
|
var anchors = RegexLib.Anchors.Matches(scene.Description);
|
||||||
|
// get a list of all unique condition combinations from the anchors
|
||||||
|
var uniques = new List<IList<string>>();
|
||||||
foreach (Match anchor in anchors)
|
foreach (Match anchor in anchors)
|
||||||
{
|
{
|
||||||
string target;
|
string target;
|
||||||
IList<string> conditions, toggles;
|
IList<string> conditions, toggles;
|
||||||
Utilities.ParseHref(anchor.Groups["href"].Value, out target, out conditions, out toggles);
|
Utilities.ParseHref(anchor.Groups["href"].Value, out target, out conditions, out toggles);
|
||||||
|
if (conditions != null)
|
||||||
|
{
|
||||||
|
// union with the conditions required to reach this scene, if any
|
||||||
|
if (scene.Conditions != null)
|
||||||
|
{
|
||||||
|
conditions = conditions.Union(scene.Conditions).ToList();
|
||||||
|
if (conditions.Count == scene.Conditions.Count)
|
||||||
|
continue; //WARN this anchor will never resolve false
|
||||||
|
}
|
||||||
|
|
||||||
|
AddUnique(uniques, conditions);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// resolve the current scene
|
||||||
|
newScenes[key].Add(ResolveScene(scene, anchors));
|
||||||
|
// resolve the uniques
|
||||||
|
foreach (var unique in uniques)
|
||||||
|
{
|
||||||
|
var uscene = scene.Clone();
|
||||||
|
uscene.Conditions = unique;
|
||||||
|
newScenes[key].Add(ResolveScene(uscene, anchors));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
story.Scenes = newScenes;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddUnique(IList<IList<string>> uniques, IList<string> conditions)
|
||||||
|
{
|
||||||
|
// ignore this combo if there's a contradiction
|
||||||
|
if (conditions.Where(c => !c.StartsWith("!"))
|
||||||
|
.Any(c => conditions.Contains(string.Format("!{0}", c))))
|
||||||
|
return; // WARN this anchor will never resolve true
|
||||||
|
|
||||||
|
// make sure this is actually unique
|
||||||
|
if (uniques.Any(u => u.Intersect(conditions).Count() == conditions.Count)) return;
|
||||||
|
|
||||||
|
uniques.Add(conditions);
|
||||||
|
|
||||||
|
// we need to treat this unioned with all other existing uniques as another potential unique
|
||||||
|
var existing = new List<IList<string>>(uniques);
|
||||||
|
foreach (var old in existing)
|
||||||
|
{
|
||||||
|
AddUnique(uniques, old.Union(conditions).ToList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Scene ResolveScene(Scene scene, MatchCollection anchors)
|
||||||
|
{
|
||||||
|
foreach (Match anchor in anchors)
|
||||||
|
{
|
||||||
|
var satisfied = Utilities.ConditionsSatisfied(anchor.Groups["conditions"].Value, scene.Conditions);
|
||||||
|
}
|
||||||
|
return scene;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void VerifySanity(Story story)
|
||||||
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,5 +47,10 @@
|
||||||
}
|
}
|
||||||
else throw new FormatException(string.Format("Invalid href: {0}", href));
|
else throw new FormatException(string.Format("Invalid href: {0}", href));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static bool ConditionsSatisfied(string cquery, IList<string> conditions)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
namespace Ficdown.Parser
|
namespace Ficdown.Parser
|
||||||
{
|
{
|
||||||
using System.IO;
|
|
||||||
using Engine;
|
using Engine;
|
||||||
using Model.Story;
|
using Model.Story;
|
||||||
|
|
||||||
|
@ -21,11 +20,13 @@
|
||||||
set { _sceneLinker = value; }
|
set { _sceneLinker = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Story ParseStory(string storyFilePath)
|
public Story ParseStory(string storyText)
|
||||||
{
|
{
|
||||||
var lines = File.ReadAllLines(storyFilePath);
|
var lines = storyText.Split('\n');
|
||||||
var blocks = BlockHandler.ExtractBlocks(lines);
|
var blocks = BlockHandler.ExtractBlocks(lines);
|
||||||
return BlockHandler.ParseBlocks(blocks);
|
var story = BlockHandler.ParseBlocks(blocks);
|
||||||
|
SceneLinker.ExpandScenes(story);
|
||||||
|
return story;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
{
|
{
|
||||||
Name = scene.Name,
|
Name = scene.Name,
|
||||||
Description = scene.Description,
|
Description = scene.Description,
|
||||||
Conditions = new List<string>(scene.Conditions)
|
Conditions = scene.Conditions == null ? null : new List<string>(scene.Conditions)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Description { get; set; }
|
public string Description { get; set; }
|
||||||
public Scene FirstScene { get; set; }
|
public string FirstScene { get; set; }
|
||||||
public IDictionary<string, IList<Action>> States { get; set; }
|
public IDictionary<string, IList<Action>> States { get; set; }
|
||||||
public IDictionary<string, IList<Scene>> Scenes { get; set; }
|
public IDictionary<string, IList<Scene>> Scenes { get; set; }
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue