코딩 강좌/OrTools
#2 OrTools로 n-Queens 솔루션 결과 출력
요긴소프트
2022. 11. 21. 11:46
728x90
반응형
이전 글에서 orTools로 n-Queens 솔루션을 찾는 방법을 설명했습니다. 이번 글에서는 지난 번 글에 이어지는 글로 솔루션의 결과를 출력하는 방법을 소개합니다.
### 모델 해결
solver = cp_model.CpSolver()
### 모델 다이어그램 출력
printer = DiagramPrinter(queens)
### 모델 다이어그램 출력
status = solver.SearchForAllSolutions(model, printer)
print()
print('찾은 솔루션 개수 : %i' % printer.SolutionCount())
print("걸린 시간: ", solver.WallTime(), "ms")
지난 번 소스 맨 마지막 부분을 보면 solver를 통해 솔루션을 찾기에서 DiagramPrinter라는 클래스 인스턴스를 생성하고 SearchForAllSolutions에 인자로 전달하는 부분이 있습니다. 해당 클래스는 솔루션 결과에 대한 후속 작업을 정의할 수 있는 콜백 클래스라고 보시면 됩니다. 아래 DiagramPrinter 클래스 정의 소스를 보시면 __init__, OnSolutionCallback, SolutionCount 라는 메소드를 정의하고 있습니다.
class DiagramPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, variables):
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def OnSolutionCallback(self):
self.__solution_count += 1
for v in self.__variables:
queen_col = int(self.Value(v))
board_size = len(self.__variables)
# 퀸이 있는 행 인쇄
for j in range(board_size):
if j == queen_col:
# j열, i행에 여왕이 있으면 Q 인쇄
print("Q", end=" ")
else:
print("_", end=" ")
print()
print()
def SolutionCount(self):
return self.__solution_count
__init__메소드를 통해 초기화하고, OnSolutionCallback이란 메소드를 통해 솔루션이 있을 때마다 솔루션 count를 1증가하고 화면에 queens 배열에 저장된 솔루션 값을 인쇄합니다.
전체 소스는 아래와 같습니다.
import sys
# CP-SAT 솔버
from ortools.sat.python import cp_model
def main(board_size):
model = cp_model.CpModel()
# 변수 생성
# 배열의 인덱스는 열(column), 값은 행(Row)
queens = [model.NewIntVar(0, board_size - 1, 'x%i' % i) for i in range(board_size)]
# 제약조건 생성
# 모든 여왕은 다른 행에 있어야 한다는 조건
model.AddAllDifferent(queens)
# 참고: 배열은 인덱스가 모두 다르므로 기본적으로 모든 여왕은 다른 열에 있고,
# 배열의 값을 모두 다르게 지정하면 여왕은 모두 다른 행에 위치 하게 됨
# 두 개의 여왕이 동일한 대각선에 있을 수 없다는 제약 조건 설정
diag1 = []
for i in range(board_size):
q1 = model.NewIntVar(0, 2 * board_size, 'diag1_%i' % i)
diag1.append(q1)
model.Add(q1 == queens[i] + i)
diag2 = []
for i in range(board_size):
q2 = model.NewIntVar(-board_size, board_size, 'diag2_%i' % i)
diag2.append(q2)
model.Add(q2 == queens[i] - i)
model.AddAllDifferent(diag1)
model.AddAllDifferent(diag2)
### 모델 해결
solver = cp_model.CpSolver()
### 모델 다이어그램 출력
printer = DiagramPrinter(queens)
### 모델 다이어그램 출력
status = solver.SearchForAllSolutions(model, printer)
print()
print('찾은 솔루션 개수 : %i' % printer.SolutionCount())
print("걸린 시간: ", solver.WallTime(), "ms")
class DiagramPrinter(cp_model.CpSolverSolutionCallback):
def __init__(self, variables):
cp_model.CpSolverSolutionCallback.__init__(self)
self.__variables = variables
self.__solution_count = 0
def OnSolutionCallback(self):
self.__solution_count += 1
for v in self.__variables:
queen_col = int(self.Value(v))
board_size = len(self.__variables)
# 퀸이 있는 행 인쇄
for j in range(board_size):
if j == queen_col:
# j열, i행에 여왕이 있으면 Q 인쇄
print("Q", end=" ")
else:
print("_", end=" ")
print()
print()
def SolutionCount(self):
return self.__solution_count
board_size = 4
main(board_size)
참고로 python 문법으로 소스를 좀더 축약 시킬 수 있는 부분이 있습니다. 소스 18-28행은 다음과 같이 단 2줄로 축약이 가능합니다.
diag1 = [queens[i] + i for i in range(board_size)]
diag2 = [queens[i] - i for i in range(board_size)]
728x90
반응형