Trouble with memorize arrays in SugarCube 2

I’ve been trying to record endings for my current project. Trying to use memorize() and recall() so that they won’t be inconsistent between saves. I created a debugging passage to double check to see if the repeats of memorize (‘key’ { value : true }) code will create duplicates.

Here is the code:

<<run memorize('ends', { sorry : true })>>
<<run memorize('ends', { lame : true })>>
<<run memorize('ends', { lame : true })>>

<<print "total ends: " + recall('ends').length>>

What I want:




total ends: 2

What I get:




total ends: undefined

I am very confused. Removing the repeated macro did not solve the issue. I thought I was creating an array. The best resource outside of the documentation I can find just vaguely gives me the impression that I’m completely wrong about that, but I still can’t make out how to actually apply it to what I’m trying to do.

I have not used memorize, though I have used SugarCube a fair bit, and JavaScript a lot, so given that…

Firstly, { sorry : true } is a dictionary, not an array, so has no length. If you do:

<<print "total ends: " + { sorry : true }.length>>

You will get:

total ends: undefined

Try this instead (it gets the keys of the dictionary as an array and counts them):

<<print "total ends: " + Object.keys(recall('ends')).length>>

Secondly, and this is where I am less sure - and the documentation kind of suggests what you do should work - I think that this:

<<run memorize('ends', { sorry : true })>>
<<run memorize('ends', { lame : true })>>
<<run memorize('ends', { lame : true })>>

Will just override the “ends” value each time. You save it as { sorry : true } first, then overwrite it with the same value, then with { lame : true }, so I think you will only every have one saved.

So if it is still not working after sorting out the first issue, this is likely the problem, and the fix will be a bit more complicated…

Firstly. memorize() is a function, not a macro. Knowing the proper terminology for things is important.

Secondly. I’m not exactly clear on what you’re confused about:

  • If you’re confusing arrays and generic objects, then the values you’re attempting to set are generic objects. If this is the issue, neither would be merged with the previous value anyway.
  • If you’re confused about how memorize() and friends work upon, then they operate on a key↔︎value store, not an array. None of its official documentation remotely suggests that it works that way. Neither its signature, nor its description, nor its, admittedly few, examples.

Regardless. When you set a key to a value its previous value, if any, is overwritten by the new value. To put it another way, if you set a key to a value, then set the same key to a new value, recalling the value of that key afterwards will yield the new value as-is.

For example, using your example code:

/* 1. Set the key `ends` to the value `{ sorry : true }`, which is a generic object. */
<<run memorize('ends', { sorry : true })>>

/* 2. Reset the key `ends` to the new value `{ lame : true }`, which is a generic object. */
<<run memorize('ends', { lame : true })>>

/* 3. Reset the key `ends` to the new value `{ lame : true }`, which is a generic object. */
<<run memorize('ends', { lame : true })>>

After doing the above, the value returned by the call, recall('ends'), will be an equivalent duplicate of the exact value set in #3 above, { lame : true }.


Anyway. If your goal is to keep a record of all reached ends, then I’d suggest using a generic object as you’re doing now, not an array. For example, memorizing a reached ending while keeping all existing ending key↔︎value pairs, if any:

<<run memorize('ends', Object.assign(recall('ends', {}), { sorry : true }))>>

Later, to memorize new endings while keeping all existing ones, if any:

<<run memorize('ends', Object.assign(recall('ends', {}), { lame : true }))>>

 
To give an explanation of what’s going on, here’s the first example rewritten step-by-step:

/*
	Get the current value of the key `ends`, if it exists,
	elsewise yield a new empty generic object.
*/
<<set _ends to recall('ends', {})>>

/*
	Merge the new ending key↔︎value pair into the existing
	endings object.

	In this case, equivalent to: <<set _ends.sorry to true>>
*/
<<set _ends to Object.assign(_ends, { sorry : true })>>

/*
	Set the value of the key `ends` to the updated endings
	object.
*/
<<run memorize('ends', _ends)>>

 
Checking endings could look something like:

<<set _ends to recall('ends', {})>>

Player reached <<= Object.keys(_ends).length>> endings.

<<if _ends.sorry>>
	Player reached the "sorry" ending.
<</if>>

<<if _ends.lame>>
	Player reached the "lame" ending.
<</if>>
1 Like