Pokémon example (with dual defender types)

This example applies a multiplicative handicap to the Pokémon type chart (Generation VI), including defenders with dual types. Otherwise it is the same as the other Pokémon example.


In [1]:
import _initpath

import numpy
import dataset.pokemon
import zerosum.balance
import zerosum.nash
import matplotlib
import matplotlib.pyplot as plt

# Balances the Pokemon type chart using a multiplicative handicap function.
# This one includes all possible dual-type defenses.
# Plots the handicaps versus Nash equilibrium of the original game.

# Initial payoff matrix.
type_chart = dataset.pokemon.pokemon_6_dual_defender
# Names of the Pokemon types.
row_names = type_chart.row_names
col_names = type_chart.col_names

# Single-type colors.
colors = [dataset.pokemon.pokemon_type_colors[t] for t in type_chart.row_names]

# Dual-type colors.
primary_colors = [dataset.pokemon.pokemon_type_colors[t.split('/')[0]] for t in type_chart.col_names]
secondary_colors = [dataset.pokemon.pokemon_type_colors[t.split('/')[-1]] for t in type_chart.col_names]

# Nash equilibrium of the initial game.
row_nash, col_nash = zerosum.nash.nash(type_chart.data)
# Handicaps producing a uniform Nash equilibrium.
balance = zerosum.balance.MultiplicativeBalance(type_chart.data).optimize()

# Now to plot.
dpi = 240
marker_size = 64
text_size = 15
bottom = -0.4
top = 0.4
loc = matplotlib.ticker.MultipleLocator(base=0.1)

# Plot attacker and defender on separate subplots. Attacker first.
fig = plt.figure(figsize = (18, 6))
gs = matplotlib.gridspec.GridSpec(1, 2, width_ratios=[1, 1])
ax = plt.subplot(gs[0])

# Draw a line indicating where the uniform distribution would be.
uniform_x = 1.0 / len(row_nash.strategy)
ax.plot([uniform_x, uniform_x], [bottom, top],
        color='#bfbfbf', linestyle='-', zorder=0)
plt.text(uniform_x, bottom - 0.003, 'Uniform',
         fontsize = 12,
         rotation = 0,
         ha = 'center', va = 'top')

# Scatter plot of handicaps vs. Nash of initial game.
x = row_nash.strategy
y = numpy.log(balance.row_handicaps)
y -= numpy.mean(y)

ax.scatter(x, y, s = marker_size, c = colors)

# Label each scatter plot point with the type name.
for pointx, pointy, name, color in zip(x, y, row_names, colors):
    ha = 'left'
    # manual adjustment
    if name in ['Steel', 'Water']:
        pointy += 0.01
    if name == 'Ghost':
        pointy -= 0.02
    
    name = ' ' + name + ' '
    plt.text(pointx, pointy, name,
             fontsize = text_size,
             rotation = 0,
             ha = ha, va = 'center')

ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)
ax.set_title('Attacker')

ax.set_xlabel('Nash probability of initial game', fontsize = text_size)
ax.set_ylabel('Log (handicap) producing uniform Nash', fontsize = text_size)

ax.set_xlim(left=0.0, right = 0.25)
ax.set_ylim(bottom=bottom, top = top)

# Now for the defender plot.
ax = plt.subplot(gs[1])

uniform_x = 1.0 / len(col_nash.strategy)
ax.plot([uniform_x, uniform_x], [bottom, top],
        color='#bfbfbf', linestyle='-', zorder=0)
plt.text(uniform_x, bottom - 0.003, 'Uniform',
         fontsize = 12,
         rotation = 0,
         ha = 'left', va = 'top')

x = col_nash.strategy
y = numpy.log(balance.col_handicaps)
y -= numpy.mean(y)

# Remove zero-weight strategies.
sel_nz = x > 0.0
x_nz = x[sel_nz]
y_nz = y[sel_nz]
col_names_nz = [name for i, name in enumerate(col_names) if sel_nz[i]]
primary_colors_nz = [c for i, c in enumerate(primary_colors) if sel_nz[i]]
secondary_colors_nz = [c for i, c in enumerate(secondary_colors) if sel_nz[i]]

ax.scatter(x_nz, y_nz, s = marker_size, c = primary_colors_nz)
ax.scatter(x_nz, y_nz, s = marker_size / 4, linewidths = 0, c = secondary_colors_nz, zorder=1.5)

for pointx, pointy, name in zip(x_nz, y_nz, col_names_nz):
    ha = 'left'
    # manual adjustment
    if name == 'Fairy':
        pointy += 0.01
    if name in ['Ground/Fire', 'Ground/Water']:
        pointy -= 0.01
    
    name = ' ' + name + ' '
    plt.text(pointx, pointy, name,
             fontsize = text_size,
             rotation = 0,
             ha = ha, va = 'center')

ax.xaxis.set_major_locator(loc)
ax.yaxis.set_major_locator(loc)
ax.set_title('Defender (types with nonzero Nash probability in initial game only)')

ax.set_xlabel('Nash probability of initial game', fontsize = text_size)
ax.yaxis.set_ticklabels([])

ax.set_xlim(left=0.0, right = 0.25)
ax.set_ylim(bottom=bottom, top = top)

plt.tight_layout()

plt.savefig("out/pokemon_dual_scatter.png", dpi = dpi, bbox_inches = "tight")
plt.show()