#!/usr/bin/env python3 # Copyright 2010-2022 Google LLC # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """CP/SAT model for the N-queens problem.""" import time from absl import app from absl import flags from ortools.sat.python import cp_model _SIZE = flags.DEFINE_integer("size", 8, "Number of queens.") class NQueenSolutionPrinter(cp_model.CpSolverSolutionCallback): """Print intermediate solutions.""" def __init__(self, queens): cp_model.CpSolverSolutionCallback.__init__(self) self.__queens = queens self.__solution_count = 0 self.__start_time = time.time() def SolutionCount(self): return self.__solution_count def on_solution_callback(self): current_time = time.time() print( "Solution %i, time = %f s" % (self.__solution_count, current_time - self.__start_time) ) self.__solution_count += 1 all_queens = range(len(self.__queens)) for i in all_queens: for j in all_queens: if self.Value(self.__queens[j]) == i: # There is a queen in column j, row i. print("Q", end=" ") else: print("_", end=" ") print() print() def main(_): board_size = _SIZE.value ### Creates the solver. model = cp_model.CpModel() ### Creates the variables. # The array index is the column, and the value is the row. queens = [model.NewIntVar(0, board_size - 1, "x%i" % i) for i in range(board_size)] ### Creates the constraints. # All columns must be different because the indices of queens are all # different, so we just add the all different constraint on the rows. model.AddAllDifferent(queens) # No two queens can be on the same diagonal. diag1 = [] diag2 = [] for i in range(board_size): q1 = model.NewIntVar(0, 2 * board_size, "diag1_%i" % i) q2 = model.NewIntVar(-board_size, board_size, "diag2_%i" % i) diag1.append(q1) diag2.append(q2) model.Add(q1 == queens[i] + i) model.Add(q2 == queens[i] - i) model.AddAllDifferent(diag1) model.AddAllDifferent(diag2) ### Solve model. solver = cp_model.CpSolver() solution_printer = NQueenSolutionPrinter(queens) # Enumerate all solutions. solver.parameters.enumerate_all_solutions = True # Solve. solver.Solve(model, solution_printer) print() print("Statistics") print(" - conflicts : %i" % solver.NumConflicts()) print(" - branches : %i" % solver.NumBranches()) print(" - wall time : %f s" % solver.WallTime()) print(" - solutions found : %i" % solution_printer.SolutionCount()) if __name__ == "__main__": app.run(main)