7

Pythonで数独チェッカーを作成しようとしています:

ill_formed = [[5,3,4,6,7,8,9,1,2],
              [6,7,2,1,9,5,3,4,8],
              [1,9,8,3,4,2,5,6,7],
              [8,5,9,7,6,1,4,2,3],
              [4,2,6,8,5,3,7,9],  # <---
              [7,1,3,9,2,4,8,5,6],
              [9,6,1,5,3,7,2,8,4],
              [2,8,7,4,1,9,6,3,5],
              [3,4,5,2,8,6,1,7,9]]
easy = [[2,9,0,0,0,0,0,7,0],
       [3,0,6,0,0,8,4,0,0],
       [8,0,0,0,4,0,0,0,2],
       [0,2,0,0,3,1,0,0,7],
       [0,0,0,0,8,0,0,0,0],
       [1,0,0,9,5,0,0,6,0],
       [7,0,0,0,9,0,0,0,1],
       [0,0,1,2,0,0,3,0,6],
       [0,3,0,0,0,0,0,5,9]]

そのような入力を期待しています-9つのリストのリスト。ゼロは、ユーザーが入力していない数字を表します。行、列、または 3x3 に複数回表示できます。

def check_sudoku(grid):
if len(grid) == 9:
    numsinrow = 0
    for i in range(9):
        if len(grid[i]) == 9:
            numsinrow += 1
    if numsinrow == 9:
        for i in range(9):
            rowoccurence = [0,0,0,0,0,0,0,0,0,0]
            for j in range(9):
                rowoccurence[grid[i][j]] += 1
                temprow = rowoccurence[1:10]
                if temprow == [1,1,1,1,1,1,1,1,1]:
                    return True
                else:
                    return False
    else:
        return False
else:
    return False

リスト (グリッド) の 9x9 リストがあること、および各行、列、および 3x3 の小さな正方形に重複がないことを確認する必要があることは明らかです。コードでは、最初に適切な数の行があるかどうかを確認します (9 である必要があります)。次に、各行に 9 つの要素があることを確認します (ill_formed の例では、そうではないことがわかります)。次に、各行で重複をチェックしようとしますが、そうするのに問題があります。各行をループし、その行の各要素をループして、int のリスト (rowoccurence) に 1 を追加できると考えました。たとえば、最初の数値が 2 の場合、rowoccurence[2] は 1 に等しくなければなりません。ゼロはrowoccurence [0]にあり、チェックされません(行に複数のゼロがあり、グリッドがまだ正当である可能性があるため、最初の要素であるゼロを除くすべてを取る必要がある一時的なリストがあります)。正しい値の参照リストに対して一時リスト (基本的に行発生) をチェックしようとしましたが、機能していないようです。この数独チェッカーで行の重複をチェックするのを手伝ってくれませんか? よろしくお願いします!

4

13 に答える 13

13

重複を検索しているわけではないことに注意してください。ゼロ以外の重複を検索しているだけです。これには、セットの合計が機能します。行/列の正当性も同時に確認できます。

def sudoku_ok(line):
    return (len(line) == 9 and sum(line) == sum(set(line)))

def check_sudoku(grid):
    bad_rows = [row for row in grid if not sudoku_ok(row)]
    grid = list(zip(*grid))
    bad_cols = [col for col in grid if not sudoku_ok(col)]
    squares = []
    for i in range(9, step=3):
        for j in range(9, step=3):
          square = list(itertools.chain(row[j:j+3] for row in grid[i:i+3]))
          squares.append(square)
    bad_squares = [square for square in squares if not sudoku_ok(square)]
    return not (bad_rows or bad_cols or bad_squares)
于 2013-07-12T02:20:09.430 に答える
2

欠損値またはゼロをチェックしなかった@llbの回答から参照しました。負の値、ゼロ、および欠損値に対して機能する私のソリューションは次のとおりです

def line_ok(e):
    if len(set(e)) != 9: return False
    for i in range(len(e)):
        if e[i] not in range(1,10): return False
    return True
    
def checker(grid):
    bad_rows = [False for row in grid if not line_ok(row)]
    grid = list(zip(*grid))
    bad_cols = [False for col in grid if not line_ok(col)]
    squares = []
    for i in range(0,9,3):
        for j in range(0,9,3):
            square = list(itertools.chain.from_iterable(row[j:j+3] for row in grid[i:i+3]))
            squares.append(square)
    bad_squares = [False for sq in squares if not line_ok(sq)]
    return not any([bad_rows, bad_cols, bad_squares])

print(checker(sudoku_correct))

PS: 担当者が少ないため、コメントできませんでした。必要な人が見つけてくれることを願っています:)

于 2021-01-11T04:13:31.083 に答える
1

コードが崩壊する理由は、インデントが原因だと思います。やったほうがいい:

for j in range(9):
    rowoccurence[grid[i][j]] += 1
temprow = rowoccurence[1:10]
if temprow == [1,1,1,1,1,1,1,1,1]:
    return True
else:
    return False

それよりも:

for j in range(9):
        rowoccurence[grid[i][j]] += 1
        temprow = rowoccurence[1:10]
        if temprow == [1,1,1,1,1,1,1,1,1]:
            return True
        else:
            return False

または使用Counter

from collections import Counter

...
    if numsinrow == 9:
        for i in range(9):
            count = Counter(grid[i])
            return False if max(count.values()) > 1 else True
于 2013-07-12T01:34:32.733 に答える
0

行の重複をチェックしたい場合は、代わりに

rowoccurence = [0,0,0,0,0,0,0,0,0,0]
    for j in range(9):
        rowoccurence[grid[i][j]] += 1
        temprow = rowoccurence[1:10]
        if temprow == [1,1,1,1,1,1,1,1,1]:
            return True
        else:
            return False

カウント:

b = True
for i in range(9):
    grid[i].count(grid[i][j]) > 1:
        b = False
    return b

あなたのアプローチは、重複チェックだけでなく、1桁の数字のみが存在するように注意します。そうしないと、範囲外の例外が発生します

于 2013-07-12T01:00:00.333 に答える
0

各行/列を次のようにチェックするのはどうですか:

sorted(row) == range(1,10)

またはpython 3の場合

sorted(row) == list(range(1,10))

実行時間は新しいリストを作成することによって支配されると思います(ヒストグラムアプローチまたはソートアプローチを行うかどうか)ので、log(n)の余分な要素は目立たないはずです

各行、列、およびサブスクエアをチェックするために、行列から n 番目の行、列、およびサブスクエアを取得する抽出メソッドを使用することをお勧めします (つまり、すべてを 1 つのメソッドにまとめようとしないでください)。

たとえば、次のようになります。

getSubSquare(m, i):
    subrow = (i // 3) * 3
    subcol = (i % 3) * 3
    v = [0] * 9
    for j in range(9):
        subrj = j // 3
        subcj = j % 3
        v[j] = m[subrow + subrj][subcol + subcj]
    return v

getRow(m,i):
   return m[i]

getCol(m,i):
   return [m[j][i] for j in range(9)]
于 2013-07-12T01:28:25.710 に答える
0
def check_sudoku(grid):
if len(grid) == 9:
    numsinrow = 0
    for i in range(9):
        if len(grid[i]) == 9:
            numsinrow += 1
    if numsinrow == 9:
        if checkrow(grid):
            if checkcol(grid):
                return True
            else:
                return False
        else:
            return False
    else:
        return False
else:
    return False

def checkrow(grid):
    for i in range(9):
        rowoccurence = [0,0,0,0,0,0,0,0,0,0]
        for j in range(9):
            rowoccurence[grid[i][j]] += 1
        temprow = rowoccurence[1:10]
        for q in range(9):
            if temprow[q] == 1 or temprow[q] == 0:
                continue
            else:
                return False
    return True

def checkcol(grid):
    for num in range(9):
        coloccurence = [0,0,0,0,0,0,0,0,0,0]
        for i in range(9):
            coloccurence[grid[i][num]] += 1
        tempcol = coloccurence[1:10]
        for q in range(9):
            if tempcol[q] == 1 or tempcol[q] == 0:
                continue
            else:
                return False
    return True

わかりました、機能する行をチェックする機能に戻ってきました。多大なご協力をいただき、誠にありがとうございました。私はこれに慣れていないので、いくつかの答えがわかりませんでしたが、本当の方法で戻るのが早すぎることに気付きました。また、行に複数のゼロがある場合、rowoccurence/temp リストに表示されない数値があることにも気付きました。これが、rowoccurence/temp リストで 1 と 0 の両方をチェックする必要があった理由です。列をチェックする同様の関数も作成しました。再度、感謝します!

于 2013-07-15T16:40:18.550 に答える
0

(完成した)数独ボードをモデル化するための簡単なクラスを作成しました。難しいことは何もありませんが、9x9 ボードのシンプルなソリューションです。

class SudokuBoard(object):

    DIGITS = set(range(1, 10))

    def __init__(self, values):
        self.values = values

    def row(self, n):
        return self.values[n]

    def rows(self):
        return self.values

    def cols(self):
        return [self.col(i) for i in xrange(9)]

    def col(self, n):
        return [self.values[i][n] for i in xrange(len(self.values))]

    def groups(self):
        return [self.group(i) for i in xrange(9)]

    def group(self, n):
        start_r = (n / 3) * 3
        start_c = n * 3   % 9
        values = []
        for row in xrange(start_r, start_r + 3):
            for col in xrange(start_c, start_c + 3):
                values.append(self.values[row][col])
        return values

    def is_correct(self):
        for row in self.rows():
            if self.DIGITS - set(row):
                return False
        for col in self.cols():
            if self.DIGITS - set(col):
                return False
        for group in self.groups():
            if self.DIGITS - set(group):
                return False
        return True
于 2016-02-10T02:44:27.503 に答える