The basic "brute force" solution given at the top of my answer to the earlier question can be easily adjusted to fit your modification to the NCO mechanic simply by replacing = N
with >= N
in the if
condition on the fifth line:
function: modified neon city overdrive ACTION:s DANGER:s {
BOON: (ACTION = 6) - (DANGER = 6)
if BOON > 0 { result: 5 + BOON }
loop N over {5,4,3,2,1} {
if (ACTION >= N) > (DANGER >= N) { result: N }
}
result: 0
}
output [modified neon city overdrive 5d6 5d6]
The beginning of the function above is identical to the unmodified version: if we roll k > 0 more 6s on the action dice than on the danger dice, then the result will still be k + 5. Since there are no higher numbers on the dice that could cancel out a 6, your modification to the mechanic makes no difference.
If all the 6s on the action dice are cancelled out, we then check whether the number of 5s and higher numbers rolled with the action dice exceeds those rolled with the danger dice. If yes, not all the 5s can be cancelled out, so the result is 5. Otherwise we repeat the same check for 4s and higher, then 3s and higher, etc.
(It's actually not quite obvious that this method gives the correct result. To show that, we basically need to prove a lemma saying that all action dice of value n or above can be cancelled by equal or higher valued danger dice if any only if, for every m ≥ n, the number of danger dice of value m or above equals or exceeds the number of action dice of value m or above. Proving this by induction is not very hard, but neither is it completely trivial.)
Note that this function, like the one in my answer to the earlier question, return 0 if all the action dice are eliminated. If you'd prefer the result to be 1 in that case, just change the line result: 0
at the end of the function to result: 1
.
You can also implement (one interpretation of) the additional modification you suggest at the end of your question by changing that line to result: 1 + BOON
. (Note that BOON
is always negative or zero at this point.) That way, if all action dice are cancelled out, any 6 rolled on the danger dice that does not cancel a 6 on the action dice will reduce the result by one.
Another possible interpretation of the "anti-boon" mechanic would be that, if all action dice are cancelled out, the result would be 1 (or 0) minus the number of 6s on the danger dice that are not needed to cancel any action die. This can also be calculated, but requires slightly more work, since we actually have to (effectively) pair the cancelled action dice with the danger dice instead of just relying on the lemma mentioned above. Here's one way to do it:
function: modified neon city overdrive ACTION:s DANGER:s {
BOON: (ACTION = 6) - (DANGER = 6)
if BOON > 0 { result: 5 + BOON }
loop N over {5,4,3,2,1} {
if (ACTION >= N) > (DANGER >= N) { result: N }
}
\ all action dice are cancelled: calculate how many danger 6s we had to use \
DEBT: 0
loop N over {1..5} {
DEBT: [highest of 0 and DEBT + (ACTION = N) - (DANGER = N)]
}
result: 1 + BOON + DEBT
}
Here, the DEBT
variable keeps track of how many action dice of value up to N
can not be cancelled by danger dice of value up to N
, and thus must be cancelled by higher-valued danger dice. (The fact that we know in advance that all action dice can be cancelled simplifies this calculation somewhat.) Thus, at the end of the loop, we know that DEBT
is the number of danger 6s that are needed to cancel lower-valued action dice.
Addendum: FWIW, the optimized recursive solution given later in the same answer can also be tweaked to fit your modification by adding a CARRY
parameter that tells the function how many unused higher-valued danger dice are still available to cancel lower action rolls:
function: mnco helper N:n AMAX:n DMAX:n AROLL:n DROLL:n CARRY:n {
if AROLL > DROLL + CARRY {
if N = 6 { result: 5 + AROLL - DROLL }
result: N
}
A: AMAX - AROLL
D: DMAX - DROLL
C: CARRY + DROLL - AROLL
if N = 2 { result: A > D + C }
X: d(N-1) = N-1
result: [mnco helper N-1 A D AdX DdX C]
}
function: mnco A:n D:n {
X: d6 = 6
result: [mnco helper 6 A D AdX DdX 0]
}
loop A over {5} {
loop D over {0..5} {
output [mnco A D] named "action [A]d6, danger [D]d6"
}
}
In fact, we can even optimize this code to get rid of the explicit CARRY
parameter and just add it to the danger dice roll instead:
function: mnco helper N:n AMAX:n DMAX:n AROLL:n DROLL:n {
if AROLL > DROLL {
if N = 6 { result: 5 + AROLL - DROLL }
result: N
}
if N = 2 { result: AMAX > DMAX }
A: AMAX - AROLL
D: DMAX - DROLL
C: DROLL - AROLL
X: d(N-1) = N-1
result: [mnco helper N-1 A D+C AdX DdX+C]
}
function: mnco A:n D:n {
X: d6 = 6
result: [mnco helper 6 A D AdX DdX]
}
loop A over {5} {
loop D over {0..5} {
output [mnco A D] named "action [A]d6, danger [D]d6"
}
}
The early abort check at N = 2
can also be optimized slightly by noting that A - (D + C)
always equals AMAX - DMAX
. Alas, even with these optimizations, this code still seems to be somewhat slower than the equivalent version for the unmodified Neon City Overdrive mechanic.
Further modifying this recursive code to implement the additional modifications in case all action dice are cancelled is left as an exercise. ;)
P
. \$\endgroup\$