Sending a piece to a zone with a random offset

…is this possible? Basically, I want pieces sent to the deadpile to spread out a little and not all end up in the exact same place.

There are relatively few ways (short of custom classes) to get random number generation in Vassal in a form that is easy to use during the execution of e.g. a trigger. BUT I can think of one way off hand. You will laugh at the indirection required, but it should work:

(1) Make a secret & invisible deck of “Cards” (pieces).
(2) Give the pieces in these decks different Marker traits for different X and Y offsets you’d like to use in the deadpile, e.g. XOffset -10, YOffset +25 that kind of stuff.
(3) Put them in a “deck” set to “always reshuffle”
(4) When it’s time to send a piece from the dead pile, send a single Global Key Command that causes this deck to “draw a card” and use the offsets from the card (perhaps the cards are triggered by being moved-to-map to update global properties for X and Y offsets, etc) to offset the place you send the piece (you can leverage the “advanced options” checkbox on the Send To Location to do various expressions)
(5) Optionally you could have separate decks for “X Offset” and “Y Offset”. You could even have yet another deck for “X Multiplier” and “Y Multiplier” since those are fields in the “advanced options” of Send To Location.

If you’re careful/clever you can arrange all this while firing only a single Global Key Command, so won’t be crushingly performance-intensive.

If you actually get this working, be sure to tell me, haha!

Brian

The destination fields in the Send to Location trait all take Beanshell expressions, so you could use something like

(int) (Math.random()*100) - 50

in the X and Y locations.

Cattlesquat: that’s… certainly interesting. I hope I don’t offend you when I say “I won’t be doing it that way” ;-) A custom class, however, that might be within reach… (this has become that type of problem that you really don’t need but you want to solve just for the fun of it)

Bret Easton: Ha! That’s the very first thing I tried, couldn’t get it to work. Perhaps there was syntax problems?

Many thanks to both of you!

I am a Golden God!! I cracked it. Some sleep did my noggin’ some good, it seems.

Must have mucked something up in the syntax yesterday. Many thanks, folks.

{Math.round(Math.random()*10-5)}

Hahaha! I guess that means you don’t want my CRC polynomial algorithm? :smiley: I was thinking about how to make an algorithm that would spray the pieces in a “random-seeming” pattern, but would actually algorithmically be certain never to put two pieces on the same slot – relatively straightforward with a CRC, for certain values of straightforward.

Brent’s solution is a good solution. I keep forgetting that the math functions work too, not just the strings.

Brian

Important note to Profit and others using the pattern from above.

You may well want want…
{Math.[b]floor/b}

Because Math.round is going to use 5/4 rounding.

So e.g. a six sided die would be properly implemented as:

{Math.floor(Math.random()*6) + 1}

Brian

Thus spake Cattlesquat:

Important note to Profit and others using the pattern from above.

You almost certainly want…
{Math.floor(Math.random()*10-5)}

Because Math.round is going to use 5/4 rounding.

So e.g. a six sided die would be properly implemented as:

{Math.floor(Math.random()*6) + 1}

Brian

Oh, oh, oh! PLEASE do not generate random integers this way. This
introduces a small bias away from a uniform distribution.

Thew right way to generate random integers in the range [0,n) is
to use Random.nextInt(n).


J.

Alas Random.nextInt(n) isn’t available in Beanshell expressions.

I am working on some Beanshell Random number functions. just about done.

Yay. 3.3.1 release, I assume?

Other probably-easy-to-implement and probably-useful-to-many-modules expression builder functions might be:
Abs()
Max()
Min()
Range(Num,Min,Max)

For Abs, Min & Max. I can add the corresponding Java ath. functions. I will need to allow for an expanding parameter list for min or max. This will produce the most efficient beanshell expressions. I may as well add a new drop-down with the java String. functions as well.

What is the purpose of the Range() function?

For Random numbers I am proposing

  • Random(max) - Return a Random integer between 1 and max inclusive
  • Random(min, max) - Return a Random integer between min and max inclusive
  • IsRandom(percent) - Return true percent% of the time
  • IsRandom() - Equivalent to Random(50)

Range just combines “min” and “max” into one more tidy function.

Range(Variable,0,100) would return 0 if Variable < 0, 100 if Variable > 100 and otherwise return Variable.

The random functions look great.

I’m simply trying to get an integer to round to the nearest whole number. Something very simple like getting 10% * 18 to give a 2 result. I swear there used to be a rounding expression and found reference to it here (Math.round) on this thread. However when I try it in my module it still returns a 1 for the aforementioned equation. Math.round is not listed as an expression option in VASSAL 3.4.10. Can one of you help me out? Thanks very much.

You can do that with purely integer math, e.g. ((Percent * 18) + 50) / 100 would give you 2 if “Percent” was 10. Just be sure to have the division be last operation performed in that sequence. The addition of the “50” in this case is what gives you the “5/4 Rounding” effect.

I’m pretty sure Beanshell expressions can also use floating point values (I haven’t personally done any of that), but you probably have to carefully “cast” things at the correct time. If use of floating point is critical for your application and you’re still having problems, you could post your actual expression here w/ examples of what the values of properties would be.

I got it to work but in a backwards manner I think. Please note I’m not a programmer.

The proper syntax for rounding is Math.round(X) where X is a property or expression.

The problem I was having is how VASSAL was handling decimals. It’s interesting that VASSAL will multiply 2 decimals and give a result in decimals (ex 1.2*1.2 = 1.44). But it won’t divide two numbers and give a result in decimals (ex 180/100 = 1).

What I was trying to do was multiply two Properties together, divide by 100, then round to the nearest integer. My original attempt was this:

Math.round((PropertyA*PropertyB)/100)

That didn’t work as it would round down to the next lower whole number.

What does work is this:

Math.round((PropertyAPropertyB).01)

In case this is helpful I should add that the above syntax works within the Expression field of a Calculated Property. If you are adding it as an expression anywhere else there needs to be brackets to identify it as a Beanshell expression:

{Math.round((PropertyAPropertyB).01)}

I found this helpful:
http://www.vassalengine.org/wiki/How_to_use_Random_Numbers_and_other_Math_functions_in_VASSAL

I’m sure this seems very basic but it does reveal my very limited understanding on how VASSAL and Java interrelate. Hopefully this helps others out there like me.

If someone with more knowledge than me wants to jump in and improve my input, please do so. I’m willing to learn more.

Our posts crossed :slight_smile:

Interesting in the use of the “50” to make it round properly. I just tested it and this works:

Math.round(((PropertyA*PropertyB)+50)/100)

Thanks!

Is there any reason to use the above rather than:

Math.round((PropertyAPropertyB).01)

Please let me know if so. Else I’ve got two solutions. What a great forum! Thank you again.

Just realized that with your solution, I don’t need to use the Math.round syntax.

This works too:

((PropertyA*PropertyB)+50)/100

More elegant and streamlined than my solution :slight_smile:

Thanks!

Thus spake BigAl737:

But it won’t divide two numbers and give a
result in decimals (ex 180/100 = 1).

That’s pretty much standard for mathematical expressions in programming
languages. 180 and 100 are integer literals; when both operands are
integers, you get integer division. Floating point division happens only
when at least one operand is a float or a double. If you divided 180.0/100,
you would get 1.8 instead of 1.


J.

That is very good to know. Thank you!