Using a shuffled array to select random passages: then choosing a variable that corresponds to the randomly selected passage

Twine Version: Twine 2
Story Format: Harlowe3.2.3

Hi all, sorry to be a bother again - I have gotten stuck again with some Twine coding in my story.

I am wanting to set things up so that the user selects a difficulty level, and based on that choice, they see a number of cases to solve, randomly selected from a larger set of cases. (For example, in “easy” mode they would get 4 cases out of a set of 8).

I have shamelessly plagiarized from greyelf’s code from here - thanks greyelf!!! - (Harlowe) How to set random passages to one link? - Twine Q&A - to set up an array and randomly select the 4 cases.

This is the code that I am using to set up a shuffled array of the cases:

(link-reveal-goto: "Play the game: level of difficulty - easy", "instructions")[(set: $choice to 4)(set: $list to (shuffled: "Case 1", "Case 3", "Case 4", "Case 5", "Case 7", "Case 8", "Case 11", "Case 14"))]

and similar for the other levels of difficulty.

Then this, below, is the code I am using to set up the links (in a footer passage, if that matters?) (The time counter $t stuff is tracking how much time the user spends in the game, Is it possible to measure the amount of time spent in the game (Twine, Harlowe 3.2.3)? - not actually super relevant to this post but I’ve left it in so you can see my actual code.)

(if: $choice is 4)[(link-reveal-goto: "1", $list's 1st)[(set:$t to it + time)] 
(link-reveal-goto: "2", $list's 2nd)[(set:$t to it + time)] 
(link-reveal-goto: "3", $list's 3rd)[(set:$t to it + time)] 
(link-reveal-goto: "4", $list's 4th)[(set:$t to it + time)]] 

Okay, and this works just fine, I can see when I test it that it shuffles randomly through the cases and the link-reveal-goto links correctly link to the cases, as intended.

But, the problem that I have is that I don’t actually want the link text to be “1” etc. - I’ve just put that in as a placeholder for now.

I need the link text to be a different variable depending on which case is chosen. Each case has a different variable ($Cn, a number which I’ve generated using random), for example:

(set: $C1 to (10 + (random: 1, 25)))

(set: $C2 to (40 + (random: 1, 25)))

So I want to somehow, from my shuffled list, associate the correct variable with the case number being selected in $list’s 1st, and display that variable $Cn as the link text (i.e. if Case 4 was 1st in $list, then the link text would display $C4). I suppose there could be a way to do this with some really gnarly if: and ifelse: statements but it kind of makes my brain hurt just thinking of it?

Do I need to set up a datamap with the cases and $Cn variables? This is going to sound daft but I’ve read the manual section on datamaps three times and I don’t really understand how I could apply it to this situation.

I had thought that alternatively to using the $Cn variables, I might try setting up a datamap of the shuffled list - and assigning a new number to each case, i.e.

(set: $dm to (dm: $list's 1st, 1, $list's 2nd, 2, $list's 3rd, 3, $list's 4th, 4))

so that now, if Case 4 was 1st in $list, it would be assigned to 1 - and this solution would work for what I’m trying to do with the story - but I can’t work out how, from there, to replace all of the instances of $C4 with 1 in the text of my story. Because it might actually be $C7 that I would want to replace with 1 - depending on the order of $list. So I am not sure how that could work really, in actual code.

(I have just focused on the code for “easy” mode in the above, but would need to apply the solution to slightly larger sets of cases for the harder game modes as well - with if statements based on $choice)

I am incredibly sorry if this is a dumb question - I’ve just worked my brain into knots to the point where nothing is making sense anymore. I think what I want to do should be quite simple really? I’m sure I must just be missing something - just no idea what. I would be really grateful if y’all could help unknot things!

A data-map is a means to associate a String “Key” with a value, within a collection of key/value pairs.

(dm: 
	"Name", "Jane",
	"Age", 21
)

You could use a structure like the following to associated a Case Identifier/Passage with its Link Text…
(this should likely be done within your project’s startup tagged Passage)

(set: $easy to (dm: 
	"Case 1",  (str: 10 +  (random: 1, 25)),
	"Case 3",  (str: 40 +  (random: 1, 25)),
	"Case 4",  (str: 70 +  (random: 1, 25)),
	"Case 5",  (str: 100 + (random: 1, 25)),
	"Case 7",  (str: 130 + (random: 1, 25)),
	"Case 8",  (str: 160 + (random: 1, 25)),
	"Case 11", (str: 190 + (random: 1, 25)),
	"Case 14", (str: 210 + (random: 1, 25))
))

note: I had to guess how you were randomly generating the other “Case Link Names”, and use the (str:) macro to convert the Number into a String so it can be used as a Link Text.

So now that we have defined what possible Easy cases there are, we can use the following steps to obtain a random list of 4 of them.

The (datanames:) macro will return an Array containing each “Key” (Name) within the collection…

(set: _possible to (datanames: $easy))
Debug: Possible: (print: _possible)

The (shuffled:) macro can then be used to randomise that Array of “Keys”…

(set: _shuffled to (shuffled: ..._possible))
Debug: Shuffled: (print: _shuffled )

And finally you can use the sub-array notation feature of the Array datatype to extract the first 4 elements of the shuffled list.

First 4: (print: _shuffled's 1stto4th )

Combining the above together results in a Difficulty selector something like the following…

(link-reveal-goto: "Play the game: level of difficulty - easy", "instructions")[
	(set: $list to (shuffled: ...(datanames: $easy))'s 1stto4th)
	(set: $cases to $easy)
]

(link-reveal-goto: "Play the game: level of difficulty - medium", "instructions")[
	(set: $list to (shuffled: ...(datanames: $medium))'s 1stto4th)
	(set: $cases to $medium)
]


(link-reveal-goto: "Play the game: level of difficulty - hard", "instructions")[
	(set: $list to (shuffled: ...(datanames: $hard))'s 1stto4th)
	(set: $cases to $hard)
]

…where the $list variable contains an Array of 4 Case Names after option is selected. If you want the non Easy options to have a different number of Names within the List then alter the 1stto4th sub-array to be something else.

You may notice that I assign a copy of the selected set of cases (eg those stored in the $easy variable), to a more generically named $cases variable. This is so you don’t need to keep track of which of the original data-maps was selected ($easy, $medium, $hard, etc).

note: I have left the setting up of the other case data-maps up to you… and you can rename any of the above variables to what ever you like.

You can use a (for:) macro like the following to show the links required for the random determined possible cases…

type or paste code hereCase List:
{
(for: each _case, ...$list)[
	(link-reveal-goto: $cases's (_case), _case)[
		(set: $t to it + time)
	]
	<br>
]
}

…you will notice it makes use of the generically named $cases variable, instead of having to remember which of the original $easy or $medium or $hard data-map variables the random cases were sourced from.

1 Like

This is really brilliant (and so much simpler and more elegant than the horrible knotty things that I had been trying) - thank you so much!!!

Just a wee follow up question if you don’t mind - I do want to be able to refer to those randomly generated numbers (previously $Cn) elsewhere in the story (in addition to just in those links). I think I understand from your example that I can work through an array using a “for” loop and retrieve the numbers with “$case’s (_case)” (I hope that I’ve got that right?)

So … I think I’m starting to tie my brain into knots again here … if I wanted to extract those numbers and assign them to variables for use elsewhere, would it look something like:

(for: each _case, ...$list)[
	(set: $cases's (_case) to $C$cases's (_case))
]
Debug: variables: (print: $C$cases)

… but that does not seem to do anything when I try it. (Well, not anything like what I want - it gives an error saying “Unexpected identifier”). I am sure it must be that I’ve done something wrong but I can’t quite see what it is.

I guess doing the opposite (using the $Cn variables initially, and then turning them into strings only when I need to set the link text) will not work, because datamaps only accept strings (is that correct?)

Sorry to be such a bother! I really appreciate your help, thank you so so much!!

Ahh, I am so dumb! It came to me suddenly that I could just have the $Cn variables set as previously, and then turn them into strings in the datamap (as Greyelf did above). So,

(set: $C1 to (10 + (random: 1, 25)))
(set: $C2 to (40 + (random: 1, 25)))
(set: $C3 to (70 + (random: 1, 25)))
(set: $C4 to (100 + (random: 1, 25)))
(set: $C5 to (130 + (random: 1, 25)))
(set: $C6 to (160 + (random: 1, 25)))
(set: $C7 to (190 + (random: 1, 25)))
(set: $C8 to (210 + (random: 1, 25)))
(set: $C9 to (240 + (random: 1, 25)))
(set: $C10 to (270 + (random: 1, 25)))
(set: $C11 to (270 + (random: 1, 25)))
(set: $C12 to (270 + (random: 1, 25)))
(set: $C13 to (270 + (random: 1, 25)))
(set: $C14 to (270 + (random: 1, 25)))
(set: $C15 to (270 + (random: 1, 25)))

(set: $easy to (dm: 
	"Case 1",  (str: $C1),
	"Case 3",  (str: $C3),
	"Case 4",  (str: $C4),
	"Case 5",  (str: $C5),
	"Case 7",  (str: $C7),
	"Case 8",  (str: $C8),
	"Case 11", (str: $C11),
	"Case 14", (str: $C14)
))

and that doesn’t seem to perturb the rest of the solution as far as I can see. And the variables seem to work correctly throughout the rest of the story (as of course they ought to.) So that seems to work!

Thanks again for all the help, I really really appreciate it - sorry to be such a bother!!!

Instead of using the “Number” as a reference to a specific case, use the “Case x” String “Key”.

(set: $currentCase to "Case 7")

You can then that :“Key” to access the Number any time you want it…

Case Number: (print: $cases's ($currentCase))
1 Like

ah okay, I think I understand better now how the keys work! Thank you very much for explaining!!