Widget won't work with specific combination of arguments

Twine Version: 2.3.9
Story Format: Sugarcube

So I’m doing one of those puzzles where you have three containers of different sizes and you have to pour stuff from one to another until two of them are even. (Yeah, I know, it’s been done to death, but I’m not here for feedback on my puzzle choices at this time.)

So I’ve got my buckets as objects with properties for current fill, maximum fill, and currently available space, with starting values as follows (these aren’t the finalized values for the puzzle, by the way, I’m currently just trying to get the mechanics of the thing to work):

<<set $left to {fill : 7, max : 7, space : 0}>>
<<set $right to {fill : 0, max : 5, space : 5}>>
<<set $small to {fill : 0, max : 2, space : 2}>>

Then I’ve got a “pour” macro that looks like this:

<<widget "pour">>
<<if $args[0].fill <= $args[1].space>>

<<set $args[1].fill to $args[1].fill + $args[0].fill>>
<<set $args[0].fill to 0>>
<<set $args[0].space to $args[0].max>>
<<set $args[1].space to $args[1].max - $args[1].fill>>

<<else>>

<<set $args[1].fill to $args[1].max>>
<<set $args[0].fill to $args[0].fill - $args[1].space>>
<<set $args[0].space to $args[0].max - $args[0].fill>>
<<set $args[1].space to 0>>

<</if>>

<<set $turns += 1>>
<</widget>>

The following macro calls all work as intended:

<<pour $left $right>>
<<pour $left $small>>
<<pour $right $left>>
<<pour $small $left>>

However, when I pass the macro either combination of “$right” and “$small” (<<pour $right $small>> or <<pour $small $right>>)… nothing happens. The values of the properties of $right and $small are completely unchanged. All of the macro calls here are copy-pasted right out of my markup in Twine, so you can see there are no typos or missing brackets or anything. I can’t see any reason why the right bucket and the small bucket shouldn’t be able to interact with each other when they both interact with the left bucket just fine, but they just don’t. Anyone have any idea what’s going on?

So… I think it’s just because both “right” and “small” start empty? I copied your code (links for each of the widgets inside one passage and displaying “fill” values for each vessel above) and played with it for a bit, and once I increased the “fill” on right and small with the other macros, <<pour $right $small>> worked just fine.

It is doing what you tell it to do, however, what you’re telling it to do doesn’t change anything with the default values. For example, if you do:

<<set $left to {fill : 7, max : 7, space : 0}>>
<<set $right to {fill : 0, max : 5, space : 5}>>
<<set $small to {fill : 0, max : 2, space : 2}>>
<<pour $small $right>>

Then in the macro it does:

<<if $args[0].fill <= $args[1].space>>  /* 0 <= 5 == true */
<<set $args[1].fill to $args[1].fill + $args[0].fill>>  /* 0 = 0 + 0 (no change) */
<<set $args[0].fill to 0>>  /* 0 = 0 (no change) */
<<set $args[0].space to $args[0].max>>  /* 5 = 5 (no change) */
<<set $args[1].space to $args[1].max - $args[1].fill>>  /* 2 = 2 + 0 (no change) */
...

In other words, the first half of your if/else code simply does nothing in the case of $small $right being passed to it, because you’ve told it to do nothing.

Also, if “space” is always going to be equal to “max” - “fill”, then there’s no need to keep track of “space” separately. Additionally, attempting to track “space” separately like that may produce odd results if it’s not done properly.

I think you need to rethink your math/logic there somewhere.

Assuming you’re trying to do what I think you’re trying to do, then this seems to work.

StoryInit:

<<set $left to { fill : 7, max : 7 }>>
<<set $right to { fill : 0, max : 5 }>>
<<set $small to { fill : 0, max : 2 }>>
<<set $turns = 0>>

Widget passage (with “widget” and “nobr” tags):

<<widget "pour">>
	<<if $args[0].fill <= $args[1].max - $args[1].fill>>
		<<set $args[1].fill += $args[0].fill>>
		<<set $args[0].fill = 0>>
	<<else>>
		<<set $args[0].fill -= $args[1].max - $args[1].fill>>
		<<set $args[1].fill = $args[1].max>>
	<</if>>
	<<set $turns += 1>>
	<<goto "Pouring Game">>
<</widget>>

And the “Pouring Game” passage:

''Turns:'' $turns

''Left (max $left.max):'' $left.fill <<button "Pour into Right">><<pour $left $right>><</button>> <<button "Pour into Small">><<pour $left $small>><</button>> 
''Right (max $right.max):'' $right.fill <<button "Pour into Left">><<pour $right $left>><</button>> <<button "Pour into Small">><<pour $right $small>><</button>> 
''Small (max $small.max):'' $small.fill <<button "Pour into Left">><<pour $small $left>><</button>> <<button "Pour into Right">><<pour $small $right>><</button>> 

That seems to work fine for me. You’d just need to add an <<if>> statement into the widget to go to a different passage when the “winning” goal (e.g. $left.fill == 1) occurs.

Hope that helps! :slight_smile:

Thank you both, I really appreciate your attempts to help! However, unfortunately I didn’t explain the issue properly - I am aware that n + 0 = n, but I can see why it looked like I wasn’t. Let me walk through what happens when I try to interact with the puzzle as it currently stands:

So, I go to the puzzle passage in debug mode, tracking all the values, and I pour the left bucket into the right bucket (<<pour $left $right>>). According to the debugger, the values are now:

$left: {“fill” : 2, “max” : 7, “space” : 5}
$right: {“fill” : 5, “max” : 5, “space” : 0}
$small: {“fill” : 0, “max”: 2, “space”: 2}

So far so good, right? I can then dump the left bucket into the small bucket (<<pour $left $small>>) and get:

$left: {“fill” : 0, “max” : 7, “space” : 7}
$right: {“fill” : 5, “max” : 5, “space” : 0}
$small: {“fill” : 2, “max”: 2, “space”: 0}

Still working great! Pouring the right bucket into the left bucket (<<pour $right $left>>), I get:

$left: {“fill” : 5, “max” : 7, “space” : 2}
$right: {“fill” : 0, “max” : 5, “space” : 5}
$small: {“fill” : 2, “max”: 2, “space”: 0}

Hooray! Then I try pouring the small bucket, which as you can see has a current fill value of 2, into the right bucket (<<pour $small $right>>). According to the debugger, the values are now:

$left: {“fill” : 5, “max” : 7, “space” : 2}
$right: {“fill” : 0, “max” : 5, “space” : 5}
$small: {“fill” : 2, “max”: 2, “space”: 0}

… exactly the same as before. I can then pour the small bucket into the left bucket (<<pour $small $left>>), which works as it should, returning the values to:

$left: {“fill” : 7 “max” : 7, “space” : 0}
$right: {“fill” : 0, “max” : 5, “space” : 5}
$small: {“fill” : 0, “max”: 2, “space”: 2}

I dump the left into the right again and get:

$left: {“fill” : 2, “max” : 7, “space” : 5}
$right: {“fill” : 5, “max” : 5, “space” : 0}
$small: {“fill” : 0, “max”: 2, “space”: 2}

But when I try to dump the right bucket into the small bucket (<<pour $right $small>>), again the values are unchanged:

$left: {“fill” : 2, “max” : 7, “space” : 5}
$right: {“fill” : 5, “max” : 5, “space” : 0}
$small: {“fill” : 0, “max”: 2, “space”: 2}

So as you can see, the widget very specifically does not work when trying to move anything from $right to $small or vice versa, even when the fill value of the origin bucket is not 0. However, it works exactly as intended for any other combination of buckets.

@HiEv, you’re right that I’m overcomplicating things by having a separate “space” value, so I will redo it to remove that and maybe this will all be a moot point. But I really would love to figure out why it doesn’t work as is, because I don’t see any reason why it shouldn’t. (Edit: especially as it looks like it did work as-is for @agat? I suppose there might be something else in my story file that’s interacting with it, but I don’t see what it could be - I never call those values outside of this macro.)

Also, thanks for the suggestion to add a line to the widget forwarding people to a different passage when the win conditions are met, but that is something I actually already have covered in the puzzle passage! I may reuse the widget later for a more complicated version of the puzzle, and I will want to forward people to different passages upon completion of each puzzle, so I am keeping that outside of the widget. :slight_smile:

Yeah, your original code works perfectly for me. Running this code:

$left.fill, $right.fill, $small.fill
<<pour $left $right>>$left.fill, $right.fill, $small.fill (after left to right)
<<pour $left $small>>$left.fill, $right.fill, $small.fill (after left to small)
<<pour $right $left>>$left.fill, $right.fill, $small.fill (after right to left)
<<pour $small $right>>$left.fill, $right.fill, $small.fill (after small to right)
<<pour $right $small>>$left.fill, $right.fill, $small.fill (after right to small)
<<pour $small $left>>$left.fill, $right.fill, $small.fill (after small to left)

gets me this output:

7, 0, 0
2, 5, 0 (after left to right)
0, 5, 2 (after left to small)
5, 0, 2 (after right to left)
5, 2, 0 (after small to right)
5, 0, 2 (after right to small)
7, 0, 0 (after small to left)

So I think there has to be something else going on somehow, though I can’t immediately think of what that might be?

Thanks for checking! On the one hand, it’s sort of reassuring to know there’s nothing wrong with the macro itself, but on the other hand, I’m gonna be tearing my hair out trying to figure out what’s interfering with it.

I used your original version of the widget…

<<widget "pour">>
	<<if $args[0].fill <= $args[1].space>>
		<<set $args[1].fill to $args[1].fill + $args[0].fill>>
		<<set $args[0].fill to 0>>
		<<set $args[0].space to $args[0].max>>
		<<set $args[1].space to $args[1].max - $args[1].fill>>
	<<else>>
		<<set $args[1].fill to $args[1].max>>
		<<set $args[0].fill to $args[0].fill - $args[1].space>>
		<<set $args[0].space to $args[0].max - $args[0].fill>>
		<<set $args[1].space to 0>>
	<</if>>
	<<set $turns += 1>>
<</widget>>

…and ran the following test case, that included the first four steps of your most recent example…

<<nobr>>
<<set $left to {fill : 7, max : 7, space : 0}>>
<<set $right to {fill : 0, max : 5, space : 5}>>
<<set $small to {fill : 0, max : 2, space : 2}>>
<<set $turns to 0>>

debug: Originals:<br>
- Left: <<= JSON.stringify($left)>><br>
- Right: <<= JSON.stringify($right)>><br>
- Small: <<= JSON.stringify($small)>>

<<pour $left $right>>
<br><br>
debug: From Left to Right: (5 into Right from Left)<br>
- Left: <<= JSON.stringify($left)>><br>
- Right: <<= JSON.stringify($right)>><br>
- Small: <<= JSON.stringify($small)>>

<<pour $left $small>>
<br><br>
debug: From Left to Small: (2 into Small from Left)<br>
- Left: <<= JSON.stringify($left)>><br>
- Right: <<= JSON.stringify($right)>><br>
- Small: <<= JSON.stringify($small)>>

<<pour $right $left>>
<br><br>
debug: From Right to Left: (5 into Left from Right)<br>
- Left: <<= JSON.stringify($left)>><br>
- Right: <<= JSON.stringify($right)>><br>
- Small: <<= JSON.stringify($small)>>

<<pour $small $right>>
<br><br>
debug: From Small to Right: (2 into Right from Small)<br>
- Left: <<= JSON.stringify($left)>><br>
- Right: <<= JSON.stringify($right)>><br>
- Small: <<= JSON.stringify($small)>>
<</nobr>>

…and the values in each of my debug outputs were what I expected, however the values I got for the <<pour $small $right>> step were different than your own.

1 Like

Okay, I just sent the story file to someone else and it worked perfectly for them, so now I’m really confused. But in any case, it doesn’t look like the markup is the problem. Thank you all for taking a look at it, though!