Skip to content

Instantly share code, notes, and snippets.

@jkozma
Last active July 30, 2019 01:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkozma/73442474b7a4dcfc4081aae09e521f6c to your computer and use it in GitHub Desktop.
Save jkozma/73442474b7a4dcfc4081aae09e521f6c to your computer and use it in GitHub Desktop.
Digital jigsaw puzzle
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## A Digital Jigsaw"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This program uses a recursive function to solve a \"digital\" jigsaw puzzle. The puzzle is digital in two distinct ways. First, obviously, it is presented here by means of digital information technology. Before considering the second way this is a digital puzzle, however, it may be noted that the original puzzle, from which this was copied, is not implemented on a computer, but with wooden pieces that must be arranged to fit in the recessed area of a wooden board. The next few sections of code use numpy arrays and matplotlib.pyplot to show what the board and pieces look like."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from IPython.display import clear_output\n",
"\n",
"def board_figure():\n",
" # create coordinate axis for drawing figure\n",
" fig, ax = plt.subplots(figsize=(9,9))\n",
" \n",
" # Create a black border with angular edges\n",
" x_border = [-1,-.2,-1.4,-.3,-1,2.2,5.8,8.7,12,11.1,12.4,11.2,12,8.1,4.8,2.1,-1]\n",
" y_border = [-1,2.4,5.7,8.1,12,11.4,12.1,11.3,12,8.7,6.1,2.3,-1,-.4,-1.3,-.1,-1]\n",
" plt.fill(x_border, y_border, facecolor=\"black\")\n",
" \n",
" # Color the board area white where pieces may be placed\n",
" x_bd = np.array([1,4,4,5,5,9,9,10,10,11,11,10,10,7,7,4,4,1,1,0,0,1,1])\n",
" y_bd = np.array([1,1,0,0,1,1,0,0,6,6,7,7,10,10,11,11,10,10,6,6,5,5,1]) \n",
" plt.fill(x_bd, y_bd, facecolor=\"white\")\n",
" \n",
" return fig, ax\n",
"\n",
"def show_figure(ax, title=\"Puzzle Board\"):\n",
" ax.set_title(title)\n",
" plt.axis('equal')\n",
" plt.axis('off')\n",
" \n",
" plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 648x648 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Display the empty board\n",
"fig, ax = board_figure()\n",
"show_figure(ax)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The use of numpy arrays makes it easier to write code for various operations like flipping and rotating the pieces and placing them on the board. In the declaration for the pieces, each piece is represented by an array in which zero is empty space. A different value and corresponding color is assigned to each piece, allowing them to be distinguished from one another after they have been placed on the board."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# color keys: 0 for empty squares, 1 for puzzle border\n",
"# 1.0x for pieces, where x is unique for each piece\n",
"# 10 for marker\n",
"colors = {0:'white',1:'black',\n",
" 1.01:'#909090',1.02:'#a0a0a0',1.06:'#c0c0c0',\n",
" 1.04:'#99754b',1.03:'#707070',1.05:'#332719',\n",
" 1.09:'#ffc77e',1.08:'#cc9c64',1.07:'#664e32',\n",
" 10:'red'}\n",
"\n",
"pieces = [\n",
" np.array([\n",
" [0,1,1,1],\n",
" [1,1,1,1],\n",
" [0,0,1,1]])*1.01,\n",
" np.array([\n",
" [1,0,1,0],\n",
" [1,1,1,1],\n",
" [1,1,1,0]])*1.02,\n",
" np.array([\n",
" [0,1,1,1],\n",
" [1,1,1,0],\n",
" [1,1,1,0]])*1.03,\n",
" np.array([\n",
" [1,0,1,0],\n",
" [1,1,1,0],\n",
" [1,1,1,1]])*1.04,\n",
" np.array([\n",
" [0,1,0,0],\n",
" [1,1,1,0],\n",
" [0,1,1,1],\n",
" [1,1,1,0]])*1.05,\n",
" np.array([\n",
" [0,1,0,1],\n",
" [0,1,1,1],\n",
" [1,1,1,0]])*1.06,\n",
" np.array([\n",
" [0,1,0,0],\n",
" [0,1,1,0],\n",
" [0,1,1,1],\n",
" [1,1,1,1],\n",
" [0,1,0,0]])*1.07,\n",
" np.array([\n",
" [0,1,0,0],\n",
" [1,1,1,0],\n",
" [1,1,1,0],\n",
" [1,1,1,1],\n",
" [1,0,0,0]])*1.08,\n",
" np.array([\n",
" [0,0,1,0],\n",
" [0,1,1,1],\n",
" [0,1,1,0],\n",
" [1,1,1,1],\n",
" [0,1,0,0]])*1.09\n",
" ]\n",
"\n",
"def add_piece(p, x0=0, y0=0, invert_y=True, y_top=None):\n",
" if invert_y:\n",
" y_offset = len(p)\n",
" else:\n",
" y_offset = 1\n",
" xx0 = np.array([x0, x0+1, x0+1, x0, x0])\n",
" yy0 = np.array([y0, y0, y0-1, y0-1, y0])\n",
" for x in range(len(p[0])):\n",
" for y in range(len(p)):\n",
" xx = xx0 + np.full(5,x)\n",
" yy = yy0 + np.full(5,y_offset-y)\n",
" color = colors[p[y,x]]\n",
" if p[y,x] == 0:\n",
" a = 0\n",
" else:\n",
" a = 0.6\n",
" if y_top:\n",
" yy = y_top + yy - y_offset\n",
" plt.fill(xx, yy, color, alpha=a)\n",
" return\n",
"\n",
"def add_pieces(pp):\n",
" x = [0,6,12,0,6,12,0,6,12]\n",
" y = [0,0,0,6,6,6,12,12,12]\n",
" for i in range(len(pp)):\n",
" add_piece(pp[i],x[i],y[i])"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAmIAAAJOCAYAAAAUOGurAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAADyRJREFUeJzt3E+opeddwPHfEy/YgqVFLa0jJQtdRKsLnYiDm6ELF5WUCYJbL5imtwt1HApBqxBm4cKCDHcheBNnMRhQpFAi0finBQdBBswgiJCAFERpqAut/SMuYn1dzA0MQUvoZM535p7PBwbmnnfOfX/vvc97+PLcc2dt2zYAAOzeI/UAAAD7SogBAESEGABARIgBAESEGABARIgBAESEGPDQWmu9vNY6rOcA+HYt/48Y8KBba/3TzHxgZr45M/85M386M7+0bds3yrkA7pUdMeBh8bFt275rZn58Zn5iZn4jngfgngkx4KGybduXZublmfmRtdZfrbU+/uaxtdYvrLVeXWt9Za3152utR+869uG11l+utf59rfWva61Pnz7+yFrrV9daX1xr/dta64/WWt99euxda60XTh//j7XW3661PrDrawbOLiEGPFTWWh+amZ+Zmb97y+NPzsynZ+ZnZ+b9M/PXM/MHp8feMzOfn5k/m5lzM/ODM/OF06f+8sw8OTMXT499ZWZ+5/TY4cy8d2Y+NDPfMzOfnJn/uj9XBuwj7xEDHnin7xH73pn575n56sz8ycx8au7sjL2wbdvvrbVenpnPbtt2/fQ5j8zMN2bmh2bmp2bmmW3bfuz/+Nyvzswvbtv2hdOPv29m/nlm3j0zPz8zH5+ZT27b9vf39SKBvXRQDwDwNj25bdvn735grXX3h4/OzPFa67fv/icz8/1zZ0fri//P5310Zj631vqfux775tz55YDfP33uH6613jczL8zMr2/b9sa9XAjAm/xoEjgr/mVmjrZte99df969bdvfnB77gW/xvI++5Xnv2rbtS9u2vbFt29Vt23547uyqPTF3dskA3hFCDDgrfndmfm2t9eGZmbXWe9daP3d67KWZ+eBa61fWWt+51nrPWusn73reb775xv611vvXWpdO//6RtdaPrrW+Y2a+NjNvzJ3dMoB3hBADzoRt2z43M781d36M+LWZ+YeZ+ejpsa/PzE/PzMdm5ssz848z85HTpx7PzB/PzF+stb4+M7dm5s1I++DMfHbuRNirM3Nz7vx4EuAd4c36AAARO2IAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAABEhBgAQEWIAAJGDegDuzdGl8ye7PufJi7ePdn1Ozp7b15/e+do9/9Tz1i4Pn1vP7vxemQtX3Ss7YkcMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAImvbtnoG7sHRpfMn9Qy7cPLi7aN6hrPq9vWn92INVc4/9by1e5bcetb9cr9cuLqX94odMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgc1APA23F06fzJrs958uLto12fE+CBcOGq178dsSMGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAkYN6gLPk6NL5k3oG4MFy+/rTO39dOP/U80e7Pmfi1rNec++X4mt74ep+rNu3sCMGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAESEGABARYgAAkbVtWz0D9+Do0vmTXZ/z5MXbR7s+J/fP7etP73wNzcycf+p564iHz61nd3+/XLjqXjnD7IgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABAZG3bVs8AALCX7IgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAEQO6gGA/fT4Y+dOdn3OV157/WjX5wT4VuyIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQGRt21bPcGY898wTJ7s+5yc+89LRrs+5L9e5Lx5/7NzOv5/75JXXXrd2z5CbN2/u/H65ePHiztfQvlzng8COGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABARIgBAESEGABA5KAegHvz3DNPnNQz8HB75bXXj4rzPv7Yub1Yu8V1Vt9T7o+bN2/uxb2yr+yIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQOSgHgDejueeeeJk1+f8xGdeOtr1OQuPP3Zu51/bffLKa6/vxToq3Lx509q9Ty5evGjd7ogdMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIisbdvqGQAA9pIdMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgIMQCAiBADAIgc1ANwb46Pj0/qGc6qy5cvH9Uz7MKNGzeSNXR4eLjzr29xrcV1cv9cuXLFa+59cu3atb28V+yIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQOSgHuAsOT4+PqlngIfFjRs39uJ+Ka7z8PDwaNfnLFy5cmUv1lDh2rVre7GGHgR2xAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACAixAAAIkIMACByUA9wlly+fPmonmEXjo+PT+oZ4GFxeHi4F68LwLfHjhgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBE1rZt9QwAAHvJjhgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBEhBgAQESIAQBE/hcZNkvBdOYkeQAAAABJRU5ErkJggg==\n",
"text/plain": [
"<Figure size 720x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Display the pieces\n",
"fig, ax = plt.subplots(figsize=(10,10))\n",
"add_pieces(pieces)\n",
"show_figure(ax,\"Pieces\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Even though they can be rotated or flipped, it's pretty easy to see that there are only eight possible orientations for each piece. That is, in essence, the second way in which this is a digital puzzle. In a conventional jigsaw puzzle, a piece might be rotated by any arbitrary amount to fit into its correct position. The pieces here have square corners and can only be rotated 90 degrees at a time, \"facing\" left, right, up or down on either side. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def generate_orientations(piece, fn=True):\n",
" piece_orientations = [(0, piece.copy())]\n",
" for i in [0, 1, 2]:\n",
" piece_orientations.append((i+1,np.rot90(piece_orientations[i][1])))\n",
" piece_orientations.append((4,piece.transpose()))\n",
" for i in [4, 5, 6]:\n",
" piece_orientations.append((i+1,np.rot90(piece_orientations[i][1])))\n",
" if fn:\n",
" return iter(piece_orientations)\n",
" else:\n",
" lst_rtn = []\n",
" for i in range(8):\n",
" lst_rtn.append(piece_orientations[i][1])\n",
" return lst_rtn"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 720x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Display all possible orientations for a piece\n",
"fig, ax = plt.subplots(figsize=(10,10))\n",
"add_pieces(generate_orientations(pieces[3], fn=False))\n",
"show_figure(ax, \"Orientations for one piece\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Assuming there's a way to specify the order in which the pieces have been placed in the puzzle, it should thus be possible to find the solution by trying every possible combination of orientations for each possible sequence of pieces.\n",
"\n",
"How many possibilities are there? Since each piece has eight possible orientations, for any given order of nine pieces there will be 8<sup>9</sup>, or 134,217,728 possible combinations. The number of different orders for nine pieces is given by 9 factorial, or 362,880, so the total number of possibilities, 9! x 8<sup>9</sup>, is 48,704,929,136,640. The computer on which these notes are being written has a 2.6 GHz processor. Assuming it could check one possible solution per clock cycle, it would take 48,704,929,136,640 / 2,600,000,000, or about 18,733 seconds to go through them all. That's a little more than two days.\n",
"\n",
"Fortunately, it's not necessary to check every possible sequence. It will often be obvious after placing just one or two pieces that there'd be no way the rest will fit. Before considering how to design an algorithm that will effectively prune the search tree, however, the ordering of pieces that have been placed on the board must be clearly defined. A simple scheme is to look at the squares in the puzzle row by row, left to right. Since all the squares on the board would have to be filled by a correct solution, the first piece in the solution would have to fill the first square on the board."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"bd = np.array([[1,1,1,1,0,0,0,1,1,1,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,0],\n",
" [0,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,0,0,0,0,0,0,0,0,0,1],\n",
" [1,1,1,1,0,1,1,1,1,0,1]])\n",
"\n",
"def locat(xy_array, val=0, test_equal=True):\n",
" # return the x, y indices of the first element in the array\n",
" # that meets the specified condition\n",
" # first value in return tuple is the left-right index,\n",
" # second return value is top-bottom index \n",
" try:\n",
" if test_equal:\n",
" return next(zip(np.where(xy_array==val)[1],np.where(xy_array==val)[0]))\n",
" else:\n",
" return next(zip(np.where(xy_array>=val)[1],np.where(xy_array>=val)[0]))\n",
" except:\n",
" return (-1, -1)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 648x648 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Show the first square on the board\n",
"marker = np.array([[10]])\n",
"fig, ax = board_figure()\n",
"x, y = locat(bd)\n",
"add_piece(marker, x, y, y_top=11)\n",
"show_figure(ax, \"First empty square\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is also clear that for a given orientation of any piece to be the first piece in a solution, the \"first\" non-empty square in that piece must fill the first empty square on the board."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 720x720 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Show the first square for all possible orientations of a piece\n",
"import copy\n",
"marked_orientations = copy.deepcopy(generate_orientations(pieces[6], fn=False))\n",
"for pp in marked_orientations:\n",
" y, x = locat(pp, val=1, test_equal=False)\n",
" pp[x][y] = 10\n",
"fig, ax = plt.subplots(figsize=(10,10))\n",
"add_pieces(marked_orientations)\n",
"show_figure(ax, \"First square for orientations of one piece\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If a piece in a given orientation will not fit in the first position on the board, then any potential solutions with that piece in that orientation can be eliminated from consideration."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 648x648 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Show an orientation of a piece that cannot be placed first on the board\n",
"fig, ax = board_figure()\n",
"wrong_piece = generate_orientations(pieces[3], fn=False)[2]\n",
"x, y = locat(bd)\n",
"add_piece(wrong_piece, x, y, y_top=11)\n",
"show_figure(ax, \"Piece in orientation that does not fit in first position\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"On the other hand, if a piece in a given orientation can be placed in the first available position, the board with the piece thus placed can be viewed as a new problem in which one of the remaining pieces must next be placed in the first remaining space. This is the essence of a recursive approach to solving the puzzle. To implement a recursive algorithm, it's necessary to keep track of which pieces have been placed on the board. This can be done by adding each succesive piece to the numpy array that represents the board. However, only arrays of the same size can be added, so each piece must be padded with the correct number of zeros on each side (top, bottom, left and right) so that its first non-empty space is in the same position as the first empty space on the board."
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"def pad_piece(board, piece, location=None):\n",
" # x and y are used to make the numpy array references more readable\n",
" x = 0\n",
" y = 1\n",
" # determine the location where the piece will be placed\n",
" if location == None:\n",
" location = locat(board, 0)\n",
" # skip leading empty spaces on the top row of the piece\n",
" pc_offset = locat(piece,0.5,False)[x]\n",
" location = (location[x] - pc_offset, location[y])\n",
" \n",
" # check whether the piece is off the left side of the board\n",
" # note, it's not necessary to check whether the piece extends over the\n",
" # top of the board, since the to of the piece hast to fill the first\n",
" # empty space on the board\n",
" if location[x] < 0:\n",
" return (False, board)\n",
" \n",
" bd_width = len(board[x])\n",
" bd_height = len(board)\n",
" piece_width = len(piece[x])\n",
" piece_height = len(piece)\n",
"\n",
" # check whether the piece is off the right side of the board\n",
" if location[x] + piece_width > bd_width:\n",
" return (False, board)\n",
" # check whether the piece extends past the bottom of the board\n",
" if location[y] + piece_height > bd_height:\n",
" return (False, board)\n",
" \n",
" # compute the padding to locate the piece correctly\n",
" pad_left = location[x]\n",
" pad_right = bd_width - piece_width - location[x]\n",
" pad_top = location[y]\n",
" pad_bottom = bd_height - piece_height - location[y]\n",
" \n",
" pp = np.pad(piece,((pad_top,pad_bottom),(pad_left,pad_right)),'constant')\n",
" bd_with_piece = pp + board\n",
"\n",
" # When the piece is added to the board, any squares where the added piece\n",
" # overlaps with the board or a previously placed piece will have a value\n",
" # greater than 2\n",
" overlap = locat(bd_with_piece, 2, False)\n",
" if overlap[1] < 0:\n",
" return (True, bd_with_piece)\n",
" else:\n",
" return (False, board)"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 648x648 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Add a padded piece to the board and display the result\n",
"fit, new_bd = pad_piece(bd, pieces[0])\n",
"if fit:\n",
" fig, ax = board_figure()\n",
" add_piece(new_bd)\n",
" show_figure(ax, \"Board with piece added\")"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 648x648 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Add a second piece to the board with the previously added piece\n",
"# and display the result\n",
"next_piece = generate_orientations(pieces[2], fn=False)[3]\n",
"fit, new_bd_2 = pad_piece(new_bd, next_piece)\n",
"if fit:\n",
" fig, ax = board_figure()\n",
" add_piece(new_bd_2)\n",
" show_figure(ax, \"Board with two pieces added\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The general approach for the recursive function will be for the function to call itself whenever a piece in a particular orientation can be placed in the next available available space on the board. The arguments for the recursive call will be the current board state-- i.e., the board with all the pieces placed so far-- and the set of pieces that have not yet been placed.\n",
"\n",
"Whenever a piece is considered, different orientations are tried until a solution is found or none of eight possible orientations yields a solution. To keep track of which pieces have been found not to work as the next piece for a given board state, each piece thus rejected is moved to the end of the list of unplaced pieces, and a reject count is incremented. If the reject count exceeds the number of remaining pieces, the current board state is rejected as a possible partial solution.\n",
"\n",
"A solution to the puzzle requires that all the pieces are placed with no overlaps. If the recursive function is called with an empty set of pieces to be placed, the solution has been found.\n",
"\n",
"To display the progress of the program, a counter is maintained to keep track of how many calls have been made to the recursive function, and to display the board state at specified count intervals."
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"def fit_pieces(board, pieces, show_board_count=2500):\n",
" recursive_call_count = [0]\n",
" answer = []\n",
" def rec(board, pieces, reject_count):\n",
" recursive_call_count[0] += 1\n",
" if recursive_call_count[0] % show_board_count == 0:\n",
" clear_output()\n",
" fig, ax = board_figure()\n",
" add_piece(board)\n",
" show_figure(ax, \"Working... currently trying\")\n",
" if len(pieces) == 0:\n",
" answer.clear()\n",
" answer.append(board)\n",
" return True\n",
" elif len(pieces) < reject_count:\n",
" return False\n",
" else:\n",
" for piece_orientation in generate_orientations(pieces[0]):\n",
" (first_piece_fits, bd_with_piece) = pad_piece(board, piece_orientation[1])\n",
" if first_piece_fits:\n",
" other_pieces_fit = rec(bd_with_piece, pieces[1:], 0)\n",
" if other_pieces_fit:\n",
" return True\n",
" # Couldn't fit this piece here--\n",
" # Put it at the back of the list, increment reject_count and try next piece\n",
" reordered_pieces = pieces[1:]\n",
" reordered_pieces.append(pieces[0])\n",
" reject_count = reject_count + 1\n",
" rec(board, reordered_pieces, reject_count)\n",
" rec(board, pieces, 0)\n",
" clear_output()\n",
" fig, ax = board_figure()\n",
" add_piece(answer[-1])\n",
" show_figure(ax, \"Found solution:\")\n",
" return answer[-1]"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Solve the puzzle and display the solution\n",
"ans = fit_pieces(bd, pieces)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Refactoring and modifications"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The recursive function above uses a lists initialized outside the function declaration, which makes changes to the list elements essentially global, to keep track of the solution and recursive call counter. Is there an alternative way to do this?\n",
"\n",
"Can you modify the program so that it displays the recursive call count? Would you expect the final count to be the same if the initial order of the pieces were changed? \n",
"\n",
"Could there be other solutions? Can you modify the program to find them, or to show there aren't any?"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.0"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment