Hayatımda nasıl daha fazla Klotski alabilirim?


15

Karo bulmacaları gerçekten çok seviyorum, ama son zamanlarda onlar için zamanım olmadı. Bu nedenle, bana karo fayans bulmacalarını, özellikle Klotski bulmacalarını düzeltmem için bir programa ihtiyacım var.

Girişiniz şu biçimde olacaktır:

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

burada #duvarları .temsil eder, açık bir alanı gtemsil eder, hedefi temsil eder ve bitişik sayılar farklı blokları temsil eder. Şunu kabul edebilirsiniz:

  1. 10 bloktan fazla olmayacak
  2. Aynı numaraya sahip iki blok olmayacak
  3. Tüm bloklar duvarlarla çevrilecektir
  4. Izgara dikdörtgen şeklindedir
  5. 0Blok hedefi kareler tümünü kapsayacak şekilde geniş yeterlidir.
  6. Geçerli bir çözüm var

0Tüm hedef kareleri kapsayacak şekilde bloğu koyacak bir dizi hamle geri döndürmeniz gerekir . Bloklar duvarlardan veya diğer bloklardan geçemez. Yukarıdaki bulmaca için uygun bir sıra

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

2blok 1 karenin sola hareket etmesini , 1blok 2 karenin sağını (hedefin üstünde) sonra 1 kare aşağıyı ve sonra 03 kareyi sağa bloklamayı temsil eder.

Aslında yukarıdaki problem için çalışacak birkaç dizi vardır ve bunlardan herhangi birini üretmek kabul edilebilir. Çözümünüz optimal olmalı, yani bulmacayı mümkün olduğunca az adımda çözen bir sıra üretmelidir.

Sekans yukarıdaki gibi yazdırılmalıdır, ancak virgül, yeni satır veya boşlukla ayrılmış olabilir. Sonunda virgül veya boşluk olup olmadığı umurumda değil. Çıkışı makul sürede üretmelisiniz (aşağıdaki bulmacalarda maksimum 120 saniye).

Bulmaca 1:

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

Bulmaca 2:

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

Bulmaca 3:

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

Bulmaca 4:

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

Bu kod golf, bu yüzden en kısa çözüm (bayt cinsinden) kazanır!


Sadece bir düşünce - bunu okurken biraz kafa karıştırıcı bir şey buldum. "Gizli" olan hedefleri bazen görmek zordu. Sahip olduğunuz örnekte, resonable doğrulukla "tahmin edilebilir", ancak bir bloğun hedefi tamamen kaplaması durumunda, tüm hedefi açıkça belirtmek için bir yolunuz olmalıdır. Ya eğer: Bloklar için mektuplar, o nokta bir gol olduğunda büyük harf? . uzay için, * gol için? her şey aynı mı? bu daha açık olur muydu?
Ditto

@Kesinlikle bir bloğun hedef karesinde başladığı bir durum yoktur. Son örnekte bağlantısız iki hedef karesi vardır.
Nathan Merrill

Her giriş bulmacasının bir çözümü olduğunu varsayabilir miyiz?
orlp

@orlp evet, bunu problem ifadesine ekleyeceğim.
Nathan Merrill

@NathanMerrill İşleri doğru yaptığımızdan emin olmak için 1-4 arası bulmaca için en uygun hamle miktarını ekleyebilir misiniz?
orlp

Yanıtlar:


5

Python, 1761

Bu soruya biraz yanmış, bu yüzden kendimi golf için getiremedim. Her iki durumda da, şu anda her şeyi zaman sınırı içinde çözen tek çözümdür (en uzun, # 3, 27 saniye sürer).

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

Vay harika! Ve kesinlikle en hızlı dilde değil
edc65

Tamamen farklı bir yaklaşım gibi görünüyor ve Python'u iyi anlamıyorum. Ama aynı şekle sahip parçaları bulma fikrini seviyorum. Bu, kodumdaki ziyaret edilen konum alanını çok azaltabilir. Çözümüm için ödünç alabilir miyim?
edc65

@ edc65 Elbette. Yine de farklı bir yaklaşım değil, aynı zamanda ilk genişlik aramasını da yapıyorum - sadece aynı tahtaya iki kez bakmıyorum (ve aynı tahta ile aynı şekle sahip bloklar sayılıyor).
orlp

4

JavaScript (ES6), 446 388

Genişlik İlk Arama, bu yüzden bulunan ilk çözüm en kısa olanıdır.
Hala bunun iyi bir çözüm olduğunu düşünmeme rağmen, yeterince iyi değil. Milyonlarca pozisyonu kontrol ettikten sonra bile (çalışma zamanı birkaç dakika), örneğin 2 ve 3 için bir çözüm bulamadım.

Düzenleme ES6 versiyonunu modifiye JavaScript yürütme süresi sınırını aşmak için. Bulmaca 3 7dk, 145 adımda çözüldü. Puzzle 2, 10dk, 116 adımda çözüldü

Düzenle 2 @ orlp'nin aynı şekle sahip iki bloğa eşit olduğunu düşünme fikrini kullanarak büyük hızlanma (özel olan '0' bloğu hariç). Bu, BSF sırasında ziyaret edilen konumların alanını azaltır. Örneğin, bulmaca 2 için, 1,2,3 veya 5 bloğu değiştirilmiş herhangi bir pozisyon gerçekten aynıdır.

Zamanlama: en uzun dizüstü bilgisayarımda bulmaca 3, ~ 20 sn.

Test etmek için yeni JsFiddle ile oynamak için Firefox'u kullanın .

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

demode

EcmaScript 6 (FireFox) JSFiddle

EcmaScript 5 (Chrome) JSFiddle

Misal

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

Bulmaca 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

Bulmaca 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

Bulmaca 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

Bulmaca 4

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

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

Çözümünüzü (ve diğer çözümleri) doğrulamak için, gönderdiğim her sorun için alacağınız hamle sayısını kaydedebilir misiniz?
Nathan Merrill
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.