+1 vote
by (220 points)
Throughout the beginning of my story, dependent on the choices you make different numerical variables go ul and down. I was hoping that there would be some way to take the highest number out of the four variables, and depending on which variable it was set a fifth variable to display that. In case I didn't explain that clear enough, here's an example:

You have four variables. $cat $dog $onion and $ilikecheese. As the story progresses their numerical values increase at different rates. At a set point in the story it will take whichever variable is the highest and variable number five $zebra to be a specific word based on which of the first four variables it was that was highest.

The only problem with this is in the case that  two or more variables have equal numerical values, so I was also curious if there is some way to take the ones that are tied for highest and then randomly select one of them to treat as highest.

Thanks in advance for the help, I couldn't for the life of me figure out how to do this myself.

1 Answer

0 votes
by (61.5k points)
selected by
 
Best answer

You can find the highest of a group of numbers using an array and the (for:) macro:

(set: $array to (a: 3, 6, 42, 8, 27))
(set: $highest to -1)

(for: each _item, ...$array)[
	(if: _item > $highest)[
		(set: $highest to _item)
	]
]

To find the name associated with the highest value, you'll need to do a little more work, but the general idea is the same. Specifically, you'll want to:

  1. Create a data map that associates a value with a name.
  2. Split the map into two arrays, one containing the values, one containing the names.
  3. Use a counter to find the index in the array of values and use that index to get the name from the other array.

A finished chunk of code that does what you ask might look something like this:

{
<!-- set our values -->
(set: $cat to 3)
(set: $dog to 9)
(set: $onion to 2)
(set: $ilikecheese to 6)
(set: $zebra to '')

<!-- a few more variables we'll need later -->
(set: $count to 0)
(set: $highest to -1)
(set: $index to 0)

<!-- create our data structure -->
(set: $test to (dm: 
    'cat', $cat, 
    'dog', $dog, 
    'onion', $onion, 
    'ilikecheese', $ilikecheese
))

<!-- split it into two arrays -->
(set: $testNames to (datanames: $test))
(set: $testValues to (datavalues: $test))

<!-- run the test -->
(for: each _item, ...$testValues)[
 
   <!-- count each loop -->
    (set: $count to it + 1)
    (if: _item > $highest)[
        (set: $highest to _item)

        <!-- use our counter to record the index for our arrays -->
        (set: $index to $count)
        (set: $zebra to $testNames's ($index))
    ]
]

}
$zebra: $highest

There might be a better or easier way, but if there is, I don't know it. 

by (220 points)
This works nearly perfectly, thanks for the help! The only problem that is appearing is when two variables have the same value. Rather than randomly selecting one of the two (or more) that have the same quantity it has a 100% chance to choose one (seemingly the first variable alphabetically) of them. Is there a way to randomize the selection between ties?
by (61.5k points)

Sorry, missed that in the question.  You could add another clause that tests for _item being equal to $highest, and then use (either:) to pick one of the names.

{
(set: $cat to 9)
(set: $dog to 9)
(set: $onion to 2)
(set: $ilikecheese to 6)
(set: $zebra to '')

(set: $count to 0)
(set: $highest to -1)
(set: $index to 0)


(set: $test to (dm: 
    'cat', $cat, 
    'dog', $dog, 
    'onion', $onion, 
    'ilikecheese', $ilikecheese
))

(set: $testNames to (datanames: $test))
(set: $testValues to (datavalues: $test))

(for: each _item, ...$testValues)[
    (set: $count to it + 1)

    (if: _item > $highest)[
        (set: $highest to _item)
        (set: $index to $count)
        (set: $zebra to $testNames's ($index))

    <!-- randomly select between equal values -->
    ](elseif: _item is $highest and $count is not 1)[
        (set: $index to $count)
        (set: $zebra to 
            (either: $zebra, $testNames's ($index))
        )
    ]
]

}
$zebra: $highest

Before it was selecting the first one in the order it was fed into the loop, i.e. the order it appears in the array, not necessarily alphabetical order.

by (220 points)
After throwing in that last snippet of code things started working perfectly! Once again, thanks for the help!
by (100 points)

Hi there, I'm trying to do something similar to this. I want to  sort the names of a datamap according to the variables in their corresponding values. I've mostly got it working but there's one problem: duplicate values aren't sorted correctly for some reason. I tired adapting your code above, but couldn't quite figure out how to. Any chance you could give me a hand?

{
(set: $joy to (random: 0, 50))
(set: $sadness to (random: 0, 50))
(set: $anger to (random: 0, 50))
(set: $fear to (random: 0, 50))
(set: $trust to (random: 0, 50))
(set: $disgust to (random: 0, 50))

(set: $emotionMap to (dm:
    "<div id='anger' class='square'> $anger </div> ANGER", 			$anger,
    "<div id='disgust' class='square'> $disgust </div> DISGUST", 	$disgust,
    "<div id='fear' class='square'> $fear </div> FEAR", 			$fear,
    "<div id='joy' class='square'> $joy </div> JOY",				$joy,
    "<div id='sadness' class='square'> $sadness </div> SADNESS", 	$sadness,
	"<div id='trust' class='square'> $trust </div> TRUST", 			$trust,))
(set: $nameArray to (datanames: $emotionMap))
(set: $valueArray to (datavalues: $emotionMap))

(set: $emotionList to (a:))

<!--- SORTER --->

(for: each _i, ...(range:1,6))[
	(set: $count to 0)
	(set: $highest to -1)
	(for: each _value, ...$valueArray)[
		(set: $count to it +1)
		(if: _value >= $highest)[
			(set: $highest to _value)
			(set: $index to $count)]]
	(set: $emotionList to it + (a: $nameArray's ($index)))
	(set: $valueArray's ($index) to 0)]
}
(print: $emotionList.join("<br>"))

[RANDOMIZE]<next|(click: ?next)[(goto: "DATAMAP SORTER")]

 

Welcome to Twine Q&A, where you can ask questions and receive answers from other members of the community.

You can also find hints and information on Twine on the official wiki and the old forums archive.

See a spam question? Flag it instead of downvoting. A question flagged enough times will automatically be hidden while moderators review it.
...