Omitting visited page numbers from a random number generator

I have a selection mechanism in my game which works like this.

[[Selection process]]:

var rnd = Math.ceil(Math.random() * 20); // random number between 1 and 20


i.e. depending on the random number generated, the user is sent to [[page1]], [[page2]] etc.

On each numbered page some other game stuff happens, and the user either succeeds (and progresses) or fails and is sent back to [[Selection process]] to try again. Another random number is generated, they're sent to that page, they succeed or fail and either progress or go back to [[Selection process]] again. This loop keeps going until they succeed and progress, or if they fail all twenty pages they're sent elsewhere.

However they should only be able to visit any given page number, eg [[page1]], [[page2]] etc, once. Can anyone advise me on how to keep track of the page numbers that have already been visited, and omit those numbers from the random number generator at [[Selection process]]?

My answer is really kludgy and I'm sure some aces can probably avoid all the repeating bits. "Seen" commands would have been ideal but I don't know how to make seen work against a variable. That being the case, I just bully through with my own flag system. Here, I'd doing it with two pages - you'll have to C&P and modify the code to work with twenty.


@set loopCnt=1
@set page1
@set page2

[[Start this process]](Selection process)

[[Selection process]]:

    var rnd = Math.ceil(Math.random() * 2); // notice this is 1-2 for illustration purposes.


    if (get("loopCnt")>2){squiffy.story.go("pageDone");}
        if ((get("pageNumber")==1) && (get("page1"))){
        if ((get("pageNumber")==2) && (get("page2"))){
        //Copy and past the two line sections from above here.


@set not page1
@inc loopCnt
I'm in page one=========

[[try again]](Selection process)


@set not page2
@inc loopCnt
I'm on page two=========

[[try again]](Selection process)


We're done

Not my best work. Nothing to ooh and ahh about. This was brute force. On the plus side, you don't have to hit continue every time - you'll just work through your pages and then exit.

Hi Bluevoss!

Thank you again for replying so quickly! So this almost works the way I need it to! I've run it a number of times, and the only problem is that if the random number generator produces the same number the second time through the loop, it doesn't generate another random number as an alternative.

eg if rng generates a pageNumber of 1 the first time, you visit [[page1]], return to [[Selection process]], and then the pageNumber randomly generated is 1 again, the loop stops there.

I don't know Squiffy, but it bugs me that the solution presented above isn't completely random. So I'll try to come up with an alternative:


    squiffy.set("pagesToVisit", "123456789ABCDEFGHIJK")

I assume there's a way to do the above ↑ just in Squiffy, but I'll stick to using only functions that I've seen you use

[[Start this process]](Selection process)

[[Selection process]]:

    var pages = get("pagesToVisit");
    if (pages) {
      var rnd = pages.charAt(Math.floor(Math.random() * pages.length)); // pick a random character from pages
      squiffy.set("pageNumber", rnd);
      squiffy.set("pagesToVisit", pages.replace(rnd, "")); // remove that page from the list so it won't be picked again
    } else {


In this version, the pages would be named page1, page2, page3, page4, page5, page6, page7, page8, page9, pageA, pageB, pageC, pageD, pageE, pageF, pageG, pageH, pageI, pageJ, and pageK - dealing with characters works out with simpler code than handling a list of numbers. Hope that isn't a problem.

I basically made a string "123456789ABCDEFGHIJK", then pick a random character from the string instead of just choosing a number; and remove the chosen character from the string using replace so it won't be chosen again next time. When there's no pages left in the string (if (pages) tests for an empty string) it redirects to pageDone as in Bluevoss's version

mrangel you're a genius! That works beautifully! With that and bluevoss' solution to send them to pageDone if they fail all twenty pages, my random selection is working absolutely perfectly!

Seriously, thank you both so much!

Pretty slick. I'm weak in JS but I learned something new.

It's still bugging me that I haven't solved the original problem as stated, so with numbers 1 to 20:

    if (!window.getRandomPage) {
      var pages = Array.from(Array(20).keys()).map(i=>i+1);
      window.getRandomPage = function () { return (pages.length ? pages.splice(Math.floor(Math.random()*pages.length), 1)[0] : squiffy.story.go("PageDone")) };
    squiffy.set ("pageNumber", getRandomPage());


If it needs explanation:

  • if (!window.getRandomPage) { - if we haven't already done this
    • var pages = Array.from(Array(20).keys()).map(i=>i+1); - generate an array containing the numbers from 1 to 20
    • window.getRandomPage = function () { return ( - create a javascript function, getRandomPage, which returns the value of a single expression
      • pages.length ? - if the "pages" array has any elements in it
        • pages.splice(Math.floor(Math.random()*pages.length), 1)[0] - remove a random element from an array and return the element removed (the [0] at the end is because splice() returns an array)
      • : - "else"
        • squiffy.story.go("PageDone") - we've been to all the pages, so go to PageDone
  • Then we can just call getRandomPage

Hi mrangel - sorry for the delay, I've had a week :/

I've just been testing this, and it works except that sometimes pageNumber sets to 'true' - I'll get several number results as expected, but then at a random point, pageNumber=true and the selection process won't go any further. That can be on the first random number generated, the 9th, and 14th, etc. Any idea why this is happening?

I can't see where that's happening. Which version are you using now?

I've not tried it in Squiffy, but have run through the javascript a few times and it always seems to behave as expected.

This is the latest version, selecting a number from 1-20 rather than a character from the number and letter string. The one starting if (!window.getRandomPage)

Doing some more testing, it looks like this happens when I test the game multiple times (ie using the Restart or Run buttons). Between runs through the game the numbers generated seem to be stored - so if in game one I get numbers 5, 3, and 10, and then in game two I get 7, 12, 16, those all go fine, but then if in game three I get 19, 1, 3 - it either stalls (Continue link doesn't work) or sends me to [[PageDone]] at 3 because I had that number back in game one.

If I close Squiffy (I'm using the desktop app) and start again, it clears it, but running the game multiple times in a Squiffy session using Run or Restart seems to cause this anomaly!

Ah, I didn't think about restarting.
In that case, you'd need to split it up; put:

      var pages = Array.from(Array(20).keys()).map(i=>i+1);
      window.getRandomPage = function () { return (pages.length ? pages.splice(Math.floor(Math.random()*pages.length), 1)[0] : squiffy.story.go("PageDone")) };

on a page before the random pages, and then use

    squiffy.set ("pageNumber", getRandomPage());


each time.

I'm guessing that the "broken link" behaviour means that for some reason squiffy.story.go('PageDone') is returning true rather than sending the player to the right page. I'm not used to Squiffy, so not sure why that would happen.

Almost there! That's mostly solved the stalling issue - the only problem I still have is that it will do 19 loops but not 20 (ie the pages are [[page1]] - [[page20]], so the user should have 20 chances before being sent to [[PageDone]], but they're stopping at 19!)

That's odd. Is it missing the same one each time?

It doesn't seem to be - I just did some more testing, on my first attempt it ran through all 20, but on the next it only went to 19 before going to PageDone.

The question here is which one is it missing out? Any kind of pattern to it?

Try it a few times and make a note of which ones it goes through; then see if there's any kind of pattern to the conditions where it fails.

I've done the same here, but that doesn't help to debug because for me it always gets to 20.

This topic is now closed. Topics are closed after 60 days of inactivity.