From 04f613a5b1a7e65f406464ec1b1543f0fff41e94 Mon Sep 17 00:00:00 2001 From: David Masad Date: Sat, 27 Feb 2021 13:38:30 -0500 Subject: [PATCH 1/3] Implementing weighted random --- examples/duchess_party.html | 40 +++++++++++++++++++++++-- examples/simple_space_example.html | 48 +++++++++++++++++++++++++----- examples/tutorial.html | 48 +++++++++++++++++++++++++----- storymanager.js | 40 +++++++++++++++++++++++-- 4 files changed, 156 insertions(+), 20 deletions(-) diff --git a/examples/duchess_party.html b/examples/duchess_party.html index fb691cb..c8cf12a 100644 --- a/examples/duchess_party.html +++ b/examples/duchess_party.html @@ -123,7 +123,8 @@ StoryManager.getAllStorylets = function(tag=null) { return allStorylets; } -StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { +StoryManager.getStorylets = + function(n=null, tag=null, selection="ordered", respect_interrupt=true) { /* Get n storylets, prioritizing the highest-priority ones first. @@ -143,12 +144,24 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { if (allStorylets[i].interrupt) return [allStorylets[i]]; } - // Get n stories in priority order + // Return n or the max if (n != null) { n = Math.min(n, allStorylets.length); if (n == 0) return []; } else n = allStorylets.length; + + let selectedStorylets; + if (selection == "ordered") + selectedStorylets = this.sortByPriority(allStorylets, n); + else if (selection == "weighted") + selectedStorylets = this.weightedRandom(allStorylets, n); + + return selectedStorylets; +} + +// Get storylets strictly by priority +StoryManager.sortByPriority = function(allStorylets, n) { let selectedStorylets = []; // Select by strict priority; randomize among matching priority. @@ -166,8 +179,29 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { return selectedStorylets; } -// Set up macros +// Get storylets via weighted random choice +StoryManager.weightedRandom = function(allStorylets, n) { + let selectedStorylets = []; + let sum, counter, index, rand; + while (selectedStorylets.length < n) { + sum = allStorylets.reduce((a, x) => a + x.priority, 0); + counter = 0; + rand = Math.random() * sum; + for (let i=0; i a + x.priority, 0); + counter = 0; + rand = Math.random() * sum; + for (let i=0; i> - <> + <> \ + <> \ [[_storylet.description|_storylet.passage][$currentStorylet=_storylet]]
- <
> - <
> + <
> \ + <> \ `); } }) diff --git a/examples/tutorial.html b/examples/tutorial.html index 4a6620d..700871a 100644 --- a/examples/tutorial.html +++ b/examples/tutorial.html @@ -123,7 +123,8 @@ StoryManager.getAllStorylets = function(tag=null) { return allStorylets; } -StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { +StoryManager.getStorylets = + function(n=null, tag=null, selection="ordered", respect_interrupt=true) { /* Get n storylets, prioritizing the highest-priority ones first. @@ -143,12 +144,24 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { if (allStorylets[i].interrupt) return [allStorylets[i]]; } - // Get n stories in priority order + // Return n or the max if (n != null) { n = Math.min(n, allStorylets.length); if (n == 0) return []; } else n = allStorylets.length; + + let selectedStorylets; + if (selection == "ordered") + selectedStorylets = this.sortByPriority(allStorylets, n); + else if (selection == "weighted") + selectedStorylets = this.weightedRandom(allStorylets, n); + + return selectedStorylets; +} + +// Get storylets strictly by priority +StoryManager.sortByPriority = function(allStorylets, n) { let selectedStorylets = []; // Select by strict priority; randomize among matching priority. @@ -166,19 +179,40 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { return selectedStorylets; } -// Set up macros +// Get storylets via weighted random choice +StoryManager.weightedRandom = function(allStorylets, n) { + let selectedStorylets = []; + let sum, counter, index, rand; + while (selectedStorylets.length < n) { + sum = allStorylets.reduce((a, x) => a + x.priority, 0); + counter = 0; + rand = Math.random() * sum; + for (let i=0; i> - <> + <> \ + <> \ [[_storylet.description|_storylet.passage][$currentStorylet=_storylet]]
- <
> - <
> + <
> \ + <> \ `); } }) diff --git a/storymanager.js b/storymanager.js index 130f705..1693809 100644 --- a/storymanager.js +++ b/storymanager.js @@ -20,7 +20,8 @@ StoryManager.getAllStorylets = function(tag=null) { return allStorylets; } -StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { +StoryManager.getStorylets = + function(n=null, tag=null, selection="ordered", respect_interrupt=true) { /* Get n storylets, prioritizing the highest-priority ones first. @@ -40,12 +41,24 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { if (allStorylets[i].interrupt) return [allStorylets[i]]; } - // Get n stories in priority order + // Return n or the max if (n != null) { n = Math.min(n, allStorylets.length); if (n == 0) return []; } else n = allStorylets.length; + + let selectedStorylets; + if (selection == "ordered") + selectedStorylets = this.sortByPriority(allStorylets, n); + else if (selection == "weighted") + selectedStorylets = this.weightedRandom(allStorylets, n); + + return selectedStorylets; +} + +// Get storylets strictly by priority +StoryManager.sortByPriority = function(allStorylets, n) { let selectedStorylets = []; // Select by strict priority; randomize among matching priority. @@ -63,8 +76,29 @@ StoryManager.getStorylets = function(n=null, tag=null, respect_interrupt=true) { return selectedStorylets; } -// Set up macros +// Get storylets via weighted random choice +StoryManager.weightedRandom = function(allStorylets, n) { + let selectedStorylets = []; + let sum, counter, index, rand; + while (selectedStorylets.length < n) { + sum = allStorylets.reduce((a, x) => a + x.priority, 0); + counter = 0; + rand = Math.random() * sum; + for (let i=0; i Date: Sat, 27 Feb 2021 13:44:59 -0500 Subject: [PATCH 2/3] Debugging weighted random --- examples/duchess_party.html | 6 +++--- examples/simple_space_example.html | 6 +++--- examples/tutorial.html | 6 +++--- storymanager.js | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/duchess_party.html b/examples/duchess_party.html index c8cf12a..e0b99cf 100644 --- a/examples/duchess_party.html +++ b/examples/duchess_party.html @@ -124,7 +124,7 @@ StoryManager.getAllStorylets = function(tag=null) { } StoryManager.getStorylets = - function(n=null, tag=null, selection="ordered", respect_interrupt=true) { + function(n=null, tag=null, selection="weighted", respect_interrupt=true) { /* Get n storylets, prioritizing the highest-priority ones first. @@ -156,7 +156,7 @@ StoryManager.getStorylets = selectedStorylets = this.sortByPriority(allStorylets, n); else if (selection == "weighted") selectedStorylets = this.weightedRandom(allStorylets, n); - + return selectedStorylets; } @@ -189,7 +189,7 @@ StoryManager.weightedRandom = function(allStorylets, n) { rand = Math.random() * sum; for (let i=0; i Date: Sat, 27 Feb 2021 22:37:00 -0500 Subject: [PATCH 3/3] Testing linkToNextStorylet macro --- examples/progress_example.html | 278 +++++++++++++++++++++++++++++++++ examples/progress_example.tw | 51 ++++++ storymanager.js | 30 ++-- 3 files changed, 350 insertions(+), 9 deletions(-) create mode 100644 examples/progress_example.html create mode 100644 examples/progress_example.tw diff --git a/examples/progress_example.html b/examples/progress_example.html new file mode 100644 index 0000000..c178d72 --- /dev/null +++ b/examples/progress_example.html @@ -0,0 +1,278 @@ + + + + +Simple progress example + + + + + + + + + + + + + + + + +
+
+
Your browser lacks required capabilities. Please upgrade it or switch to another to continue.
+
Loading…
+
+ + + + diff --git a/examples/progress_example.tw b/examples/progress_example.tw new file mode 100644 index 0000000..6475c47 --- /dev/null +++ b/examples/progress_example.tw @@ -0,0 +1,51 @@ +:: StoryTitle +Simple progress example + +:: StoryData +{ + "ifid": "724F804D-9451-4347-BB4D-A0725429BC93" +} + +:: Story JavaScript [script] +Config.passages.nobr = true; // No unspecified linebreaks. + +let animals = ["moose", "fox", "toad"]; +State.variables.progress = 0; + +StoryManager.storylets["walk"] = { + name: "Walking", + generate: function*() { + for (let animal of animals) { + yield { + passage: "Walking", + animal: animal, + priority: 1 + } + } + } +} + +StoryManager.storylets["end"] = { + name: "The End", + generate: function*() { + if (State.variables.progress > 3) { + yield { + passage: "End", + priority: 2 + } + } + } +} + + +:: Start + +You <> through the woods. + +:: Walking +You walk deeper into the woods. You see a <>
+<> +<> + +:: End +You reach the end of the forest! \ No newline at end of file diff --git a/storymanager.js b/storymanager.js index 2200182..5ca0c89 100644 --- a/storymanager.js +++ b/storymanager.js @@ -21,7 +21,7 @@ StoryManager.getAllStorylets = function(tag=null) { } StoryManager.getStorylets = - function(n=null, tag=null, selection="weighted", respect_interrupt=true) { + function(n=null, tag=null, selection="ordered", respect_interrupt=true) { /* Get n storylets, prioritizing the highest-priority ones first. @@ -35,10 +35,14 @@ StoryManager.getStorylets = // Check for interruptions - // TODO: Handle more than one interruption if (respect_interrupt) { - for (let i in allStorylets) - if (allStorylets[i].interrupt) return [allStorylets[i]]; + let interruptions = []; + for (let storylet of allStorylets) + if (storylet.interrupt) interruptions.push(storylet); + if (interruptions.length > 0) { + interruptions.sort((a, b) => b.priority - a.priority); + return [interruptions[0]]; + } } // Return n or the max @@ -85,7 +89,7 @@ StoryManager.weightedRandom = function(allStorylets, n) { counter = 0; rand = Math.random() * sum; for (let i=0; i rand) { selectedStorylets.push(allStorylets.splice(i, 1)[0]); break; } @@ -102,9 +106,9 @@ StoryManager.weightedRandom = function(allStorylets, n) { Macro.add("getStoryletLinks", { handler: function() { let n, tag; - [n=null, tag=null] = this.args; - State.temporary.nextStorylets = StoryManager.getStorylets(n, tag); - $(this.output).wiki(` + [n=null, tag=null, selection="ordered"] = this.args; + State.temporary.nextStorylets = StoryManager.getStorylets(n, tag, selection); + $(this.output).wiki(`\ <> \ <> \ [[_storylet.description|_storylet.passage][$currentStorylet=_storylet]]
@@ -112,7 +116,15 @@ Macro.add("getStoryletLinks", { <
> \ `); } -}) +}); +Macro.add("linkToNextStorylet", { + handler: function() { + let text, tag, selection; + [text, tag=null, selection="weighted"] = this.args; + State.temporary.nextStorylet = StoryManager.getStorylets(1, tag, selection)[0]; + $(this.output).wiki(`<>[[${text}|_nextStorylet.passage][$currentStorylet=_nextStorylet]]<>`); + } +}); window.SM = StoryManager; \ No newline at end of file