Você é um rato. Seus amigos do mouse foram capturados e estão inconscientes e presos em um labirinto que tem apenas uma entrada / saída. Por acaso, você tem um mapa perfeito do labirinto, para poder planejar uma solução para entrar e levá-los todos em segurança. No entanto, o labirinto é protegido por um sistema de segurança que acionará um alerta se um limite 1000
for atingido, fazendo com que você seja capturado e falhe em sua missão de resgate.
De suas investigações anteriores do labirinto, cada quadrado que você pisa (ou seja, cada movimento horizontal ou vertical - os ratos não podem se mover na diagonal ) é adicionado 1
ao balcão do sistema de segurança. No entanto, se você está carregando um peso (um bloco de dinamite ou um amigo inconsciente do mouse), ele adiciona, 2
pois detecta a pressão adicional. A praça de entrada / saída não possui esse sistema de segurança e, portanto, não é adicionada ao balcão.
Você tem um suprimento ilimitado de dinamite que você trouxe para a entrada, então você pode simplesmente explodir todas as paredes para libertar seus amigos. Mas você precisa ser cauteloso ao fazer isso, pois cada explosão aumenta 50
o contador devido à pressão concussiva. Além disso, você só pode carregar uma coisa de cada vez, um mouse ou um bloco de dinamite. Como cada bloco de dinamite pode detonar apenas um espaço de parede, isso significa que, se houver várias paredes seguidas, você precisará fazer uma viagem de mãos vazias de volta à entrada para obter mais.
Exemplo elaborado
Suponha que nosso labirinto se pareça com o seguinte:
######
#M# E#
######
Vou usar c
no balcão. Começamos no E
ntrance, movemos um quadrado à esquerda enquanto carregamos dinamite c=2
. Nós detonamos a dinamite para explodir a parede c=52
. Movemos dois quadrados para a esquerda, de mãos vazias, para chegar c=54
, e agora estamos de pé no quadrado do mouse. Pegamos nosso amigo e movemos 3 quadrados de volta para o E
xit, mas o último quadrado não conta, pois não possui sensores, então são apenas 2 quadrados com algo nas costas. Isso significa que quando chegamos à saída com o mouse final c=58
, que é menor que 1000
e, portanto, a missão é bem-sucedida.
Desafio
Dado um labirinto de entrada, verifique se você, o herói do mouse, pode resgatar com êxito todos os ratos presos dentro das restrições descritas acima ou se a missão é uma falha.
Entrada
- Um labirinto 2D em qualquer formato aceitável (cadeia de linhas múltiplas, matriz de linhas, etc.).
- Para esse desafio,
#
usarei as paredes internas e externas,M
os amigos do mouse eE
a entrada. - A entrada nunca será imediatamente adjacente a uma parede interna (sempre haverá pelo menos um espaço para se movimentar livremente).
- Você pode substituir qualquer caractere ASCII imprimível que desejar, desde que consistente. Isso permite que você use dois símbolos diferentes para paredes internas versus paredes externas, desde que mantenha a consistência (por exemplo, se você optar por usar
@
paredes interiores e deixar#
para o exterior, todas as paredes internas devem ser@
e todas as paredes externas#
) - O labirinto sempre será completamente delimitado por paredes, mas não é necessariamente retangular. Se desejar, você pode assumir que o labirinto é preenchido com espaços para criar uma entrada retangular (opcional).
- O labirinto pode ter seções inacessíveis sem dinamite.
- Você não pode dinamitar as paredes exteriores do labirinto.
Saída
Um valor de verdade / falsey . Na verdade, para "Sim, o mouse pode resgatar qualquer outro mouse" ou Falsey para "Não, o sistema de alarme será acionado".
As regras
- Um programa completo ou uma função são aceitáveis.
- As brechas padrão são proibidas.
- Isso é código-golfe, portanto todas as regras usuais de golfe se aplicam e o código mais curto (em bytes) vence.
Exemplos
Exemplos de verdade, separados por linhas em branco.
#####
#M E#
#####
######
#M# E#
######
########
#E # M#
# # #
# # #
# #
########
#############################
# ## # # #
# M ## M # # #
# ## # M # E #
#M ## # # #
#############################
###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMM MM#
#MMMMMMMMMMMME#
###############
Exemplos de Falsey, separados por linhas em branco
#############################
#M ## ## ## #
# M ## M ## ## #
# ## ## M ## E #
#M ## ## ## #
#############################
#############################
########
########
# # #
# M # M#
########
#####
# M #
#####
#####
#####
#####
###################
# # # ## ## # # #
#M#M#M## E ##M#M#M#
# # # ## ## # # #
###################
#######
######
#####
####
# M#
####
###############
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMMM#
#MMMMMMMMMMMME#
###############
fonte
Respostas:
Perl,
216215 bytesInclui +2 para
-0p
Dê entrada no STDIN. Use
%
para paredes externas, paredes#
internas,0
espaços vazios,8
ratos er
posição inicial. As placas inteiras devem ser acolchoadas para formar um retângulo. Você pode transformar e executar os exemplos como:dynamite.pl
:Substitua as
\xhh
fugas pela pontuação reivindicada.O programa não pode lidar realisticamente com casos complexos. Em particular, ele não pode lidar com nenhum dos casos de falha. Isso ocorre porque existem muitas maneiras diferentes de explodir as paredes internas ou pegar ratos, de modo que a pesquisa se torna muito ampla e usa muita memória, embora seja pelo menos inteligente o suficiente para nunca processar o mesmo estado várias vezes. O limite de pressão deve ser reduzido para mais
100
ou menos para tempos de execução suportáveis e uso de memória.Explicação
Eu uso o padrão de bits de um caractere para representar o estado de um campo:
Por exemplo, o herói (
01000000
) carregando dinamite (00000001
) deve estar em um lugar em que possa andar (00010000
) e queremos que todos os valores sejam ASCII (00100000
) imprimíveis . Tomar o bit a bitor
de todas essas máscaras de bits fornece01110001
qual é o código ASCIIq
. No total, isso se torna:O programa considerará apenas o herói se movendo para a direita (a rotação explicada mais adiante cuidará das outras direções). As máscaras de bits foram escolhidas com cuidado, de modo que o herói sempre seja representado por uma letra e um local para onde ele possa se mover por um dígito (exceto o herói em casa carregando uma vítima, mas novamente isso é intencional, de modo que o único movimento do herói seja soltar). a vítima). Assim, um herói que pode avançar é correspondido por
/\pL\d/
. A substring correspondente deve ser modificada para que o herói e o que ele está carregando sejam removidos do primeiro caractere e adicionados ao segundo, o que pode ser feito com um bit a bitxor
com o mesmo valor para os dois caracteres. O valor xor consiste no bit de herói (01000000
), no bit de dinamite (00000001
) e no bit de mouse de transporte (00000100
). Juntos, elesor
a01000101
que é ASCIIE
. Então, movendo o herói se torna:O herói pode explodir um muro se ele estiver bem na frente dele e estiver carregando dinamite (
q
,s
ouy
). O herói perderá sua dinamite (xor
com00000001
) e a parede#
mudará para uma passagem0
(xor com00010011
), entãoPara lidar com as outras direções, a placa inteira é girada (a placa girada termina em
$o
):Além de se mover, o herói também tem várias outras opções que ele pode fazer:
Isso é feito por
O tabuleiro termina se o herói estiver em casa carregando nada (
x
) e não houver mais vítimas para resgatar (não2
). Isso pode ser convenientemente testado usandoUma vez resolvido o quadro, quero lembrar desse estado e, no final, imprimi-lo. Para isso, carrego a bandeira "está resolvido"
$\
e a imprimo no final do programa sem imprimir$_
, portantoOs estados a serem processados na pressão 0 são mantidos
@0
, na pressão 1 ligada@1
etc. A pressão atual é mantida$%
. Usando$n
ou algo assim seria mais curto, mas o código não funciona se a variável não é inicializado para alguma coisa, porque autovivification, caso contrário, alterar$n
a um reference.Looping ARRAY sobre os estados em um determinado pressão é feito através de umfor
e não umamap
causa com a,for
você pode estender a matriz enquanto ela ainda estiver sendo repetida e capturar os novos elementos. Isso é necessário porque as rotações e as opções de campo único do herói acontecem no tempo 0 e acabam na mesma matriz de pressão. Portanto, o loop para uma dada pressão é feito porIsso é repetido até que a pressão atinja 1000 ou seja encontrada uma solução:
Tudo o que resta é adicionar estados recém-descobertos às suas respectivas matrizes de pressão. Isso será feito por sub-rotina
f
. Queremos adicionar um estado apenas se ele ainda não foi visto. Os estados que foram vistos anteriormente são mantidos em%a
:$n
representa a nova pressão para um estado. Deduzirei isso do estado que as variáveis regex ainda têm como resultado da ação do herói que levou a essa chamada:Isso leva à seguinte fórmula para
$n
:Todas as substituições obtêm um
r
modificador para retornar o estado alterado e deixar o estado atual$_
sozinho.f
é chamado nesse estado alterado, para que você obtenha código comoComo o cálculo de
$n
precisa das variáveis regex, elas devem ser desabilitadas como padrão, caso as substituições não alterem nada (porque a condição para acioná-las não é cumprida). Também não devo pegar nenhuma variável regex de um loop anterior. Portanto, as substituições são agrupadas em{}
blocos para salvar e restaurar o estado regex. É assim que você obtém declarações comoEm particular, a rotação é tão empacotada que chama
f
sem variáveis regex e obtém uma contribuição de pressão de 0.A única coisa a fazer é
@0
começar com o estado inicial no inícioIsso está no loop principal e, portanto, também tenta aumentar os
$_
arrays de pressão posteriores, mas como o estado inicial já estará,%a
nada acontecerá.Juntos, tudo isso basicamente encontra a solução mais curta usando o algoritmo de Dijkstra . Existe um problema em potencial. O código atual não adicionará um estado se for redescoberto com uma pressão menor que a primeira descoberta. Não pude construir um quadro que desencadeasse isso, mas também não consegui provar que é impossível.
fonte
JavaScript,
863834785781 bytesEconomizou 29 bytes graças à ETHproductions
Economizou 53 bytes graças à Jordan
Recebe a entrada como uma sequência multilinha.
Isso define uma função anônima que usa uma função recursiva
f
para determinar se você dispara o alarme antes de recuperar todos os ratos.f
retorna1000
se a pressão estiver acima de 1000 (para evitar recursão sem fim), retorna a pressão se não houver mais mouses para resgatar e o mouse na saída e retorna a pressão mínima de todos os movimentos possíveis do estado atual. Ele usa uma matrizL
para acompanhar as posições já visitadas, ondeL[pos]==0
se é visitada e indefinida, se não for. Isso pode não ser necessário, mas impede que o mouse faça movimentos inúteis e gere erros de recursão, no mínimo. (Isso significa que você deve redefinirL
se estiver testando isso várias vezes)Isso usa o formato da pergunta que não seja o que exige que você use um caractere diferente para as paredes externas. (Qualquer coisa que não seja
# MEmecd
)Versão mais legível:
fonte
s in L|p > 999
.eval
e substituir@
com$1
(não tenho certeza se isso vai funcionar, mas você escreve$1
um monte)f
umaf=(...)=>s in L|p>999?1e3:!/M/.test(s,L[s]=0)&/E/.test(s)?p:Math.min(...
$1
18 vezes e.replace("@","$1")
tem 18 bytes. Não vejo uma maneira de fazer isso.