Files
game-and-watch-patch/tools/draw_mario.py

232 lines
7.0 KiB
Python

"""Extract and draw graphics from Mario
By Jake Vanderplas, 2013 <http://jakevdp.github.com>
License: GPL.
Feel free to use and distribute, but keep this attribution intact.
"""
import zipfile
import numpy as np
from matplotlib import pyplot as plt
from matplotlib.colors import ListedColormap
class NESGraphics(object):
"""Class interface for stripping graphics from an NES ROM"""
def __init__(self, filename="mario_ROM.zip", offset=2049):
self.offset = offset
if zipfile.is_zipfile(filename):
zp = zipfile.ZipFile(filename)
data = np.unpackbits(np.frombuffer(zp.read(zp.filelist[0]), dtype=np.uint8))
else:
data = np.unpackbits(np.fromfile(filename, dtype=np.uint8))
self.data = data.reshape((-1, 8, 8))
def generate_image(self, A, C=None, transparent=False):
"""Generate an image from the pattern table.
Parameters
----------
A : array_like
an array of integers indexing the thumbnails to use.
The upper-left corner of the image is A[0, 0], and the
bottom-right corner is A[-1, -1]. A negative index indicates
that the thumbnail should be flipped horizontally.
C : array-like
The color table for A. C should have shape A.shape + (4,).
C[i, j] gives the values associated with the four bits of A
for the output image.
transparent : array_like
if true, then zero-values in A will be masked for transparency
Returns
-------
im : ndarray or masked array
the image encoded by A and C
"""
A = np.asarray(A)
if C is None:
C = range(4)
# broadcast C to the shape of A
C = np.asarray(C) + np.zeros(A.shape + (1,))
im = np.zeros((8 * A.shape[0], 8 * A.shape[1]))
for i in range(A.shape[0]):
for j in range(A.shape[1]):
# extract bits
ind = int(2 * (abs(A[i, j]) + self.offset))
thumb = self.data[ind] + 2 * self.data[ind + 1]
# set bit colors
thumb = C[i, j, thumb]
# flip image if negative
if A[i, j] < 0:
thumb = thumb[:, ::-1]
im[8 * i : 8 * (i + 1), 8 * j : 8 * (j + 1)] = thumb
if transparent:
im = np.ma.masked_equal(im, 0)
return im
def draw_mario():
"""Draw a grid of mario graphics"""
NG = NESGraphics(sys.argv[1])
cmap = ListedColormap(["white", "red", "orange", "brown"])
im = 252 + np.zeros((17, 19))
# Big Mario row 1
im[1:5, 1:3] = [[0, 1], [2, 3], [4, 5], [6, 7]]
im[1:5, 4:6] = [[8, 9], [10, 11], [12, 13], [14, 15]]
im[1:5, 7:9] = [[16, 17], [18, 19], [20, 21], [22, 23]]
im[1:5, 10:12] = [[24, 25], [26, 27], [28, 29], [30, 31]]
im[1:5, 13:15] = [[32, 33], [34, 35], [36, 37], [38, 39]]
im[1:5, 16:18] = [[0, 1], [76, 77], [74, -74], [75, -75]]
# Small Mario row 1
im[9:13, 1:3] = [[8, 9], [40, 41], [42, 43], [44, 45]]
im[9:13, 4:6] = [[8, 9], [10, 11], [12, 48], [49, 45]]
im[9:13, 7:9] = [[8, 9], [10, 11], [46, 47], [49, 45]]
im[9:13, 10:12] = [[8, 9], [10, 11], [12, 48], [92, 93]]
im[9:13, 13:15] = [[8, 9], [10, 11], [12, 48], [94, 95]]
im[9:13, 16:18] = [[252, 252], [8, 9], [88, 89], [90, -90]]
# Big Mario row 2
im[6:8, 1:3] = [[54, 55], [56, 57]]
im[6:8, 4:6] = [[50, 51], [52, 53]]
im[6:8, 7:9] = [[58, 55], [59, 60]]
im[6:8, 10:12] = [[61, 62], [63, 64]]
im[6:8, 13:15] = [[50, 65], [66, 67]]
im[6:8, 16:18] = [[58, 55], [79, -79]]
# Small Mario row 2
im[14:16, 1:3] = [[50, 51], [68, 69]]
im[14:16, 4:6] = [[50, 51], [70, 71]]
im[14:16, 7:9] = [[50, 51], [72, 73]]
im[14:16, 10:12] = [[50, 51], [144, 145]]
im[14:16, 13:15] = [[58, 55], [146, 147]]
im[14:16, 16:18] = [[158, -158], [159, -159]]
im = NG.generate_image(im)
fig = plt.figure(figsize=(6, 6 * 17.0 / 19.0))
ax = fig.add_axes((0, 0, 1, 1), xticks=[], yticks=[])
ax.imshow(im, cmap=cmap, interpolation="nearest", clim=(0, 3))
def draw_graphics():
"""Draw foreground and background mario graphics"""
NG = NESGraphics(sys.argv[1])
cmap = ListedColormap(
[
"#88AACC",
"black",
"#EECCCC",
"#BB3333",
"green",
"orange",
"red",
"gold",
"#EEEEEE",
"gray",
]
)
im = 252 + np.zeros((17, 16))
colors = np.zeros((17, 16, 4))
# question block
im[1:3, 1:3] = [[339, 340], [341, 342]]
colors[1:3, 1:3] = [0, 7, 3, 1]
# coin
im[1:3, 4:6] = [[421, 422], [423, 424]]
colors[1:3, 4:6] = [0, 7, 8, 1]
# mushroom
im[1:3, 7:9] = [[118, 119], [120, 121]]
colors[1:3, 7:9] = [0, 6, 8, 5]
# 1-up mushroom
im[1:3, 10:12] = [[118, 119], [120, 121]]
colors[1:3, 10:12] = [0, 4, 8, 7]
# fire flower
im[1:3, 13:15] = [[214, -214], [217, -217]]
colors[1, 13:15] = [0, 6, 8, 5]
colors[2, 13:15] = [0, 4, 4, 4]
# green koopa-troopa
im[4:7, 1:3] = [[252, 160], [161, 162], [163, 164]]
im[4:7, 4:6] = [[252, 165], [166, 167], [168, 169]]
colors[4:7, 1:6] = [0, 4, 8, 5]
# red koopa-troopa
im[4:7, 7:9] = [[252, 160], [161, 162], [163, 164]]
im[4:7, 10:12] = [[252, 165], [166, 167], [168, 169]]
colors[4:7, 7:12] = [0, 6, 8, 5]
# cloud turtle
im[4:7, 13:15] = [[185, 184], [432, 434], [433, 435]]
colors[4, 13:15] = [0, 4, 8, 5]
colors[5:7, 13:15] = [0, 8, 8, 4]
# spiny
im[8:10, 1:3] = [[148, -148], [149, -149]]
im[8:10, 4:6] = [[150, 151], [152, 153]]
im[8:10, 7:9] = [[154, 155], [156, 157]]
colors[8:10, 1:9] = [0, 6, 8, 5]
# Goombas
im[8:10, 10:12] = [[112, 113], [114, 115]]
im[8:10, 13:15] = [[112, 113], [-115, -114]]
colors[8:10, 10:15] = [0, 1, 2, 3]
# fish
im[11:13, 1:3] = [[178, 179], [180, 181]]
im[11:13, 4:6] = [[182, 179], [183, 181]]
colors[11:13, 1:6] = [0, 9, 8, 5]
# beetle
im[11:13, 7:9] = [[170, 171], [172, 173]]
im[11:13, 10:12] = [[174, 175], [176, 177]]
colors[11:13, 7:12] = [0, 1, 2, 3]
# flag
im[14:16, 1:3] = [[84, 85], [86, 87]]
colors[14:16, 1:3] = [0, 6, 8, 5]
# brown block
im[14:16, 4:6] = [[343, 344], [345, 346]]
colors[14:16, 4:6] = [0, 7, 3, 1]
# brown block 2
im[14:16, 7:9] = [[436, 437], [438, 439]]
colors[14:16, 7:9] = [0, 2, 3, 1]
# bricks
im[14:16, 10:12] = [[325, 325], [327, 327]]
colors[14:16, 10:12] = [0, 2, 3, 1]
# cannon
im[12:16, 13:15] = [[454, 455], [456, 457], [458, 459], [460, 461]]
colors[12:16, 13:15] = [0, 2, 3, 1]
im = NG.generate_image(im, colors)
fig = plt.figure(figsize=(5, 5 * 17.0 / 16.0))
ax = fig.add_axes((0, 0, 1, 1), xticks=[], yticks=[])
ax.imshow(im, cmap=cmap, interpolation="nearest", clim=(0, 9))
if __name__ == "__main__":
import sys
draw_mario()
draw_graphics()
plt.show()