내 인생에서 더 많은 Klotski를 얻는 방법은 무엇입니까?


15

나는 슬라이딩 타일 퍼즐을 정말 좋아하지만 최근에는 시간이 없었습니다. 따라서 슬라이딩 타일 퍼즐, 특히 Klotski 퍼즐을 고칠 수있는 프로그램이 필요합니다.

입력 내용은 다음과 같습니다.

#######
#001gg#
##.222#
.######

여기서 #벽, .열린 영역, g목표, 인접한 숫자는 다른 블록을 나타냅니다. 다음과 같이 가정 할 수 있습니다.

  1. 10 개 이하의 블록이 없습니다
  2. 같은 숫자를 가진 두 개의 블록은 없습니다
  3. 모든 블록은 벽으로 둘러싸여 있습니다
  4. 그리드는 직사각형
  5. 0블록은 목표 사각형을 모두 커버하는 대형 충분하다.
  6. 유효한 해결책이 있습니다

0모든 목표 제곱을 포함하도록 블록 을 배치 할 일련의 동작을 반환해야합니다 . 블록은 벽이나 다른 블록을 통과 할 수 없습니다. 위 퍼즐의 경우 적절한 순서는

2L,1R,1R,1D,0R,0R,0R

while은 2블록을 1 칸 왼쪽으로 이동하고 , 1블록은 2 칸 오른쪽 (목표 상단), 1 칸 아래로 이동, 03 칸은 오른쪽으로 이동을 나타냅니다.

실제로 위의 문제에 대해 작동하는 몇 가지 시퀀스가 ​​있으며 이들 중 하나를 생성하는 것이 허용됩니다. 솔루션은 최적이어야합니다. 즉, 가능한 한 적은 단계로 퍼즐을 해결하는 시퀀스를 생성해야합니다.

순서는 위와 같이 인쇄되어야하지만 쉼표, 줄 바꿈 또는 공백으로 구분 될 수 있습니다. 뒤에 쉼표 나 공백이 있는지 상관하지 않습니다. 합리적인 시간에 출력을 만들어야합니다 (아래 퍼즐에서 최대 120 초).

퍼즐 1 :

..####..
..#00#..
###00###
#......#
#.1122.#
##3124##
.#3344#.
.##55##.
..#gg#..
..####..

퍼즐 2 :

######
#1002#
#1002#
#3445#
#3675#
#8gg9#
######

퍼즐 3 :

.####.
##1g##
#22g3#
#4255#
#4.56#
#.006#
#7008#
######

퍼즐 4 :

.####.
##00##
#.00g#
#.0.1#
#..g2#
######

이것은 코드 골프이므로 가장 짧은 솔루션 (바이트)이 이깁니다!


단지 생각-이것을 읽으면서 약간 혼란스러운 것을 발견했습니다. "숨겨진"목표는 때때로보기 힘들었다. 당신이 가지고있는 예에서, 그것들은 공명 할 수있는 정확성으로 "추측"될 수 있지만, 블록이 목표를 완전히 덮고있는 경우, 전체 목표를 명확하게 나타내는 방법이 있어야합니다. 만약에 : 블록 문자, 그 자리가 목표에있을 때 대문자? . 공간, * 목표? 다른 모든 것? 더 분명할까요?
Ditto

@Ditto 목표 광장에서 블록이 시작되는 경우는 없습니다. 마지막 예에는 단순히 연결이 끊어진 두 개의 목표 제곱이 있습니다.
Nathan Merrill

모든 입력 퍼즐에 솔루션이 있다고 가정 할 수 있습니까?
orlp

@orlp 예, 문제 진술에 추가하겠습니다.
Nathan Merrill

@NathanMerrill 우리가 올바르게하고 있는지 확인하기 위해 퍼즐 1-4에 최적의 움직임을 추가 할 수 있습니까?
orlp

답변:


5

파이썬, 1761

이 질문에 불타 버렸기 때문에 스스로 골프를 타지 못했습니다. 어느 쪽이든 지금 당장은 제한 시간 내에 모든 것을 해결하는 유일한 솔루션입니다 (가장 긴 # 3, 27 초 소요).

pieces = {}
taken = set()
goals = set()

y = 0
while True:
    try:
        for x, c in enumerate(input()):
            if c == ".": continue
            if c == "g":
                goals.add((x, y))
            else:
                if c in "0123456789":
                    if c not in pieces: pieces[c] = set()
                    pieces[c].add((x, y))
                taken.add((x, y))

        y += 1

    except: break

def translate_comp(coords):
    o = min(sorted(coords))
    return set((c[0] - o[0], c[1] - o[1]) for c in coords)

similar = {}
for piece in pieces:
    k = tuple(translate_comp(pieces[piece]))
    if k not in similar: similar[k] = []
    similar[k].append(piece)


seen = set()
states = [(pieces, taken, ())]
while states:
    state = states.pop(0)
    if not goals - state[0]["0"]:
        names = {
            (-1, 0): "L",
            (1, 0): "R",
            (0, 1): "D",
            (0, -1): "U",
        }

        print(len(state[2]))
        print(" ".join(piece + names[d] for d, piece in state[2]))
        break

    for piece in pieces:
        for d in ((-1, 0), (1, 0), (0, 1), (0, -1)):
            new_pieces = state[0].copy()
            new_pieces[piece] = {(c[0] + d[0], c[1] + d[1]) for c in state[0][piece]}
            new_taken = state[1] - state[0][piece]

            # Collision
            if new_pieces[piece] & new_taken:
                continue

            gist = tuple(frozenset().union(*(new_pieces[piece] for piece in similar_set))
                         for similar_set in similar.values())

            if gist in seen:
                continue

            seen.add(gist)
            new_taken |= new_pieces[piece]
            states.append((new_pieces, new_taken, state[2] + ((d, piece),)))

와우! 그리고 가장 빠른 언어는 아닙니다
edc65

완전히 다른 접근법으로 보이며 파이썬을 잘 이해하지 못합니다. 그러나 나는 같은 모양의 조각을 찾는 아이디어를 좋아합니다. 그것은 내 코드에서 방문 위치를 많이 줄일 수 있습니다. 솔루션을 위해 빌릴 수 있습니까?
edc65

@ edc65 물론입니다. 그러나 다른 접근 방식은 아니지만 폭 넓은 첫 번째 검색도 수행합니다. 같은 보드를 두 번 보지 않습니다 (같은 보드와 같은 모양의 수를 가진 블록).
orlp

4

자바 스크립트 (ES6), 446 388

너비 우선 검색이므로 찾은 첫 번째 솔루션이 가장 짧습니다.
여전히 이것이 좋은 해결책이라고 생각하지만 충분하지 않습니다. 수백만 개의 위치 (런타임 몇 분)를 확인한 후에도 예를 들어 2와 3에 대한 솔루션을 찾을 수 없습니다.

자바 스크립트 실행 시간 제한을 극복하도록 ES6 수정 버전편집하십시오 . 퍼즐 3은 7 분, 145 단계로 해결되었습니다. 10 분, 116 단계로 해결되는 퍼즐 2

@orlp의 모양이 동일한 두 블록을 동일하게 고려한다는 아이디어를 사용하여 2 Big speedup을 편집하십시오 (특별한 블록 '0'제외). 이것은 BSF 동안 방문 위치의 공간을 줄입니다. 예를 들어 퍼즐 2의 경우 블록 1, 2, 3 또는 5가 교환 된 위치는 실제로 동일합니다.

타이밍 : 가장 긴 것은 내 노트북에서 ~ 20 초 퍼즐 3입니다.

Firefox를 사용하여 새로운 JsFiddle 을 사용하여 테스트하십시오.

F=g=>(o=>{
for(u=[i=s=''],v={},h=[],b={},k={'.':-1},l={},
g=[...g].map((c,p)=>c>'f'?(h.push(p),'.'):c<'0'?c:
l[k[c]?k[c]+=','+(p-b[c]):k[b[c]=p,c]=~(c>0),k[c]]=c),
b=Object.keys(b),b.map(c=>k[c]=l[k[c]]);
h.some(p=>g[p]!='0');[s,g]=u[++i])
b.map(b=>[-1,1,o,-o].map((d,i)=>
g.every((c,p)=>c!=b?1:(c=g[p+d])!=b&c!='.'?0:m[g[p-d]!=b?m[p]='.':1,p+d]=b,m=g.slice(0))
&&!v[q=m.map(c=>k[c]||'')+'']?v[q]=u.push([s+b+'LRUD'[i]+' ',m]):0))
})(o=~g.search(/\n/))||s

시대에 뒤쳐진

EcmaScript 6 (FireFox) JSFiddle

EcmaScript 5 (Chrome) JSFiddle

#######
#001gg#
##.222#
.######
T(ms) 10,Len7
1R 0R 1R 0R 2L 1D 0R

퍼즐 1

..####..
..#00#..
###00###
#......#
#.1122.#
##3124##
.#3344#.
.##55##.
..#gg#..
..####..

T(ms) 8030,Len70
1U 2U 3U 4U 5U 5L 4D 2R 1R 3U 5U 4L 4D 5R 5R 3D 1L 3D 1L 5L 5U 5U 2D 5R 
1R 5R 1R 1D 0D 4D 1D 0D 0L 0L 1U 1U 1U 1U 2L 2L 2U 5D 2R 0R 3R 3R 0D 0D
2L 2L 2L 5U 0U 3U 3U 4U 4U 4R 0D 3L 3U 5D 5L 5L 5L 4U 4U 0R 0D 0D

퍼즐 2

######
#1002#
#1002#
#3445#
#3675#
#8gg9#
######

T(ms) 646485, Checked 10566733, Len 116
8R 3D 4L 7U 9L 5D 7R 4R 3U 8L 9L 5L 7D 4R 6U 9U 8R 3D 6L 4L 2D 7D 2D 0R
1R 6U 6U 3U 3U 9L 8L 5L 7L 7U 2D 4R 5U 8R 8R 5D 1D 6R 3U 9U 5L 1D 1D 9R
9U 4L 4L 2U 8R 7D 2L 8U 7R 2D 4R 3D 6L 9U 4R 1U 1U 2L 8L 8D 4D 0D 9R 6R
3U 9R 6R 1U 5U 2U 8L 8L 7L 7L 4D 0D 6D 6R 1R 2U 2U 0L 6D 9D 6D 9D 1R 2R
3R 5U 5U 0L 9L 6U 4U 7R 8R 7R 8R 0D 9L 9L 6L 6L 4U 8U 8R 0R

퍼즐 3

.####.
##1g##
#22g3#
#4255#
#4.56#
#.006#
#7008#
######

T(ms) 433049, Checked 7165203, Len 145
3L 3U 5U 6U 0U 7U 8L 8L 8L 0D 0R 7R 7U 7R 4D 2D 8R 4D 2D 5L 5L 3D 1R 3R
1D 1D 5R 5U 3L 6U 2U 4U 7R 1D 8L 0L 7D 1R 2R 4U 4U 8U 8U 0L 2D 3D 3L 6L  
1U 7D 2R 0R 8D 4D 8D 4D 3L 3U 4U 4R 8U 8U 0L 7L 2D 1D 6R 4R 4U 1L 1L 1U
2U 2L 6D 6D 4R 1R 1U 2U 2L 6L 6U 4D 1R 6U 7U 7U 0R 8D 0R 2D 3D 8D 2D 3D
7L 6D 5D 5L 1L 1U 1L 6U 4U 7R 7R 6D 6L 4L 4U 7U 7U 0U 0U 2R 3D 2R 3R 3D 
6D 5D 1D 1L 4L 7L 7U 0U 2U 3R 6D 5D 4D 7L 3R 6R 8R 5D 4D 7D 4L 7D 7D 0L 
0U

퍼즐 4

.####.
##00##
#.00g#
#.0.1#
#..g2#
######

T(ms) 25,Len6
1L 1D 1L 1L 0D 0R

솔루션 (및 기타 솔루션)을 확인하기 위해 내가 게시 한 각 문제에 대한 이동 수를 게시 할 수 있습니까?
Nathan Merrill
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.