{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "I would like to highly recommend this Board Game \"Penguins on Ice\" for kids and parents - this was a gift from my aunt: \n",
    "\n",
    "http://www.toysrus.com/buy/educational/penguins-on-ice-sg155us-44233536"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Quoting the site:\n",
    "\"From SmartGames, the worldwide leader in single player puzzle games, comes Penguins on Ice. Penguins on Ice is an award-winning, completely unique game based on ancient Greek Pentomino...featuring puzzle pieces that shift in order to fit into place! Arrange the sliding ice blocks so that they all fit on the game board while making sure that the five penguins are in the right spots as shown in the included challenge booklet. With simple challenges for beginners to complex puzzles that will test experienced players, Penguins on Ice is a fun way to develop logical thinking skills and spatial reasoning abilities.\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![Penguins on Ice](http://www.toysrus.com/graphics/product_images/pTRU1-19340859dt.jpg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This games takes its origins from Pentominoes coined by Solomon W. Golomb in 1953. Pentominoes are 5-square figures, resulting in 15 different shapes:\n",
    "\n",
    "![All Pentominoes](https://upload.wikimedia.org/wikipedia/commons/thumb/6/69/Pentomino_Naming_Conventions.svg/300px-Pentomino_Naming_Conventions.svg.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "These shapes can tile 2D plane in various ways:\n",
    "    \n",
    "![Tiling with Pentominoes](https://upload.wikimedia.org/wikipedia/commons/thumb/0/09/Pentomino_Puzzle_Solutions.svg/400px-Pentomino_Puzzle_Solutions.svg.png)\n",
    "\n",
    "**Now back to pengiuns!!!**"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "from IPython.display import YouTubeVideo"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "        <iframe\n",
       "            width=\"400\"\n",
       "            height=\"300\"\n",
       "            src=\"https://www.youtube.com/embed/WKKy7x1gRzc\"\n",
       "            frameborder=\"0\"\n",
       "            allowfullscreen\n",
       "        ></iframe>\n",
       "        "
      ],
      "text/plain": [
       "<IPython.lib.display.YouTubeVideo at 0x7f9660135780>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "YouTubeVideo(\"WKKy7x1gRzc\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's try to solve this board game using Python and numpy arrays!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#check python version\n",
    "\n",
    "import sys\n",
    "if sys.version_info < (3,0):\n",
    "    PY3=False\n",
    "    if sys.version_info >= (2,7):\n",
    "        raise Exception('not supported Python runtime {}'.format(sys.version_info))\n",
    "else:\n",
    "    PY3=True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "if not PY3:\n",
    "    from __future import print_function, unicode_literals, absolute_imports"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  0.],\n",
       "       [ 0.,  0.,  0.,  0.,  0.]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#setup the board\n",
    "\n",
    "b=np.zeros([5,5])\n",
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[16  1  0  0  0]\n",
      " [ 0  1  1  1  0]]\n",
      "5\n",
      "[[ 0 16  1  0  0]\n",
      " [ 0  1  1  1  0]]\n",
      "5\n",
      "[[ 0  0 16  1  0]\n",
      " [ 0  1  1  1  0]]\n",
      "5\n",
      "[[ 0  0  0 16  1]\n",
      " [ 0  1  1  1  0]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "#setup all 5 pieces and possible configurations\n",
    "\n",
    "## 16 = penguin cell on piece\n",
    "## 1  = ice cell on piece\n",
    "## 0  = empty\n",
    "\n",
    "p1=[np.array([[16,1,0,0,0],\n",
    "              [0,1,1,1,0]]),\n",
    "    np.array([[0,16,1,0,0],\n",
    "              [0,1,1,1,0]]),\n",
    "    np.array([[0,0,16,1,0],\n",
    "              [0,1,1,1,0]]),\n",
    "    np.array([[0,0,0,16,1],\n",
    "              [0,1,1,1,0]])]\n",
    "for p in p1:\n",
    "    print(p)\n",
    "    print(p[p>0].size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[16  1  0  0]\n",
      " [ 0  1  1  0]\n",
      " [ 0  1  0  0]]\n",
      "5\n",
      "[[ 0 16  1  0]\n",
      " [ 0  1  1  0]\n",
      " [ 0  1  0  0]]\n",
      "5\n",
      "[[ 0  0 16  1]\n",
      " [ 0  1  1  0]\n",
      " [ 0  1  0  0]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "p2=[np.array([[16,1,0,0],\n",
    "              [0,1,1,0],\n",
    "              [0,1,0,0]]),\n",
    "    np.array([[0,16,1,0],\n",
    "              [0,1,1,0],\n",
    "              [0,1,0,0]]),\n",
    "    np.array([[0,0,16,1],\n",
    "              [0,1,1,0],\n",
    "              [0,1,0,0]])]\n",
    "for p in p2:\n",
    "    print(p)\n",
    "    print(p[p>0].size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0 16  0  0]\n",
      " [ 0  1  1  0]\n",
      " [ 1  1  0  0]]\n",
      "5\n",
      "[[ 0 16  0  0]\n",
      " [ 0  1  1  0]\n",
      " [ 0  1  1  0]]\n",
      "5\n",
      "[[ 0 16  0  0]\n",
      " [ 0  1  1  0]\n",
      " [ 0  0  1  1]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "p3=[np.array([[0,16,0,0],\n",
    "              [0,1,1,0],\n",
    "              [1,1,0,0]]),\n",
    "    np.array([[0,16,0,0],\n",
    "              [0,1,1,0],\n",
    "              [0,1,1,0]]),\n",
    "    np.array([[0,16,0,0],\n",
    "              [0,1,1,0],\n",
    "              [0,0,1,1]])]\n",
    "for p in p3:\n",
    "    print(p)\n",
    "    print(p[p>0].size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[16  0  0  0]\n",
      " [ 1  1  1  1]]\n",
      "5\n",
      "[[ 0 16  0  0]\n",
      " [ 1  1  1  1]]\n",
      "5\n",
      "[[ 0  0 16  0]\n",
      " [ 1  1  1  1]]\n",
      "5\n",
      "[[ 0  0  0 16]\n",
      " [ 1  1  1  1]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "p4=[np.array([[16,0,0,0],\n",
    "              [1,1,1,1]]),\n",
    "    np.array([[0,16,0,0],\n",
    "              [1,1,1,1]]),\n",
    "    np.array([[0,0,16,0],\n",
    "              [1,1,1,1]]),\n",
    "    np.array([[0,0,0,16],\n",
    "              [1,1,1,1]])]\n",
    "for p in p4:\n",
    "    print(p)\n",
    "    print(p[p>0].size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 1  1 16]\n",
      " [ 1  0  0]\n",
      " [ 1  0  0]]\n",
      "5\n",
      "[[ 1  1 16]\n",
      " [ 0  1  0]\n",
      " [ 0  1  0]]\n",
      "5\n",
      "[[ 1  1 16]\n",
      " [ 0  0  1]\n",
      " [ 0  0  1]]\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "p5=[np.array([[1,1,16],\n",
    "              [1,0,0],\n",
    "              [1,0,0]]),\n",
    "    np.array([[1,1,16],\n",
    "              [0,1,0],\n",
    "              [0,1,0]]),\n",
    "    np.array([[1,1,16],\n",
    "              [0,0,1],\n",
    "              [0,0,1]])]\n",
    "for p in p5:\n",
    "    print(p)\n",
    "    print(p[p>0].size)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[16  1  0  0]\n",
      " [ 0  1  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [ 0  1]\n",
      " [ 1  1]\n",
      " [16  0]]\n",
      "\n",
      "[[ 0 16]\n",
      " [ 1  1]\n",
      " [ 1  0]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  1  0]\n",
      " [ 0  0  1 16]]\n",
      "\n",
      "[[16  1  0]\n",
      " [ 1  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [ 1  1]\n",
      " [16  1]]\n",
      "\n",
      "[[ 1 16]\n",
      " [ 1  1]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  1]\n",
      " [ 0  1 16]]\n",
      "\n",
      "[[ 0 16  1]\n",
      " [ 1  1  1]]\n",
      "\n",
      "[[ 1  1]\n",
      " [16  1]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 1  0]\n",
      " [ 1 16]\n",
      " [ 1  1]]\n",
      "\n",
      "[[ 1  1  1]\n",
      " [ 1 16  0]]\n",
      "\n",
      "[[ 0  0 16  1]\n",
      " [ 1  1  1  0]]\n",
      "\n",
      "[[ 1  0]\n",
      " [16  1]\n",
      " [ 0  1]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 1  0]\n",
      " [ 1  0]\n",
      " [ 1 16]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 0  1  1  1]\n",
      " [ 1 16  0  0]]\n",
      "\n",
      "[[16  1  0]\n",
      " [ 0  1  1]\n",
      " [ 0  1  0]]\n",
      "\n",
      "[[ 0  1  0]\n",
      " [ 1  1  1]\n",
      " [16  0  0]]\n",
      "\n",
      "[[ 0  0 16]\n",
      " [ 1  1  1]\n",
      " [ 0  1  0]]\n",
      "\n",
      "[[ 0  1  0]\n",
      " [ 1  1  0]\n",
      " [ 0  1 16]]\n",
      "\n",
      "[[16  1]\n",
      " [ 1  1]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  0]\n",
      " [16  1  1]]\n",
      "\n",
      "[[ 1  1 16]\n",
      " [ 0  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [ 1  1]\n",
      " [ 1 16]]\n",
      "\n",
      "[[ 0 16  1]\n",
      " [ 1  1  0]\n",
      " [ 1  0  0]]\n",
      "\n",
      "[[ 1  0  0]\n",
      " [16  1  0]\n",
      " [ 0  1  1]]\n",
      "\n",
      "[[ 1  1  0]\n",
      " [ 0  1 16]\n",
      " [ 0  0  1]]\n",
      "\n",
      "[[ 0  0  1]\n",
      " [ 0  1  1]\n",
      " [ 1 16  0]]\n",
      "\n",
      "[[ 0 16  0]\n",
      " [ 0  1  1]\n",
      " [ 1  1  0]]\n",
      "\n",
      "[[ 0  1  0]\n",
      " [16  1  1]\n",
      " [ 0  0  1]]\n",
      "\n",
      "[[ 1  0  0]\n",
      " [ 1  1 16]\n",
      " [ 0  1  0]]\n",
      "\n",
      "[[ 0  1  1]\n",
      " [ 1  1  0]\n",
      " [ 0 16  0]]\n",
      "\n",
      "[[16  0]\n",
      " [ 1  1]\n",
      " [ 1  1]]\n",
      "\n",
      "[[ 0  1  1]\n",
      " [16  1  1]]\n",
      "\n",
      "[[ 1  1 16]\n",
      " [ 1  1  0]]\n",
      "\n",
      "[[ 1  1]\n",
      " [ 1  1]\n",
      " [ 0 16]]\n",
      "\n",
      "[[16  0  0]\n",
      " [ 1  1  0]\n",
      " [ 0  1  1]]\n",
      "\n",
      "[[ 0  0  1]\n",
      " [ 0  1  1]\n",
      " [16  1  0]]\n",
      "\n",
      "[[ 0  1 16]\n",
      " [ 1  1  0]\n",
      " [ 1  0  0]]\n",
      "\n",
      "[[ 1  1  0]\n",
      " [ 0  1  1]\n",
      " [ 0  0 16]]\n",
      "\n",
      "[[16  0  0  0]\n",
      " [ 1  1  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [ 0  1]\n",
      " [ 0  1]\n",
      " [16  1]]\n",
      "\n",
      "[[ 1 16]\n",
      " [ 1  0]\n",
      " [ 1  0]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  1  1]\n",
      " [ 0  0  0 16]]\n",
      "\n",
      "[[ 0 16  0  0]\n",
      " [ 1  1  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [ 0  1]\n",
      " [16  1]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 1  0]\n",
      " [ 1 16]\n",
      " [ 1  0]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  1  1]\n",
      " [ 0  0 16  0]]\n",
      "\n",
      "[[ 0  0 16  0]\n",
      " [ 1  1  1  1]]\n",
      "\n",
      "[[ 0  1]\n",
      " [16  1]\n",
      " [ 0  1]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 1  0]\n",
      " [ 1  0]\n",
      " [ 1 16]\n",
      " [ 1  0]]\n",
      "\n",
      "[[ 1  1  1  1]\n",
      " [ 0 16  0  0]]\n",
      "\n",
      "[[ 0  0  0 16]\n",
      " [ 1  1  1  1]]\n",
      "\n",
      "[[16  1]\n",
      " [ 0  1]\n",
      " [ 0  1]\n",
      " [ 0  1]]\n",
      "\n",
      "[[ 1  0]\n",
      " [ 1  0]\n",
      " [ 1  0]\n",
      " [ 1 16]]\n",
      "\n",
      "[[ 1  1  1  1]\n",
      " [16  0  0  0]]\n",
      "\n",
      "[[ 1  1 16]\n",
      " [ 1  0  0]\n",
      " [ 1  0  0]]\n",
      "\n",
      "[[16  0  0]\n",
      " [ 1  0  0]\n",
      " [ 1  1  1]]\n",
      "\n",
      "[[ 1  1  1]\n",
      " [ 0  0  1]\n",
      " [ 0  0 16]]\n",
      "\n",
      "[[ 0  0  1]\n",
      " [ 0  0  1]\n",
      " [16  1  1]]\n",
      "\n",
      "[[ 1  1 16]\n",
      " [ 0  1  0]\n",
      " [ 0  1  0]]\n",
      "\n",
      "[[16  0  0]\n",
      " [ 1  1  1]\n",
      " [ 1  0  0]]\n",
      "\n",
      "[[ 0  0  1]\n",
      " [ 1  1  1]\n",
      " [ 0  0 16]]\n",
      "\n",
      "[[ 0  1  0]\n",
      " [ 0  1  0]\n",
      " [16  1  1]]\n",
      "\n",
      "[[ 1  1 16]\n",
      " [ 0  0  1]\n",
      " [ 0  0  1]]\n",
      "\n",
      "[[16  1  1]\n",
      " [ 1  0  0]\n",
      " [ 1  0  0]]\n",
      "\n",
      "[[ 0  0  1]\n",
      " [ 0  0  1]\n",
      " [ 1  1 16]]\n",
      "\n",
      "[[ 1  0  0]\n",
      " [ 1  0  0]\n",
      " [16  1  1]]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# for all pieces look at all possible rotations!\n",
    "\n",
    "for p in [p1,p2,p3,p4,p5]:\n",
    "    for piece in p:\n",
    "        for rot in range(4):\n",
    "            piece=piece[~np.all(piece == 0, axis=1)]\n",
    "            piece=piece.T[~np.all(piece == 0, axis=0)].T\n",
    "            piece=np.rot90(piece,rot)\n",
    "            print(piece)\n",
    "            print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# set piece on the board based on location, rotation, and condition\n",
    "\n",
    "def set_piece(board,piece,loc=(0,0),rot=0,condition=None):\n",
    "    \n",
    "    #cleanup horizontal and vertical lines with all zeros\n",
    "    piece=piece[~np.all(piece == 0, axis=1)]\n",
    "    piece=piece.T[~np.all(piece == 0, axis=0)].T\n",
    "    \n",
    "    # piece can be rotated in 4 positions\n",
    "    piece=np.rot90(piece,rot)\n",
    "    a,b=piece.shape\n",
    "    if ((a+loc[0]<=board.shape[0]) #piece within board bounds\n",
    "      and\n",
    "      (b+loc[1]<=board.shape[1])):\n",
    "        board[loc[0]:a+loc[0],loc[1]:b+loc[1]]+=piece #set piece\n",
    "        if ((board[board==2].size>0) # overlap type #1\n",
    "          or\n",
    "          (board[board==17].size>0) # overlap type #2\n",
    "          or\n",
    "          (board[board==32].size>0) # overlap type #3\n",
    "          or\n",
    "          ((not condition is None) and \n",
    "          (board[(board==1) & condition].size>0))): # game positions\n",
    "            board[loc[0]:a+loc[0],loc[1]:b+loc[1]]-=piece #rollback if bad\n",
    "            return False \n",
    "        else:    \n",
    "            return True\n",
    "    else:\n",
    "        return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0 0 0\n",
      "0 0 0 1\n",
      "0 0 0 2\n",
      "0 0 1 0\n",
      "0 0 1 1\n",
      "0 0 1 2\n",
      "0 0 2 0\n",
      "0 0 2 1\n",
      "0 0 2 2\n",
      "0 0 3 0\n",
      "0 0 3 1\n",
      "0 0 3 2\n",
      "0 1 0 0\n",
      "0 1 0 1\n",
      "0 1 0 2\n",
      "0 1 1 0\n",
      "0 1 1 1\n"
     ]
    }
   ],
   "source": [
    "#set empty board and empty condition\n",
    "b=np.zeros([5,5])\n",
    "condition=np.zeros([5, 5], dtype=bool)\n",
    "\n",
    "#problem #28\n",
    "#condition[1,0]=True\n",
    "#condition[2,0]=True\n",
    "#condition[2,2]=True\n",
    "#condition[0,3]=True\n",
    "#condition[2,3]=True\n",
    "\n",
    "#problem #30\n",
    "#condition[2,0]=True\n",
    "#condition[1,2]=True\n",
    "#condition[3,2]=True\n",
    "#condition[0,4]=True\n",
    "#condition[4,4]=True\n",
    "\n",
    "#problem #44\n",
    "#condition[1,0]=True\n",
    "#condition[1,2]=True\n",
    "#condition[3,2]=True\n",
    "#condition[2,4]=True\n",
    "#condition[3,4]=True\n",
    "\n",
    "#problem #58\n",
    "condition[1,1]=True\n",
    "condition[2,1]=True\n",
    "condition[2,2]=True\n",
    "condition[3,3]=True\n",
    "\n",
    "#problem #59\n",
    "# condition[1,0]=True\n",
    "# condition[2,0]=True\n",
    "# condition[0,3]=True\n",
    "# condition[1,3]=True\n",
    "\n",
    "#basic testing, set second piece on board based on condition\n",
    "from itertools import product\n",
    "for i,j,r,e in product(range(4),range(4),range(4),range(len(p2))):\n",
    "    print(i,j,r,e)\n",
    "    if set_piece(b,p2[e],loc=(i,j),rot=r,condition=condition):\n",
    "        #print i,j,t,r,e\n",
    "        break"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[  0.,   1.,   1.,   0.,   0.],\n",
       "       [  0.,  16.,   1.,   1.,   0.],\n",
       "       [  0.,   0.,   0.,   0.,   0.],\n",
       "       [  0.,   0.,   0.,   0.,   0.],\n",
       "       [  0.,   0.,   0.,   0.,   0.]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([ 16.,   0.,   0.,   0.])"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# list all cells with penguin locations, whether set or not\n",
    "b[condition]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[False, False, False, False, False],\n",
       "       [False,  True, False, False, False],\n",
       "       [False,  True,  True, False, False],\n",
       "       [False, False, False,  True, False],\n",
       "       [False, False, False, False, False]], dtype=bool)"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "condition"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "solved 5\n",
      "CPU times: user 4.7 s, sys: 15.7 ms, total: 4.71 s\n",
      "Wall time: 4.67 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "\n",
    "#main algorithm for backtracking solver\n",
    "\n",
    "b=np.zeros([5,5])\n",
    "\n",
    "#paths visited in tree\n",
    "paths=[{},{},{},{},{}]\n",
    "solved=False\n",
    "\n",
    "#sequence of pieces to set\n",
    "pieces=[p5,p4,p3,p2,p1]\n",
    "\n",
    "#path depth\n",
    "pn=0\n",
    "\n",
    "#sequence of board positions\n",
    "bhist=[b.copy()]\n",
    "\n",
    "#set of pieces set on board\n",
    "phist=[]\n",
    "\n",
    "\n",
    "#iterate until solved or exhausted all options\n",
    "while not solved:\n",
    "    p=pieces.pop()\n",
    "    level_set=False\n",
    "    \n",
    "    #try all locations, rotations, and piece configurations\n",
    "    for i,j,r,e in product(range(4),range(4),\n",
    "                             range(4),\n",
    "                             range(len(p))):\n",
    "        if (i,j,r,e) in paths[pn]:\n",
    "            pass #print(\"skip: \", (pn,i,j,r,e))\n",
    "        else:\n",
    "            if set_piece(b,p[e],loc=(i,j),rot=r,condition=condition):\n",
    "                # if piece is placed on board correcly,\n",
    "                # then record this and move on\n",
    "                paths[pn][i,j,r,e]=True\n",
    "                level_set=True\n",
    "                #print pn,i,j,t,r,e\n",
    "                pn+=1\n",
    "                phist.append(p)\n",
    "                bhist.append(b.copy())\n",
    "                if len(pieces)==0:\n",
    "                    print(\"solved\", pn)\n",
    "                    solved=True\n",
    "                break\n",
    "    if not level_set:\n",
    "        # if failed to place the piece on board,\n",
    "        # then backtrack one piece back in history\n",
    "        # clean paths visited up to this level\n",
    "        paths[pn:]=[{} for i in range(pn,len(paths))]\n",
    "        pn-=1\n",
    "        #print(pn, \"backtrack\")#, len(pieces)\n",
    "        if pn<0:\n",
    "            print(\"something wrong\")\n",
    "            break\n",
    "        pieces.append(phist.pop())\n",
    "        pieces.append(p) \n",
    "        b=bhist.pop()\n",
    "        b=bhist[-1].copy()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# no pieces left\n",
    "pieces"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[{(0, 0, 2, 0): True,\n",
       "  (0, 1, 1, 0): True,\n",
       "  (0, 1, 1, 1): True,\n",
       "  (0, 1, 3, 1): True},\n",
       " {(2, 0, 0, 0): True},\n",
       " {(0, 2, 2, 0): True, (0, 3, 1, 0): True},\n",
       " {(3, 2, 0, 2): True},\n",
       " {(0, 0, 3, 1): True}]"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# paths tried on last leaves of tree\n",
    "\n",
    "paths"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.]\n",
      " [ 0.  0.  0.  0.  0.]]\n",
      "\n",
      "[[  0.   1.   1.  16.   0.]\n",
      " [  0.   0.   1.   1.   0.]\n",
      " [  0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.]\n",
      " [  0.   0.   0.   0.   0.]]\n",
      "\n",
      "[[  0.   1.   1.  16.   0.]\n",
      " [  0.   0.   1.   1.   0.]\n",
      " [  0.  16.   0.   0.   0.]\n",
      " [  0.   1.   1.   0.   0.]\n",
      " [  1.   1.   0.   0.   0.]]\n",
      "\n",
      "[[  0.   1.   1.  16.   1.]\n",
      " [  0.   0.   1.   1.   1.]\n",
      " [  0.  16.  16.   1.   1.]\n",
      " [  0.   1.   1.   0.   0.]\n",
      " [  1.   1.   0.   0.   0.]]\n",
      "\n",
      "[[  0.   1.   1.  16.   1.]\n",
      " [  0.   0.   1.   1.   1.]\n",
      " [  0.  16.  16.   1.   1.]\n",
      " [  0.   1.   1.  16.   1.]\n",
      " [  1.   1.   1.   1.   1.]]\n",
      "\n",
      "[[  1.   1.   1.  16.   1.]\n",
      " [  1.  16.   1.   1.   1.]\n",
      " [  1.  16.  16.   1.   1.]\n",
      " [  1.   1.   1.  16.   1.]\n",
      " [  1.   1.   1.   1.   1.]]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# sequence of setting pieces on the board starting from piece #1 (p1)\n",
    "\n",
    "for bi in bhist:\n",
    "    print(bi)\n",
    "    print()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(108, 5, 5)\n",
      "(128, 5, 5)\n",
      "(120, 5, 5)\n",
      "(120, 5, 5)\n",
      "(160, 5, 5)\n"
     ]
    }
   ],
   "source": [
    "# Setup all possible numpy arrays with board positions with only one piece on board\n",
    "\n",
    "b=np.zeros([5,5])\n",
    "pnpl=[]\n",
    "for pi,p in enumerate([p5,p4,p3,p2,p1]):\n",
    "    plist=[]\n",
    "    for i,j,r,e in product(range(4),range(4),\n",
    "                                 range(4),\n",
    "                                 range(len(p))):\n",
    "                b0=b.copy()\n",
    "                if set_piece(b0,p[e],loc=(i,j),rot=r):\n",
    "                    plist.append(b0)\n",
    "    pnpl.append(np.array(plist))\n",
    "    print(pnpl[-1].shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(4400, 5, 5)\n",
      "CPU times: user 177 ms, sys: 3.89 ms, total: 181 ms\n",
      "Wall time: 181 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Find all board positions with pieces #1 and #2 on board without conflicts\n",
    "b12=[]\n",
    "for b1,b2 in product(pnpl[0],pnpl[1]):\n",
    "    board=b1+b2\n",
    "    if (board[(board==1) | (board==16)].size==10):\n",
    "        b12.append(board)\n",
    "b12=np.array(b12)\n",
    "print(b12.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(61056, 5, 5)\n",
      "CPU times: user 24.4 s, sys: 19.4 ms, total: 24.4 s\n",
      "Wall time: 24.4 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Find all board positions with pieces #3, #4 and #5 on board without conflicts\n",
    "b345=[]\n",
    "for b3,b4,b5 in product(pnpl[2],pnpl[3],pnpl[4]):\n",
    "    board=b3+b4+b5\n",
    "    if (board[(board==1) | (board==16)].size==15):\n",
    "        b345.append(board)\n",
    "b345=np.array(b345)\n",
    "print(b345.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(48568, 5, 5)\n",
      "CPU times: user 1min 15s, sys: 11.8 ms, total: 1min 15s\n",
      "Wall time: 1min 15s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Find all board positions with pieces #2, #3, #4 and #5 on board without conflicts\n",
    "b2345=[]\n",
    "for bi,bj in product(pnpl[1],b345):\n",
    "    board=bi+bj\n",
    "    if (board[(board==1) | (board==16)].size==20):\n",
    "        b2345.append(board)\n",
    "b2345=np.array(b2345)\n",
    "print(b2345.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(296, 5, 5)\n",
      "CPU times: user 50.7 s, sys: 32 ms, total: 50.8 s\n",
      "Wall time: 50.8 s\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "# Find all board positions with all pieces on board without conflicts\n",
    "ball=[]\n",
    "for bi,bj in product(pnpl[0],b2345):\n",
    "    board=bi+bj\n",
    "    if (board[(board==1) | (board==16)].size==25):\n",
    "        ball.append(board)\n",
    "ball=np.array(ball)\n",
    "print(ball.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(296,)"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "ball[:,0,0].shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False,  True,  True, False,\n",
       "       False, False, False, False, False, False, False,  True,  True,\n",
       "        True,  True, False, False, False, False, False, False, False,\n",
       "       False, False,  True, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False, False,\n",
       "       False, False, False, False, False, False, False, False], dtype=bool)"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "(ball[:,0,0]==16) & (ball[:,1,1]==16)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0 0 2\n",
      "0 2 0 0\n",
      "0 3 1 2\n",
      "0 4 2 4\n",
      "1 0 2 1\n",
      "1 2 0 3\n",
      "2 0 4 0\n",
      "2 1 1 0\n",
      "2 3 3 4\n",
      "2 4 0 4\n",
      "3 2 4 1\n",
      "3 4 2 3\n",
      "4 0 2 0\n",
      "4 1 3 2\n",
      "4 2 4 4\n",
      "4 4 4 2\n"
     ]
    }
   ],
   "source": [
    "#find all unique board positions, contrained by 2 pieces only!\n",
    "\n",
    "for a,b in product(range(5),range(5)):\n",
    "    for i,j in product(range(5),range(5)):\n",
    "        if abs(a-i)+abs(b-j)<2:\n",
    "            pass\n",
    "        else:\n",
    "            ix1=ball[:,a,b]==16\n",
    "            ix2=ball[:,i,j]==16\n",
    "            if ball[ix1 & ix2].size==25:\n",
    "                print(a,b,i,j)\n",
    "                #print(ball[ix1 & ix2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 0 1 3 4 1\n",
      "0 0 1 4 4 3\n",
      "0 0 4 1 1 3\n",
      "0 0 4 3 1 4\n",
      "0 1 1 4 4 0\n",
      "0 1 1 4 4 2\n",
      "0 1 2 4 3 0\n",
      "0 1 2 4 4 1\n",
      "0 1 2 4 4 2\n",
      "0 1 3 0 2 4\n",
      "0 1 3 0 4 4\n",
      "0 1 4 0 1 4\n",
      "0 1 4 1 2 4\n",
      "0 1 4 2 1 4\n",
      "0 1 4 2 2 4\n",
      "0 1 4 4 3 0\n",
      "0 2 2 0 4 3\n",
      "0 2 2 4 3 0\n",
      "0 2 3 0 2 4\n",
      "0 2 3 0 3 4\n",
      "0 2 3 0 4 3\n",
      "0 2 3 4 3 0\n",
      "0 2 4 3 2 0\n",
      "0 2 4 3 3 0\n",
      "0 3 2 0 4 3\n",
      "0 3 3 1 4 4\n",
      "0 3 4 3 2 0\n",
      "0 3 4 4 3 1\n",
      "0 4 1 0 3 3\n",
      "0 4 3 0 4 3\n",
      "0 4 3 3 1 0\n",
      "0 4 4 3 3 0\n",
      "1 0 0 4 3 3\n",
      "1 0 1 4 4 2\n",
      "1 0 3 3 0 4\n",
      "1 0 4 2 1 4\n",
      "1 1 3 4 4 0\n",
      "1 1 4 0 3 4\n",
      "1 3 0 0 4 1\n",
      "1 3 4 1 0 0\n",
      "1 4 0 0 4 3\n",
      "1 4 0 1 4 0\n",
      "1 4 0 1 4 2\n",
      "1 4 1 0 4 2\n",
      "1 4 2 0 4 2\n",
      "1 4 2 0 4 3\n",
      "1 4 4 0 0 1\n",
      "1 4 4 2 0 1\n",
      "1 4 4 2 1 0\n",
      "1 4 4 2 2 0\n",
      "1 4 4 3 0 0\n",
      "1 4 4 3 2 0\n",
      "2 0 0 2 4 3\n",
      "2 0 0 3 4 3\n",
      "2 0 1 4 4 2\n",
      "2 0 1 4 4 3\n",
      "2 0 4 2 1 4\n",
      "2 0 4 3 0 2\n",
      "2 0 4 3 0 3\n",
      "2 0 4 3 1 4\n",
      "2 4 0 1 3 0\n",
      "2 4 0 1 4 1\n",
      "2 4 0 1 4 2\n",
      "2 4 0 2 3 0\n",
      "2 4 3 0 0 1\n",
      "2 4 3 0 0 2\n",
      "2 4 4 1 0 1\n",
      "2 4 4 2 0 1\n",
      "3 0 0 1 2 4\n",
      "3 0 0 1 4 4\n",
      "3 0 0 2 2 4\n",
      "3 0 0 2 3 4\n",
      "3 0 0 2 4 3\n",
      "3 0 0 4 4 3\n",
      "3 0 2 4 0 1\n",
      "3 0 2 4 0 2\n",
      "3 0 3 4 0 2\n",
      "3 0 4 3 0 2\n",
      "3 0 4 3 0 4\n",
      "3 0 4 4 0 1\n",
      "3 1 0 3 4 4\n",
      "3 1 4 4 0 3\n",
      "3 3 0 4 1 0\n",
      "3 3 1 0 0 4\n",
      "3 4 0 2 3 0\n",
      "3 4 1 1 4 0\n",
      "3 4 3 0 0 2\n",
      "3 4 4 0 1 1\n",
      "4 0 0 1 1 4\n",
      "4 0 1 1 3 4\n",
      "4 0 1 4 0 1\n",
      "4 0 3 4 1 1\n",
      "4 1 0 0 1 3\n",
      "4 1 0 1 2 4\n",
      "4 1 1 3 0 0\n",
      "4 1 2 4 0 1\n",
      "4 2 0 1 1 4\n",
      "4 2 0 1 2 4\n",
      "4 2 1 0 1 4\n",
      "4 2 1 4 0 1\n",
      "4 2 1 4 1 0\n",
      "4 2 1 4 2 0\n",
      "4 2 2 0 1 4\n",
      "4 2 2 4 0 1\n",
      "4 3 0 0 1 4\n",
      "4 3 0 2 2 0\n",
      "4 3 0 2 3 0\n",
      "4 3 0 3 2 0\n",
      "4 3 0 4 3 0\n",
      "4 3 1 4 0 0\n",
      "4 3 1 4 2 0\n",
      "4 3 2 0 0 2\n",
      "4 3 2 0 0 3\n",
      "4 3 2 0 1 4\n",
      "4 3 3 0 0 2\n",
      "4 3 3 0 0 4\n",
      "4 4 0 1 3 0\n",
      "4 4 0 3 3 1\n",
      "4 4 3 0 0 1\n",
      "4 4 3 1 0 3\n"
     ]
    }
   ],
   "source": [
    "#find all unique board positions, contrained by 3 pieces only!\n",
    "\n",
    "d=4\n",
    "for k,l in product(range(5),range(5)):\n",
    "    for a,b in product(range(5),range(5)):\n",
    "        for i,j in product(range(5),range(5)):\n",
    "            if abs(a-i)+abs(b-j)<d:\n",
    "                pass\n",
    "            elif abs(a-k)+abs(b-l)<d:\n",
    "                pass\n",
    "            elif abs(i-k)+abs(j-l)<d:\n",
    "                pass\n",
    "            else:\n",
    "                ix1=ball[:,a,b]==16\n",
    "                ix2=ball[:,i,j]==16\n",
    "                ix3=ball[:,k,l]==16\n",
    "                if ball[ix1 & ix2 & ix3].size==25:\n",
    "                    print(k,l,a,b,i,j)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "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.4.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}