xkcd-Name-Dominoes.ipynb
This commit is contained in:
1 parent
7db423307e
commit
06e7a9f520
1 file changed
+136
-105
+136
-105
@@ -8,13 +8,12 @@
|
||||
"# `xkcd` Name Dominoes\n",
|
||||
"\n",
|
||||
"The March 21, 2018 `xkcd` comic number 1970 was [Name Dominoes](https://xkcd.com/1970/): domino tiles laid out in a legal array,\n",
|
||||
"but with each tile having names of famous poeple rather than numbers. In regular [dominoes](https://en.wikipedia.org/wiki/Dominoes), each tile has two halves, and a tile can be legally placed only if one half is adjacent to another tile with the same number/name, and neither half is adjacent to any tile with a different number/name. (The very first tile in a game has no adjacent tiles, so it can be placed anywhere.) `xkcd 1970` makes two exceptions to the rules: (1) some tiles have three names, and matches are allowed against the middle name, and (2) approximate matches are allowed, like \"Amy\" and \"Aimee\".\n",
|
||||
"but with each tile having names of famous poeple rather than numbers. In regular [dominoes](https://en.wikipedia.org/wiki/Dominoes), each tile has two halves, and a tile can be legally placed only if one half is adjacent to another tile with the same number/name, and neither half is adjacent to any tile with a different number/name. (The very first tile in a game has no adjacent tiles, so it can be placed anywhere.) `xkcd 1970` also allows some tiles to three names, with matches allowed against the middle name; I won't allow that.\n",
|
||||
"\n",
|
||||
"I will write a function to lay out dominoes in a random, legal array. I won't implement the two `xkcd` exceptions. I'll start with two key data structures:\n",
|
||||
"I will write a function to lay out dominoes in a random, legal array. I'll start with two key data structures:\n",
|
||||
"\n",
|
||||
"- **`Board(n)`**: Creates an [n × n] 2-dimensional array of locations; each location holds as a value one half of a tile, or it can be `empty`, or it can be a `border`, meaning nothing can be placed there.\n",
|
||||
"- **`tiles(text)`**: a function to create a list of tiles, each of which is a 2-element list, like `['a', 'b']`, indicating the two halves. The input is a string, consisting of space-separated tiles, where the two halves of the tile are separated by a `|` character.\n",
|
||||
"\n"
|
||||
"- **`tiles(text)`**: a function to create a list of tiles, each of which is a 2-element list, like `['a', 'b']`, indicating the two halves. The input is a string, consisting of comma-and/or-space-separated tiles, where the two halves of the tile are separated by a `|` character."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -39,14 +38,7 @@
|
||||
" \n",
|
||||
" def get(self, loc): return self[loc[1]][loc[0]]\n",
|
||||
" \n",
|
||||
" def put(self, loc, value): self[loc[1]][loc[0]] = value\n",
|
||||
" \n",
|
||||
"def tiles(text):\n",
|
||||
" \"tiles('a|b b|c') => [['a', 'b'], ['b', 'c']\"\n",
|
||||
" return [tile.split('|') for tile in text.split()]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"names1 = tiles('Bo|Ja Ja|Ry Ja|Po Ry|Ke Gr|Ke Gr|Ho Bo|Po Ry|Ja')"
|
||||
" def put(self, loc, value): self[loc[1]][loc[0]] = value"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -80,44 +72,17 @@
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": true
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[['Bo', 'Ja'],\n",
|
||||
" ['Ja', 'Ry'],\n",
|
||||
" ['Ja', 'Po'],\n",
|
||||
" ['Ry', 'Ke'],\n",
|
||||
" ['Gr', 'Ke'],\n",
|
||||
" ['Gr', 'Ho'],\n",
|
||||
" ['Bo', 'Po'],\n",
|
||||
" ['Ry', 'Ja']]"
|
||||
]
|
||||
},
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"names1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now I need a strategy to fill the board with tiles, legally. I will randomly place dominoes one at a time, and I will *not* consider removing a tile from the board and backtracking; this is a greedy search. Some more concepts:\n",
|
||||
"def tiles(text):\n",
|
||||
" \"tiles('Bo|Ja, Ja|Po') => [['Bo', 'Ja'], ['Ja', 'Po']\"\n",
|
||||
" return [tile.split('|') for tile in split(text)]\n",
|
||||
"\n",
|
||||
"- **`frontier`**: I'll maintain a *frontier*, a set of locations that are adjacent to tiles on the board, and thus are candidates for placing new tiles.\n",
|
||||
"- **`dominoes(tiles)`**: places a random tile for the first tile, then repeatedly calls `place1` to legally place an additional tile, stopping when either there is no `frontier` left (meaning no place to put a tile) or no `tiles` left to place.\n",
|
||||
"- **`place1(tiles, board, frontier)`**: find a location in the frontier, such that some tile can legally put one of its halves there, and the other half on an adjacent location; when found, `put` the tile there, and remove it from `tiles`.\n",
|
||||
"- **`legal(value, loc, board)`**: a value can be placed in a location if the location is empty, and no neighboring location has a different value (but it is ok if a neighbor is empty or is a border).\n",
|
||||
"- **`neighbors(loc)`**: returns the four neighbors of a location.\n",
|
||||
"- **`put(board, loc0, loc1, tile, frontier)`**: places a tile on the board, it accomplishes this by making two calls to the board's `put` method, one for each half of the tile. The `put` function also updates the `frontier` to say that the just-covered locations are no longer in the frontier, but the empty neighbors of the tile are.\n",
|
||||
"- **`shuffle(sequence)`**: used to randomize lists; calls `random.shuffle` and returns the result."
|
||||
"def split(text): return text.replace(',', ' ').split()\n",
|
||||
"\n",
|
||||
"tiles1 = tiles('Bo|Ja, Ja|Po, Ja|Ry, Ry|Ke, Gr|Ke, Gr|Ho')"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -130,14 +95,12 @@
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[['--', '--', '--', '--', '--', '--', '--', '--'],\n",
|
||||
" ['--', ' ', 'Po', 'Ja', 'Ja', 'Ry', ' ', '--'],\n",
|
||||
" ['--', ' ', 'Po', ' ', ' ', 'Ry', 'Ke', '--'],\n",
|
||||
" ['--', ' ', 'Bo', 'Bo', ' ', ' ', 'Ke', '--'],\n",
|
||||
" ['--', ' ', ' ', 'Ja', ' ', ' ', 'Gr', '--'],\n",
|
||||
" ['--', ' ', ' ', 'Ja', 'Ry', ' ', 'Gr', '--'],\n",
|
||||
" ['--', ' ', ' ', ' ', ' ', ' ', 'Ho', '--'],\n",
|
||||
" ['--', '--', '--', '--', '--', '--', '--', '--']]"
|
||||
"[['Bo', 'Ja'],\n",
|
||||
" ['Ja', 'Po'],\n",
|
||||
" ['Ja', 'Ry'],\n",
|
||||
" ['Ry', 'Ke'],\n",
|
||||
" ['Gr', 'Ke'],\n",
|
||||
" ['Gr', 'Ho']]"
|
||||
]
|
||||
},
|
||||
"execution_count": 4,
|
||||
@@ -145,10 +108,54 @@
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"tiles1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Now I need a strategy to fill the board with tiles, legally. I will randomly place dominoes one at a time, and I will *not* consider removing a tile from the board and backtracking; this is a greedy search. Some more concepts:\n",
|
||||
"\n",
|
||||
"- **`frontier`**: I'll maintain a *frontier*, a set of locations that are adjacent to tiles on the board, and thus are candidates for placing new tiles.\n",
|
||||
"- **`dominoes(tiles)`**: places a random tile for the first tile, then repeatedly calls `place1` to legally place an additional tile, stopping when either there is no `frontier` left (meaning no place to put a tile) or no `tiles` left to place.\n",
|
||||
"- **`place1(tiles, board, frontier)`**: find a location in the frontier, such that some tile can legally put one of its halves there, and the other half on an adjacent location; when found, `put` the tile there, and remove it from `tiles`.\n",
|
||||
"- **`legal(value, loc, board)`**: a value can be placed if the location is empty, and the value matches all the neighboring location values.\n",
|
||||
"- **`legal_match(value, nbrval)`**: a value matches if the neighbor is empty or a border, or is equal to the value.\n",
|
||||
"- **`neighbors(loc)`**: returns the four neighbors of a location.\n",
|
||||
"- **`put(board, loc0, loc1, tile, frontier)`**: places a tile on the board, it accomplishes this by making two calls to the board's `put` method, one for each half of the tile. The `put` function also updates the `frontier` to say that the just-covered locations are no longer in the frontier, but the empty neighbors of the tile are.\n",
|
||||
"- **`shuffle(sequence)`**: used to randomize lists; calls `random.shuffle` and returns the result."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[['--', '--', '--', '--', '--', '--', '--'],\n",
|
||||
" ['--', ' ', ' ', 'Ja', 'Ja', 'Bo', '--'],\n",
|
||||
" ['--', ' ', 'Ry', 'Ry', ' ', ' ', '--'],\n",
|
||||
" ['--', ' ', 'Ke', ' ', ' ', ' ', '--'],\n",
|
||||
" ['--', ' ', 'Ke', 'Gr', ' ', ' ', '--'],\n",
|
||||
" ['--', ' ', ' ', 'Gr', 'Ho', ' ', '--'],\n",
|
||||
" ['--', '--', '--', '--', '--', '--', '--']]"
|
||||
]
|
||||
},
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"import random\n",
|
||||
"\n",
|
||||
"def dominoes(tiles, n=6):\n",
|
||||
"def dominoes(tiles, n=24):\n",
|
||||
" \"Place as many tiles on board as possible, legally and randomly.\"\n",
|
||||
" tiles = shuffle(list(tiles))\n",
|
||||
" board = Board(n)\n",
|
||||
@@ -175,9 +182,13 @@
|
||||
"def legal(value, loc, board):\n",
|
||||
" \"Is it legal to place this value on this location on board?\"\n",
|
||||
" return (board.get(loc) is empty and\n",
|
||||
" all(board.get(nbr) in (empty, border, value) \n",
|
||||
" all(legal_match(value, board.get(nbr)) \n",
|
||||
" for nbr in neighbors(loc)))\n",
|
||||
"\n",
|
||||
"def legal_match(value, nbrval):\n",
|
||||
" \"Does this value match the neighbor's value?\"\n",
|
||||
" return nbrval in (empty, border, value)\n",
|
||||
" \n",
|
||||
"def neighbors(loc):\n",
|
||||
" \"Neighbors of this location.\"\n",
|
||||
" x, y = loc\n",
|
||||
@@ -197,7 +208,7 @@
|
||||
" random.shuffle(seq)\n",
|
||||
" return seq\n",
|
||||
" \n",
|
||||
"dominoes(names1)"
|
||||
"dominoes(tiles1, 5)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -214,7 +225,7 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"collapsed": true
|
||||
},
|
||||
@@ -223,8 +234,8 @@
|
||||
"%matplotlib inline\n",
|
||||
"import matplotlib.pyplot as plt\n",
|
||||
"\n",
|
||||
"def plot_board(board, size=6):\n",
|
||||
" plt.figure(figsize=(size, size))\n",
|
||||
"def plot_board(board, figsize=6):\n",
|
||||
" plt.figure(figsize=(figsize, figsize))\n",
|
||||
" plt.axis('off') \n",
|
||||
" plt.axis('equal')\n",
|
||||
" for (x0, y0, x1, y1) in board.boxes:\n",
|
||||
@@ -263,16 +274,16 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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\nGOEGGEa4AYYRboBhhBtgGOEGGEa4AYYRboBhhBtgGOEGGEa4AYYRboBhhBtgGOEGGEa4AYYRboBh\nhBsOsKo6WlWXqupsVZ2vqq+v3sR6wg0H34XuPtnddyT5YFV9aPUg1hJuGKKqjiR5U5I/VdWXtk/g\nT1XVx1ZvY38dWT0AeFXHqupskn9KcjHJTUmOJ7kzyduS/EdV/bC7L6+byH5y4oaD78qtkvcneTbJ\nrUme7C3PJ/lDkncsXci+cuKGWS4leU+S26uqsnXifmeSPy5dxb4Sbjj4rtwqqSQvJLkvyQ1Jzmfr\nu+bPuU1yuFR3r94AG2M7sOnuk2uXXL9NuIZN5x43wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wA\nwwg3wDDCDTCMcAMMI9wAwwg3wDAe67oBquozSU6v3rFLt2z/+9mlK3bvRJJU1fOrh+zCW5L8evUI\nXp4T92Y4neS21SN26Z+3/wFehRP35rg4+fnJV06ok69hU1x5HjcHlxM3wDDCDTCMcAMMI9wAwwg3\nwDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wA\nwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcPOyqupoVf149Y7dmH4N2/svVdXZqjpfVV9fvYn1hBsO\nvgvdfbK770jywar60OpBrCXcvKqqOl1V57ZPfN+qqlq96VptyDUcSfKmJH+qqi9tX8tTVfWx1dvY\nX8LNTjzW3Se2T3w3Jjm+etB1mHwNx6rqbJJfJPmvJDdla/+dST6a5KtV5c/yIeLNZieOV9VPqupc\nkg8neffqQddh8jVcuVXy/iTPJrk1yZO95fkkf0jyjqUL2VdHVg9ghAeT3NPdz1bVI0nG3WbIZlxD\nklxK8p4kt2/f7nlbkncm+ePSVewr4eaVVJKXkjyc5PGq+uXiPddjE67hyq2SSvJCkvuS3JDkfLa+\na/5cd19eN4/9Vt29egO7tP2HOt19co9f9+4kn+juT+3l677Mf+v5JOnut+/x6+7bNWyK1+rrib3j\nxM1VVdXpJPcn+fTqLddrE64BrsaJewNswgnptTpxc+024etp0/mpEoBhhBtgGOEGGEa4AYYRboBh\nhBtgGOEGGEa4AYYRboBhhBtgGOEGGMZDpjgo3pb8/3MyWOq2JBdXj+DlOXED/+hikjOrR/DynLg5\nKM4lnkgHO+HEDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCM\ncAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcHNVVXW0qi5V1dmq\neqqqPrt6E7DlyOoBHGgXuvtUVb0+yS+q6qHu/svqUXDYOXGzE29O8oYkp6rqa1c+WVWPV9V7182C\nw0m4eSXHqupckt8m+UaSHyT5SFW9sarel+TF7v7N0oVwCAk3r+RCd59IciLJqe6+nOTRJB9P8skk\n3145Dg4r97h5Vd39dFX9rqruzVasv5PkpiRfXjoMDiknbnbqq0ke6O7fJflrkie6+2+LN8Gh5MTN\nVXX3M0lO/d3HP09y1/aHLyV5aMEsIE7cXIOquqGq/j3J77v7V6v3wGHlxM2Obd8auXf1DjjsnLgB\nhhFugGGEG2AY4QYYRrgBhhFugGGEG2AY4QYYRrgBhhFugGGEG2AYzyrZDCeSpKrOLt6xG7clubh6\nBEzgxM1BcTHJmdUjYILq7tUbALgGTtwAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3\nwDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wA\nwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAwwg3wDDCDTCMcAMMI9wAw/wvWmtXa1IdtysA\nAAAASUVORK5CYII=\n",
|
||||
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAAFpCAYAAACMK9MWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAADMBJREFUeJzt3V+Ipfddx/HP12xSGxJTQjVWqU1VTPEPWQjYNiTdRBYq\nKQjBgrDFSqstiDctIlRRvBAhF5ZQNF40LdYWV2OLNKkYMKHZQGka7cJWS7GlQmqxtVZIqKm5yJ+v\nF3PWbrO7sxszu895vvN6wZCZc7Hz4eyZ9/7mmd0n1d0BYP2+Z+kBAOwNQQcYQtABhhB0gCEEHWAI\nQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEE\nHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0\ngCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtAB\nhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcY\nQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAI\nQQcYQtABhhB0gCEEHWCIA0sPAHihquqdSY4sveMFOtrd77+Qn8AJHVijI0kOLj3iBTiYi/AHkBM6\nsFYnuvuWpUecj6o6djE+jxM6wBCCDjCEoAMMIegAQwg6wBCCDjCEoAMMIegAQwg6wBCCDjCEoAMM\nIegAQwg6wBCCDjCEoAMMIegAQwg6wBCCDjCEoAMMIegAQwg6wBCCDuxbVXVtVT34vMe+vNSeF0vQ\nAYY4sPQAgG1TVdck+VCSy5N8O8mvdPc3Fx11HpzQgf3uhqo6dvJt89hvJ/nL7j6U5K82H289QQf2\nu+PdfcvJt81j1yX59Ob9Tyd5zSLLXiBBBzjdF5PcuHn/xs3HW881dIDT3ZHkz6vq15L8T5K3Lrzn\nvAg6sG9192NJDj/vsR/fvPvGiz7oRXLJBWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAI\nQQcYQtABhljFvVyq6p1Jjiy9Y6hXbP779UVXzHW0u9+/9IjzsbKvs4NJvrH0iG2zlhP6kez8BrL3\nfmzzxt47mPUEMlnX19kVSa5ZesS2WcUJfePEKTefZ49U1RNJ4rnde6f832/WZBVfZydft3y3tZzQ\nATgHQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0\ngCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYYl8FvaqurarHq+pYVX22qo4svelcNpsfXHrH+VjL1ue9\nDh6tqnctvWmSqrq+qu6vqoer6lNVdXdVXbr0rrNZ297dHFh6wAKOd/fhqvq+JP9UVX/d3c8sPYqL\n7uTr4JIkX6iqu7v720uPWruquirJR5Lc3t3/unnspiSXJHl68/El3f3sciu/Y217z2VfndBP1d3f\nSvIfSd6yOaU9UlW/t/Sus6mqI5sTxCNV9YGqqqU3nc2atia5PMllSQ5X1ftOPlhVD1TVq5abtVpv\nSnLfyTgmSXd/KskPVtU/VtVHkty92LrTrW3vrvZt0Kvqh5Nck+R3k7wxyY1JDlXV9YsOO7v7uvtQ\nd78+yZVJbl560C7WsPWGqno4yVeT3JXkE0luqqqXVNWrkzzT3V9ZdOE6vTI7z2mq6vs3l7U+n+Tl\nSa5N8hvd/fYF9z3f2vbuaj8G/Yaqeig732a9J8k3uvuJ7u4kn0ly3aLrzu7mqvrkJkKvzc4LcVut\nYevx7j6U5FCSw939XJKPJ7k9yduSfHDJcSv21Wx+v7v7m919S5LPJvneJJ/ffGe8Tda2d1f7MejH\nu/vW7v65JB9Nck1VvWxzWeB1Sb647LyzuiPJWzYRejTJNl/GWM3W7v5ckq9V1W3Zifjbk9yW5N5F\nh63X3yX5har60VMeO/mzum28Dr22vbvajz8U/T/d/VxV/VaSv0/yXJL7N1/g26Sy88L6cJIHqupf\nFt6zmzVtPdWdSe7q7jdU1VNJHurup5cetUbd/URVvTXJn1bVS5M8leTfkmzlD5zXtvdcaudKw3ar\nqmNJsvl2aF+pqluT/PKFuo5XVU8kSXe/bA9+rQu69WKoqr9J8p7u/tIe/FrHkvW8bte0dy9ftxfD\nxXpu9/UJfdtt/p78u5O8Y+kt57KmrWey+XvH9yZ5bC9iDksQ9C3W3UeTHF16x/lY09Yz2VxiuW3p\nHfBi7McfigKMJOgAQwg6wBCCDjCEoAMMIegAQwg6wBCCDjCEoAMMsZZ/KXoo+c79EFbgFdm51/oa\nXJV4bi+QK5I8uaLn9mCSbyw94jyt7XV7MMmJC/1JnNAvjGuy88XM3lvTc/tk1hPIZOd5Xcsflmtz\nIhfh1hirOKF399beT/tMVnbXumPJOrYm69u7JifvYLgSDydeB8/nhA4whKADDCHoAEMIOsAQgg4w\nhKADDCHoAEMIOsAQgg4whKADDCHoAEMIOsAQgg4whKADDCHoAEMIOsAQgg4whKADDCHoAEMIOsAQ\ngg4whKBvuaq6tqoeXHrHJJvn9PGqOlZVj1bVu5betJtTXwNVdWVVPVxVb15615msaetEB5YeAAs5\n3t2Hq+qSJF+oqru7+9tLj9pNVV2Z5G+T/El3f2zpPbtZ09ZJnNBXoqqObE47j1TVB6qqlt40xOVJ\nLktyuKred/LBqnqgql613KzTXJHkE0nu6u6PVtWlm9fBQ1X1qar62aUHnmJNW0cR9PW4r7sPdffr\nk1yZ5OalB63cDVX1cJKvJrkrOwG6qapeUlWvTvJMd39l0YXf7TVJrkpy3+bjX03y5e6+NckvJrlz\nqWFnsKatowj6etxcVZ/cROi1SV659KCVO97dh5IcSnK4u59L8vEktyd5W5IPLjnuDD6b5C+S3FNV\nB5L8TJJfqqpjSe7JTkC3xZq2juIa+nrckeTnu/vrVXVPEpdc9kB3f66qvlZVt2Un4h9KcnWSP1h0\n2Bl09x9V1dVJ/izJZ7Jz6r0zSarqskXHPc+atk7ihL79KsmzST6c5IGq+liSS5adNM6dSd7T3V9L\n8lSSh7r76YU3nVF3/06SJ5P8dJLrNtelH0ryh8suO92atk7hhL79rk3y79393iTvXXjLCN39WJLD\np3z8z0nesPnw2SR3LzDrrM6w99eXW7O7NW2dSNC3WFUdSfLuJO9Yest0VXVpknuTPNbdX1p6D/x/\nCPoW6+6jSY4uvWM/2FxiuW3pHfBiuIYOMISgAwwh6ABDCDrAEIIOMISgAwwh6ABDCDrAEIIOMIR/\nKcraHEqSza1Y2VtXJat5bg8mObH0iG3jhA6s0Ym4LcZpnNBZle52H3g4Cyd0gCEEHWAIQQcYQtAB\nhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcYQtABhhB0gCEEHWAIQQcY\nQtABhhB0gCEEHWAIQd9SVXVtVT1eVceq6pGq+uOlNwHbTdC32/HuvqW7X5/kJ6vqp5YeBGwvQV+B\nqjqQ5KVJ/ruqfn9zYn+0qt609DZgexxYegC7uqGqjiX5oSQnklyd5OYkNya5Ksk/VNX93f3cchOB\nbeGEvt1OXnL5iSRfT3J9ks/0jieS/GeSly+6ENgaTujr8XiSH0nyuqqq7JzQfyDJfy26Ctgagr7d\nTl5yqSTfSvKWJJcmeSQ73139psstwEnV3UtvGGcT4XT3LcsuObc1bQV25xo6wBCCDjCEoAMMIegA\nQwg6wBCCDjCEoAMMIegAQwg6wBCCDjCEoAMM4eZcF8ah5Dv3SdlyB7Nzr3Vg5ZzQOZHk6NIjgBfP\n3RYBhnBCBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGG\nEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC\n0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhB\nBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQd\nYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSA\nIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGG\nEHSAIQQdYAhBBxhC0AGGEHSAIQQdYAhBBxhC0AGG+F+rp70mZEIyLQAAAABJRU5ErkJggg==\n",
|
||||
"text/plain": [
|
||||
"<matplotlib.figure.Figure at 0x109e2a6d8>"
|
||||
"<matplotlib.figure.Figure at 0x111873cf8>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -280,7 +291,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"plot_board(dominoes(names1))"
|
||||
"plot_board(dominoes(tiles1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -289,43 +300,10 @@
|
||||
"source": [
|
||||
"# Scaling Up Names\n",
|
||||
"\n",
|
||||
"Now let's try with more tiles, with names taken (mostly) from `xkcd 1970`.\n",
|
||||
"Now let's try with more tiles, with names taken (mostly) from `xkcd 1970`, and with approximate matches, like \"Amy\" matching \"Aimee\".\n",
|
||||
"\n",
|
||||
"I could modify the program to back up if it got stuck before placing all the tiles, but instead I'll just add a new function, `best_dominoes(tiles, repeat=R)` that calls `dominoes` R times, and returns (and optionally prints) the\n",
|
||||
"board that has placed the most tiles (which we can measure with `len(board.boxes)`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"names2 = tiles(\n",
|
||||
" 'The|Rock Chris|Rock Rock|Hudson Chris|Isaac Isaac|Newton Olivia|Newton Isaac|Hayes '\n",
|
||||
" 'Shawn|Hayes Wallace|Shawn Charles|Wallace George|Wallace Charles|Manson Ray|Charles '\n",
|
||||
" 'Rachel|Ray Ray|Allen Tim|Allen Lily|Allen Tim|Cook James-Earl|Ray James-Earl|Jones '\n",
|
||||
" 'Man|Ray Bat|Man Super|Man Tim|Howard Ron|Howard Ron|Paul Paul|Allen Rand|Paul Ayn|Rand '\n",
|
||||
" 'Paul|Ryan Jack|Ryan Debby|Ryan Paul|Simon Carly|Simon John|Kelly Megyn|Kelly John|Henry '\n",
|
||||
" 'Grace|Kelly Grace|Jones Grace|Hopper Jack|Ma Ma|Bell Yo-Yo|Ma Jack|Ruby Jack|Russell '\n",
|
||||
" 'Charles|Parker Marilyn|Manson Marilyn|Monroe James|Monroe George|Bush George|Clinton Bill|Clinton '\n",
|
||||
" 'Jack|White Meg|Ryan Meg|White Barry|White Walter|White Betty|White Betty|Ford Henry|Ford Harrison|Ford '\n",
|
||||
" 'Tommy|John John|Irving John|Kerry Kerry|Washington Jimmy|John John|Adams Amy|Adams Amy|Man '\n",
|
||||
" 'Benjamin|Harrison Benjamin|Franklin Aretha|Franklin Franklin|Graham James|Garfield Garfield| '\n",
|
||||
" 'Kristen|Bell Kristen|Stewart Martha|Stewart Martha|Washington Wsshington|Irving John|Irving '\n",
|
||||
" 'Jimmy|Buffett Jimmy|Jones Warren|Buffett Elizabeth|Warren '\n",
|
||||
" 'Kevin|Bacon Kevin|Kline Kevin|Love Kevin|Smith Kevin|Costner Will|Smith Tommy|Lee Robert-E|Lee '\n",
|
||||
" 'John|Wayne Wayne|Newton Wayne|Knight Wayne|Howard Wayne|Brady Tommy|Brady James|Brady')\n",
|
||||
"\n",
|
||||
"def best_dominoes(tiles, n=20, size=16, verbose=True, repeat=300):\n",
|
||||
" board = max((dominoes(tiles, n) for _ in range(repeat)), \n",
|
||||
" key=lambda board: len(board.boxes))\n",
|
||||
" if verbose:\n",
|
||||
" print(len(board.boxes), '/', len(tiles), 'tiles placed')\n",
|
||||
" plot_board(board, size)\n",
|
||||
" return board"
|
||||
"With many names, the program can get stuck before it has placed many tiles. I could modify the program to *back up* in this case, but it will be easier to just add a new function, `best_dominoes(tiles, repeat=R)` that calls `dominoes` R times, and returns (and optionally displays) the\n",
|
||||
"board that has placed the most tiles out of those R boards (as measured by `len(board.boxes)`)."
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -334,19 +312,72 @@
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"tiles2 = tiles(\"\"\"\n",
|
||||
" The|Rock, Chris|Rock, Rock|Hudson, Chris|Isaac, Isaac|Newton, Olivia|Newton-John, Isaac|Hayes, \n",
|
||||
" Sean|Hayes, Wallace|Shawn, Charles|Wallace, George|Wallace, Charles|Manson, Ray|Charles, \n",
|
||||
" Rachel|Ray, Ray|Allen, Tim|Allen, Lily|Allen, Tim|Cook, James-Earl|Ray, James-Earl|Jones, \n",
|
||||
" Man|Ray, Ray|Mann, Bat|Man, Super|Man, Tim|Howard, Ron|Howard, Ron|Paul, Paul|Allen, \n",
|
||||
" Rand|Paul, Ayn|Rand, Paul|Ryan, Jack|Ryan, Debby|Ryan, Paul|Simon, Carly|Simon, John|Kelly, \n",
|
||||
" Megyn|Kelly, John|Henry, Grace|Kelly, Grace|Jones, Grace|Hopper, Jack|Ma, Ma|Bell, Yo-Yo|Ma, \n",
|
||||
" Jack|Ruby, Jack|Russell, Marilyn|Manson, Marilyn|Monroe, James|Monroe, George|Bush, \n",
|
||||
" George|Clinton, Bill|Clinton, Jack|White, Meg|Ryan, Meg|White, Barry|White, Walter|White, \n",
|
||||
" Betty|White, Charlie|Parker, Tommy|John, John|Kerry, Kerry|Washington, Jimmy|John, \n",
|
||||
" John|Adams, Amy|Adams, Aimee|Man, Benjamin|Harrison, Benjamin|Franklin, Aretha|Franklin, \n",
|
||||
" Franklin|Graham, James|Garfield, Garfield|, Kristen|Bell, Kristen|Stewart, Martha|Stewart, \n",
|
||||
" Martha|Washington, Wsshington|Irving, John|Irving, Jimmy|Buffett, Jimmy|Jones, Warren|Buffett, \n",
|
||||
" Elizabeth|Warren, Betty|Ford, Henry|Ford, Harrison|Ford, Kevin|Bacon, Kevin|Kline, Kevin|Love, \n",
|
||||
" Kevin|Smith, Kevin|Costner, Will|Smith, Tommy|Lee, Robert-E|Lee, John|Wayne, Wayne|Newton, \n",
|
||||
" Wayne|Knight, Wayne|Howard, Wayne|Brady, Tom|Brady, James|Brady, Cam|Newton, Cameron|Diaz,\n",
|
||||
" James|Cameron, Etta|James, John|Oliver, John|Candy, John|Edward, John|Edwards, John|Lewis,\n",
|
||||
" Huey|Lewis, Huey|Newton, Huey|Long, Long|John-Silver, Prince|, Prince|Harry, Harry|Potter,\n",
|
||||
" Harry|Truman, Little|Prince, Stuart|Little, Little|Richard, Rich|Little, Chris|Pratt,\n",
|
||||
" Chris|Evans, Bob|Evans, Tommy|Lee-Jones, Super|Grover\n",
|
||||
" \"\"\")\n",
|
||||
"\n",
|
||||
"def synonyms(text): return [set(group.split('=')) for group in split(text)]\n",
|
||||
"\n",
|
||||
"match_groups = synonyms(\"\"\"\n",
|
||||
" Charlie=Charles, Newton=Newton-John, Sean=Shawn, James=James-Earl=Jimmy, Man=Mann, Amy=Aimee,\n",
|
||||
" Jack=John=John-Silver, Tom=Tommy, Will=William, Robert-E=Robert=Bob, Cam=Cameron, Oliver=Olivia,\n",
|
||||
" Edward=Edwards, Rich=Richard, Lee=Lee-Jones, Jones=Lee-Jones\n",
|
||||
" \"\"\")\n",
|
||||
"\n",
|
||||
"def legal_match(value, nbrval):\n",
|
||||
" \"Does this value match the neighbor's value?\"\n",
|
||||
" return (nbrval in (empty, border, value) or \n",
|
||||
" any(value in group and nbrval in group\n",
|
||||
" for group in match_groups))\n",
|
||||
"\n",
|
||||
"def best_dominoes(tiles, n=24, figsize=16, verbose=True, repeat=300):\n",
|
||||
" board = max((dominoes(tiles, n) for _ in range(repeat)), \n",
|
||||
" key=lambda board: len(board.boxes))\n",
|
||||
" if verbose:\n",
|
||||
" print(len(board.boxes), '/', len(tiles), 'tiles placed')\n",
|
||||
" plot_board(board, figsize)\n",
|
||||
" return board"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"84 / 100 tiles placed\n"
|
||||
"110 / 126 tiles placed\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"data": {
|
||||
"image/png": "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 truncated
|
||||
"image/png": "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 truncated
|
||||
"text/plain": [
|
||||
"<matplotlib.figure.Figure at 0x11342c940>"
|
||||
"<matplotlib.figure.Figure at 0x11af01320>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
@@ -354,7 +385,7 @@
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"best_dominoes(names2);"
|
||||
"best_dominoes(tiles2);"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user