RushHour: dragging with algorithmically specified constraints

Create a GUI for the RushHour game.

  • Features:

    • Graphics-driven assignments

    • Validate legal dragging by calling a function that raises an exception on illegal values.

  • Try me:

    • Try dragging the cars to let the red car pass through.

from pyquibbler import iquib, initialize_quibbler, q, quiby
initialize_quibbler()
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Rectangle
%matplotlib osx
# Board parameters:
l = 6  # size of the board
d = 3  # number of car steps per square
spc = 0.2  # space betweek cars

# initial car configuration:
xv = np.array([2, 0, 1, 0, 1, 2, 2, 3, 4, 4]) * d
yv = np.array([0, 2, 2, 0, 0, 2, 4, 2, 0, 3]) * d
dxv = np.array([1, 1, 1, 1, 1, 1, 1, 1, 1, 1]) * d
dyv = np.array([-2, -2, -2, 2, 2, 2, 2, 3, 2, 2]) * d  # pos/neg for vertical/horizontal cars

yv = iquib(yv)

# prepare figure:
plt.figure(0)
plt.clf()
ax = plt.gca()
ax.axis(np.array([-0.5, l - 0.5, -0.5, l - 0.5]) * d)
ax.axis('square')
plt.setp(ax, xticks=[], yticks=[])

# Draw cars:
clr = np.array([0.4, 0, 0])
for x, y, dx, dy in zip(xv, yv, dxv, dyv):
    if dy < 0:
        x, y, dx, dy = y, x, -dy, dx
    rect = Rectangle(xy=(x - d/2 + spc, y - d/2 + spc),
                     width=dx - 2*spc, height=dy - 2*spc,
                     facecolor=0.7 * clr)
    ax.add_patch(rect)
    plt.plot(x - d/2 + dx/2, y - d/2 + dy/2, 'o',
             color=clr, markersize=30, pickradius=30)
    clr = np.array([0.2, 0.8, 0.2])
# Raise exception on illegal car position
# This will prevent dragging cars on top of each other
@quiby(is_graphics=True)
def check_valid(xx, yy, dxx, dyy):
    z = np.zeros((l*d, l*d), dtype=np.int8)
    for x, y, dx, dy in zip(xx, yy, dxx, dyy):
        if dy < 0:
            x, y, dx, dy = y, x, -dy, dx
        if x < 0 or y < 0 or x + dx > l*d or y + dy > l*d:
            raise ValueError('out of range')
        z[x:x+dx, y:y+dy] += 1

    if np.any(z>1):
        print('raising')
        raise ValueError('overlap')

    if yy[0] == 4 * d:
        ax.set_title('Yeh!', fontsize=24)

check = check_valid(xv, yv, dxv, dyv);
../_images/quibdemo_rushhour.gif