Как мне получить больше Клоцких в моей жизни?

15

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

Ваш вклад будет в следующем формате:

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

где #представляет стены, .представляет открытую область, gпредставляет цель, а соседние числа представляют различные блоки. Вы можете предположить, что:

  1. Там будет не более 10 блоков
  2. Там не будет двух блоков с одинаковым номером
  3. Все блоки будут обнесены стенами
  4. Сетка прямоугольная
  5. 0Блок достаточно большой , чтобы охватить все гола квадратов.
  6. Есть правильное решение

Вам необходимо вернуть последовательность ходов, которая поместит 0блок так, чтобы он охватывал все квадраты ворот. Блоки не могут проходить через стены или другие блоки. Для вышеупомянутой загадки соответствующая последовательность будет

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

в то время как представляет перемещение 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#
######

Это код-гольф, поэтому выигрывает самое короткое (в байтах) решение!

Натан Меррилл
источник
Просто мысль - когда я прочитал это, я нашел что-то немного запутанное. Цели, будучи «скрытыми», иногда было трудно увидеть. В приведенном вами примере их можно «угадать» с разумной точностью, однако, если блок полностью покрывает цель, у вас должен быть способ четко обозначить всю цель. Что если: буквы для блоков, верхний регистр, когда это место находится на цели? , для космоса, * для цели? все остальное такое же? это было бы более ясно?
То же
@ Так же никогда не бывает, чтобы блок начинался с поля ворот. В последнем примере просто есть два отключенных поля для ворот.
Натан Меррилл
Можем ли мы предположить, что у каждой входной головоломки есть решение?
orlp
@ или да, я добавлю это к постановке задачи.
Натан Меррилл
@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),)))
orlp
источник
Вау здорово! И, конечно, не на самом быстром языке
edc65
Кажется, это совершенно другой подход, и я плохо понимаю Python. Но мне нравится идея найти части с одинаковой формой. Это может значительно уменьшить пространство посещаемой позиции в моем коде. Могу ли я взять его для моего решения?
edc65
@ edc65 Конечно. Хотя это не другой подход, я также сначала выполняю поиск в ширину - я просто не смотрю на одну и ту же доску дважды (и блоки с одинаковой формой поменялись местами, как и на одной доске).
Орл
4

JavaScript (ES6), 446 388

Поиск в ширину, поэтому первое найденное решение является самым коротким.
Хотя я все еще думаю, что это хорошее решение, этого недостаточно. Даже после проверки миллионов позиций (время выполнения несколько минут), я не смог найти решение для примера 2 и 3.

Отредактируйте модифицированную версию ES6, чтобы преодолеть ограничение по времени выполнения JavaScript. Головоломка 3 решается за 7 минут, 145 шагов. Головоломка 2 решена за 10 минут, 116 шагов

Изменить 2 Большое ускорение, используя идею @ orlp считать равными любые два блока с одинаковой формой (исключая специальный блок '0'). Это уменьшает пространство посещаемых позиций во время BSF. Например, для головоломки 2 любая позиция с замененным блоком 1,2,3 или 5 действительно одинакова.

Время: самая длинная головоломка 3 ~ 20 секунд на моем ноутбуке.

Используйте 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
edc65
источник
Чтобы проверить ваше решение (и другие решения), можете ли вы опубликовать количество ходов, которые вы получаете за каждую опубликованную мной проблему?
Натан Меррилл