Last active
October 30, 2018 22:40
-
-
Save JossWhittle/165842cafe9c15c4ee63e6daa84ff0e1 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "cells": [ | |
| { | |
| "cell_type": "code", | |
| "execution_count": 1, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "from ortools.sat.python import cp_model" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 2, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Very lightweight wrapper to allow for a simple callback function to be used to collect results\n", | |
| "class Collector(cp_model.CpSolverSolutionCallback):\n", | |
| " def __init__(self, func):\n", | |
| " cp_model.CpSolverSolutionCallback.__init__(self)\n", | |
| " self.num_solutions = 0\n", | |
| " self.func = func\n", | |
| " \n", | |
| " def OnSolutionCallback(self):\n", | |
| " self.num_solutions += 1\n", | |
| " self.func(self, self.num_solutions)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 3, | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "def solve_nqueens(board_size):\n", | |
| " model = cp_model.CpModel()\n", | |
| "\n", | |
| " # Variable for the queen in column i representing it's row j in [0,boardsize)\n", | |
| " queens = [model.NewIntVar(0, board_size-1, 'q%d' % (i)) for i in range(board_size)]\n", | |
| "\n", | |
| " # Implicit - Queens are in different columns because we are solving for the row of each column\n", | |
| " \n", | |
| " # Explicit - Queens are in different rows \n", | |
| " model.AddAllDifferent(queens)\n", | |
| " \n", | |
| " # Explicit - Queens are in different diagonals\n", | |
| " # q[i] = j therefore q[i] + i = j + i for the queen in column i\n", | |
| " # If any two queens j_1 + i_1 == j_2 + i_2 then they lay on an up-right diagonal\n", | |
| " # If any two queens j_1 - i_1 == j_2 - i_2 then they lay on a down-right diagonal\n", | |
| " \n", | |
| " asc = []\n", | |
| " dsc = []\n", | |
| " for i in range(board_size):\n", | |
| " # Create variables to hold the results of our equations j + i and j - i for the current i\n", | |
| " j_add_i = model.NewIntVar( 0, board_size*2, 'j_add_%d' % (i))\n", | |
| " j_sub_i = model.NewIntVar(-board_size, board_size , 'j_sub_%d' % (i))\n", | |
| " \n", | |
| " # Constrain that these variables must be equal to the results of the equations\n", | |
| " model.Add(j_add_i == queens[i] + i)\n", | |
| " model.Add(j_sub_i == queens[i] - i)\n", | |
| " \n", | |
| " # Append the variables which equal the results of j + i and j - i respectively to seperate lists\n", | |
| " asc += [j_add_i]\n", | |
| " dsc += [j_sub_i]\n", | |
| " \n", | |
| " # Constraining that each list contains all different values ensures that no two share the same value\n", | |
| " # This asserts that queens can never be on the same ascending or descending diagonals\n", | |
| " model.AddAllDifferent(asc)\n", | |
| " model.AddAllDifferent(dsc)\n", | |
| " \n", | |
| " # Callback function to pretty print the solution as a grid\n", | |
| " def on_solution(solution, count):\n", | |
| " print('Solution:', count)\n", | |
| " for i in range(board_size):\n", | |
| " j = int(solution.Value(queens[i]))\n", | |
| " line = '|'.join(['Q' if (k == j) else ' ' for k in range(board_size)])\n", | |
| " print(line + (('\\n' + '-'*len(line)) if (i != board_size-1) else ''))\n", | |
| " print()\n", | |
| " \n", | |
| " # Run the solver\n", | |
| " solver = cp_model.CpSolver()\n", | |
| " status = solver.SearchForAllSolutions(model, Collector(on_solution))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 4, | |
| "metadata": { | |
| "scrolled": true | |
| }, | |
| "outputs": [ | |
| { | |
| "name": "stdout", | |
| "output_type": "stream", | |
| "text": [ | |
| "Solution: 1\n", | |
| " | |Q| | | \n", | |
| "-----------\n", | |
| " | | | | |Q\n", | |
| "-----------\n", | |
| " |Q| | | | \n", | |
| "-----------\n", | |
| " | | | |Q| \n", | |
| "-----------\n", | |
| "Q| | | | | \n", | |
| "-----------\n", | |
| " | | |Q| | \n", | |
| "\n", | |
| "Solution: 2\n", | |
| " | | |Q| | \n", | |
| "-----------\n", | |
| "Q| | | | | \n", | |
| "-----------\n", | |
| " | | | |Q| \n", | |
| "-----------\n", | |
| " |Q| | | | \n", | |
| "-----------\n", | |
| " | | | | |Q\n", | |
| "-----------\n", | |
| " | |Q| | | \n", | |
| "\n", | |
| "Solution: 3\n", | |
| " |Q| | | | \n", | |
| "-----------\n", | |
| " | | |Q| | \n", | |
| "-----------\n", | |
| " | | | | |Q\n", | |
| "-----------\n", | |
| "Q| | | | | \n", | |
| "-----------\n", | |
| " | |Q| | | \n", | |
| "-----------\n", | |
| " | | | |Q| \n", | |
| "\n", | |
| "Solution: 4\n", | |
| " | | | |Q| \n", | |
| "-----------\n", | |
| " | |Q| | | \n", | |
| "-----------\n", | |
| "Q| | | | | \n", | |
| "-----------\n", | |
| " | | | | |Q\n", | |
| "-----------\n", | |
| " | | |Q| | \n", | |
| "-----------\n", | |
| " |Q| | | | \n", | |
| "\n" | |
| ] | |
| } | |
| ], | |
| "source": [ | |
| "solve_nqueens(6)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "metadata": {}, | |
| "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.6.4" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 2 | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment