This notebook contains several visualizations to help predict the outcome of a battle in the game of risk.
For a primer on the rules of risk, check out http://media.wizards.com/2015/downloads/ah/Risk_rules.pdf
In this notebook, I use the following terminology:
There are three types of graphs in this notebook. You may need to scroll through a lot of code to see them.
There are a limited number of outcomes during a roll:
The height of each bar represents the probability that a battle will result in a certain outcome. Outcomes on the right are more favorable to the attacker. Outcomes on the left are more favorable to the defender.
You will notice that in the middle there is a dip. This is because if one army is almost destroyed, it has fewer dice and thus less chance to make a comeback.
Each x, y location in the matrix corresponds to a certain starting configuration. The row/y corresponds with the number of attacking armies. The col/x corresponds with the number of defending armies.
The color of each cell maps to the probability of success for the attacker. Green means the attacker is likely to succeed, red means the defender is likely to succeed, and white means neither party is likely to succeed.
The first number in each cell is the probability of success described as a percentage. The second line shows the 25th percentile outcome (in terms of how well it went for the attacker). The third line shows the 50th percentile outcome. The fourth line shows the 75th percentile outcome. Each outcome is displayed as an ordered pair where the first element is the number of attacker armies remaining and the second element is the number of defender armies remaining.
from collections import namedtuple, defaultdict
import itertools
Armies = namedtuple("Armies", ["attackers", "defenders"])
def loss_str(armies):
return "Attacker loses %d, Defender loses %d" % (-armies.attackers, -armies.defenders)
assert(loss_str(Armies(-4, -6)) == "Attacker loses 4, Defender loses 6")
def remains_str(armies):
return "%d attackers and %d defenders" % (armies.attackers, armies.defenders)
assert(remains_str(Armies(6, 3)) == "6 attackers and 3 defenders")
def tuple_str(armies):
return "(%d, %d)" % (armies.attackers, armies.defenders)
def assert_close(actual, expected):
"assert that the two values are pretty darn close... like they should be equal if they weren't floats"
if abs(actual - expected) > 0.00001:
raise AssertionError("Bad stuff.\nActual: %s\nExpected: %s\n" % (actual, expected))
def eval_roll(attacker_dice, defender_dice):
"Return the delta for each side... (delta_attackers, delta_defenders)"
attacker_wins, defender_wins = 0, 0
for attacker_roll, defender_roll in zip(sorted(attacker_dice)[::-1], sorted(defender_dice)[::-1]):
if attacker_roll > defender_roll:
attacker_wins += 1
else: #defender wins tie
defender_wins += 1
return Armies(-defender_wins, -attacker_wins)
assert(eval_roll([5, 4, 1], [5, 1]) == Armies(-1, -1))
assert(eval_roll([6, 6, 6], [6]) == Armies(-1, 0))
def generate_rolls(n_dice):
"generate every possible roll given n_dice"
return itertools.product((1, 2, 3, 4, 5, 6), repeat=n_dice)
def scale_dict(d, scale):
"scale each value in a dict by |scale|"
ret = defaultdict(lambda: 0)
for key in d:
ret[key] = d[key] * scale
return ret
def normalize_dict(d):
"scale down all dict values so they sum to 1.0"
return scale_dict(d, 1.0 / sum(d.values()))
def get_roll_stats(n_attack_dice, n_defence_dice):
"find the likelyhood of each outcome given x attack dice and y defence dice"
res = defaultdict(lambda: 0)
for attacker_roll in generate_rolls(n_attack_dice):
for defender_roll in generate_rolls(n_defence_dice):
res[eval_roll(attacker_roll, defender_roll)] += 1
return normalize_dict(res)
assert_close(get_roll_stats(1, 1)[Armies(0, -1)], 15/36)
assert_close(get_roll_stats(1, 1)[Armies(-1, 0)], 21/36)
assert_close(get_roll_stats(3, 2)[Armies(-1, -1)], 2611/7776)
import plotly.plotly as py
import plotly.graph_objs as go
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
init_notebook_mode(connected=False)
def make_roll_chart(n_attacker_dice, n_defender_dice):
"Generate a pie chart showing the probability of each outcome for a an X by Y roll"
outcomes = get_roll_stats(n_attacker_dice, n_defender_dice)
labels = [loss_str(key) for key in outcomes]
values = [val for (key, val) in outcomes.items()]
fig = {
'data': [{
'labels': labels,
'values': values,
'type': 'pie'
}],
'layout': {
'title': 'Possible outcomes when rolling %d attack die and %d defence die' %
(n_attacker_dice, n_defender_dice)
}
}
iplot(fig)
make_roll_chart(1, 1)
make_roll_chart(1, 2)
make_roll_chart(2, 1)
make_roll_chart(2, 2)
make_roll_chart(3, 1)
make_roll_chart(3, 2)
import functools
def join_dicts(a, b):
"Sum the values by key of a defaultdict"
keys = set(a.keys()).union(set(b.keys()))
res = defaultdict(lambda: 0)
for key in keys:
res[key] = a[key] + b[key]
return res
_x, _y, _xy = defaultdict(lambda: 0), defaultdict(lambda: 0), defaultdict(lambda: 0)
_x["left"], _x["both"] = 1, 2
_y["both"], _y["right"] = 4, 8
_xy["left"], _xy["both"], _xy["right"] = 1, 6, 8
assert(join_dicts(_x, _y) == _xy)
def get_best_roll(attacker_armies, defender_armies):
attacker_dice = min(3, attacker_armies - 1)
defender_dice = min(2, defender_armies)
return Armies(attacker_dice, defender_dice)
assert(get_best_roll(6, 1) == Armies(3, 1))
assert(get_best_roll(1, 6) == Armies(0, 2))
#cache the roll stats so we don't have to recompute them every time
roll_stats = {roll: get_roll_stats(roll.attackers, roll.defenders) for roll in [
Armies(1, 1), Armies(1, 2),
Armies(2, 1), Armies(2, 2),
Armies(3, 1), Armies(3, 2)
]}
@functools.lru_cache()
def gen_battle_outcomes(attacker_armies, defender_armies):
"Determine the likelyhood of each posible outcome given a starting configuration"
res = defaultdict(lambda: 0)
if attacker_armies == 1:
res[Armies(attacker_armies, defender_armies)] = 1
return res
if defender_armies == 0:
res[Armies(attacker_armies, defender_armies)] = 1
return res
roll = get_best_roll(attacker_armies, defender_armies)
for outcome, liklihood in roll_stats[roll].items():
res = join_dicts(res,
scale_dict(gen_battle_outcomes(attacker_armies + outcome.attackers,
defender_armies + outcome.defenders),
liklihood))
res = normalize_dict(res)
return res
assert_close(gen_battle_outcomes(2, 2)[Armies(1, 2)],
get_roll_stats(1, 2)[Armies(-1, 0)])
assert_close(gen_battle_outcomes(2, 2)[Armies(2, 0)],
get_roll_stats(1, 2)[Armies(0, -1)] *
get_roll_stats(1, 1)[Armies(0, -1)])
assert_close(gen_battle_outcomes(5, 5)[Armies(4, 0)],
(get_roll_stats(3, 2)[Armies(0, -2)] * #(5, 3)
get_roll_stats(3, 2)[Armies(0, -2)] * #(5, 1)
get_roll_stats(3, 1)[Armies(-1, 0)] * #(4, 1)
get_roll_stats(3, 1)[Armies(0, -1)]) + #(4, 0)
(get_roll_stats(3, 2)[Armies(0, -2)] * #(5, 3)
get_roll_stats(3, 2)[Armies(-1, -1)] * #(4, 2)
get_roll_stats(3, 2)[Armies(0, -2)]) * 2) #(4, 0)
def armies_comparator(a):
"Sort armies first by attackers then by -defenders (assuming int)"
return a[0].attackers + 1.0 / (a[0].defenders + 1)
assert(armies_comparator([Armies(5, 6)]) < armies_comparator([Armies(6, 6)]))
assert(armies_comparator([Armies(6, 7)]) < armies_comparator([Armies(6, 6)]))
def get_percentile_outcome(outcomes, percentile):
outcomes = list(outcomes.items())
outcomes.sort(key=armies_comparator)
x = 0.0
for outcome, probability in outcomes:
x += probability
if x >= percentile:
return outcome
return outcomes[-1][0]
assert(get_percentile_outcome(gen_battle_outcomes(5, 5), 0.25) == Armies(1, 4))
assert(get_percentile_outcome(gen_battle_outcomes(5, 5), 0.5) == Armies(1, 2))
assert(get_percentile_outcome(gen_battle_outcomes(5, 5), 0.75) == Armies(3, 0))
def get_win_rate(outcomes):
return sum(probability for outcome, probability in outcomes.items() if outcome.defenders == 0)
assert_close(get_win_rate({
Armies(5, 5): 0.3,
Armies(2, 0): 0.3,
Armies(6, 0): 0.2,
Armies(1, 6): 0.2
}), 0.5)
def make_battle_chart(attacker_armies, defender_armies):
"Graph the probability distribution for each outcome of a battle of X v Y"
outcomes = list(gen_battle_outcomes(attacker_armies, defender_armies).items())
outcomes.sort(key=armies_comparator)
labels = []
values = []
for outcome, probability in outcomes:
labels.append(remains_str(outcome))
values.append(probability)
trace0 = go.Bar(x = labels,
y = values)
layout = go.Layout(title='Distribution of outcomes with %d attacking armies and %d defending armies' %
(attacker_armies, defender_armies),
margin = go.Margin(b=200, r=150))
fig = go.Figure(data=[trace0], layout=layout)
iplot(fig)
make_battle_chart(5, 5)
make_battle_chart(10, 10)
make_battle_chart(15, 15)
make_battle_chart(20, 25)
make_battle_chart(25, 20)
make_battle_chart(25, 25)
make_battle_chart(50, 50)
from IPython.display import HTML, display
def colorize(success_rate):
"Assign a color to the stats collected by run_many_battles"
whiteness = int(255 * (1 - (2 * abs(success_rate - 0.5))**1.5))
if success_rate > 0.5:
return "#%02xff%02x" % (whiteness, whiteness)
else:
return "#ff%02x%02x" % (whiteness, whiteness)
def render_matrix_html(attacker_armies, defender_armies):
"Render the probabilities of success given X attackers and Y defenders as an html table"
rows = []
first_row = ["<th></th>"]
for num_defenders in range(1, defender_armies + 1):
first_row.append("<th>d=%s</th>" % (num_defenders))
rows.append(''.join(first_row))
for num_attackers in range(1, attacker_armies + 1):
cells = ["<th>a=%s</th>" % (num_attackers)]
for num_defenders in range(1, defender_armies + 1):
outcomes = gen_battle_outcomes(num_attackers, num_defenders)
success_rate = get_win_rate(outcomes)
first_quartile = get_percentile_outcome(outcomes, 0.25)
second_quartile = get_percentile_outcome(outcomes, 0.5)
third_quartile = get_percentile_outcome(outcomes, 0.75)
color = colorize(success_rate)
cells.append("<td style='background-color: %s; width: 90px;'>%2.0f%%<br />%s<br />%s<br />%s</td>" %
(color, success_rate * 100, tuple_str(first_quartile),
tuple_str(second_quartile), tuple_str(third_quartile)))
rows.append(''.join(cells))
rows = ["<tr>%s</tr>" % (row) for row in rows]
return HTML("<table>%s</table>" % (''.join(rows)))
display(render_matrix_html(20, 16))
d=1 | d=2 | d=3 | d=4 | d=5 | d=6 | d=7 | d=8 | d=9 | d=10 | d=11 | d=12 | d=13 | d=14 | d=15 | d=16 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
a=1 | 0% (1, 1) (1, 1) (1, 1) | 0% (1, 2) (1, 2) (1, 2) | 0% (1, 3) (1, 3) (1, 3) | 0% (1, 4) (1, 4) (1, 4) | 0% (1, 5) (1, 5) (1, 5) | 0% (1, 6) (1, 6) (1, 6) | 0% (1, 7) (1, 7) (1, 7) | 0% (1, 8) (1, 8) (1, 8) | 0% (1, 9) (1, 9) (1, 9) | 0% (1, 10) (1, 10) (1, 10) | 0% (1, 11) (1, 11) (1, 11) | 0% (1, 12) (1, 12) (1, 12) | 0% (1, 13) (1, 13) (1, 13) | 0% (1, 14) (1, 14) (1, 14) | 0% (1, 15) (1, 15) (1, 15) | 0% (1, 16) (1, 16) (1, 16) |
a=2 | 42% (1, 1) (1, 1) (2, 0) | 11% (1, 2) (1, 2) (1, 1) | 3% (1, 3) (1, 3) (1, 2) | 1% (1, 4) (1, 4) (1, 3) | 0% (1, 5) (1, 5) (1, 4) | 0% (1, 6) (1, 6) (1, 5) | 0% (1, 7) (1, 7) (1, 6) | 0% (1, 8) (1, 8) (1, 7) | 0% (1, 9) (1, 9) (1, 8) | 0% (1, 10) (1, 10) (1, 9) | 0% (1, 11) (1, 11) (1, 10) | 0% (1, 12) (1, 12) (1, 11) | 0% (1, 13) (1, 13) (1, 12) | 0% (1, 14) (1, 14) (1, 13) | 0% (1, 15) (1, 15) (1, 14) | 0% (1, 16) (1, 16) (1, 15) |
a=3 | 75% (2, 0) (3, 0) (3, 0) | 36% (1, 2) (1, 1) (2, 0) | 21% (1, 3) (1, 2) (1, 1) | 9% (1, 4) (1, 3) (1, 2) | 5% (1, 5) (1, 4) (1, 3) | 2% (1, 6) (1, 5) (1, 4) | 1% (1, 7) (1, 6) (1, 5) | 0% (1, 8) (1, 7) (1, 6) | 0% (1, 9) (1, 8) (1, 7) | 0% (1, 10) (1, 9) (1, 8) | 0% (1, 11) (1, 10) (1, 9) | 0% (1, 12) (1, 11) (1, 10) | 0% (1, 13) (1, 12) (1, 11) | 0% (1, 14) (1, 13) (1, 12) | 0% (1, 15) (1, 14) (1, 13) | 0% (1, 16) (1, 15) (1, 14) |
a=4 | 92% (3, 0) (4, 0) (4, 0) | 66% (1, 1) (3, 0) (4, 0) | 47% (1, 2) (1, 1) (3, 0) | 31% (1, 3) (1, 2) (3, 0) | 21% (1, 4) (1, 3) (1, 1) | 13% (1, 5) (1, 4) (1, 2) | 8% (1, 6) (1, 5) (1, 3) | 5% (1, 7) (1, 6) (1, 4) | 3% (1, 8) (1, 7) (1, 5) | 2% (1, 9) (1, 8) (1, 6) | 1% (1, 10) (1, 9) (1, 7) | 1% (1, 11) (1, 10) (1, 8) | 0% (1, 12) (1, 11) (1, 9) | 0% (1, 13) (1, 12) (1, 10) | 0% (1, 14) (1, 13) (1, 11) | 0% (1, 15) (1, 14) (1, 12) |
a=5 | 97% (4, 0) (5, 0) (5, 0) | 79% (2, 0) (4, 0) (5, 0) | 64% (1, 2) (3, 0) (4, 0) | 48% (1, 3) (1, 1) (4, 0) | 36% (1, 4) (1, 2) (3, 0) | 25% (1, 5) (1, 3) (2, 0) | 18% (1, 6) (1, 4) (1, 2) | 12% (1, 7) (1, 5) (1, 3) | 9% (1, 8) (1, 6) (1, 4) | 6% (1, 9) (1, 7) (1, 5) | 4% (1, 10) (1, 8) (1, 6) | 3% (1, 11) (1, 9) (1, 7) | 2% (1, 12) (1, 10) (1, 8) | 1% (1, 13) (1, 11) (1, 9) | 1% (1, 14) (1, 12) (1, 10) | 0% (1, 15) (1, 13) (1, 11) |
a=6 | 99% (5, 0) (6, 0) (6, 0) | 89% (4, 0) (5, 0) (6, 0) | 77% (2, 0) (4, 0) (5, 0) | 64% (1, 2) (3, 0) (5, 0) | 51% (1, 3) (2, 0) (4, 0) | 40% (1, 4) (1, 2) (4, 0) | 30% (1, 5) (1, 3) (3, 0) | 22% (1, 6) (1, 4) (1, 1) | 16% (1, 7) (1, 5) (1, 2) | 12% (1, 8) (1, 6) (1, 3) | 8% (1, 9) (1, 7) (1, 4) | 6% (1, 10) (1, 8) (1, 5) | 4% (1, 11) (1, 9) (1, 6) | 3% (1, 12) (1, 10) (1, 7) | 2% (1, 13) (1, 11) (1, 8) | 1% (1, 14) (1, 12) (1, 9) |
a=7 | 100% (6, 0) (7, 0) (7, 0) | 93% (5, 0) (6, 0) (7, 0) | 86% (4, 0) (5, 0) (6, 0) | 74% (1, 1) (4, 0) (6, 0) | 64% (1, 2) (4, 0) (5, 0) | 52% (1, 3) (2, 0) (5, 0) | 42% (1, 4) (1, 2) (4, 0) | 33% (1, 5) (1, 3) (3, 0) | 26% (1, 6) (1, 4) (2, 0) | 19% (1, 7) (1, 5) (1, 2) | 15% (1, 8) (1, 6) (1, 3) | 11% (1, 9) (1, 7) (1, 4) | 8% (1, 10) (1, 8) (1, 5) | 6% (1, 11) (1, 9) (1, 6) | 4% (1, 12) (1, 10) (1, 7) | 3% (1, 13) (1, 11) (1, 8) |
a=8 | 100% (7, 0) (8, 0) (8, 0) | 97% (6, 0) (7, 0) (8, 0) | 91% (5, 0) (6, 0) (7, 0) | 83% (3, 0) (5, 0) (7, 0) | 74% (1, 1) (5, 0) (6, 0) | 64% (1, 2) (4, 0) (6, 0) | 54% (1, 3) (2, 0) (5, 0) | 45% (1, 4) (1, 2) (4, 0) | 36% (1, 5) (1, 3) (4, 0) | 29% (1, 6) (1, 4) (3, 0) | 22% (1, 7) (1, 5) (1, 1) | 17% (1, 8) (1, 6) (1, 2) | 13% (1, 9) (1, 7) (1, 3) | 10% (1, 10) (1, 8) (1, 4) | 7% (1, 11) (1, 9) (1, 5) | 5% (1, 12) (1, 10) (1, 6) |
a=9 | 100% (8, 0) (9, 0) (9, 0) | 98% (7, 0) (8, 0) (9, 0) | 95% (6, 0) (7, 0) (8, 0) | 89% (4, 0) (6, 0) (8, 0) | 82% (3, 0) (6, 0) (7, 0) | 73% (1, 1) (5, 0) (7, 0) | 64% (1, 2) (4, 0) (6, 0) | 55% (1, 3) (3, 0) (5, 0) | 46% (1, 4) (1, 1) (5, 0) | 38% (1, 5) (1, 2) (4, 0) | 31% (1, 6) (1, 3) (3, 0) | 25% (1, 7) (1, 4) (1, 1) | 20% (1, 8) (1, 5) (1, 2) | 15% (1, 9) (1, 6) (1, 3) | 12% (1, 10) (1, 7) (1, 4) | 9% (1, 11) (1, 8) (1, 5) |
a=10 | 100% (9, 0) (10, 0) (10, 0) | 99% (8, 0) (9, 0) (10, 0) | 97% (7, 0) (8, 0) (9, 0) | 93% (5, 0) (7, 0) (9, 0) | 87% (4, 0) (7, 0) (8, 0) | 81% (3, 0) (6, 0) (8, 0) | 73% (1, 1) (5, 0) (7, 0) | 65% (1, 2) (4, 0) (6, 0) | 56% (1, 3) (3, 0) (6, 0) | 48% (1, 4) (1, 1) (5, 0) | 40% (1, 5) (1, 2) (4, 0) | 33% (1, 6) (1, 3) (4, 0) | 27% (1, 7) (1, 4) (2, 0) | 22% (1, 8) (1, 5) (1, 2) | 17% (1, 9) (1, 6) (1, 3) | 14% (1, 10) (1, 7) (1, 4) |
a=11 | 100% (10, 0) (11, 0) (11, 0) | 99% (9, 0) (10, 0) (11, 0) | 98% (8, 0) (9, 0) (10, 0) | 95% (6, 0) (8, 0) (10, 0) | 92% (5, 0) (8, 0) (9, 0) | 86% (4, 0) (7, 0) (9, 0) | 80% (3, 0) (6, 0) (8, 0) | 72% (1, 1) (5, 0) (7, 0) | 65% (1, 2) (4, 0) (7, 0) | 57% (1, 3) (3, 0) (6, 0) | 49% (1, 4) (1, 1) (5, 0) | 42% (1, 5) (1, 2) (5, 0) | 35% (1, 6) (1, 3) (4, 0) | 29% (1, 7) (1, 4) (3, 0) | 24% (1, 8) (1, 5) (1, 1) | 19% (1, 9) (1, 6) (1, 2) |
a=12 | 100% (11, 0) (12, 0) (12, 0) | 100% (10, 0) (11, 0) (12, 0) | 99% (9, 0) (10, 0) (11, 0) | 97% (7, 0) (9, 0) (11, 0) | 94% (6, 0) (9, 0) (10, 0) | 91% (5, 0) (8, 0) (10, 0) | 85% (4, 0) (7, 0) (9, 0) | 79% (3, 0) (6, 0) (8, 0) | 72% (1, 1) (5, 0) (8, 0) | 65% (1, 2) (4, 0) (7, 0) | 58% (1, 3) (3, 0) (6, 0) | 51% (1, 4) (2, 0) (6, 0) | 43% (1, 5) (1, 2) (5, 0) | 37% (1, 6) (1, 3) (4, 0) | 31% (1, 7) (1, 4) (3, 0) | 26% (1, 8) (1, 5) (2, 0) |
a=13 | 100% (12, 0) (13, 0) (13, 0) | 100% (11, 0) (12, 0) (13, 0) | 99% (10, 0) (11, 0) (12, 0) | 98% (8, 0) (10, 0) (12, 0) | 96% (7, 0) (10, 0) (11, 0) | 93% (6, 0) (9, 0) (11, 0) | 90% (5, 0) (8, 0) (10, 0) | 84% (4, 0) (7, 0) (9, 0) | 79% (3, 0) (6, 0) (9, 0) | 72% (1, 1) (5, 0) (8, 0) | 66% (1, 2) (4, 0) (7, 0) | 58% (1, 3) (4, 0) (7, 0) | 52% (1, 4) (2, 0) (6, 0) | 45% (1, 5) (1, 2) (5, 0) | 39% (1, 6) (1, 3) (4, 0) | 33% (1, 7) (1, 4) (4, 0) |
a=14 | 100% (13, 0) (14, 0) (14, 0) | 100% (12, 0) (13, 0) (14, 0) | 100% (11, 0) (12, 0) (13, 0) | 99% (9, 0) (11, 0) (13, 0) | 98% (8, 0) (11, 0) (12, 0) | 96% (7, 0) (10, 0) (12, 0) | 93% (6, 0) (9, 0) (11, 0) | 89% (5, 0) (8, 0) (10, 0) | 84% (4, 0) (7, 0) (10, 0) | 79% (3, 0) (6, 0) (9, 0) | 72% (1, 1) (5, 0) (8, 0) | 66% (1, 2) (5, 0) (8, 0) | 59% (1, 3) (4, 0) (7, 0) | 53% (1, 4) (3, 0) (6, 0) | 46% (1, 5) (1, 2) (5, 0) | 40% (1, 6) (1, 3) (5, 0) |
a=15 | 100% (14, 0) (15, 0) (15, 0) | 100% (13, 0) (14, 0) (15, 0) | 100% (12, 0) (13, 0) (14, 0) | 99% (10, 0) (12, 0) (14, 0) | 98% (9, 0) (12, 0) (13, 0) | 97% (8, 0) (11, 0) (13, 0) | 95% (7, 0) (10, 0) (12, 0) | 92% (6, 0) (9, 0) (11, 0) | 88% (5, 0) (8, 0) (11, 0) | 83% (4, 0) (7, 0) (10, 0) | 78% (3, 0) (6, 0) (9, 0) | 72% (1, 1) (6, 0) (9, 0) | 67% (1, 2) (5, 0) (8, 0) | 60% (1, 3) (4, 0) (7, 0) | 54% (1, 4) (3, 0) (6, 0) | 47% (1, 5) (1, 1) (6, 0) |
a=16 | 100% (15, 0) (16, 0) (16, 0) | 100% (14, 0) (15, 0) (16, 0) | 100% (13, 0) (14, 0) (15, 0) | 100% (11, 0) (13, 0) (15, 0) | 99% (10, 0) (13, 0) (14, 0) | 98% (9, 0) (12, 0) (14, 0) | 96% (8, 0) (11, 0) (13, 0) | 94% (7, 0) (10, 0) (12, 0) | 91% (6, 0) (9, 0) (12, 0) | 88% (5, 0) (8, 0) (11, 0) | 83% (4, 0) (7, 0) (10, 0) | 78% (3, 0) (7, 0) (10, 0) | 73% (1, 1) (6, 0) (9, 0) | 67% (1, 2) (5, 0) (8, 0) | 61% (1, 3) (4, 0) (7, 0) | 55% (1, 4) (3, 0) (7, 0) |
a=17 | 100% (16, 0) (17, 0) (17, 0) | 100% (15, 0) (16, 0) (17, 0) | 100% (14, 0) (15, 0) (16, 0) | 100% (12, 0) (14, 0) (16, 0) | 99% (11, 0) (14, 0) (15, 0) | 99% (10, 0) (13, 0) (15, 0) | 98% (9, 0) (12, 0) (14, 0) | 96% (8, 0) (11, 0) (13, 0) | 94% (7, 0) (10, 0) (13, 0) | 91% (6, 0) (9, 0) (12, 0) | 87% (5, 0) (8, 0) (11, 0) | 83% (4, 0) (8, 0) (11, 0) | 78% (3, 0) (7, 0) (10, 0) | 73% (1, 1) (6, 0) (9, 0) | 67% (1, 2) (5, 0) (8, 0) | 61% (1, 3) (4, 0) (8, 0) |
a=18 | 100% (17, 0) (18, 0) (18, 0) | 100% (16, 0) (17, 0) (18, 0) | 100% (15, 0) (16, 0) (17, 0) | 100% (13, 0) (15, 0) (17, 0) | 100% (12, 0) (15, 0) (16, 0) | 99% (11, 0) (14, 0) (16, 0) | 98% (10, 0) (13, 0) (15, 0) | 97% (9, 0) (12, 0) (14, 0) | 95% (8, 0) (11, 0) (14, 0) | 93% (7, 0) (10, 0) (13, 0) | 90% (6, 0) (9, 0) (12, 0) | 87% (5, 0) (9, 0) (12, 0) | 83% (4, 0) (8, 0) (11, 0) | 78% (3, 0) (7, 0) (10, 0) | 73% (1, 1) (6, 0) (9, 0) | 68% (1, 2) (5, 0) (9, 0) |
a=19 | 100% (18, 0) (19, 0) (19, 0) | 100% (17, 0) (18, 0) (19, 0) | 100% (16, 0) (17, 0) (18, 0) | 100% (14, 0) (16, 0) (18, 0) | 100% (13, 0) (16, 0) (17, 0) | 99% (12, 0) (15, 0) (17, 0) | 99% (11, 0) (14, 0) (16, 0) | 98% (10, 0) (13, 0) (15, 0) | 97% (9, 0) (12, 0) (15, 0) | 95% (8, 0) (11, 0) (14, 0) | 93% (7, 0) (10, 0) (13, 0) | 90% (6, 0) (10, 0) (13, 0) | 87% (5, 0) (9, 0) (12, 0) | 82% (4, 0) (8, 0) (11, 0) | 78% (3, 0) (7, 0) (10, 0) | 73% (1, 1) (6, 0) (10, 0) |
a=20 | 100% (19, 0) (20, 0) (20, 0) | 100% (18, 0) (19, 0) (20, 0) | 100% (17, 0) (18, 0) (19, 0) | 100% (15, 0) (17, 0) (19, 0) | 100% (14, 0) (17, 0) (18, 0) | 100% (13, 0) (16, 0) (18, 0) | 99% (12, 0) (15, 0) (17, 0) | 99% (11, 0) (14, 0) (16, 0) | 98% (10, 0) (13, 0) (16, 0) | 97% (9, 0) (12, 0) (15, 0) | 95% (8, 0) (11, 0) (14, 0) | 92% (7, 0) (11, 0) (14, 0) | 89% (6, 0) (10, 0) (13, 0) | 86% (5, 0) (9, 0) (12, 0) | 82% (4, 0) (8, 0) (11, 0) | 78% (3, 0) (7, 0) (11, 0) |