Làm thế nào để tôi có được nhiều Klotski hơn trong cuộc sống của tôi?


15

Tôi thực sự thích các câu đố gạch trượt, nhưng gần đây, tôi không có thời gian cho chúng. Do đó, tôi cần một chương trình để cung cấp cho tôi cách khắc phục các câu đố trượt, đặc biệt là các câu đố Klotski.

Đầu vào của bạn sẽ có định dạng sau:

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

trong đó #đại diện cho các bức tường, .đại diện cho một khu vực mở, gđại diện cho mục tiêu và các số liền kề đại diện cho các khối khác nhau. Bạn có thể cho rằng:

  1. Sẽ không có quá 10 khối
  2. Sẽ không có hai khối có cùng số
  3. Tất cả các khối sẽ được bao quanh bởi các bức tường
  4. Lưới hình chữ nhật
  5. Các 0khối là đủ lớn để trang trải tất cả các hình vuông được mục tiêu.
  6. Có một giải pháp hợp lệ

Bạn cần trả về một chuỗi các bước di chuyển sẽ đặt 0khối sao cho nó bao phủ tất cả các ô vuông mục tiêu. Các khối không thể xuyên qua tường hoặc các khối khác. Đối với câu đố trên, một chuỗi thích hợp sẽ là

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

trong khi đại diện cho việc di chuyển 2khối 1 hình vuông sang trái, 1khối 2 hình vuông bên phải (trên cùng của mục tiêu) sau đó 1 hình vuông xuống, và sau đó 0khối 3 hình vuông bên phải.

Thực tế, có một số trình tự sẽ hoạt động cho vấn đề trên, và sản xuất bất kỳ trong số chúng là chấp nhận được. Giải pháp của bạn phải là tối ưu, có nghĩa là nó sẽ tạo ra một chuỗi giải câu đố trong càng ít bước càng tốt.

Trình tự nên được in ra như trên, nhưng có thể là dấu phẩy, dòng mới hoặc khoảng cách. Tôi không quan tâm nếu có dấu phẩy hoặc khoảng trắng. Bạn nên tạo đầu ra trong thời gian hợp lý (tối đa 120 giây cho các câu đố bên dưới).

Câu đố 1:

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

Câu đố 2:

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

Câu đố 3:

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

Câu đố 4:

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

Đây là môn đánh gôn, vì vậy giải pháp ngắn nhất (tính bằng byte) sẽ thắng!


Chỉ là một suy nghĩ - khi tôi đọc điều này, tôi thấy có gì đó hơi khó hiểu. Các mục tiêu, bị "ẩn" đôi khi rất khó nhìn thấy. Trong ví dụ bạn có, chúng có thể được "đoán" với độ chính xác có thể cộng hưởng, tuy nhiên, trong trường hợp một khối bao phủ toàn bộ mục tiêu, bạn nên có cách để biểu thị rõ ràng toàn bộ mục tiêu. Điều gì xảy ra nếu: Chữ cái cho các khối, Chữ hoa khi điểm đó nằm trên một mục tiêu? . cho không gian, * cho mục tiêu? mọi thứ khác giống nhau? điều đó sẽ rõ ràng hơn?
Ditto

@Ditto không bao giờ có trường hợp một khối bắt đầu trên ô vuông mục tiêu. Ví dụ cuối cùng đơn giản là có hai ô vuông mục tiêu bị ngắt kết nối.
Nathan Merrill

Chúng ta có thể giả sử mọi câu đố đầu vào có một giải pháp?
orlp

@orlp có, tôi sẽ thêm nó vào báo cáo vấn đề.
Nathan Merrill

@NathanMerrill Để chắc chắn rằng chúng tôi đang làm mọi thứ chính xác, bạn có thể thêm số lần di chuyển tối ưu cho câu đố 1-4 không?
orlp 28/03/2015

Câu trả lời:


5

Con trăn, 1761

Loại câu hỏi này bị đốt cháy, vì vậy tôi không thể tự mình chơi golf. Dù bằng cách nào, ngay bây giờ, đây là giải pháp duy nhất giải quyết mọi thứ trong thời gian giới hạn (dài nhất, # 3, mất 27 giây).

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),)))

Woa thật tuyệt! Và chắc chắn không phải bằng ngôn ngữ nhanh nhất
edc65

Có vẻ như một cách tiếp cận hoàn toàn khác và tôi không hiểu rõ về Python. Nhưng tôi thích ý tưởng tìm kiếm những mảnh ghép có hình dạng tương tự. Điều đó có thể làm giảm rất nhiều không gian của vị trí được truy cập trong mã của tôi. Tôi có thể mượn nó cho giải pháp của tôi?
edc65

@ edc65 Chắc chắn rồi. Tuy nhiên, đây không phải là một cách tiếp cận khác, tôi cũng thực hiện tìm kiếm đầu tiên theo chiều rộng - tôi chỉ không nhìn vào cùng một bảng hai lần (và các khối có cùng hình dạng được hoán đổi như cùng một bảng).
orlp

4

JavaScript (ES6), 446 388

Breadth First Search, vì vậy giải pháp đầu tiên được tìm thấy là ngắn nhất.
Mặc dù tôi vẫn nghĩ đó là một giải pháp tốt, nhưng nó không đủ tốt. Ngay cả sau khi kiểm tra hàng triệu vị trí (thời gian chạy vài phút), tôi không thể tìm thấy giải pháp cho ví dụ 2 và 3.

Chỉnh sửa phiên bản sửa đổi ES6 để vượt qua giới hạn thời gian thực hiện javascript. Câu đố 3 đã giải trong 7 phút, 145 bước. Câu đố 2 đã giải trong 10 phút, 116 bước

Chỉnh sửa 2 Tăng tốc lớn, sử dụng ý tưởng của @ orlp về việc xem xét bằng nhau bất kỳ hai khối có cùng hình dạng (không bao gồm khối '0' là đặc biệt). Điều này làm giảm không gian của các vị trí được truy cập trong BSF. Ví dụ, đối với câu đố 2, bất kỳ vị trí nào có khối 1,2,3 hoặc 5 được trao đổi đều thực sự giống nhau.

Thời gian: dài nhất là câu đố 3, ~ 20 giây trên máy tính xách tay của tôi.

Sử dụng Firefox để chơi với JsFiddle mới để kiểm tra.

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

Lỗi thời

EcmaScript 6 (FireFox) JSFiddle

EcmaScript 5 (Chrome) JSFiddle

Thí dụ

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

Câu đố 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

Câu đố 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

Câu đố 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

Câu đố 4

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

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

Để xác minh giải pháp của bạn (và các giải pháp khác), bạn có thể đăng số lượng di chuyển bạn nhận được cho mỗi vấn đề tôi đã đăng không?
Nathan Merrill
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.