Weighted Sampling Condition

For what's not in 'Top Priority Game Design'. Post your ideas, visions, suggestions for the game, rules, modifications, etc.

Moderator: Oberlus

Post Reply
Message
Author
Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Weighted Sampling Condition

#1 Post by Ophiuchus »

some suggestion for syntax of single hardcoded weighted random sampling without replacement in the context of target conditions. Targeting a single ship is 3 times as likely as targeting a single fighter:

Code: Select all

WeightedAlternativesOf scope = [[COMBAT_TARGETS_VISIBLE_ENEMY]] alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Fighter
]
i try to figure out a way to do this without calculation all the alternatives in advance (or to skip it most of the time).

Implementation probably could calculate one target set, then use (relative_weight * size(target_set))/size(universe_set)) to determine if it should pick a target from the set, else carry on with the next target set.

In this example there could be planets in the target set, which the algoritm would interpret as "no alternative", so resulting in no target (with weight 1).
I got geoff's input in the dev meetup, as the stated use case is possible with current implementation (chained if-else effects with dependent probabilities) he doesn't want to complicate the scripting context with adding something maybe more complex (e.g. complexity like the LocalCandidate (e.g. what would happen about invariants?, would one need to store very different values e.g. string, int, float, vector<*>..)).

Weighted selection of objects (without replacement) in a condition makes more sense for him, but also there we do not have a pressing use case (there are usually workarounds). So for the moment I guess wait/dig for valid use cases (anyway having a selection-without-replacement function in random would not hurt).
Another syntax suggestion for only shooting most dangerous enemies first (number parameter is not really necessary/not very useful for targeting, scaling that up could prevent overshooting)

Code: Select all

RandomNumberOf number = [[COUNT_OF_THIS_WEAPON_IN_SYSTEM]] / 2  weightkey = LocalCandidate.Attack conditions =  [
    [[COMBAT_TARGETS_VISIBLE_ENEMY]] 
    Or [ Ship Fighter ]
]
(Related: Some old targeting implementations in Use OrderedAlternativesOf condition for combat target tiers in fighte… , uses MaximumNumberOf to get an equal propability target set of the most dangerous enemies; that one really needs to set number to prevent overshooting a lot)

Trying to use what is already in the language:
std::sample would solve picking N times without replacement from a range. Not sure what happens with probabilities if you we e.g. add primary targets three times and secondary targets only once there. We could throw away the D duplicates in the results. Bigger problem is that we get N-D results and cant fill the the missing D ones in a meaningful way (retrying sampling without the D elements will skew probabilites for certain).

One could try std::shuffle to remove that problem - take as many items from the front until you have N non-duplicates.
The other main problem here is that in order to get the weights, i would still need a full pass to find out which are primaries.

edit: changed preferred syntax for WeightedAlternativesOf (universe -> scope, conditions -> alternatives, Alternative -> Weighted)
Last edited by Ophiuchus on Tue Nov 30, 2021 12:20 pm, edited 3 times in total.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: Weighted Sampling Condition

#2 Post by Ophiuchus »

Was pondering the use of WeightedAlternativesOf

The case is similar as for OrderedAlternativesOf, as both have conditionally applied subconditions.

WeightedAlternativesOf [ A B C ] cant be really commutative:

Code: Select all

And [                                                                                                                                                                                                                        
    Not And [ A B ]                  // imagine candidates matching A and also candidates matching B                                                                                                                          
    WeightedAlternativesOf [ A B C ] // this might select a candidate matching B                                                                                                                                              
    Not B                            // which then gets killed, leaving no match although the candidate matching A was fine                                                                                                   
 ]                                                                                                                                                                                                                            
 
So we either need to pass in the complete relevant Universe. Or simply dissallowing commutative use(?)

We could specify that WeightedAlternativesOf gets evaluated last, but that is not feasable in the general case

Code: Select all

 And [                                                                                                                                                                                                                        
    And [                                                                                                                                                                                                                     
       WeightedAlternativesOf [ A B C ] //  needs to be pulled up a level                                                                                                                                                     
    ]                                                                                                                                                                                                                         
    WeightedAlternativesOf [ D E ] // ok, which of the WeightedAlternativesOf comes last                                                                                                                                      
    Not B                                                                                                                                                                                                                     
 ]                                          

We can apply the clunky workaround we use for OrderedAlternativesOf, move conditions into all subconditions (which is mostly the same as passing in the complete relevant universe, just much more verbose and clunky)

Code: Select all

 WeightedAlternativesOf [                                                                                                                                                                                                     
       And [ A Not B ]                                                                                                                                                                                                        
       And [ B Not B ]  // kills the alternative                                                                                                                                                                              
       And [ C Not B ]  // so either an A or a C will be the (correct) subresult                                                                                                                                                 
 ]
edit1: actually for WeightedAlternativesOf this workaround still needs the condition outside of WeightedAlternativesOf to restrict the universe and it needs to be executed before WeightedAlternativesOf in order to work correctly. Else the count total will be wrong. E.g. in combat, it would also count your own vessels not only your enemies.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: Weighted Sampling Condition

#3 Post by Ophiuchus »

I have an implementation for WeightedAlternativesOf mostly ready. I am trying to keep calculations necessary to a minimum.

By restricting scope you know the total number of candidates in advance, so you can roll a die, starting from the first subcondition you find out how many objects match; if the roll is lower than the number of matches found you choose this subcondition, else you continue with the next subcondition.

This works beautiful and efficient unless you add weights/have overlapping conditions. And adding weights is the whole point of the thing.

Overlapping conditions I do not want to support (so I consider a scripting error), so for this discussion I ignore those.

So I probably need to add some "backtracking" capability reacting to knowing after the fact that a roll was invalid.

First idea, look for maximum weight in advance, multiply the total number of candidates by that and roll against that. I.e. the roll could be higher than the number of actual weighted matches.

If the roll is higher than the number of actual weighted matches: the main downside is that one matches all subconditions. But now one knows the real total weighted number of candidates, so one can simply reroll (and writing down the actual number of matches and weights for all subconditions) and reevaluate the chosen subcondition.

In a next step one could try to lower the chance of rolling too high. e.g you could take the average weight instead of the maximum weight. But this is not so easy then:
if you guess a probable sum of total weighted matches you need to make sure that the maximum roll is not lower than the actual sum of weighted matches, because in that case the roll was invalid (because considering it valid would skew propabilities).

In order to proof that one can take the maximum weighted sum of unknown matches (max_weighted(X)) and total weighted sum of known matches (weighted(K)).
If the roll (R) is higher or equal the minimum number of all known and unknown weighted matches, everything is fine. R >= weighted(K) + max_weighted(X)); The number of unknown matches (X) is the number of candidates (C) minus the number of known matches (K). Multiplying that by the maximum weight of unevaluated subconditions gives max_weighted(X) = max_weight(unevaluated_subconditions) * (C-K).
If the roll is invalid, one has to reroll against a higher assumed sum of weighted matches. If the roll is low enough an already evaluated subcondition is chosen and one only needs to reevaluate that one. If the roll is higher, one has to proceed with evaluating the subconditions.

Another (additional) option is passing in a total weighted sum heuristic function which provides the scripter with the task of setting a heuristic or a maximum bound for the sum. But this is an extra calculation which could be as expensive as calculating all subconditions.

Another idea would be to pass a weight function (valueref) which gets applied on all objects in the given scope and then summed up. But this means a lot of small extra calculations.

So if I do not come up with anything better, assuming the highest possible total weighted sum of candidates is the next thing to implement and leave any further improvement for later (or for never, whatever comes first).
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Weighted Sampling Condition

#4 Post by Geoff the Medio »

Ophiuchus wrote: Thu Nov 18, 2021 3:55 pmTargeting a single ship is 3 times as likely as targeting a single fighter:

Code: Select all

WeightedAlternativesOf scope = [[COMBAT_TARGETS_VISIBLE_ENEMY]] alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Fighter
]
Does this mean that, as long as there is at least one visible ship and one visible fighter in the universe, there is a 75% chance that a ship will be picked and a 25% chance that a fighter will be picked and a 100% chance that that something will be picked?

Or does it mean that if the universe has 3 fighters and 1 ship in it, all visible, that there is a 50% chance that the ship is picked, and that each fighter has a 16.7% chance of being picked, and that there is an overall 100% chance of picking something?

If there are no ships and one fighter, is there a 100% chance or a 25% chance of picking the fighter?

Why do you need a separate scope filter instead of putting the visibility into the subconditions? How would the result be different (or have different probabilities) than

Code: Select all

WeightedNumberOf number = 1 [
    weight = 3 condition = And [Ship [[COMBAT_TARGETS_VISIBLE_ENEMY]] ]
    weight = 1 condition = And [Fighter [[COMBAT_TARGETS_VISIBLE_ENEMY]] ]
]

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: Weighted Sampling Condition

#5 Post by Ophiuchus »

Geoff the Medio wrote: Tue Nov 30, 2021 10:42 am
Ophiuchus wrote: Thu Nov 18, 2021 3:55 pmTargeting a single ship is 3 times as likely as targeting a single fighter:

Code: Select all

WeightedAlternativesOf scope = [[COMBAT_TARGETS_VISIBLE_ENEMY]] alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Fighter
]
Does this mean that, as long as there is at least one visible ship and one visible fighter in the universe, there is a 75% chance that a ship will be picked and a 25% chance that a fighter will be picked and a 100% chance that that something will be picked?
No, I think that would be pretty useless. (I also think it would be possible to do that in FOCS already).

Three times as likely for a single ship as a for a single fighter.
Geoff the Medio wrote: Tue Nov 30, 2021 10:42 am Or does it mean that if the universe has 3 fighters and 1 ship in it, all visible, that there is a 50% chance that the ship is picked, and that each fighter has a 16.7% chance of being picked, and that there is an overall 100% chance of picking something?
Exactly. And if you have 3 ships and 3 fighters the chance that any ship is picked is 3 to 1 (75%).
Geoff the Medio wrote: Tue Nov 30, 2021 10:42 am If there are no ships and one fighter, is there a 100% chance or a 25% chance of picking the fighter?
100%
Geoff the Medio wrote: Tue Nov 30, 2021 10:42 am Why do you need a separate scope filter instead of putting the visibility into the subconditions?
the scope is mostly an optimisation to prevent having to always evaluate all subconditions against all candidates.

it might also be necessary for strict commutativity if surrounded with e.g. an And. passing in its independent scope will make it independent of the other conditions. one can work around that by correctly scripting mostly, but that also means that you will have to evaluate that condition multiple times unnecessarily. it also means that the order of conditions matters, so no real commutativity.
Geoff the Medio wrote: Tue Nov 30, 2021 10:42 am How would the result be different (or have different probabilities) than

Code: Select all

WeightedNumberOf number = 1 [
    weight = 3 condition = And [Ship [[COMBAT_TARGETS_VISIBLE_ENEMY]] ]
    weight = 1 condition = And [Fighter [[COMBAT_TARGETS_VISIBLE_ENEMY]] ]
]
Well, this picks a single (or fixed number of) candidate(s). WeightedAlternativesOf evaluates to a set of matches from the chosen subcondition.
For using top level in combatTargets both WeightedAlternativesOf and WeightedNumberOf number = 1 will have the same result.

For the number = n case. Well this is much more involved computationally (cpu and memory) i think. you need to evaluate all subcondition against all candidates, put them multiple times (if weight>1) into a vector and then have that one shuffled. I am not sure there are any shortcuts.
Probabilities for taking n random candidates directly from WeightedAlternativesOf will not be the same as WeightedNumberOf number = n; the candidates will all be from the chosen subcondition for WeightedAlternativesOf while they can be different for WeightedNumberOf.

I am not sure that WeightedNumberOf is conditional like WeightedAlternativesOf is (did not think enough about that). Edit: Actually I think all the *NumberOf are conditional/non-commutative. If that is actually OK, for WeightedAlternativesOf I could(?) probably get rid of the scope param and maybe even not look at non_matches (you simply have to write it the conditions above the WeightedAlternativesOf in a surrounding And condition).

Also note that WeightedNumberOf lends itself better to per-object weight (as given in my initial example).
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: Weighted Sampling Condition

#6 Post by Ophiuchus »

Ophiuchus wrote: Tue Nov 30, 2021 11:40 am Edit: Actually I think all the *NumberOf are conditional/non-commutative. If that is actually OK, for WeightedAlternativesOf I could(?) probably get rid of the scope param and maybe even not look at non_matches (you simply have to write it the conditions above the WeightedAlternativesOf in a surrounding And condition).
If I have it correctly, the following will return the ship with second highest structure

Code: Select all

And [
    MaximumNumberOf number = 2 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
    MinimumNumberOf number = 1 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
]
But if you switch, it will return the ship with the lowest structure

Code: Select all

And [
    MinimumNumberOf number = 1 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
    MaximumNumberOf number = 2 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
]
If we accept that conditionality, one of the examples I posted would be interpreted differently

Code: Select all

// the following returns no matches with a probability of (#B / (#A+#B+#C)) 
And [ Or [ A B C]
    WeightedAlternativesOf [ A B C ] // this might select all candidate matching B
    Not B                            // which then all get killed, leaving no match although candidates matching A were fine for WeightedAlternativesOf
 ]        
if we dont accept that conditionality the following should return the same, but does not

Code: Select all

// it returns either A with a probability of (#A / (#A+#C)) or C with a probability of (#C / (#A+#C))
 And [ Or [ A B C]
    Not B                            // kills all B
    WeightedAlternativesOf [ A B C ] // if A or B candidates which are Not B exist, will always return some matches
 ]
 
Geoff, would it be ok to just accept that conditionality (which exists in the other *NumberOf conditions anyway)? besides being consistent and simplifying the condition in FOCS (getting rid of scope) it would also greatly simplify the implementation.

In that case if searching for non_matches to remove from the matches in the MATCHES domain, I only need look at the current matches - so if at the point the WeightedAlternativesOf condition is evaluated, there are e.g. 123 ships in the matches, the total number of possible matches is actually 123. Is that correct?
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Weighted Sampling Condition

#7 Post by Geoff the Medio »

What do you want to happen if:

Code: Select all

WeightedAlternativesOf scope = All alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Or [Ship Fighter]
]
or

Code: Select all

WeightedNumberOf number = 1 [
    weight = 3 condition = Ship
    weight = 1 condition = Or [Ship Fighter]
]
with equal numbers of ships and fighters in the universe?

WeightedAlternativesOf evaluates to a set of matches from the chosen subcondition.
[...]
Probabilities for taking n random candidates directly from WeightedAlternativesOf will not be the same as WeightedNumberOf number = n; the candidates will all be from the chosen subcondition for WeightedAlternativesOf while they can be different for WeightedNumberOf.
I assume you mean that all the matches of WeightedAlternativesOf are guaranteed to be chosen so that there is (at least) one of the subconditions that all the returned matches match. So with

Code: Select all

WeightedAlternativesOf scope = All alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Fighter
]
if you added a number = 3 parameter to the WeightedAlternativesOf example above, and there were 2 ships and 6 fighters in the universe, it would have a 50% chance of matching 2 ships and a 50% chance of matching 3 fighters?

For the number = n case. Well this is much more involved computationally (cpu and memory) i think. you need to evaluate all subcondition against all candidates, put them multiple times (if weight>1) into a vector and then have that one shuffled.
I don't see how you can avoid matching all the subconditions if you want to weight the probabilities of picking between subconditions with how many candidates match those subconditions. Matching subconditions necessarily means putting the matches into vectors, as implemented now. But you don't have to put them into the vector multiple times to pick one with weights. Doing that would also restrict to integer weights, which also insn't strictly necessary.

Also note that WeightedNumberOf lends itself better to per-object weight (as given in my initial example).
Weighted random pick could probably be implemented as a new sorting mode for SortedNumberOf, where the value determined per-object is used as a weight for random selection instead of for donig actual sorting. It might be inefficient to calculate the value of the sort key for each object instead of each subcondition, but it could work.

User avatar
Geoff the Medio
Programming, Design, Admin
Posts: 13587
Joined: Wed Oct 08, 2003 1:33 am
Location: Munich

Re: Weighted Sampling Condition

#8 Post by Geoff the Medio »

Ophiuchus wrote: Fri Dec 03, 2021 12:10 pm If I have it correctly, the following will return the ship with second highest structure

Code: Select all

And [
    MaximumNumberOf number = 2 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
    MinimumNumberOf number = 1 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
]
But if you switch, it will return the ship with the lowest structure

Code: Select all

And [
    MinimumNumberOf number = 1 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
    MaximumNumberOf number = 2 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
]
If working as intended, I think the results would be the same. SortedNumberOf checks its subcondition against all the input matches and non-matches, combines the subcondition-matching-input-non-matches and subcondition-matching-input-matches into a single set of candidate matches, picks the requested number of objects to be matches of the main condition, and then moves things back where they started or into the appropriate output container depending whether matches or non-matches is being moved from and whether each input object was matched and picked. Whether an input object is initially in the input matches or non-matches doesn't change its chance of being picked if it matches the subcondition, so the result of whether the SortedNumberOf condition matches an object or not shouldn't depend on the order it is in an And or Or condition. This could be buggily implemented or il-conceived, though.

Is there a reason what you want to do with WeightedAlternativesOf (or WeightedNumberOf) can't do the same?
In that case if searching for non_matches to remove from the matches in the MATCHES domain, I only need look at the current matches - so if at the point the WeightedAlternativesOf condition is evaluated, there are e.g. 123 ships in the matches, the total number of possible matches is actually 123. Is that correct?
That would make it order dependent, but I don't think it needs to be.

Ophiuchus
Programmer
Posts: 3433
Joined: Tue Sep 30, 2014 10:01 am
Location: Wall IV

Re: Weighted Sampling Condition

#9 Post by Ophiuchus »

Geoff the Medio wrote: Fri Dec 03, 2021 10:21 pm What do you want to happen if:

Code: Select all

WeightedAlternativesOf scope = All alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Or [Ship Fighter]
]
My current suggestion would be this being illegal because of overlapping candidates. (If the counts of evaluated subconditions add up being higher than the count of scope, the implementation is able to spot a bad script and print and log an error message. Also )
Geoff the Medio wrote: Fri Dec 03, 2021 10:21 pm

Code: Select all

WeightedNumberOf number = 1 [
    weight = 3 condition = Ship
    weight = 1 condition = Or [Ship Fighter]
]
with equal numbers of ships and fighters in the universe?
For WeightedNumberOf this would not be illegal. I would it expect it to be the same as:

Code: Select all

WeightedNumberOf number = 1 [
    weight = 4 condition = Ship
    weight = 1 condition = Fighter
]
Geoff the Medio wrote: Fri Dec 03, 2021 10:21 pm
WeightedAlternativesOf evaluates to a set of matches from the chosen subcondition.
[...]
Probabilities for taking n random candidates directly from WeightedAlternativesOf will not be the same as WeightedNumberOf number = n; the candidates will all be from the chosen subcondition for WeightedAlternativesOf while they can be different for WeightedNumberOf.
I assume you mean that all the matches of WeightedAlternativesOf are guaranteed to be chosen so that there is (at least) one of the subconditions that all the returned matches match. So with

Code: Select all

WeightedAlternativesOf scope = All alternatives =  [
    Weighted weight = 3 condition = Ship
    Weighted weight = 1 condition = Fighter
]
if you added a number = 3 parameter to the WeightedAlternativesOf example above, and there were 2 ships and 6 fighters in the universe, it would have a 50% chance of matching 2 ships and a 50% chance of matching 3 fighters?
Basically yes. But one could instead wrap WeightedAlternativesOf in a RandomNumberOf number = 3 for the same result.

Geoff the Medio wrote: Fri Dec 03, 2021 10:21 pm don't see how you can avoid matching all the subconditions if you want to weight the probabilities of picking between subconditions with how many candidates match those subconditions.
Well, it is possible. If you know you have 100 candidates, you can e.g. roll a 100 sided dice. If you roll a 1, you can take the first subcondition with a match and do not need to know anything about the other subconditions.

Geoff the Medio wrote: Fri Dec 03, 2021 10:21 pm
Also note that WeightedNumberOf lends itself better to per-object weight (as given in my initial example).
Weighted random pick could probably be implemented as a new sorting mode for SortedNumberOf, where the value determined per-object is used as a weight for random selection instead of for donig actual sorting. It might be inefficient to calculate the value of the sort key for each object instead of each subcondition, but it could work.
in my example calculation is simple (just looking up structure) and the scope restricted (only combatants, not the whole universe); this is not different from evaluating an object dependent valueref in e.g. a condition; i also guess the invariance checking we have can be used to speed up calculation in case the sort key is not object dependent.
I think WeightedNumberOf cant take any meaningful shortcuts anyway having to evaluate all subconditions on all objects in scope, assigning a weight and picking, so the feature does not come at extra cost (if ).

edit; some more detail on sampling without replacement: Ok, i think the probabilities are fine if you do dependent picks, as the probabilities change each time you pick/remove a sample (especially on low populations). So depending on implementation picking multiple samples could be costly. If you do a naive single "random" sort based on weight and take the first N samples the probabilities get skewed. As example if you pick 2 samples out of A,B,C with probabilities pA=0.5, pB=0.3, pC=0.2 the dependent probability of p(B|A) is 0.6, not 0.3.

If you are ok with wrong probabilities we probably get an efficient pretty straightforward implementation. For a correct one I guess we either have to stick to integer weights or we would need some library.
Geoff the Medio wrote: Fri Dec 03, 2021 10:43 pm If working as intended, I think the results would be the same.
Ok, I misinterpreted how the *NumberOf work. If I get it right it considers all matches and non_matches and rolls independently of that and when looking in MATCHES only keeps results in the end which were already in matches. So if the outer condition does not match the inner condition, you will have a chance of choosing a outer-condition non_match in the *NumberOf even if there are candidates which both match the inner and the outer condition.

So in the case I gave it probably does not return any matches - only if the highest structure ships are also the lowest structure ships and the two rolls choose the same ship. So if you have a single ship there will be a guaranteed result; if you have two ships with different structure you get a match in 50% of the cases. Here it is again:

Code: Select all

And [
    MaximumNumberOf number = 2 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
    MinimumNumberOf number = 1 sortkey = LocalCandidate.Structure condition = [[YOUR_SHIP]]
]
So basically it does not make much sense to wrap a *NumberOf in an And condition for functional reasons - unless you want to the wrapping condition to create no results at all in some cases using weird probabilities. For restricting the possible matches without ignoring valid matches one needs to put the And condition inside the *NumberOf.
Geoff the Medio wrote: Fri Dec 03, 2021 10:43 pm Is there a reason what you want to do with WeightedAlternativesOf (or WeightedNumberOf) can't do the same?
Probably just don't see much benefit from commutativity if one has to wrap everything inside the *NumberOf (or *AlternativesOf). Makes the implementation harder to read and get right for sure.

I need to come up with the total count of alternatives for *AlternativesOf that is what is special/different from the current *NumberOf in order to get probabilities right.
If have that number early, I can skip a lot of unnecessary calculations.
I guess I rename the scope parameter to e.g. alternatives and not pull from universe but from matches and non_matches instead. Then I have the total count and I do not have to filter for shared conditions multiple times.
Any code or patches in anything posted here is released under the CC and GPL licences in use for the FO project.

Look, ma... four combat bouts!

Post Reply