Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Twine 2 arrays?

Does anyone know how to use arrays in Twine 2? Actually, I want to make an inventory list, so I need to:
  • add an entry to the list
  • remove an entry from th elist
  • see if any entry is on the list
  • list all the contents of the list, separated by commas, in a passage
List contents would just be strings.

Alternatively, how do I get to Javascript?

Comments

  • NOTE: The following is based on the Twine 2 Harlowe Story Format documentation, any mistakes or misunderstandings are purely mine. If someone else knows / works out a better answer please post it.

    Following is an example Twine 2 passage which may answer some of your questions about using Harlowe macros in relationship to a javascript Array.
    (note: using TWEE format)

    :: Array Examples

    ''1. Create an array with the following elements: "first", "second", "third"'' (set: $list to (array: "first", "second", "third"))
    Print Array Length: (print: $list.length)
    Print Array Items: (print: $list)

    ''2. Append a "forth" element to the end of the Array:'' (set: $list to $list + (array: "forth"))
    Print Array Length: (print: $list.length)
    Print Array Items: (print: $list)

    ''3. Check if the Array contains the value "third":'' (print: $list contains "third")

    ''4. Delete the "third" element from Array.'' (move: $list.2 into $y)
    Print Array Length: (print: $list.length)
    Print Array Items: (print: $list)
    //NOTE: you need to 'know' the array index number of the element you want to delete for this to work, not sure how to programmatically determine the index.//
    A break down of the Harlowes Story Format features I used in each point.
    In point 1 I used the (array) macro to create the $list Array.
    In point 2 I used the ability to add two arrays together to add another element to the array.
    In point 3 I used the 'contains' keyword to check each of the elements of the array.
    In point 4 I used the (move) macro to (re)move an element from the array.


    NOTE: I tried to use standard javascript Array methods like push and indexOf but kept getting errors like the following:

    (set: $list to $list.push("forth"))
    Error: Array.prototype.push called on null or undefined
    In relation to your "how do I get to Javascript" question, all javascript is meant to be placed within the "Edit Story Javascript" area which you access by clicking on the blue upwards triangle / arrow head in the lower left corner that appears after your Story name and selecting the relevant option on the menu that appears.

    Hope that helps
  • Some design remarks:

    * The main motivation for using an (array:) macro instead of using Javascript's [] literal syntax is primarily readability and clarity to new users - that, and the [] is too reminiscent of the hook syntax, and might imply a false similarity. I've also added a shorter form called (a:), but I'm wondering if that'd be too hard to get.
    * I'm really wanting to go with 1-indexing for TwineScript arrays, and lines like
    ''4. Delete the "third" element from Array.'' (move: $list.2 into $y)
    reinforce this feeling, but I feel like that may be a bridge too far. Not to say that it's unheard of in proglangs, but that it's unheard of for something that is ostensibly a JavaScript array.  (One argument is that it goes with the dot-notation for indexing much better - dot notation like $a.1.2 is reminiscent of formal document section headings, and 1-indexing is, of course, used for those. Another argument is that it provides symmetry with hypothetical negative-indexing sugar that I might add in the future - $a.1 is the start, $a.-1 is the end.).
    * I dislike the names "pop", "push", "shift" and "unshift" from a neophyte usability perspective, so the (move: x into y) macro was created as a substitute for those. But I'm wondering if its name is itself a little too baroque. Sadly, there isn't really a readily available English metaphor that unambiguously means removing a data item from one place and placing it in another - or if there is, I've mislaid it.
    * As you may have surmised, I've tried to design away from the concept of "method calls" in the Twine macro API (which don't gel with the macro concept), sticking with the more verbose but less conceptually strenuous plain functions. I'm not sure what would serve as an "indexOf" or "find" equivalent just yet - especially since a computed indexing operation isn't quite available yet either :(

  • Some other notes:

    Print Array Length: (print: $list.length)
    Print Array Items: (print: $list)
    (print:) is technically unnecessary: just $list will suffice. Anything that involves operators, though, requires a (print:) wrapping.

    ''2. Append a "forth" element to the end of the Array:'' (set: $list to $list + (array: "forth"))
    As a small shorthand, you can write (set: $list to it + (array: "forth")).

    ''3. Check if the Array contains the value "third":'' (print: $list contains "third")
    You may also write (print: "third" is in $list).

    ''4. Delete the "third" element from Array.'' (move: $list.2 into $y)
    Ah, yes, there isn't a dedicated (delete:) macro either. I think I might overload (remove:) for this, if I can develop a conceptual model where (remove: ?hook), (remove: $var) and (remove: $arr.0) make the same kind of "sense".

    EDIT: Hm, no, that isn't going to work after all. I actually think I might instead overload - (minus), the argument being that it meshes with the concatenation overloading of +, and of the general principle I've been using that sequence types should be "functional" in the rudimentary sense that operations on them return new values instead of modifying in-place (as is true of the JS string primitive). The big problem with this is that suddenly, unlike "array + array", "changer + changer" and "string - string", the right-hand type on "array - x" will usually be a non-array, and that bothers me a good deal. Apologies if all this design talk doesn't instill confidence in me... I'm still trying to nail down all the concepts for this language.
  • After some thought, I've decided to go with overloading subtraction after all, BUT with the proviso that the right side must be an array. So, to remove the number 5 from an array, do (set: $a to it - (a:5)), and to remove element 0, you could try (set: $a to it - (a:it.0))

    ...That's a bit too awkward, though, so what I also want to do is add (at some point) slice syntax sugar, so you can remove element 0 of an array by doing (set: $a to $a.1..-1) (Or, if I make the leap from 0-indexing to 1-indexing, that'd be $a.2..-1). Of course, I'll need to think hard about what separator to use, etc. (I observe that the Rubyish Perlish ".." may conceptually/visually conflict with the dot accessor.)
  • On a related note, shouldn't this work (I'm using latest downloadable version)?
    (set: $x to 1)
    (set: $foo to (a: "zero","one","two","three"))
    (print: $foo.$x)
    It gives a "Operation.get(...).Operation is undefined" error.

    However, this DOES work:
    (set: $x to 1)
    (set: $foo to (a: "zero","one","two","three"))
    (print: $foo[$x])
    But neither:
    (set: $foo to (a: "zero","one","two","three"))
    (set: $x to (random: 0, $foo.length -1))
    (move: $foo.$x into $bar)
    (print: $bar)
    nor
    (set: $foo to (a: "zero","one","two","three"))
    (set: $x to (random: 0, $foo.length -1))
    (move: $foo[$x] into $bar)
    (print: $bar)
    work.
Sign In or Register to comment.