Pulling numbers from a string?

Hmm… I think that you have a bit of a misunderstanding about how to most efficiently use arrays for your problem. I will break down how I think the program should flow:

  1. Initial Setup
  2. Create Variables and Dictionaries
  3. Choice to Input Save String
  4. Query and Validate User Input
    • Get user input
    • Validate length, if fail, go back to 3
  5. Extract Numbers from Input and Set Variables
    • Validate numbers, if fail, go back to 3
    • If valid, save to variables
  6. Skip Past Variable Sets.

Before I get into what goes on in each section, I think that it is really only necessary to store a numerical value for the catbreed and dogbreed if you are going to use arrays, but I can see the convenience of also storing the string if you are going to use it frequently in the text.

I also noticed that you prefixed the text variables with t_ and numbers with n_, so I will follow that convention and set the dictionaries as the same without prefixes.

Additionally, I think detailed error messages for parsing the string are unnecessary so long as you provide a way for the user to obtain a save string after they have made the choices (I will reply to this message with an example solution for this problem). Otherwise, I would include it in a help section, accessible from the stats page, maybe listing the acceptable ranges for the variables and the order they appear in the save string.


Initial Setup

  • Set title
  • Set author
  • Set scene_list
*title Story Title
*author Author Name

*scene_list
    startup

Create Variables and Dictionaries

  • Declare any variables that store values for the story

First, let’s assume that you are going to use the dog breeds and numbers elsewhere, say during normal section or at least allow them to correct an incorrect string containing the save data. In that case, you would want to be able to access the dog and cat breeds without setting all the values to an array every time. We should set the dog and cat breeds to their own arrays.

Think of an arrays in ChoiceScript like a dictionary which allows you to look up a value (such as a string containing a dog or cat breed) using integers (or strings if you construct them manually). In the case of your problem:

catbreed                      |    dogbreed
 count -> 20                  |     count -> 8
 1 -> "domestic shorthair"    |     1 -> "shitzu"
 2 -> "domestic longhair"     |     2 -> "chihauhua"
 3 -> "persian"               |     3 -> "pitbull"
 .                            |     .
 .                            |     .
 .                            |     .
20 -> "sphinx"                |     8 -> "german shepard"

This is accomplished with the following code:

*create_array catbreed 20 "domestic shorthair" "domestic longhair" "persian" ... "sphinx"
*create_array dogbreed 8 "shitzu" "chihauhua" "pitbull" ... "german shepard"

Now we can look up the type of dog or cat based on a number. A couple examples:

  • catbreed[1] gives "domestic shorthair"
  • dogbreed[8] gives "german shepard"

Note that the catbreed[count] and dogbreed[count] or catbreed_count and dogbreed_count are automatically specified by the *create_array command as seen here.

Since you intend to get a string from user input and extract these variable values from it, you will need a variable for the string, a variable telling the number of characters that each variable needs (note that the dogbreed requires two digits to store 10-20), a dictionary/array for the variables contained in the string, and variables for the breeds in text and numerical form:

*create inputString ""
*create variableLength 2
*create_array inputVariable 2 "catbreed" "dogbreed"
*create t_catbreed "???"
*create n_catbreed 0
*create t_dogbreed "???"
*create n_dogbreed 0

If you wanted different numbers of digits for each variable, things would get much more complicated (this is what I am doing for my project).


Choice to Input Save String

This is necessary to allow the user to have somewhere to go after entering a string incorrectly.

*label input_or_play
Do you want to input a save string or play the choices?
*choice
  #Input a save string.
    *goto input_string
  #Play the choices.
    *goto play_choices

Query and Validate User Input

We first take the user input and save it to inputString, then we check the length to make sure it is correct.

*label input_string
Please input your character string:
*input_text inputString

*temp n (length(inputString))

*if n = (variableLength * inputVariable_count)
  *gosub extract_numbers_from_string
  *goto skipped_choices
*else
  ERROR: Invalid save string length. Please re-enter your generation code to ensure there are no-typos. If it still doesn't work, please ensure it is from the most recent iteration of the game!
  
  *goto input_or_play

Extract Numbers from Input and Set Variables

Now, we can use our dictionary/array of variables inputVariable to extract and check to ensure that the values are possible (within the acceptable range). We can accomplish this with the following:

*label extract_numbers_from_string

*temp i 1
*temp j 0
*temp extractVar 1
*temp subString ""
*temp extractedNumber
*temp currentVarName

*label loop
*set subString & (inputString#{i})
*set i + 1
*set j + 1

*if j = variableLength
  *set extractedNumber (subString + 0)
  *set currentVarName (inputVariable[extractVar])
  *if ((extractedNumber < 0) or (extractedNumber > ({currentVarName & "_count"})))
    ERROR: Variable "${currentVarName}" out of acceptable range. Please re-enter your generation code to ensure there are no-typos. If it still doesn't work, please ensure it is from the most recent iteration of the game!

    *goto input_or_play
  *else
    *set n[currentVarName] extractedNumber
    *set t[currentVarName] {(currentVarName & "_") & extractedNumber}
    *set subString ""
    *set extractVar + 1
    *set j 0
    *goto check

*label check
*if extractVar <= inputVariable_count
  *goto loop
*else
  *return

Since the code might be difficult to understand, I will explain what the variables are:

  • i - keeps track of the current position in the input string
  • j - keeps track of the current position in the substring (always between 1 and variableLength)
  • extractVar - keeps track of which variable is being extracted (as a number)
  • subString - stores the portion of the input string making up the extractVar
  • extractedNumber - stores the complete substring for an extractVar converted to a numeric value
  • currentVarName - stores the string that describes the name of the current extractVar

Now, I will explain what this part does in words.

  1. First we initialize all of the variables above with default values. Then, we begin the loop.
  2. Start by adding the i-th character of inputString to subString.
  3. Next, increment i by one so we reference the next character.
  4. Next, increment j by one to show indicate the subString has gotten 1 character longer.
  5. If j, the length of the subString has gotten to be as long as we specified in variableLength then we have the entire value and can proceed to step 6. Otherwise proceed to step 13.
  6. We set extractedNumber equal to the numeric value of subString.
  7. If the extractedNumber is negative or greater than the number of options for that variable, throw an error and return to the page to choose whether to input a string. Otherwise, the extractedNumber is valid and we continue to step 8.
  8. Save the extractedNumber to the corresponding variable.
  9. Save the string corresponding to extractedNumber to the corresponding variable.
  10. Reset the subString to "".
  11. Increment the extractVar by one to allow us to extract the next variable.
  12. Reset j to 0.
  13. If we have extracted all of the variables specified by inputVariable_count end the loop and *return to where the subroutine was called from. If we have not, return to step 2.

Skip Past Variable Sets

Below is are the *fake_choice variable sets that you would skip by inputting the string.

*label play_choices

Choose a catbreed:
*fake_choice
  #${catbreed[1]}
    *set n_catbreed 1
    *set t_catbreed (catbreed[1])
  #${catbreed[2]}
    *set n_catbreed 2
    *set t_catbreed (catbreed[2])
  #${catbreed[3]}
    *set n_catbreed 3
    *set t_catbreed (catbreed[3])
  .
  .
  .
  #${catbreed[20]}
    *set n_catbreed 20
    *set t_catbreed (catbreed[20])

Choose a dogbreed:
*fake_choice
  #${dogbreed[1]}
    *set n_dogbreed 1
    *set t_dogbreed (dogbreed[1])
  #${dogbreed[2]}
    *set n_dogbreed 2
    *set t_dogbreed (dogbreed[2])
  #${dogbreed[3]}
    *set n_dogbreed 3
    *set t_dogbreed (dogbreed[3])
  .
  .
  .
  #${dogbreed[8]}
    *set n_dogbreed 8
    *set t_dogbreed (dogbreed[8])

*comment you can also include a "*goto skipped_choices" here if desired

And here is the *label that you jump to by inputting the string.

*label skipped_choices
This is the text after the choices.

Cat breed: ${t_catbreed}

Dog breed: ${t_dogbreed}
*finish

Putting it all together

To construct a minimum working example that will work when copied and pasted into startup, the missing dog and cat breeds were omitted leaving us with four of each. This code will work if the original 20 cat breeds and 8 dog breeds are specified, though.

*title Pulling numbers from a string? v2
*author Joe S. Fung

*scene_list
    startup

*create_array catbreed 4 "domestic shorthair" "domestic longhair" "persian" "sphinx"
*create_array dogbreed 4 "shitzu" "chihauhua" "pitbull" "german shepard"

*create inputString ""
*create variableLength 2
*create_array inputVariable 2 "catbreed" "dogbreed"
*create t_catbreed "???"
*create n_catbreed 0
*create t_dogbreed "???"
*create n_dogbreed 0

*label input_or_play
Do you want to input a save string or play the choices?
*choice
  #Input a save string.
    *goto input_string
  #Play the choices.
    *goto play_choices


*label play_choices

Choose a catbreed:
*fake_choice
  #${catbreed[1]}
    *set n_catbreed 1
    *set t_catbreed (catbreed[1])
  #${catbreed[2]}
    *set n_catbreed 2
    *set t_catbreed (catbreed[2])
  #${catbreed[3]}
    *set n_catbreed 3
    *set t_catbreed (catbreed[3])
  #${catbreed[4]}
    *set n_catbreed 4
    *set t_catbreed (catbreed[4])

Choose a dogbreed:
*fake_choice
  #${dogbreed[1]}
    *set n_dogbreed 1
    *set t_dogbreed (dogbreed[1])
  #${dogbreed[2]}
    *set n_dogbreed 2
    *set t_dogbreed (dogbreed[2])
  #${dogbreed[3]}
    *set n_dogbreed 3
    *set t_dogbreed (dogbreed[3])
  #${dogbreed[4]}
    *set n_dogbreed 4
    *set t_dogbreed (dogbreed[4])

*comment you can also include a "*goto skipped_choices" here if desired

*label skipped_choices
This is the text after the choices.

Cat breed ${n_catbreed}: ${t_catbreed}

Dog breed ${n_dogbreed}: ${t_dogbreed}
*finish

*comment =================================================
*comment Subroutines
*comment =================================================

*label input_string
Please input your character string:
*input_text inputString

*temp n (length(inputString))

*if n = (variableLength * inputVariable_count)
  *gosub extract_numbers_from_string
  *goto skipped_choices
*else
  ERROR: Invalid save string length. Please re-enter your generation code to ensure there are no-typos. If it still doesn't work, please ensure it is from the most recent iteration of the game!
  
  *goto input_or_play


*label extract_numbers_from_string

*temp i 1
*temp j 0
*temp extractVar 1
*temp subString ""
*temp extractedNumber
*temp currentVarName

*label loop
*set subString & (inputString#{i})
*set i + 1
*set j + 1

*if j = variableLength
  *set extractedNumber (subString + 0)
  *set currentVarName (inputVariable[extractVar])
  *if ((extractedNumber < 0) or (extractedNumber > ({currentVarName & "_count"})))
    ERROR: Variable "${currentVarName}" out of acceptable range. Please re-enter your generation code to ensure there are no-typos. If it still doesn't work, please ensure it is from the most recent iteration of the game!

    *goto input_or_play
  *else
    *set n[currentVarName] extractedNumber
    *set t[currentVarName] {(currentVarName & "_") & extractedNumber}
    *set subString ""
    *set extractVar + 1
    *set j 0
    *goto check

*label check
*if extractVar <= inputVariable_count
  *goto loop
*else
  *return

Sorry for the wall of text. Hopefully this answers all of your questions.

1 Like