Ракетка -> Питон

Я начал изучать ракетку, и я использую произвольные деревья арности и генеративную рекурсию, чтобы получить каждую возможную версию доски с данной доски.

Допустим, у меня есть эта доска, где false означает пустое:

(list "X" "X" "O" "O" "X" "O" "X" #false "X")

Решение для этого в соответствии с требованиями будет:

(list
 (list "X" "X" "O" "O" "X" "O" "X" "X" "X")
 (list "X" "X" "O" "O" "X" "O" "X" "O" "X"))

Решение в ракетке отлично работает. Я попробовал то же самое в Python, но это не совсем так, как ожидалось.

Я продолжаю получать такие результаты:

[['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X'], [['X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X'], []]]

или же

['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X', 'X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X']

или хуже.

Я не могу получить его, чтобы дать мне результат, который я хочу.

Я думал о том, чтобы сделать некоторую постобработку на выходе, если больше ничего не работает, но я хотел бы избежать этого.

Что мне нужно, это:

[['X', 'X', 'O', 'O', 'X', 'O', 'X', 'X', 'X'], ['X', 'X', 'O', 'O', 'X', 'O', 'X', 'O', 'X']]

В любом случае, дайте мне знать, если вы можете помочь.

Вот мой код Python:

"""
Brute force solution for tic-tac-toe.
"""


"""
Data definitions:

;; Value is one of:
;; - false
;; - "X"
;; - "O"
;; interp. a square is either empty (represented by false) or has and "X" or an "O"


;; Board is (listof Value)
;; a board is a list of 9 Values

"""

#
## CONSTANTS
#
B0 = [False for i in range(9)]
B1 = [
    False,  "X",  "O",
     "O",   "X",  "O",
    False, False, "X"
]
B2 = [
        "X",  "X",  "O",
        "O",  "X",  "O",
        "X", False, "X",
      ]

B3 = [
        "X", "O",  "X",
        "O", "O", False,
        "X", "X", False,
]


"""
PROBLEM 1

 In this problem we want you to design a function that produces all
 possible filled boards that are reachable from the current board.

 In actual tic-tac-toe, O and X alternate playing. For this problem
 you can disregard that. You can also assume that the players keep
 placing Xs and Os after someone has won. This means that boards that
 are completely filled with X, for example, are valid.

"""


def fill_board(index, bd):
    """
    Returns a list of 2 board versions with
    the index filled with "X" and "O"

    :param index: int; index of position in list to be filled
    :param bd: Board
    :return: (listof Board)
    """
    return [
        bd[:index] + ["X"] + bd[index+1:],
        bd[:index] + ["O"] + bd[index + 1:],
    ]


assert fill_board(0, B1) == [
    [
    "X",  "X",  "O",
     "O",   "X",  "O",
    False, False, "X"
    ],
    [
    "O",  "X",  "O",
     "O",   "X",  "O",
    False, False, "X"
    ],
]

assert fill_board(5, B3) == [
[
        "X", "O",  "X",
        "O", "O", "X",
        "X", "X", False,
],
[
        "X", "O",  "X",
        "O", "O", "O",
        "X", "X", False,
],
]


def find_blank(bd):
    """
    Return the index of the
    first empty (False) value
    in the board.
    ASSUME: there is at least one
    empty cell.

    :param bd: Board
    :return:  Index
    """
    return bd.index(False)

assert find_blank(B0) == 0
assert find_blank(B2) == 7
assert find_blank(B3) == 5


def next_boards(bd):
    """
    Produce the next version of initial board.
    Finds the first empty (False) cell, and produces
    2 versions of the board; one with X and one with O
    :param bd: Board
    :return: (listof Board)
    """

    return fill_board(find_blank(bd), bd)


assert next_boards(B0) == [
    ["X"] + B0[1:],
    ["O"] + B0[1:],
]


assert next_boards(B3) == [
[
        "X", "O", "X",
        "O", "O", "X",
        "X", "X", False,
],
[
        "X", "O", "X",
        "O", "O", "O",
        "X", "X", False,
],
]


def solve(bd):
    """
    Produce all possible filled boards that are
    reachable from the current board.

    :param bd: Board (listof Value)
    :return:  (listof Board)
    """
    def is_full(bd):
        """
        Returns true if board is full; meaning
        if every value on the board is a string.

        :param bd: Board (listof Value)
        :return: Boolean
        """
        return all(type(i) is str for i in bd)

    def solve__bd(bd):
        """
        Mutually refential function with
        solve__lobd. This is where all the actual
        computation takes place.
        The two functions are responsible for
        generating and operating on the tree.
        The tree (arbitraty arity tree) represents
        another version of the board filled with an
        additional X or O.

        :param bd: Board (listof Value)
        :return: (listof Board)
        """

        if is_full(bd):
            return list(bd)

        return solve__lobd(next_boards(bd))

    def solve__lobd(lobd):
        """
        Helper function of solve, alongside solve__bd
        :param lobd: (listof Board)
        :return:     (listof Board)
        """

        if not lobd:
            return []

        return [solve__bd(lobd[0]), solve__lobd(lobd[1:])]

    return solve__bd(bd)


assert solve(B2) == [
    [
        "X", "X", "O",
        "O", "X", "O",
        "X", "X", "X",
      ],
    [
        "X", "X", "O",
        "O", "X", "O",
        "X", "O", "X",
      ],
]


assert solve(B3) == [
    [
        "X", "O", "X",
        "O", "O", "X",
        "X", "X", "X",
    ],
    [
        "X", "O", "X",
        "O", "O", "X",
        "X", "X", "O",
    ],
    [
        "X", "O", "X",
        "O", "O", "O",
        "X", "X", "X",
    ],
    [
        "X", "O", "X",
        "O", "O", "O",
        "X", "X", "O",
    ],
]

1 ответ

Это похоже на недоумение, похожее на мошенничество. Я не проверял это, но держу пари, что ваша проблема возникает здесь:

return [solve__bd(lobd[0]), solve__lobd(lobd[1:])]

Я предполагаю, что вы хотите

return [solve__bd(lobd[0])] + solve__lobd(lobd[1:])]

... вместо

НО: списки Python не являются связанными списками. cons эффективный и разумный способ добавления элемента в список в Racket, но формирование списка с использованием Python + Оператор для одноэлементного списка и более длинного списка потребует копирования всех последующих элементов списка.

Для коротких списков (линейные операции над списками, скажем, менее 10K элементов или квадратичные операции над списками, состоящими менее чем из 100 элементов или около того), это не имеет значения. Для более длинных это будет. Люди из Python скажут вам, что вы делаете это неправильно, что вы должны использовать мутацию в существующих массивах. Ракетки скажут вам, что люди из Python застряли в прошлом. Добро пожаловать в удивительный мир программирования!

Другие вопросы по тегам