Судоку! Возврат, программа ограничений ~ Буду признателен за советы и полировки - PullRequest
0 голосов
/ 12 апреля 2020

Я написал этот код для решения Судоку, он использует программирование возврата и ограничения. Первоначально моя функция удовлетворенная () заняла ВСЕ время. Я сделал это намного быстрее, взгляни. В общем, я просто хочу получить общие советы о том, как настроить sh программу, ускорить выполнение любых медленных функций и т. Д. c, общую обратную связь и т. Д. c. Спасибо!

from typing import Generic, TypeVar, Dict, List, Optional, NamedTuple
from abc import ABC, abstractmethod

V = TypeVar('V')
D = TypeVar('D')

class Constraint(Generic[V,D], ABC):
  def __init__(self, variables: List[V]) -> None:
    self.variables = variables

  @abstractmethod
  def satisfied(self, assignment: Dict [V,D], last: D) -> bool:
    ...

class CSP(Generic[V,D]):
  def __init__(self, variables: List[V], domains: Dict[V, List[D]]) -> None:
    self.variables: List[V] = variables
    self.domains: Dict[V, List[D]] = domains
    self.constraints: Dict[V, List[Constraint[V,D]]] = {}
    for variable in self.variables:
      self.constraints[variable] = []
      if variable not in self.domains:
        raise LookupError("Every variable needs a domain to it")

  def add_constraint(self,constraint: Constraint[V,D]) -> None:
    for variable in constraint.variables:
      if variable not in self.variables:
        raise LookupError("Not in CSP")
      else:
        self.constraints[variable].append(constraint)

  def consistent(self, variable: V, assignment: Dict[V,D], last: D)-> bool:
    for constraint in self.constraints[variable]:
      if not constraint.satisfied(assignment, last):
        return False
      return True

  def backtracking(self, assignment: Dict[V,D] = {}) -> Optional[Dict[V,D]]:
    if len(assignment) == len(self.variables):
      return assignment

    unassigned: List[V] = [v for v in self.variables if v not in assignment]
    first: V = unassigned[0]
    for value in self.domains[first]:
      local_assignment = assignment.copy()
      local_assignment[first] = value
      #print(local_assignment)

      if self.consistent(first, local_assignment, value):
       result: Optional[Dict[V,D]] = self.backtracking(local_assignment)
       if result is not None:
          #print(first, "*", result)
          return result

    #print(first, "stuck")
    return None

class SudokuCell(NamedTuple):
  row: int
  column: int

class SudokuConstraint(Constraint[SudokuCell, int]):
  def __init__(self, cells: List[SudokuCell]) -> None:
    super().__init__(cells)
    self.cells: List[str] = cells

  def satisfied(self, assignment: Dict[SudokuCell,int], last: int) -> bool:
    vlast = [cell for cell,val in assignment.items() if val == last]
    nlast = len(vlast)
    vrows = [cell.row for cell in vlast]
    if len(set(vrows)) < nlast:
      return False
    vcolumns = [cell.column for cell in vlast]
    if len(set(vcolumns)) < nlast:
      return False
    vblock = [(cell.row//3, cell.column//3) for cell in vlast]
    if len(set(vblock)) < nlast:
      return False
    return True

def solve_sudoku(start_assignm: Dict[SudokuCell, int] = {}):
  cells: List[SudokuCell] = []
  values: Dict[SudokuCell, List[int]] = {}
  for i in range(0,9):
    for l in range (0,9):
      cells.append(SudokuCell(i,l))
      values[SudokuCell(i,l)] = list(range(1,10))

  csp_sudoku: CSP[SudokuCell,int] = CSP(cells,values)
  csp_sudoku.add_constraint(SudokuConstraint(cells))

  sol_sudoku: Optional[Dict[SudokuCell,int]] = csp_sudoku.backtracking(start_assignm)

  if sol_sudoku is None:
    print("No solution")
  else:
    print(str_sudoku(sol_sudoku))

def str_sudoku(sol_sudoku: Dict[SudokuCell,int]) -> str:
  output: str = "\n"
  for i in range(0,9):
    if (i%3 == 0):
      output+= "║═══╬═══╬═══║\n"
    for l in range(0,9):
      if(l%3 == 0):
        output+= "║"
      v = sol_sudoku.get(SudokuCell(i,l))
      if v is None:
        output += " "
      else:
        output += str(v)
    output += "║\n"
  output += "╚═══╩═══╩═══╝\n"
  return output

def try_to_solve_sudoku(fname = ""):
  try: 
    fd = open(fname)
    rows = fd.read().split()
    fd.close()

  except IOError:
    rows = ["xx5xxxx1x", "xx3xxx29x", "x4xx6xxx8",
           "57xxx4xxx", "x9xxxxxxx", "xxx2x8x5x",
           "x69x7xxxx", "xxxxxx74x", "x3x9xx6xx"]
    print("Using default puzzle")

  start_assignment: Dict[SudokuCell,int] = {}
  for i in range(0,9):
    for l in range (0,9):
      if rows[i][l].isdigit():
        start_assignment[SudokuCell(i,l)] = int(rows[i][l])
  print(str_sudoku(start_assignment))
  solve_sudoku(start_assignment)


...