# copyright 2002-2010 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
# contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
#
# This file is part of logilab-constraint.
#
# logilab-constraint is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 2.1 of the License, or (at your
# option) any later version.
#
# logilab-constraint is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
# for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with logilab-constraint. If not, see <http://www.gnu.org/licenses/>.


from logilab.constraint import *


# games found on http://www.websudoku.com/
# I'm not sure how they rate the difficulty of their problems.
easy = ["  5   27 ",
        " 4   79  ",
        "1 6 8  35",
        "4 32 16 9",
        "   5 8   ",
        "8 76 95 3",
        "73  2 1 6",
        "  41   2 ",
        " 12   8  "]

medium = [" 9 85    ",
          "  3 1 5  ",
          " 283   1 ",
          "   2  4 7",
          " 3     5 ",
          "4 7  5   ",
          " 4   362 ",
          "  2 7 1  ",
          "    26 3 "]

hard = [" 19 73  4",
        "   98 72 ",
        "        5",
        "      4 6",
        "93     72",
        "4 6      ",
        "8        ",
        " 92 36   ",
        "5  42 31 "]

evil = ["  1  9   ",
        " 5 4     ",
        "2   1 365",
        "     327 ",
        "9       8",
        " 821     ",
        "473 5   1",
        "     6 4 ",
        "   3  8  "]

def sudoku(problem, verbose=0):
    assert len(problem) == 9 # more sizes later
    variables = ['v%02d_%02d'%(i,j) for i in range(9) for j in range(9)]
    domains = {}
    constraints = []
    values = list('123456789')
    for v in variables:
        domains[v] = fd.FiniteDomain(values)

    # line and column constraints
    for i in range(9):
        constraints.append(fd.AllDistinct(['v%02d_%02d'%(i,j) for j in range(9)]))
        constraints.append(fd.AllDistinct(['v%02d_%02d'%(j,i) for j in range(9)]))

    # square constraints:
    for i in (0, 3, 6):
        for j in (0, 3, 6):
            constraints.append(fd.AllDistinct(['v%02d_%02d'%(i+ii,j+jj)
                                               for ii in (0, 1, 2)
                                               for jj in (0, 1, 2)]))

    # fixed values:
    for i, line in enumerate(problem):
        for j, value in enumerate(line):
            if value != ' ':
                constraints.append(fd.Equals('v%02d_%02d'%(i,j), value))

    r = Repository(variables, domains, constraints)
    s = Solver().solve_one(r, verbose)
    return s

def display_solution(d):
    for i in range(9):
        for j in range(9):
            print d['v%02d_%02d'%(i,j)],
        print

if __name__ == '__main__':
    import sys, getopt
    opts, args = getopt.getopt(sys.argv[1:], 'dv')
    verbose = 0
    display = 0
    for o,v in opts:
        if o == '-v':
            verbose += 1
        if o == '-d':
            display = 1
    sol = sudoku(evil, verbose)
    if display:
        display_solution(sol)
    else:
        print sol
