1

Python で倉庫番パズル アプリケーションを構築しようとしています。

(ルールの説明: http://en.m.wikipedia.org/wiki/Sokoban )

ゲームの実装には成功しましたが、特定のパズルを解くための最適な解をコンピュータが計算できるようになればもっと良いと思いました。

リファレンスを探しているときに、次のPython 実装 on Rosetta Codeを見つけました。

from array import array
from collections import deque
import psyco
     
data = []
nrows = 0
px = py = 0
sdata = ""
ddata = ""

def init(board):
    global data, nrows, sdata, ddata, px, py
    data = filter(None, board.splitlines())
    nrows = max(len(r) for r in data)
 
    maps = {' ':' ', '.': '.', '@':' ', '#':'#', '$':' '}
    mapd = {' ':' ', '.': ' ', '@':'@', '#':' ', '$':'*'}
 
    for r, row in enumerate(data):
        for c, ch in enumerate(row):
            sdata += maps[ch]
            ddata += mapd[ch]
            if ch == '@':
                px = c
                py = r
 
def push(x, y, dx, dy, data):
    if sdata[(y+2*dy) * nrows + x+2*dx] == '#' or \
       data[(y+2*dy) * nrows + x+2*dx] != ' ':
        return None
 
    data2 = array("c", data)
    data2[y * nrows + x] = ' '
    data2[(y+dy) * nrows + x+dx] = '@'
    data2[(y+2*dy) * nrows + x+2*dx] = '*'
    return data2.tostring()
 
def is_solved(data):
    for i in xrange(len(data)):
        if (sdata[i] == '.') != (data[i] == '*'):
            return False
    return True
 
def solve():
    open = deque([(ddata, "", px, py)])
    visited = set([ddata])
    dirs = ((0, -1, 'u', 'U'), ( 1, 0, 'r', 'R'),
            (0,  1, 'd', 'D'), (-1, 0, 'l', 'L'))
 
    lnrows = nrows
    while open:
        cur, csol, x, y = open.popleft()
 
        for di in dirs:
            temp = cur
            dx, dy = di[0], di[1]
 
            if temp[(y+dy) * lnrows + x+dx] == '*':
                temp = push(x, y, dx, dy, temp)
                if temp and temp not in visited:
                    if is_solved(temp):
                        return csol + di[3]
                    open.append((temp, csol + di[3], x+dx, y+dy))
                    visited.add(temp)
            else:
                if sdata[(y+dy) * lnrows + x+dx] == '#' or \
                   temp[(y+dy) * lnrows + x+dx] != ' ':
                    continue
 
                data2 = array("c", temp)
                data2[y * lnrows + x] = ' '
                data2[(y+dy) * lnrows + x+dx] = '@'
                temp = data2.tostring()
 
                if temp not in visited:
                    if is_solved(temp):
                        return csol + di[2]
                    open.append((temp, csol + di[2], x+dx, y+dy))
                    visited.add(temp)
 
    return "No solution"
 
 
level = """\
#######
#     #
#     #
#. #  #
#. $$ #
#.$$  #
#.#  @#
#######"""
 
psyco.full()
init(level)
print level, "\n\n", solve()

基本的には、パズルを表すテキスト文字列を読み取り、BFS を使用して解決します。

しかし、私が理解するのに苦労したことの 1 つは、それぞれ何sdataddata表すかでした。似ているように見え、別の文字sdataddataマップしますが、その理由はわかりません。

何か案は?

ありがとう :)

4

2 に答える 2

1

データが何にマッピングされているかを見ると:

. = end point
@ = the guy
# = wall
$ = diamond
maps = {' ':' ', '.': '.', '@':' ', '#':'#', '$':' '}
mapd = {' ':' ', '.': ' ', '@':'@', '#':' ', '$':'*'}

ssata は終点と壁の地図のように見えます。

ddata は、プレーヤーとダイヤモンドのマップのようです。

于 2013-10-08T15:38:02.017 に答える
0

sdataは迷路の静的データ (検索時に変化しない部分) を保持し、ddataは動的データ (検索時に変化する部分) を保持し、初期状態を保持するために使用されます。

ボックスと男がゴールと同じ位置にいる可能性があるため、おそらくこの方法で行われます。これにより、多くのコードが実装がより複雑になります。

検索の開始位置として最初に開いているリストにプッシュされ、既に検索された位置をマークするために訪問済みセットにプッシュされるのはddataです。

于 2015-10-22T12:27:34.167 に答える