Skip to content

Conversation

@mavnn
Copy link

@mavnn mavnn commented Dec 31, 2025

Based on one of the proposals in #967 , this PR implements a new Stack data type for storing an ordered collection of values. I'm putting it up here as a draft for visibility, especially as I'm not even sure if it is a feature that would be considered valuable for the main Inkle project.

Stacks can hold values of any other type, and are not required to be predefined in any way. A stack is initialized using square brackets [ / ] and can optionally contain other values. Note that a global stack cannot be initialized with values stored in other variables.

VAR aStack = ["one", 2]
~aStack += "three" // = [ "one", 2, "three" ]

VAR thing = "thing"
VAR otherStack = [thing] // error

Stacks are "immutable" - this means that you cannot add or remove items from a stack in place, but instead you produce a new stack with the value added or removed. They support the equality operator as well as addition and substraction with slightly unusual properties:

VAR aStack = ["one", "two"]
VAR result = []

// Adding two stacks concatinates them
~result = aStack + ["three", "four"] 
// = ["one", "two", "three", "four"]

// Subtracting from a stack removes the first
// instance of each "equal" value in the second stack
~result = ["one", "one", "two", "two", "one"] - ["one", "two"]
// = ["one", "two", "one"]

// Adding or subtracting an other type from a stack treats the
// other type as if it were a stack holding a single value
~result = aStack + "three"
// = ["one", "two", "three"]

~result = aStack - "two"
// = ["one"] 

To "work through" a stack, we have four native functions. The three pop functions are used to take the newest, oldest, or a random value from the stack while the STACK_COUNT function is used to test whether there any further values to pop.

VAR aStack = ["one", "two"]
VAR result = []
VAR popped = ()

// Pass the stack and a variable reference to a pop function to "pop"
// the next value. The reduced stack is returned as the result of the function.
~result = STACK_POP_NEWEST(aStack, popped)
// result == ["one"], popped == "two"

~result = STACK_POP_OLDEST(aStack, popped)
// result == ["two"], popped == "one"

{STACK_COUNT(aStack)} // == 2

Using these functions, we can also iterate through all the values of a stack if that is useful. This is especially useful in situations where we want to present the player the option to choose one of the values in the stack:

LIST cards = Punch1, Punch2, Kick1, Kick2, Dodge1, Dodge2
VAR hand = []
VAR played = ()

Hello

~hand += Punch1
~hand += Punch1
~hand += Kick1

-> branching(hand) ->

Done! You played {played}!

=== branching(options)
{ STACK_COUNT(options) == 0:
  * ->->
- else:
  ~temp nextOption = ()
  ~temp rest = STACK_POP_NEWEST(options, nextOption)

  <- branching(rest)
  * [{nextOption}]
    ~played += nextOption
    ->->
}

Shows:

Hello

1) Punch1
2) Punch1
3) Kick1

... 1 ...

Done! You played Punch1!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant