diff --git a/.ipynb_checkpoints/Solving a Sudoku with AI - Lessons Problem-checkpoint.ipynb b/.ipynb_checkpoints/Solving a Sudoku with AI - Lessons Problem-checkpoint.ipynb new file mode 100644 index 0000000..abe5a15 --- /dev/null +++ b/.ipynb_checkpoints/Solving a Sudoku with AI - Lessons Problem-checkpoint.ipynb @@ -0,0 +1,1868 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Table of Content\n", + "\n", + "1. Intro\n", + "2. Solving a Sudoku\n", + "3. Setting up the Board\n", + "4. [Encoding the Board](#cell_encoding_the_board)\n", + "5. [Strategy1: Elimination](#cell_elimination)\n", + "6. [Strategy2: Only Choice](#cell_only_choice)\n", + "7. [Constraint Propagation](#cell_constraint_propagation)\n", + "8. [Harder Sudoku](#cell_harder_sudoku)\n", + "9. [Strategy3: Search](#cell_search)\n", + "\n", + "** Goals of this project **\n", + "\n", + "The main goal of this project is to build an intelligent agent that will solve every sudoku while introducing you to two powerful techniques that are used throughout the field of AI:\n", + "\n", + "** Constraint Propagation ** \n", + "\n", + "When trying to solve a problem, you'll find that there are some local constraints to each square. These constraints help you narrow the possibilities for the answer, which can be very helpful. We will learn to extract the maximum information out of these constraints in order to get closer to our solution. Additionally, you'll see how we can repeatedly apply simple constraints to iteratively narrow the search space of possible solutions. Constraint propagation can be used to solve a variety of problems such as calendar scheduling, and cryptographic puzzles.\n", + "\n", + "** Search **\n", + "\n", + "In the process of problem solving, we may get to the point where two or more possibilities are available. What do we do? What if we branch out and consider both of them? Maybe one of them will lead us to a position in which three or more possibilities are available. Then, we can branch out again. At the end, we can create a whole tree of possibilities and find ways to traverse the tree until we find our solution. This is an example of how search can be used.\n", + "These ideas may seem simple and they're actually intended to be! Through this lesson you'll see how AI is really composed of very simple ideas that can be put together to solve complex problems. Throughout this lesson, we challenge you to think of how you can apply these ideas to build AI agents to solve other puzzles and problems in your world!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Step1: Encoding the Sudoku Board " + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n" + ] + } + ], + "source": [ + "'''\n", + "Exercise1: Encoding the Board\n", + ">>> from utils import display\n", + ">>> display(grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'))\n", + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . .\n", + "'''\n", + "\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + " \n", + "\n", + "#2. function.py ----------------------------\n", + "'''\n", + "Instruction: create grid_values(grid) A function to convert the string representation \n", + "of a puzzle into a dictionary form.\n", + "'''\n", + "#2.1 grid_values function (input> strong of sudoku problem, output> dictionary of a suduku with corresponding boxes) \n", + "#from utils import * #remove this when use as a file\n", + "def grid_values(grid):\n", + " # In this function, you will take a sudoku as a string\n", + " # and return a dictionary where the keys are the boxes,\n", + " # for example 'A1', and the values are the digit at each\n", + " # box (as a string) or '.' if the box has no value\n", + " # assigned yet.\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " \n", + "#3. Test function.py ---------------------------- \n", + "# print(grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'))\n", + "\n", + "#4. Test utils.py ---------------------------- \n", + "display(grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Step2: Strategy1: Elimination\n", + "### If a box has a value assigned, then none of the peers of this box can have this value. \n", + "\n", + "#### 2.1 First things first, let's look at a box and analyze the values that could go in there.\n", + " \n", + "\n", + "#### 2.2 Elimination strategy\n", + "Now that we know how to eliminate values, we can take one pass, go over every box that has a value, and **eliminate the values that can't appear on the box, based on its peers**. Once we do so, the board looks like this \n", + "\n", + "\n", + "\n", + "** This seems like something we can code!** \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n" + ] + } + ], + "source": [ + "'''\n", + "Exercise2.1: Improved grid_values()\n", + "\n", + "As of now, we are recording the puzzles in dictionary form, where the keys are the boxes ('A1', 'A2', ... , 'I9') \n", + "and the values are either the value for each box (if a value exists) or '.' (if the box has no value assigned yet). \n", + "What we really want is for each value to represent all the available values for that box. \n", + "For example, the box in the second row and fifth column above will have key 'B5' and value '47' \n", + "(because 4 and 7 are the only possible values for it). The starting value for every empty box will thus be '123456789'.\n", + "Update the grid_values() function to return '123456789' instead of '.' for empty boxes.\n", + "\n", + ">>> from utils import display\n", + ">>> display(grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'))\n", + "123456789 123456789 3 |123456789 2 123456789 | 6 123456789 123456789 \n", + " 9 123456789 123456789 | 3 123456789 5 |123456789 123456789 1 \n", + "123456789 123456789 1 | 8 123456789 6 | 4 123456789 123456789 \n", + "------------------------------+------------------------------+------------------------------\n", + "123456789 123456789 8 | 1 123456789 2 | 9 123456789 123456789 \n", + " 7 123456789 123456789 |123456789 123456789 123456789 |123456789 123456789 8 \n", + "123456789 123456789 6 | 7 123456789 8 | 2 123456789 123456789 \n", + "------------------------------+------------------------------+------------------------------\n", + "123456789 123456789 2 | 6 123456789 9 | 5 123456789 123456789 \n", + " 8 123456789 123456789 | 2 123456789 3 |123456789 123456789 9 \n", + "123456789 123456789 5 |123456789 1 123456789 | 3 123456789 123456789 \n", + "'''\n", + "\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + " \n", + "#2. function.py ----------------------------\n", + "'''\n", + "Instruction : Update the grid_values() function to return '123456789' instead of '.' for empty boxes.\n", + "'''\n", + "# 2.1 improve grid_values(grid)\n", + "# from utils import *\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "#3. Test function.py ---------------------------- \n", + "display(grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'))" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n", + "\n", + "\n", + "After implement eliminate(values) method **********************************\n", + " 45 4578 3 | 49 2 147 | 6 5789 57 \n", + " 9 24678 47 | 3 47 5 | 78 278 1 \n", + " 25 257 1 | 8 79 6 | 4 23579 2357 \n", + "---------------------+---------------------+---------------------\n", + " 345 345 8 | 1 3456 2 | 9 34567 34567 \n", + " 7 123459 49 | 459 34569 4 | 1 356 8 \n", + " 1345 13459 6 | 7 359 8 | 2 345 345 \n", + "---------------------+---------------------+---------------------\n", + " 134 1347 2 | 6 478 9 | 5 1478 47 \n", + " 8 1467 47 | 2 457 3 | 7 146 9 \n", + " 46 4679 5 | 4 1 7 | 3 268 26 \n" + ] + } + ], + "source": [ + "'''\n", + "Exercise2.2: implement eliminate()\n", + "\n", + "Now, let's finish the code for the function eliminate(), which will take as input a puzzle in dictionary form. \n", + "The function will iterate over all the boxes in the puzzle that only have one value assigned to them, \n", + "and it will remove this value from every one of its peers.\n", + "\n", + "'''\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + "\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "#2. function.py ----------------------------\n", + "# 2.1 implement eliminate(values)\n", + "# from utils import *\n", + "def eliminate(values):\n", + " \"\"\"Eliminate values from peers of each box with a single value.\n", + "\n", + " Go through all the boxes, and whenever there is a box with a single value,\n", + " eliminate this value from the set of values of all its peers.\n", + "\n", + " Args:\n", + " values: Sudoku in dictionary form.\n", + " Returns:\n", + " Resulting Sudoku in dictionary form after eliminating values.\n", + " \"\"\"\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.':\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "#3. Test utils.py ---------------------------- \n", + "values = grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..')\n", + "print(\"The original Sudoku board is **********************************************\")\n", + "display(values)\n", + "\n", + "#4. Test function.py ---------------------------- \n", + "eliminate(values)\n", + "print(\"\\n\")\n", + "print(\"After implement eliminate(values) method **********************************\")\n", + "display(values)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "\n", + "## Step3: Only Choice\n", + "### Insight: Every unit must contain exactly one occurrence of every number \n", + "\n", + "#### 3.1 Look more carefully at the top 3x3 square in the center, highlighted in red.\n", + " \n", + "\n", + "#### 3.2 Only Choice Strategy\n", + " ** If there is only one box in a unit which would allow a certain digit, then that box must be assigned that digit. ** \n", + "\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . . |8 . 1 |. . . \n", + ". . . |. . . |4 3 . \n", + "5 . . |. . . |. . 3 \n", + "------+------+------\n", + ". . . |. 7 . |8 . . \n", + ". . 4 |. . . |1 . . \n", + ". 2 . |. 3 . |. . . \n", + "------+------+------\n", + "6 . . |. . . |. 7 5 \n", + ". . 3 |4 . . |. . . \n", + "1 . . |2 . . |6 . . \n", + "\n", + "\n", + "After implement eliminate(values) method **********************************\n", + " 23479 34679 2679 | 8 24569 1 | 2579 2569 2679 \n", + " 2789 16789 126789| 5679 2569 25679 | 4 3 126789\n", + " 5 146789 126789| 679 2469 24679 | 279 12689 3 \n", + "---------------------+---------------------+---------------------\n", + " 39 13569 1569 | 1569 7 24569 | 8 24569 2469 \n", + " 3789 356789 4 | 569 25689 25689 | 1 2569 2679 \n", + " 789 2 156789| 1569 3 45689 | 579 4569 4679 \n", + "---------------------+---------------------+---------------------\n", + " 6 489 289 | 139 189 389 | 239 7 5 \n", + " 2789 5789 3 | 4 15689 56789 | 29 1289 1289 \n", + " 1 45789 5789 | 2 589 35789 | 6 489 489 \n", + "\n", + "\n", + "After implement only_choice(values) method **********************************\n", + " 4 3 2679 | 8 24569 1 | 2579 2569 2679 \n", + " 2789 16789 126789| 5679 2569 25679 | 4 3 126789\n", + " 5 146789 126789| 679 2469 24679 | 279 12689 3 \n", + "---------------------+---------------------+---------------------\n", + " 39 13569 1569 | 1569 7 24569 | 8 24569 2469 \n", + " 3789 356789 4 | 569 25689 25689 | 1 2569 2679 \n", + " 789 2 156789| 1569 3 45689 | 579 4569 4679 \n", + "---------------------+---------------------+---------------------\n", + " 6 4 289 | 3 189 389 | 3 7 5 \n", + " 2789 5789 3 | 4 15689 7 | 29 1289 1289 \n", + " 1 45789 5789 | 2 589 3 | 6 489 489 \n", + "\n", + "\n" + ] + } + ], + "source": [ + "'''\n", + "Exercise3.1: implement only_choice()\n", + "Time to code it! In the next quiz, finish the code for the function only_choice, \n", + "which will take as input a puzzle in dictionary form. The function will go through all the units, \n", + "and if there is a unit with a digit that only fits in one possible box, it will assign that digit to that box.\n", + "'''\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + "\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "def eliminate(values):\n", + " \"\"\"Eliminate values from peers of each box with a single value.\n", + "\n", + " Go through all the boxes, and whenever there is a box with a single value,\n", + " eliminate this value from the set of values of all its peers.\n", + "\n", + " Args:\n", + " values: Sudoku in dictionary form.\n", + " Returns:\n", + " Resulting Sudoku in dictionary form after eliminating values.\n", + " \"\"\"\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "#2. function.py ----------------------------\n", + "# 2.1 implement only_choice(values)\n", + "# from utils import *\n", + "def only_choice(values):\n", + " \"\"\"Finalize all values that are the only choice for a unit.\n", + "\n", + " Go through all the units, and whenever there is a unit with a value\n", + " that only fits in one box, assign the value to this box.\n", + "\n", + " Input: Sudoku in dictionary form.\n", + " Output: Resulting Sudoku in dictionary form after filling in only choices.\n", + " \"\"\"\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + "#3. Test utils.py ---------------------------- \n", + "values = grid_values('...8.1.........43.5.......3....7.8....4...1...2..3....6......75..34.....1..2..6..')\n", + "print(\"The original Sudoku board is **********************************************\")\n", + "display(values)\n", + "eliminate(values)\n", + "print(\"\\n\")\n", + "print(\"After implement eliminate(values) method **********************************\")\n", + "display(values)\n", + "\n", + "#4. Test function.py ---------------------------- \n", + "new_values = only_choice(values)\n", + "print(\"\\n\")\n", + "print(\"After implement only_choice(values) method **********************************\")\n", + "display(new_values)\n", + "print(\"\\n\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Step4: Constraint Propagation\n", + "### using local constraints in a space to dramatically reduce the search space. \n", + "\n", + "#### 4.1 General explanation of constraint propagation\n", + "As we enforce each constraint, we see how it introduces new constraints for other parts of the board \n", + "that can help us further reduce the number of possibilities. \n", + "\n", + "##### 4.1.1 Map Coloring Example \n", + "##### No two adjacent items can be the same color in the map coloring problem. \n", + " \n", + "\n", + "In the map coloring problem, we must find a way to color the map such that no two adjacent items share the same color. Indeed, we'll see how we use constraint propagation to use this simple constraint to find a solution just as we use such constraints to solve Sudoku.\n", + "\n", + "##### 4.1.2 Crypto-Arithmetic Puzzles \n", + "##### what digits do T, W, O, F, U, and R represent? \n", + " \n", + "\n", + "In Crypto-Arithmetic puzzles, each letter represents a digit, and no two letters represent the same digit. None of the numbers start with a leading zero. Our goal is to find a mapping from letters to digits that satisfies the equations. Here again, we'll find that the constraints imposed by the equation allow us to create an intelligent algorithm to solve the problem via Constraint Propagation.\n", + "\n", + "#### 4.2 Applying Constraint Propagation to Sudoku\n", + " ** combine the functions eliminate() and only_choice() to write the function reduce_puzzle(), which receives as input an unsolved puzzle and applies our two constraints repeatedly in an attempt to solve it. ** \n", + "\n", + "** Some things to watch out for: **\n", + "\n", + "- The function needs to stop if the puzzle gets solved. How to do this?\n", + "- What if the function doesn't solve the sudoku? Can we make sure the function quits when applying the two strategies stops making progress?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n", + "\n", + "\n", + "After applying constrint propagaton (both eliminate and only_choice strategies)*****************\n", + "4 8 3 |9 2 1 |6 5 7 \n", + "9 6 7 |3 4 5 |8 2 1 \n", + "2 5 1 |8 7 6 |4 9 3 \n", + "------+------+------\n", + "5 4 8 |1 3 2 |9 7 6 \n", + "7 2 9 |5 6 4 |1 3 8 \n", + "1 3 6 |7 9 8 |2 4 5 \n", + "------+------+------\n", + "3 7 2 |6 8 9 |5 1 4 \n", + "8 1 4 |2 5 3 |7 6 9 \n", + "6 9 5 |4 1 7 |3 8 2 \n" + ] + } + ], + "source": [ + "'''\n", + "Exercise4.1: Apply Constraint Propagation to Sudoku problem\n", + "Now that you see how we apply Constraint Propagation to this problem, let's try to code it! \n", + "In the following quiz, combine the functions eliminate and only_choice to write the function reduce_puzzle, \n", + "which receives as input an unsolved puzzle and applies our two constraints repeatedly in an attempt to solve it.\n", + "\n", + "Some things to watch out for:\n", + "- The function needs to stop if the puzzle gets solved. How to do this?\n", + "- What if the function doesn't solve the sudoku? Can we make sure the function quits when applying \n", + "the two strategies stops making progress?\n", + "'''\n", + "\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + "\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + "\n", + "def eliminate(values):\n", + " \"\"\"Eliminate values from peers of each box with a single value.\n", + "\n", + " Go through all the boxes, and whenever there is a box with a single value,\n", + " eliminate this value from the set of values of all its peers.\n", + "\n", + " Args:\n", + " values: Sudoku in dictionary form.\n", + " Returns:\n", + " Resulting Sudoku in dictionary form after eliminating values.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", + " \n", + "\n", + "def only_choice(values):\n", + " \"\"\"Finalize all values that are the only choice for a unit.\n", + "\n", + " Go through all the units, and whenever there is a unit with a value\n", + " that only fits in one box, assign the value to this box.\n", + "\n", + " Input: Sudoku in dictionary form.\n", + " Output: Resulting Sudoku in dictionary form after filling in only choices.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", + "\n", + "#2. function.py ----------------------------\n", + "# 2.1 combine the functions eliminate and only_choice to write the function reduce_puzzle\n", + "# from utils import *\n", + "def reduce_puzzle(values):\n", + " \"\"\"\n", + " Iterate eliminate() and only_choice(). If at some point, there is a box with no available values, return False.\n", + " If the sudoku is solved, return the sudoku.\n", + " If after an iteration of both functions, the sudoku remains the same, return the sudoku.\n", + " Input: A sudoku in dictionary form.\n", + " Output: The resulting sudoku in dictionary form.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "\n", + " \n", + "\n", + " for i in range(10):\n", + " values = eliminate(values)\n", + " values = only_choice(values);\n", + "\n", + " \n", + " return values\n", + "\n", + "#3. Test utils.py ---------------------------- \n", + "values = grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..')\n", + "print(\"The original Sudoku board is **********************************************\")\n", + "display(values)\n", + "\n", + "#4. Test function.py ---------------------------- \n", + "new_values = reduce_puzzle(values)\n", + "print(\"\\n\")\n", + "print(\"After applying constrint propagaton (both eliminate and only_choice strategies)*****************\")\n", + "display(new_values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## So, that seemed to work! Congratulation You should have got this answer. \n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Step5: Harder Sudoku\n", + "### Ok, let's see if our algorithm will work all the time. Here's a harder sudoku puzzle \n", + "\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + "4 . . |. . . |8 . 5 \n", + ". 3 . |. . . |. . . \n", + ". . . |7 . . |. . . \n", + "------+------+------\n", + ". 2 . |. . . |. 6 . \n", + ". . . |. 8 . |4 . . \n", + ". . . |. 1 . |. . . \n", + "------+------+------\n", + ". . . |6 . 3 |. 7 . \n", + "5 . . |2 . . |. . . \n", + "1 . 4 |. . . |. . . \n", + "\n", + "\n", + "After applying constrint propagaton (both eliminate and only_choice strategies)*****************\n", + " 4 1679 12679 | 139 2369 269 | 8 1239 5 \n", + " 26789 3 1256789 | 14589 24569 245689 | 12679 1249 124679 \n", + " 2689 15689 125689 | 7 234569 245689 | 12369 12349 123469 \n", + "------------------------+------------------------+------------------------\n", + " 3789 2 15789 | 3459 34579 4579 | 13579 6 13789 \n", + " 3679 15679 15679 | 359 8 25679 | 4 12359 12379 \n", + " 36789 4 56789 | 359 1 25679 | 23579 23589 23789 \n", + "------------------------+------------------------+------------------------\n", + " 289 89 289 | 6 459 3 | 1259 7 12489 \n", + " 5 6789 3 | 2 479 1 | 69 489 4689 \n", + " 1 6789 4 | 589 579 5789 | 23569 23589 23689 \n" + ] + } + ], + "source": [ + "'''\n", + "Exercise5.1: Try to solve harder sudoku using the same constraint propagation\n", + "'''\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + "\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + "\n", + "def eliminate(values):\n", + " \"\"\"Eliminate values from peers of each box with a single value.\n", + "\n", + " Go through all the boxes, and whenever there is a box with a single value,\n", + " eliminate this value from the set of values of all its peers.\n", + "\n", + " Args:\n", + " values: Sudoku in dictionary form.\n", + " Returns:\n", + " Resulting Sudoku in dictionary form after eliminating values.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", + "\n", + "def only_choice(values):\n", + " \"\"\"Finalize all values that are the only choice for a unit.\n", + "\n", + " Go through all the units, and whenever there is a unit with a value\n", + " that only fits in one box, assign the value to this box.\n", + "\n", + " Input: Sudoku in dictionary form.\n", + " Output: Resulting Sudoku in dictionary form after filling in only choices.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", + "\n", + "#2. function.py ----------------------------\n", + "# 2.1 combine the functions eliminate and only_choice to write the function reduce_puzzle\n", + "# from utils import *\n", + "def reduce_puzzle(values):\n", + " \"\"\"\n", + " Iterate eliminate() and only_choice(). If at some point, there is a box with no available values, return False.\n", + " If the sudoku is solved, return the sudoku.\n", + " If after an iteration of both functions, the sudoku remains the same, return the sudoku.\n", + " Input: A sudoku in dictionary form.\n", + " Output: The resulting sudoku in dictionary form.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for i in range(100):\n", + " values = eliminate(values)\n", + " values = only_choice(values);\n", + " \n", + " return values\n", + "\n", + "#3. Test utils.py ---------------------------- \n", + "grid_easy = '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'\n", + "grid_hard = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......'\n", + "values = grid_values(grid_hard)\n", + "print(\"The original Sudoku board is **********************************************\")\n", + "display(values)\n", + "\n", + "#4. Test function.py ---------------------------- \n", + "new_values = reduce_puzzle(values)\n", + "print(\"\\n\")\n", + "print(\"After applying constrint propagaton (both eliminate and only_choice strategies)*****************\")\n", + "display(new_values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Oh no! The algorithm didn't solve it. It seemed to reduce every box to a number of possibilites, but it won't go farther than that. We need to think of other ways to improve our solution. \n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "## Step6: Strategy 3: Search\n", + "### Search is used throughout AI from Game-Playing to Route Planning to efficiently find solutions. \n", + "\n", + "#### 6.1 An example of Search being used in Google's AlphaGo paper.\n", + "Learn more about Google's AlphaGo paper here: [Mastering the game of Go with deep neural networks and tree search](https://storage.googleapis.com/deepmind-media/alphago/AlphaGoNaturePaper.pdf) \n", + " \n", + "\n", + "#### 6.2 Search Strategy\n", + "##### Pick a box with a minimal number of possible values. Try to solve each of the puzzles obtained by choosing each of these values, recursively. \n", + "\n", + "Before we dive in to code the search function, let's first check our understanding. How would you traverse the following tree using Depth First Search?\n", + "\n", + " \n", + "\n", + "** DFS Quiz ** \n", + "Traverse the above tree using Depth First Search. The answer should be the string obtained by the labels in the order you've traversed the tree. For example, if your tree has four vertices, A, B, C, D, and you've traversed them in the order B->C->A->D, then the answer should be the string 'BCAD'.\n", + "\n", + "** DFS Answer ** >> 'ABDEHIJCFGKL'\n", + "\n", + "##### In our example, the box 'G2' has two possibilities: 8 and 9. Why don't we fill it in with a 8 and try to solve our puzzle. \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%%%html\n", + "" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + "4 . . |. . . |8 . 5 \n", + ". 3 . |. . . |. . . \n", + ". . . |7 . . |. . . \n", + "------+------+------\n", + ". 2 . |. . . |. 6 . \n", + ". . . |. 8 . |4 . . \n", + ". . . |. 1 . |. . . \n", + "------+------+------\n", + ". . . |6 . 3 |. 7 . \n", + "5 . . |2 . . |. . . \n", + "1 . 4 |. . . |. . . \n", + "Please wait about 3 minutes. The solution will be shown**********************************************\n" + ] + } + ], + "source": [ + "'''\n", + "Exercise6.1: Coding the Solution\n", + "\n", + "Time to code the final solution! Finish the code in the function search, \n", + "which will create a tree of possibilities and traverse it using DFS until it finds a solution for the sudoku puzzle.\n", + "'''\n", + "#1. utils.py ----------------------------\n", + "#1.1 define rows: \n", + "rows = 'ABCDEFGHI'\n", + "\n", + "#1.2 define cols:\n", + "cols = '123456789'\n", + "\n", + "#1.3 cross(a,b) helper function to create boxes, row_units, column_units, square_units, unitlist\n", + "def cross(a, b):\n", + " return [s+t for s in a for t in b]\n", + "\n", + "#1.4 create boxes\n", + "boxes = cross(rows, cols)\n", + "\n", + "#1.5 create row_units\n", + "row_units = [cross(r, cols) for r in rows]\n", + "\n", + "#1.6 create column_units\n", + "column_units = [cross(rows, c) for c in cols]\n", + "\n", + "#1.7 create square_units for 9x9 squares\n", + "square_units = [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in ('123','456','789')]\n", + "\n", + "#1.8 create unitlist for all units\n", + "unitlist = row_units + column_units + square_units\n", + "\n", + "#1.9 create peers of a unit from all units\n", + "units = dict((s, [u for u in unitlist if s in u]) for s in boxes)\n", + "peers = dict((s, set(sum(units[s],[]))-set([s])) for s in boxes)\n", + "\n", + "#1.10 display function receiving \"values\" as a dictionary and display a 9x9 suduku board\n", + "def display(values):\n", + " \"\"\"\n", + " Display the values as a 2-D grid.\n", + " Input: The sudoku in dictionary form\n", + " Output: None\n", + " \"\"\"\n", + " width = 1+max(len(values[s]) for s in boxes)\n", + " line = '+'.join(['-'*(width*3)]*3)\n", + " for r in rows:\n", + " print(''.join(values[r+c].center(width)+('|' if c in '36' else '')\n", + " for c in cols))\n", + " if r in 'CF': print(line)\n", + " return\n", + "\n", + "def grid_values(grid):\n", + " \"\"\"Convert grid string into {: } dict with '123456789' value for empties.\n", + "\n", + " Args:\n", + " grid: Sudoku grid in string form, 81 characters long\n", + " Returns:\n", + " Sudoku grid in dictionary form:\n", + " - keys: Box labels, e.g. 'A1'\n", + " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", + "\n", + "def eliminate(values):\n", + " \"\"\"Eliminate values from peers of each box with a single value.\n", + "\n", + " Go through all the boxes, and whenever there is a box with a single value,\n", + " eliminate this value from the set of values of all its peers.\n", + "\n", + " Args:\n", + " values: Sudoku in dictionary form.\n", + " Returns:\n", + " Resulting Sudoku in dictionary form after eliminating values.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + "# if(values[R+C] != '.'):\n", + "# a = []\n", + "# for ch in values[R+C]:\n", + "# a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", + "\n", + "def only_choice(values):\n", + " \"\"\"Finalize all values that are the only choice for a unit.\n", + "\n", + " Go through all the units, and whenever there is a unit with a value\n", + " that only fits in one box, assign the value to this box.\n", + "\n", + " Input: Sudoku in dictionary form.\n", + " Output: Resulting Sudoku in dictionary form after filling in only choices.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", + "\n", + "def reduce_puzzle(values):\n", + " \"\"\"\n", + " Iterate eliminate() and only_choice(). If at some point, there is a box with no available values, return False.\n", + " If the sudoku is solved, return the sudoku.\n", + " If after an iteration of both functions, the sudoku remains the same, return the sudoku.\n", + " Input: A sudoku in dictionary form.\n", + " Output: The resulting sudoku in dictionary form.\n", + " \"\"\"\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + "# while True:\n", + "# new_values = values.copy()\n", + "# new_values = eliminate(new_values)\n", + "# new_values = only_choice(new_values)\n", + "# if new_values == values:\n", + "# break\n", + "# values = new_values\n", + " \n", + " for i in range(1):\n", + " values = eliminate(values)\n", + " values = only_choice(values)\n", + " \n", + " return values\n", + " \n", + "#2. function.py ----------------------------\n", + "# 2.1 implement search() using Depth First Search Algorithm\n", + "#from utils import *\n", + "def check(value, R, C, i):\n", + " for r in rows:\n", + " if len(value[r+C]) == 1 and i in value[r+C]: \n", + " return False\n", + " \n", + " for c in cols:\n", + " if len(value[R+c]) == 1 and i in value[R+c]: \n", + " return False\n", + " \n", + " numR = rows.find(R)\n", + " sR = (numR//3)*3\n", + " sC = ((int(C)-1)//3)*3\n", + " for r in range(3):\n", + " for c in range(3):\n", + " curR = rows[sR + r]\n", + " curC = sC + c + 1\n", + "# print(curR, curC)\n", + " if len(value[curR+str(curC)]) == 1 and i in value[curR+str(curC)]:\n", + " return False\n", + " \n", + " return True \n", + "\n", + "def dfs(value, level):\n", + " isDone = True\n", + " \n", + "\n", + " copy = value.copy()\n", + " copy = reduce_puzzle(copy)\n", + " for R in rows:\n", + " for C in cols:\n", + " if len(copy[R+C]) > 1:\n", + " isDone = False\n", + " if len(copy[R+C]) == 0:\n", + " return (value, False)\n", + " \n", + " if isDone:\n", + " return (copy, True)\n", + " \n", + " new_copy = copy.copy()\n", + " for R in rows:\n", + " for C in cols:\n", + " done = False\n", + " if len(copy[R+C]) > 1:\n", + " temp = copy[R+C]\n", + " for i in temp:\n", + " if check(copy, R, C, i):\n", + " copy[R+C] = i\n", + "# print('----: ' + str(level))\n", + "# display(copy)\n", + "\n", + " (new_copy, done) = dfs(copy, level+1)\n", + " # print(done)\n", + " if done:\n", + "# print('ni3')\n", + " return (new_copy, True)\n", + " copy[R+C] = temp\n", + " \n", + " return (copy, False)\n", + "\n", + "def search(values):\n", + " \"Using depth-first search and propagation, create a search tree and solve the sudoku.\"\n", + " # First, reduce the puzzle using the previous function\n", + " # Search and Choose one of the unfilled squares with the fewest possibilities\n", + " # Now use recursion to solve each one of the resulting sudokus, \n", + " # and if one returns a value (not False), return that answer!\n", + " \n", + " ''' Your solution here \n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " .........\n", + " '''\n", + " values = reduce_puzzle(values)\n", + "# display(values)\n", + " (values, done) = dfs(values, 0)\n", + " return values\n", + " \n", + "\n", + "#3. Test utils.py ---------------------------- \n", + "grid_easy = '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'\n", + "grid_hard = '4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......'\n", + "values = grid_values(grid_hard)\n", + "print(\"The original Sudoku board is **********************************************\")\n", + "display(values)\n", + "\n", + "print(\"Please wait about 3 minutes. The solution will be shown **********************************************\")\n", + "\n", + "#4. Test function.py ---------------------------- \n", + "new_values = search(values)\n", + "print(\"\\n\")\n", + "print(\"After applying Depth First Search Algorithm *****************\")\n", + "display(new_values)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## So, that seemed to work! Congratulation You should have got this answer. \n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "anaconda-cloud": {}, + "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.6.1" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/Solving a Sudoku with AI - Lessons Problem.ipynb b/Solving a Sudoku with AI - Lessons Problem.ipynb index 7c70dd1..cec94c6 100644 --- a/Solving a Sudoku with AI - Lessons Problem.ipynb +++ b/Solving a Sudoku with AI - Lessons Problem.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "##### Table of Content\n", + "### Table of Content\n", "\n", "1. Intro\n", "2. Solving a Sudoku\n", @@ -40,11 +40,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n" + ] + } + ], "source": [ "'''\n", "Exercise1: Encoding the Board\n", @@ -122,7 +138,12 @@ " # for example 'A1', and the values are the digit at each\n", " # box (as a string) or '.' if the box has no value\n", " # assigned yet.\n", - " \n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", " ''' Your solution here \n", " .........\n", " .........\n", @@ -162,7 +183,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -172,11 +193,27 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n" + ] + } + ], "source": [ "'''\n", "Exercise2.1: Improved grid_values()\n", @@ -264,7 +301,12 @@ " - keys: Box labels, e.g. 'A1'\n", " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", " \"\"\"\n", - " \n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", " ''' Your solution here \n", " .........\n", " .........\n", @@ -280,11 +322,42 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n", + "\n", + "\n", + "After implement eliminate(values) method **********************************\n", + " 45 4578 3 | 49 2 147 | 6 5789 57 \n", + " 9 24678 47 | 3 47 5 | 78 278 1 \n", + " 25 257 1 | 8 79 6 | 4 23579 2357 \n", + "---------------------+---------------------+---------------------\n", + " 345 345 8 | 1 3456 2 | 9 34567 34567 \n", + " 7 123459 49 | 459 34569 4 | 1 356 8 \n", + " 1345 13459 6 | 7 359 8 | 2 345 345 \n", + "---------------------+---------------------+---------------------\n", + " 134 1347 2 | 6 478 9 | 5 1478 47 \n", + " 8 1467 47 | 2 457 3 | 7 146 9 \n", + " 46 4679 5 | 4 1 7 | 3 268 26 \n" + ] + } + ], "source": [ "'''\n", "Exercise2.2: implement eliminate()\n", @@ -349,7 +422,12 @@ " - keys: Box labels, e.g. 'A1'\n", " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", " \"\"\"\n", - " \n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", " ''' Your solution here \n", " .........\n", " .........\n", @@ -373,6 +451,28 @@ " Returns:\n", " Resulting Sudoku in dictionary form after eliminating values.\n", " \"\"\"\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.':\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", " \n", " ''' Your solution here \n", " .........\n", @@ -418,7 +518,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -428,11 +528,58 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . . |8 . 1 |. . . \n", + ". . . |. . . |4 3 . \n", + "5 . . |. . . |. . 3 \n", + "------+------+------\n", + ". . . |. 7 . |8 . . \n", + ". . 4 |. . . |1 . . \n", + ". 2 . |. 3 . |. . . \n", + "------+------+------\n", + "6 . . |. . . |. 7 5 \n", + ". . 3 |4 . . |. . . \n", + "1 . . |2 . . |6 . . \n", + "\n", + "\n", + "After implement eliminate(values) method **********************************\n", + " 23479 34679 2679 | 8 24569 1 | 2579 2569 2679 \n", + " 2789 16789 126789| 5679 2569 25679 | 4 3 126789\n", + " 5 146789 126789| 679 2469 24679 | 279 12689 3 \n", + "---------------------+---------------------+---------------------\n", + " 39 13569 1569 | 1569 7 24569 | 8 24569 2469 \n", + " 3789 356789 4 | 569 25689 25689 | 1 2569 2679 \n", + " 789 2 156789| 1569 3 45689 | 579 4569 4679 \n", + "---------------------+---------------------+---------------------\n", + " 6 489 289 | 139 189 389 | 239 7 5 \n", + " 2789 5789 3 | 4 15689 56789 | 29 1289 1289 \n", + " 1 45789 5789 | 2 589 35789 | 6 489 489 \n", + "\n", + "\n", + "After implement only_choice(values) method **********************************\n", + " 4 3 2679 | 8 24569 1 | 2579 2569 2679 \n", + " 2789 16789 126789| 5679 2569 25679 | 4 3 126789\n", + " 5 146789 126789| 679 2469 24679 | 279 12689 3 \n", + "---------------------+---------------------+---------------------\n", + " 39 13569 1569 | 1569 7 24569 | 8 24569 2469 \n", + " 3789 356789 4 | 569 25689 25689 | 1 2569 2679 \n", + " 789 2 156789| 1569 3 45689 | 579 4569 4679 \n", + "---------------------+---------------------+---------------------\n", + " 6 4 289 | 3 189 389 | 3 7 5 \n", + " 2789 5789 3 | 4 15689 7 | 29 1289 1289 \n", + " 1 45789 5789 | 2 589 3 | 6 489 489 \n", + "\n", + "\n" + ] + } + ], "source": [ "'''\n", "Exercise3.1: implement only_choice()\n", @@ -495,7 +642,12 @@ " - keys: Box labels, e.g. 'A1'\n", " - values: Value in corresponding box, e.g. '8', or '123456789' if it is empty.\n", " \"\"\"\n", - " \n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", " ''' Your solution here \n", " .........\n", " .........\n", @@ -516,6 +668,33 @@ " Returns:\n", " Resulting Sudoku in dictionary form after eliminating values.\n", " \"\"\"\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", " \n", " ''' Your solution here \n", " .........\n", @@ -538,7 +717,48 @@ " Input: Sudoku in dictionary form.\n", " Output: Resulting Sudoku in dictionary form after filling in only choices.\n", " \"\"\"\n", - " \n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", " ''' Your solution here \n", " .........\n", " .........\n", @@ -549,7 +769,7 @@ " '''\n", "\n", "#3. Test utils.py ---------------------------- \n", - "values = grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..')\n", + "values = grid_values('...8.1.........43.5.......3....7.8....4...1...2..3....6......75..34.....1..2..6..')\n", "print(\"The original Sudoku board is **********************************************\")\n", "display(values)\n", "eliminate(values)\n", @@ -561,7 +781,8 @@ "new_values = only_choice(values)\n", "print(\"\\n\")\n", "print(\"After implement only_choice(values) method **********************************\")\n", - "display(new_values)" + "display(new_values)\n", + "print(\"\\n\")" ] }, { @@ -601,7 +822,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], "source": [ @@ -613,9 +834,49 @@ "cell_type": "code", "execution_count": null, "metadata": { - "collapsed": false + "collapsed": true }, "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + ". . 3 |. 2 . |6 . . \n", + "9 . . |3 . 5 |. . 1 \n", + ". . 1 |8 . 6 |4 . . \n", + "------+------+------\n", + ". . 8 |1 . 2 |9 . . \n", + "7 . . |. . . |. . 8 \n", + ". . 6 |7 . 8 |2 . . \n", + "------+------+------\n", + ". . 2 |6 . 9 |5 . . \n", + "8 . . |2 . 3 |. . 9 \n", + ". . 5 |. 1 . |3 . . \n", + "\n", + "\n", + "After applying constrint propagaton (both eliminate and only_choice strategies)*****************\n", + "4 8 3 |9 2 1 |6 5 7 \n", + "9 6 7 |3 4 5 |8 2 1 \n", + "2 5 1 |8 7 6 |4 9 3 \n", + "------+------+------\n", + "5 4 8 |1 3 2 |9 7 6 \n", + "7 2 9 |5 6 4 |1 3 8 \n", + "1 3 6 |7 9 8 |2 4 5 \n", + "------+------+------\n", + "3 7 2 |6 8 9 |5 1 4 \n", + "8 1 4 |2 5 3 |7 6 9 \n", + "6 9 5 |4 1 7 |3 8 2 \n" + ] + } + ], "source": [ "'''\n", "Exercise4.1: Apply Constraint Propagation to Sudoku problem\n", @@ -693,6 +954,12 @@ " .........\n", " .........\n", " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", "\n", "def eliminate(values):\n", " \"\"\"Eliminate values from peers of each box with a single value.\n", @@ -714,6 +981,35 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", + " \n", "\n", "def only_choice(values):\n", " \"\"\"Finalize all values that are the only choice for a unit.\n", @@ -733,6 +1029,48 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", "\n", "#2. function.py ----------------------------\n", "# 2.1 combine the functions eliminate and only_choice to write the function reduce_puzzle\n", @@ -755,6 +1093,15 @@ " .........\n", " '''\n", "\n", + " \n", + "\n", + " for i in range(10):\n", + " values = eliminate(values)\n", + " values = only_choice(values);\n", + "\n", + " \n", + " return values\n", + "\n", "#3. Test utils.py ---------------------------- \n", "values = grid_values('..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..')\n", "print(\"The original Sudoku board is **********************************************\")\n", @@ -788,11 +1135,42 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 19, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + "4 . . |. . . |8 . 5 \n", + ". 3 . |. . . |. . . \n", + ". . . |7 . . |. . . \n", + "------+------+------\n", + ". 2 . |. . . |. 6 . \n", + ". . . |. 8 . |4 . . \n", + ". . . |. 1 . |. . . \n", + "------+------+------\n", + ". . . |6 . 3 |. 7 . \n", + "5 . . |2 . . |. . . \n", + "1 . 4 |. . . |. . . \n", + "\n", + "\n", + "After applying constrint propagaton (both eliminate and only_choice strategies)*****************\n", + " 4 1679 12679 | 139 2369 269 | 8 1239 5 \n", + " 26789 3 1256789 | 14589 24569 245689 | 12679 1249 124679 \n", + " 2689 15689 125689 | 7 234569 245689 | 12369 12349 123469 \n", + "------------------------+------------------------+------------------------\n", + " 3789 2 15789 | 3459 34579 4579 | 13579 6 13789 \n", + " 3679 15679 15679 | 359 8 25679 | 4 12359 12379 \n", + " 36789 4 56789 | 359 1 25679 | 23579 23589 23789 \n", + "------------------------+------------------------+------------------------\n", + " 289 89 289 | 6 459 3 | 1259 7 12489 \n", + " 5 6789 3 | 2 479 1 | 69 489 4689 \n", + " 1 6789 4 | 589 579 5789 | 23569 23589 23689 \n" + ] + } + ], "source": [ "'''\n", "Exercise5.1: Try to solve harder sudoku using the same constraint propagation\n", @@ -861,6 +1239,12 @@ " .........\n", " .........\n", " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", "\n", "def eliminate(values):\n", " \"\"\"Eliminate values from peers of each box with a single value.\n", @@ -882,6 +1266,34 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + " if(values[R+C] != '.'):\n", + " a = []\n", + " for ch in values[R+C]:\n", + " a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", "\n", "def only_choice(values):\n", " \"\"\"Finalize all values that are the only choice for a unit.\n", @@ -901,6 +1313,48 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", "\n", "#2. function.py ----------------------------\n", "# 2.1 combine the functions eliminate and only_choice to write the function reduce_puzzle\n", @@ -922,6 +1376,11 @@ " .........\n", " .........\n", " '''\n", + " for i in range(100):\n", + " values = eliminate(values)\n", + " values = only_choice(values);\n", + " \n", + " return values\n", "\n", "#3. Test utils.py ---------------------------- \n", "grid_easy = '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'\n", @@ -975,11 +1434,22 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "%%%html\n", "" @@ -987,11 +1457,43 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], + "execution_count": 165, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The original Sudoku board is **********************************************\n", + "4 . . |. . . |8 . 5 \n", + ". 3 . |. . . |. . . \n", + ". . . |7 . . |. . . \n", + "------+------+------\n", + ". 2 . |. . . |. 6 . \n", + ". . . |. 8 . |4 . . \n", + ". . . |. 1 . |. . . \n", + "------+------+------\n", + ". . . |6 . 3 |. 7 . \n", + "5 . . |2 . . |. . . \n", + "1 . 4 |. . . |. . . \n", + "Please wait about 3 minutes. The solution will be shown**********************************************\n", + "\n", + "\n", + "After applying Depth First Search Algorithm *****************\n", + "4 1 7 |3 2 6 |8 9 5 \n", + "2 3 9 |1 5 8 |6 4 7 \n", + "6 5 8 |7 9 4 |2 1 3 \n", + "------+------+------\n", + "8 2 1 |4 3 5 |7 6 9 \n", + "7 9 5 |5 8 2 |4 3 1 \n", + "3 4 6 |9 1 7 |5 2 8 \n", + "------+------+------\n", + "9 8 2 |6 5 3 |1 7 4 \n", + "5 7 3 |2 4 1 |9 8 6 \n", + "1 6 4 |8 7 9 |3 5 2 \n" + ] + } + ], "source": [ "'''\n", "Exercise6.1: Coding the Solution\n", @@ -1063,6 +1565,12 @@ " .........\n", " .........\n", " '''\n", + " out_grid = {}\n", + " for i in range(0,len(grid)):\n", + " c = int(i%9)+1\n", + " r = int(i/9)\n", + " out_grid[rows[r]+str(c)] = grid[i]\n", + " return out_grid\n", "\n", "def eliminate(values):\n", " \"\"\"Eliminate values from peers of each box with a single value.\n", @@ -1084,6 +1592,34 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for C in cols:\n", + " if values[R+C] == '.'or len(values[R+C]) > 1:\n", + " a = ['1','2','3','4','5','6','7','8','9']\n", + "# if(values[R+C] != '.'):\n", + "# a = []\n", + "# for ch in values[R+C]:\n", + "# a.append(ch)\n", + " for r in rows:\n", + " if values[r+C] != '.' and values[r+C] in a:\n", + " a.remove(values[r+C])\n", + " for c in cols:\n", + " if values[R+c] != '.' and values[R+c] in a:\n", + " a.remove(values[R+c])\n", + " for r in rows:\n", + " for c in cols:\n", + " numR = rows.find(R)\n", + " numr = rows.find(r)\n", + " if (int(c)-1)//3 == (int(C)-1)//3 and numr//3 == numR//3:\n", + " # print(values[r+c],r,c)\n", + " if values[r+c] != '.' and values[r+c] in a:\n", + " a.remove(values[r+c])\n", + " st = \"\"\n", + " for s in a:\n", + " st += s\n", + " values[R+C] = st\n", + " \n", + " return values\n", "\n", "def only_choice(values):\n", " \"\"\"Finalize all values that are the only choice for a unit.\n", @@ -1103,6 +1639,48 @@ " .........\n", " .........\n", " '''\n", + " for R in rows:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for C in cols:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = C\n", + " if count == 1:\n", + " values[R+index] = i\n", + " \n", + " for C in cols:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " index = '0'\n", + " for R in rows:\n", + " if values[R+C].find(i) != -1:\n", + " count += 1\n", + " index = R\n", + " if count == 1:\n", + " values[index+C] = i\n", + " \n", + " for R in [0,3,6]:\n", + " for C in [0,3,6]:\n", + " for i in \"123456789\":\n", + " count = 0\n", + " sR = '0'\n", + " sC = '0'\n", + " for r in range(0,3):\n", + " for c in range(0,3):\n", + " curR = r+R\n", + " curC = c+C\n", + " # print(curR, curC)\n", + " if values[rows[curR]+str(curC+1)].find(i) != -1:\n", + " sR = curR\n", + " sC = curC\n", + " count += 1\n", + " if count == 1:\n", + " values[rows[sR]+str(sC+1)] = i\n", + " \n", + " \n", + " return values\n", "\n", "def reduce_puzzle(values):\n", " \"\"\"\n", @@ -1121,10 +1699,82 @@ " .........\n", " .........\n", " '''\n", + "# while True:\n", + "# new_values = values.copy()\n", + "# new_values = eliminate(new_values)\n", + "# new_values = only_choice(new_values)\n", + "# if new_values == values:\n", + "# break\n", + "# values = new_values\n", + " \n", + " for i in range(1):\n", + " values = eliminate(values)\n", + " values = only_choice(values)\n", + " \n", + " return values\n", " \n", "#2. function.py ----------------------------\n", "# 2.1 implement search() using Depth First Search Algorithm\n", "#from utils import *\n", + "def check(value, R, C, i):\n", + " for r in rows:\n", + " if len(value[r+C]) == 1 and i in value[r+C]: \n", + " return False\n", + " \n", + " for c in cols:\n", + " if len(value[R+c]) == 1 and i in value[R+c]: \n", + " return False\n", + " \n", + " numR = rows.find(R)\n", + " sR = (numR//3)*3\n", + " sC = ((int(C)-1)//3)*3\n", + " for r in range(3):\n", + " for c in range(3):\n", + " curR = rows[sR + r]\n", + " curC = sC + c + 1\n", + "# print(curR, curC)\n", + " if len(value[curR+str(curC)]) == 1 and i in value[curR+str(curC)]:\n", + " return False\n", + " \n", + " return True \n", + "\n", + "def dfs(value, level):\n", + " isDone = True\n", + " \n", + "\n", + " copy = value.copy()\n", + " copy = reduce_puzzle(copy)\n", + " for R in rows:\n", + " for C in cols:\n", + " if len(copy[R+C]) > 1:\n", + " isDone = False\n", + " if len(copy[R+C]) == 0:\n", + " return (value, False)\n", + " \n", + " if isDone:\n", + " return (copy, True)\n", + " \n", + " new_copy = copy.copy()\n", + " for R in rows:\n", + " for C in cols:\n", + " done = False\n", + " if len(copy[R+C]) > 1:\n", + " temp = copy[R+C]\n", + " for i in temp:\n", + " if check(copy, R, C, i):\n", + " copy[R+C] = i\n", + "# print('----: ' + str(level))\n", + "# display(copy)\n", + "\n", + " (new_copy, done) = dfs(copy, level+1)\n", + " # print(done)\n", + " if done:\n", + "# print('ni3')\n", + " return (new_copy, True)\n", + " copy[R+C] = temp\n", + " \n", + " return (copy, False)\n", + "\n", "def search(values):\n", " \"Using depth-first search and propagation, create a search tree and solve the sudoku.\"\n", " # First, reduce the puzzle using the previous function\n", @@ -1140,6 +1790,11 @@ " .........\n", " .........\n", " '''\n", + " values = reduce_puzzle(values)\n", + "# display(values)\n", + " (values, done) = dfs(values, 0)\n", + " return values\n", + " \n", "\n", "#3. Test utils.py ---------------------------- \n", "grid_easy = '..3.2.6..9..3.5..1..18.64....81.29..7.......8..67.82....26.95..8..2.3..9..5.1.3..'\n", @@ -1148,6 +1803,8 @@ "print(\"The original Sudoku board is **********************************************\")\n", "display(values)\n", "\n", + "print(\"Please wait about 3 minutes. The solution will be shown **********************************************\")\n", + "\n", "#4. Test function.py ---------------------------- \n", "new_values = search(values)\n", "print(\"\\n\")\n", @@ -1162,12 +1819,48 @@ "## So, that seemed to work! Congratulation You should have got this answer. \n", " " ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { - "display_name": "Python [default]", + "display_name": "Python 3", "language": "python", "name": "python3" }, @@ -1181,7 +1874,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.2" + "version": "3.6.1" } }, "nbformat": 4,