Need help with complicated ternary Expressions please

Hello good people;

I have created an invisible button over a deck so that when you left-click on the Deck it automatically sends a card to one of 4 designated multi zoned grids named New Development_1 etc and need to be placed in that order. Also there must be only one card per zone…

…I have assigned a Send To Location Trait with the following Expression…

{((CountZone("New Development_1","Main Map","{BasicName.contains(\"Development\")}") > 0) ? "New Development_2" : "New Development_1")}

here…

…which works fine and dandy, moving the card from New Development _1 to _2 and ignoring all Pieces except other Development Cards. BasicName.contains is used because the BasicName property has other information describing it’s effects in the game so no two cards have the same name.

My problem is that I need to extend the Ternary to cover the same condition in Zones: Development_ 2 & _3 until all four Zones have one card each. This I can’t do and I have tried copying Ternary Expression in other modules but to no avail. Can someone show me how to do this please? I probably have a quotation or bracket in the wrong place.

Regards;
Darren

Building on your 2 zone version, I would go with a sequence of ternary expressions of the form:

condition1 ? result1 : condition2 ? result2 : condition3 ? result3 : result4

This minimises the parentheses you need. I think your required expression is therefore like this:

{CountZone("New Development_1","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_1" : CountZone("New Development_2","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_2" : CountZone("New Development_3","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_3" : "New Development_4"}

If you want to make the expression a little more concise, put a unique property on the development cards. e.g. “DevelopmentCard” ; the property can have any value, but mustn’t exist on any other pieces in the target zones. You can then use the Property form of CountZone() instead of needing an embedded expression. e.g.

{CountZone("New Development_1","Main Map","DevelopmentCard") == 0 ? "New Development_1" : CountZone("New Development_2","Main Map","DevelopmentCard") == 0 ? "New Development_2" : CountZone("New Development_3","Main Map","DevelopmentCard") == 0 ? "New Development_3" : "New Development_4"}

1 Like

Hello Mark I was looking through your Command and Colours modules in particular because I know you are the Guru for this sort of thing but they were way to complex for me. The Expression you have written is not accepted in the builder (same as my previous attempts). I think there is a problem with the bewildering array of brackets and quotations required which I have been struggling with but I have your format above as a guide and will persevere for a while longer.

Regards;
Darren

OK so continuing from where my original Expression left and using yours as a guide…

{CountZone("New Development_1","Main Map","{BasicName.contains(\"Development\")}") > 0) ? "New Development_2" : CountZone("New Development_2","Main Map","{BasicName.contains(\"Development\")}") > 0) ? "New Development_3" : CountZone("New Development_3","Main Map","{BasicName.contains(\"Development\")}") ? "New Development_4" : "New Development_1"}

…is what i am after. Which says (I think) ;

IF New Development_1 is occupied ? go to New Development_2 : IF New Development_2 is occupied ? go to New Development_3 : IF New Development_3 is occupied ? go to New Development_4 : Otherwise, it’s New Development_1. It doesn’t work though, your version has fewer brackets than my original True/False only version but I added the missing brackets and still no go. I have spent a full day on this which is over my limit so that will do until next weekend maybe. Thank you again. :saluting_face:

Regards;
Darren

There are 3 issues with

First is a simple repeating syntax error: an extra closing parenthesis “)” before the first 2 “?”.
Second is another syntax error: the > 0 is missing from the final test.
The more important error is in your logic: that statement is saying ‘if there’s already a piece with “Development” in its Basic Name in zone “New Development_1”, the result is “New Development_2”; else, if there’s already a piece with “Development” in its Basic Name in zone “New Development_2”, the result is “New Development_3”; else, if there’s already a piece with “Development” in its Basic Name in zone “New Development_3”, the result is “New Development_4”; else, the result is “New Development_1”.’

That is only going to check "New Development_2" if there are no pieces in "New Development_1", and so on, which is the reverse of what you want.

The correct statement should be:

{CountZone("New Development_1","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_1" : CountZone("New Development_2","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_2" : CountZone("New Development_3","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_3" : "New Development_4"}

As a side note, this formula will continue to dump pieces in “New Development_4” if all 4 zones are already occupied (as it just assumes that’s the correct zone once the other 3 are full).

I hope this helps!

1 Like

It surely does and is doing exactly what I want. Much obliged to you Jonathan.

This doesn’t seem to be problem, continually pressing the button doesn’t add more cards to the fourth Zone but if it did - should the last part (: “New Development_4”) be changed to something like this?..

: CountZone("New Development_4","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_4" : 0

or

: CountZone("New Development_4","Main Map","{BasicName.contains(\"Development\")}") == 0 ? "New Development_4" : ""

In other words…What is the best thing to use in a Ternary which means “nothing happens”? :slightly_smiling_face:

Anyway, now I have a Ternary I understand I can use this as a template for others. Thanks again. :+1:

Regards;
Darren

I worked out why this isn’t happening There is a Restrict Command Trait in place that prevents it. If I were to add the extra above to the Ternary than I am guessing this Trait would not be needed.

Regards;
Darren

Sorry Darren, my examples didn’t paste as code properly; so the quotation marks got corrupted to so-called “smart quotes”. Once I corrected this they work again. Meanwhile, I see that you’re making progress thanks to @jrwatts, thankfully.

Since the result of the formula is the final Zone for a Send to Location command, I believe the 2nd alternative (an empty string) would be the correct form; the first form would try to send the piece to a Zone called “0”, which I assume would do nothing if such a Zone doesn’t exist, but that isn’t ideal (and I’m assuming a blank Zone will do nothing–it might trigger an error, instead). In any case, since you already have a Restrict Commands trait to prevent more than 4 cards being moved, I would just stick with that.

1 Like

Yes all good Mark, thanks for taking the time to help.

Regards;
Darren

So an expression would not be better? I read here somewhere that Beanshell could slow the game down sometimes but also too many traits in a Piece could do the same thing. Not a problem with this game but my other Project: (B-17) has multiple Pieces with 50+ Traits in them.

My concern is that there is no documented intended behavior for a Send to Location to an unknown or blank location; I don’t know what it currently does (nothing, or log an error?), and there’s no guarantee that behavior won’t change (deliberately or accidentally) in a future revision of VASSAL. Since you’re committed to running the Send to Location by the time your expression is evaluated, I feel it’s better to use the Restrict Commands trait to prevent from running at all if there isn’t a valid destination. You would have to profile your module’s run times to determine if there is an actual difference in speed between the 2 methods.

2 Likes

I have found 2 problems. The first was I had these cards dealing in the wrong order, they are supposed to go 4-3-2-1 which was fixed easy enough by reversing the order of the Ternary expression provided by Jonathan. The other is the Restrict Command prevents more cards from being dealt if there is a card in the last Zone (now “New Development_1”) when the others are empty. I am thinking now it might be better to use a Send to Location to deal the card to “New Development_4” combined with a "Move Fixed Distance" that can shift the Card to the left until it finds an empty Zone. The Zones are all evenly spaced and have a Rectangular grid so the cards will still snap to position.

This will have to wait until next weekend.

Regards;
Darren

Hi All;
OK…this Restrict Command is not supposed to activate until all 4 Zones have one card each so how can I do that in the Property Match field for the RC? I need something like;

CountZone("New Development_1") + CountZone("New Development_2") + CountZone("New Development_3") + CountZone("New Development_4") == 4 

and I did try this but it doesn’t work. Should I have a separate Calculated Property for each Zone then add CPs together? What is the most efficient way to do this, I know that too many CPs can slow down the game. Or can someone point me to some information that explains how to add in beanshell? I can find only basic examples in the reference manual, maybe it can’t be done.

Regards;
Darren

Never mind I forgot to include the Map name this is what happens I try to this after work. :face_with_spiral_eyes:

It doesn’t sound like you need to put the Restrict Command formula into a Calculated Property. The Restrict Command will evaluate only when the piece receives a Key Command that is to be restricted, so putting the formula directly one or more Restrict Command traits is probably more efficient.

Instead of the formula you quoted (with Map added), let’s suppose the piece being restricted is on a Map called “Main Map”, how about the following ?

CountMap("Main Map", "{CurrentZone.startsWith(\"New Development_\"}") == 4

If you put a unique Global Property into the New Development zones, you can simplify the formula still further. Let’s suppose you add a Global Property NewDev to each zone, and set it to any non-null value, you could use the following in your Restrict Command formula:

CountMap("Main Map", "New_Dev") == 4

I think this would be the most efficient, though in an isolated case there’s probably no noticeable difference.

1 Like

I think I get what you mean. Had to delete my other post i don’t think it made sense Lol! Weekends are the best for this sort of thing. Thanks mark.

Regards;
Darren

Hello Mark;
Now a more sensible response to the information you gave me, this will replace the other I deleted. I took your tip about using a zone level property, using it as a kind of Marker Trait (I think)…

…and took it one step further. I gave each Zone a Property with the same name ZoneNumber and gave it a Value that matches the number of the Zone included in it’s name. With that, I came up with this much shorter Expression…

{CountMap("Main Map","{ZoneNumber == $ZoneNumber$ -1}") == 0 ? CurrentX -327 : CurrentX}

…that replaces this one…

{(CountZone("New Development_3","Main Map","{Deck == \"Dev\"}") == 0 && CurrentZone == "New Development_4") ? (CurrentX -327) : (CountZone("New Development_2","Main Map","{Deck == \"Dev\"}") == 0 && CurrentZone == "New Development_3") ? (CurrentX -327) : (CountZone("New Development_1","Main Map","{Deck == \"Dev\"}") == 0 && CurrentZone == "New Development_2") ? (CurrentX -327) : (CurrentX)}

…and does the same thing. At least it seems to work, no problems so far. The only issue is that “New Development Zone_1” is looking for a value of 0 which doesn’t exist and returns a weird count of 124 but that doesn’t matter because that Zone is the end of the line and can’t move.

Thanks again, it is amazing the difference a day off work can make.

Regards;
Darren