Files
ortools-clone/examples/python/hidato_table.py
2014-06-13 10:03:03 +00:00

208 lines
5.4 KiB
Python

# Copyright 2010-2013 Google
# 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.
"""Hidato puzzle in Google CP Solver.
http://www.hidato.com/
'''
Puzzles start semi-filled with numbered tiles.
The first and last numbers are circled.
Connect the numbers together to win. Consecutive
number must touch horizontally, vertically, or
diagonally.
'''
"""
from google.apputils import app
from ortools.constraint_solver import pywrapcp
def BuildPairs(rows, cols):
"""Build closeness pairs for consecutive numbers.
Build set of allowed pairs such that two consecutive numbers touch
each other in the grid.
Returns:
A list of pairs for allowed consecutive position of numbers.
Args:
rows: the number of rows in the grid
cols: the number of columns in the grid
"""
return [(x * cols + y, (x + dx) * cols + (y + dy))
for x in range(rows) for y in range(cols)
for dx in (-1, 0, 1) for dy in (-1, 0, 1)
if (x + dx >= 0 and x + dx < rows and
y + dy >= 0 and y + dy < cols and (dx != 0 or dy != 0))]
def main(unused_argv):
for model in range(1, 7):
print
print('----- Solving problem %i -----' % model)
print
Solve(model)
def Solve(model):
"""Solve the given model."""
# Create the solver.
solver = pywrapcp.Solver('hidato-table')
#
# models, a 0 indicates an open cell which number is not yet known.
#
#
puzzle = None
if model == 1:
# Simple problem
puzzle = [[6, 0, 9],
[0, 2, 8],
[1, 0, 0]]
elif model == 2:
puzzle = [[0, 44, 41, 0, 0, 0, 0],
[0, 43, 0, 28, 29, 0, 0],
[0, 1, 0, 0, 0, 33, 0],
[0, 2, 25, 4, 34, 0, 36],
[49, 16, 0, 23, 0, 0, 0],
[0, 19, 0, 0, 12, 7, 0],
[0, 0, 0, 14, 0, 0, 0]]
elif model == 3:
# Problems from the book:
# Gyora Bededek: "Hidato: 2000 Pure Logic Puzzles"
# Problem 1 (Practice)
puzzle = [[0, 0, 20, 0, 0],
[0, 0, 0, 16, 18],
[22, 0, 15, 0, 0],
[23, 0, 1, 14, 11],
[0, 25, 0, 0, 12]]
elif model == 4:
# problem 2 (Practice)
puzzle = [[0, 0, 0, 0, 14],
[0, 18, 12, 0, 0],
[0, 0, 17, 4, 5],
[0, 0, 7, 0, 0],
[9, 8, 25, 1, 0]]
elif model == 5:
# problem 3 (Beginner)
puzzle = [[0, 26, 0, 0, 0, 18],
[0, 0, 27, 0, 0, 19],
[31, 23, 0, 0, 14, 0],
[0, 33, 8, 0, 15, 1],
[0, 0, 0, 5, 0, 0],
[35, 36, 0, 10, 0, 0]]
elif model == 6:
# Problem 15 (Intermediate)
puzzle = [[64, 0, 0, 0, 0, 0, 0, 0],
[1, 63, 0, 59, 15, 57, 53, 0],
[0, 4, 0, 14, 0, 0, 0, 0],
[3, 0, 11, 0, 20, 19, 0, 50],
[0, 0, 0, 0, 22, 0, 48, 40],
[9, 0, 0, 32, 23, 0, 0, 41],
[27, 0, 0, 0, 36, 0, 46, 0],
[28, 30, 0, 35, 0, 0, 0, 0]]
r = len(puzzle)
c = len(puzzle[0])
print('Initial game (%i x %i)' % (r, c))
PrintMatrix(puzzle)
#
# declare variables
#
positions = [solver.IntVar(0, r * c - 1, 'p of %i' % i) for i in range(r * c)]
#
# constraints
#
solver.Add(solver.AllDifferent(positions))
#
# Fill in the clues
#
for i in range(r):
for j in range(c):
if puzzle[i][j] > 0:
solver.Add(positions[puzzle[i][j] - 1] == i * c + j)
# Consecutive numbers much touch each other in the grid.
# We use an allowed assignment constraint to model it.
close_tuples = BuildPairs(r, c)
for k in range(1, r * c - 1):
solver.Add(solver.AllowedAssignments((positions[k], positions[k + 1]),
close_tuples))
#
# solution and search
#
# db: DecisionBuilder
db = solver.Phase(positions,
solver.CHOOSE_MIN_SIZE_LOWEST_MIN,
solver.ASSIGN_MIN_VALUE)
solver.NewSearch(db)
num_solutions = 0
while solver.NextSolution():
num_solutions += 1
PrintOneSolution(positions, r, c, num_solutions)
solver.EndSearch()
print('solutions : %i' % num_solutions)
print('failures : %i' % solver.Failures())
print('branches : %i' % solver.Branches())
print('wall time : %i' % solver.WallTime())
def PrintOneSolution(positions, rows, cols, num_solution):
"""Print a current solution."""
print('Solution %i:' % num_solution)
# Create empty board.
board = []
for unused_i in range(rows):
board.append([0] * cols)
# Fill board with solution value.
for k in range(rows * cols):
position = positions[k].Value()
board[position // cols][position % cols] = k + 1
# Print the board.
PrintMatrix(board)
def PrintMatrix(game):
"""Pretty print of a matrix."""
rows = len(game)
cols = len(game[0])
for i in range(rows):
line = ''
for j in range(cols):
if game[i][j] == 0:
line += ' .'
else:
line += '% 3s' % game[i][j]
print(line)
print
if __name__ == '__main__':
app.run()