Mercurial > hg > toys
changeset 25:af24a1a7194b default tip
sudoku.py
author | Jordi Gutiérrez Hermoso <jordigh@octave.org> |
---|---|
date | Mon, 22 May 2017 11:30:19 -0400 |
parents | 7bcb491ce57e |
children | |
files | haskell/levenshtein/fuco.hs python/sudoku.py |
diffstat | 2 files changed, 184 insertions(+), 6 deletions(-) [+] |
line wrap: on
line diff
old mode 100644 new mode 100755 --- a/haskell/levenshtein/fuco.hs +++ b/haskell/levenshtein/fuco.hs @@ -1,13 +1,16 @@ -nthRow n len = n : replicate (len - 1) 0 +#!/usr/bin/runhaskell -updateRow prev n letter word - = reverse $ foldl (\l@(last:_) (j1,j,cl) +import Data.List + +updateRow prev n letter word = + reverse $ foldl' (\l@(last:_) (j1,j,cl) -> minimum [1 + last, 1 + j, j1 + (if letter == cl then 0 else 1)] : l) [n] p where p = zip3 prev (tail prev) word -leven a b = last $ foldl (\x(n,letter) - -> updateRow x n letter b) [0..(length b)] (zip [0..] a) +leven a b = last $ foldl' + (\x(n,letter) -> updateRow x n letter b) + [0..(length b)] (zip [0..] a) -main = print $ leven (show [1..1000]) (show [2..1001]) \ No newline at end of file +main = print $ leven (show [1..300]) (show [2..301]) \ No newline at end of file
new file mode 100644 --- /dev/null +++ b/python/sudoku.py @@ -0,0 +1,175 @@ +from copy import deepcopy + + +class InvalidMove(Exception): + pass + + +class InvalidBoard(Exception): + pass + + +class InvalidEntry(Exception): + pass + + +def possibles(): + return set(range(1, 10)) + + +class Board(object): + def __init__(self, board=None): + self.rows = [] + self.cols = [] + for i in range(0, 9): + self.rows.append(possibles()) + self.cols.append(possibles()) + + self.subboards = [] + for i in range(0, 3): + self.subboards.append([]) + for j in range(0, 3): + self.subboards[-1].append(possibles()) + + self.board = [] + for i in range(0, 9): + self.board.append(["."]*9) + + if board is not None: + self.read(board) + + def __repr__(self): + return """ + +---+---+---+ + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + +---+---+---+ + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + +---+---+---+ + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + |{}{}{}|{}{}{}|{}{}{}| + +---+---+---+""".format(*sum(self.board, [])) + + def is_solved(self): + return all(["." not in row for row in self.board]) + + def read(self, board): + i = 0 + j = 0 + while i < 9 and j < 9: + for entry in board: + if entry == ".": + j += 1 + elif entry in "123456789": + self.insert(i, j, int(entry)) + j += 1 + + if j == 9: + j = 0 + i += 1 + + def get_possibles(self, i, j): + if self.board[i][j] != ".": + return {self.board[i][j]} + return ( + self.rows[i] & + self.cols[j] & + self.subboards[i//3][j//3] + ) + + def show_all_possibles(self): + for i in range(0, 9): + for j in range(0, 9): + print self.get_possibles(i, j) + print + + def insert(self, i, j, val): + if self.board[i][j] != ".": + raise InvalidEntry() + + if val not in self.get_possibles(i, j): + raise InvalidMove() + + self.board[i][j] = val + self.rows[i].remove(val) + self.cols[j].remove(val) + self.subboards[i//3][j//3].remove(val) + + def reduce(self): + reduced = True + while reduced: + reduced = False + for i in range(0, 9): + for j in range(0, 9): + if self.board[i][j] == ".": + possibles = self.get_possibles(i, j) + if len(possibles) == 1: + try: + self.insert(i, j, possibles.pop()) + except InvalidEntry: + raise InvalidBoard() + reduced = True + + return self + + def all_feasibles(self): + all_feasibles = [] + for i in range(0, 9): + for j in range(0, 9): + feasibles = self.get_possibles(i, j) + if len(feasibles) > 1: + all_feasibles.append([i, j, feasibles]) + if len(feasibles) == 0: + raise InvalidBoard() + + all_feasibles = sorted( + all_feasibles, + key=lambda x: len(x[2]) + ) + + if len(all_feasibles) == 0: + raise InvalidBoard() + + return all_feasibles + + + def solve(self): + self.reduce() + while not self.is_solved(): + all_feasibles = self.all_feasibles() + try_i, try_j, feasibles = all_feasibles[0] + for feasible in feasibles: + attempt = deepcopy(self) + attempt.insert(try_i, try_j, feasible) + try: + self = attempt.solve() + except InvalidBoard: + continue + + # I.e. not an invalid board, it's solved + break + else: + raise InvalidBoard + + return self + +if __name__=="__main__": + b = Board(board=""" + ... .5. .74 + 8.1 ... ... + ... ... ... + + .7. 24. ... + 6.. ... 1.. + ... ... ... + + 2.. 1.6 3.. + .4. ... .2. + ... 8.. ... + + """) + print b.solve()