不使用 numpy.array 的二维数组 9x9 整数(MutableSequence 的子类)

问题描述 投票:0回答:1

几天前,我发现了下一个如何通过从 collections.abc 子类化 MutableSequence 来实现自定义列表类的示例。

class TypedList(MutableSequence):

    def __init__(self, oktypes, *args):
        self.oktypes = oktypes
        self.list = list()
        self.extend(list(args))

    def check(self, v):
        if not isinstance(v, self.oktypes):
            raise TypeError(v)

    def __len__(self): return len(self.list)

    def __getitem__(self, i): return self.list[i]

    def __delitem__(self, i): del self.list[i]

    def __setitem__(self, i, v):
        self.check(v)
        self.list[i] = v

    def insert(self, i, v):
        self.check(v)
        self.list.insert(i, v)

    def __str__(self):
        return str(self.list)

TypedList的使用示例:

    tl = TypedList(int)
    # ok
    tl.append(1)
    # next TypeError will be raised
    tl.append('1')

我的问题:

我想知道是否有方法以类似的方式实现二维数独数组(MutableSequence)类来在游戏中管理数独数组?

为了给您一个想法,下面您可以看到 SudokuArray(MutableSequence) 的可能实现(非操作):

class SudokuArray(MutableSequence):

    def __init__(self, n_rows=9, n_columns=9, init_value=None):
        self.n_rows = n_rows
        self.n_columns = n_columns
        self.array = [[init_value for _ in range(0, self.n_columns, 1)] for _ in range(0, self.n_rows, 1)]

    def check(self, row_number, column_number, number):
        if number in self.get_row_values(row_number) or
                                         number in self.get_column_values(column_number) or
                                         number in self.get_nonet_values(row_number, column_number)):
            raise ExistentNumberError("Existent number in row, column or nonet",
                                      number, row_number, column_number)

    def __len__(self): return self.n_rows, self.n_columns

    def __getitem__(self, row_number, column_number): return self.array[column_number][row_number]

    def __delitem__(self, row_number, column_number): del self.array[column_number][row_number]

    def __setitem__(self, row_number, column_number, number):
        self.check(number, row_number, column_number)
        self.array[column_number][row_number] = number

    def insert(self, row_number, column_number, number):
        self.check(row_number, column_number, number)
        self.array.insert(row_number, column_number, number)

    def __str__(self):
        return str(self.array)

    def get_row_values(self, row_number):
        # todo implement get_row_values method
        pass

    def get_column_values(self, column_number):
        # todo implement get_column_values method
        pass

    def get_nonet_values(self, row_number, column_number):
        # todo implement get_nonet_values method
        pass

class ExistentNumberError(Exception):
    def __init__(self, message, number, row_number, column_number):
        super().__init__(message)
        self.number = number
        self.row_number = row_number
        self.column_number = column_number

数独数组的使用示例:

    sudoku_array = SudokuArray()
    sudoku_array[0][0] = 1
    # next ExistentNumberError will be raised
    sudoku_array[0][0] = 1

当然我可以使用 numpy.array 但我认为我们的 9x9 数组使用 numpy 非常简单。我也想避免依赖。

有什么想法吗?

python arrays sudoku
1个回答
0
投票

您的尝试中存在以下问题:

  • if
    中的
    check
    语句缺少左括号。
  • __len__
    应该返回一个数字,而不是一个元组。
  • __getitem__
    和类似方法不应采用两个索引参数,而应采用一个。然而,这个参数可以是一个元组(2 个坐标)
  • 数独总是具有相同的行数和列数,因此我不会为行数和列数设置单独的构造函数参数。只有一个参数。
  • insert
    __delitem__
    方法不应在数独上使用:您不想更改任何行上的条目数。在下面的更正中,我仍然会包含它们,因为也许你有充分的理由?
  • get_***_values
    方法未实现。

这是建议的代码:

from collections.abc import MutableSequence
from math import isqrt

class SudokuArray(MutableSequence):

    def __init__(self, size=9, init_value=None):
        self.size = size
        self.array = [[init_value for _ in range(self.size)] for _ in range(self.size)]

    def check(self, row_number, column_number, number):
        if (number in self.get_row_values(row_number) or
                  number in self.get_column_values(column_number) or
                  number in self.get_nonet_values(row_number, column_number)):
            raise ExistentNumberError("Existent number in row, column or nonet",
                                      number, row_number, column_number)

    def __len__(self):
        return self.size * self.size

    def __getitem__(self, coordinates): 
        return self.array[coordinates[0]][coordinates[1]]

    def __delitem__(self, coordinates): 
        del self.array[coordinates[0]][coordinates[1]]

    def __setitem__(self, coordinates, number):
        self.check(coordinates[0], coordinates[1], number)
        self.array[coordinates[0]][coordinates[1]] = number

    def insert(self, coordinates, number):
        self.check(coordinates[0], coordinates[1], number)
        self.array[coordinates[0]].insert(coordinates[1], number)

    def __str__(self):
        return "\n".join(" ".join(map(str, row)) for row in self.array).replace("None", ".")
                         
    def get_row_values(self, row_number):
        return self.array[row_number][:]

    def get_column_values(self, column_number):
        return [row[column_number] for row in self.array]

    def get_nonet_values(self, row_number, column_number):
        width = isqrt(self.size)
        row_number -= row_number % width
        column_number -= column_number % width
        return [val for row in self.array[row_number:row_number+width]
                    for val in row[column_number:column_number+width]]

使用示例:

sudoku = SudokuArray()
sudoku[1, 2] = 9
sudoku[2, 3] = 8
sudoku[5, 5] = 4
sudoku[4, 4] = 3
sudoku[3, 3] = 6
print(sudoku)
© www.soinside.com 2019 - 2024. All rights reserved.