Roguelike pathfinding
Sua tarefa será, dada uma matriz bidimensional dos elementos descritos abaixo, que representa uma masmorra, produzir ou retornar um único número representando a quantidade de peças de ouro que o ladino pode coletar sem acordar nenhum monstro.
Os elementos da matriz são os seguintes:
- Os espaços vazios são representados por um
.
ou um espaço, sua chamada; - A posição inicial de Rogue é representada por, é claro
@
,; - Uma peça de ouro é representada por
$
; - Paredes são representadas por
#
; - Monstros são representados por personagens da seguinte expressão regular:
[a-zA-Z*&]
.
A matriz não deve conter caracteres não listados acima, portanto, você pode assumir que qualquer coisa que não seja uma parede, um espaço vazio, um trapaceiro ou uma peça de ouro é um monstro.
As regras para a busca de caminhos são:
- O ladino só pode andar através de células vazias ou células contendo ouro;
- Leva uma volta para mover para uma célula adjacente ou diagonalmente adjacente;
- Pegar o ouro é instantâneo;
- O ladino não pode permanecer adjacente ou diagonalmente a um monstro por mais de um turno sem acordá-lo, o que é proibido;
- O ladino pode entrar na área de consciência de um monstro várias vezes, o monstro só acordará se o ladino passar dois turnos consecutivos perto dele.
Regras de entrada e saída
Você pode obter a entrada em qualquer formato razoável, incluindo uma matriz bidimensional, uma matriz plana, uma string ou qualquer outra coisa. Se facilitar a sua vida, você também pode obter as dimensões da matriz.
É garantido que o ladino não estará perto de um monstro no começo.
Um programa completo ou uma função está bem.
Pontuação
Isso é código-golfe , a pontuação é a contagem de bytes do seu envio, com menos sendo melhores.
Casos de teste
Eu uso pontos para espaços vazios aqui para fins de legibilidade, se você desejar, poderá usar espaços (veja acima). Observe também que é uma pura coincidência que o invasor esteja sempre no canto superior esquerdo; seu código também deve lidar com qualquer outra posição válida.
1)
@..
.$.
... -> 1
Apenas um teste de sanidade.
2)
@....
...g$
..... -> 0
Mais uma vez, um teste de sanidade.
3)
@....
...$g
..... -> 1
O ladino pode pegar o ouro movendo-se da esquerda.
4)
@....g..
.......$
........
.....h.. -> 1
O ladino pode zigue-zague entre os monstros, nunca ficando por mais de um turno perto de cada um.
5)
@....z..
.......$
.....b.. -> 0
As táticas do caso de teste anterior não funcionam aqui - as áreas de sensibilidade dos monstros se sobrepõem.
6)
@$#.
###$
.... -> 1
Teste de sanidade.
7)
@..#..
$.$g.$
...#.. -> 2
Idem.
8)
@#.d#$
$...##
e.....
..$...
##..$b
.#..g$ -> 3
De todo o ouro aqui, apenas três podem ser alcançados com segurança: o ouro perto da posição inicial pode ser obtido descendo um e depois voltando à posição inicial. Para escapar do canto superior esquerdo, o ladino deve se mover diagonalmente para baixo e para a direita duas vezes. O ouro no meio não apresenta nenhum desafio. O ouro externo é guardado g
e b
pode ser obtido movendo-se na diagonal do local à direita do meio do ouro e depois retornando. O resto não pode ser obtido: o ouro no canto superior direito é bloqueado pelas paredes e o ouro no canto inferior direito requer duas voltas nas áreas de sensibilidade dos monstros.
Os seguintes casos de teste foram generosamente doados pelo mbomb007.
9)
12345678
a @....g.D
b .......$
c ......#.
d .....h.. -> 1
Este é complicado. Um caminho é b4-b5-c6-b7-c8-b8(grab)
.
10)
12345678
a @....g.D
b .......$
c .......#
d .....h.. -> 1
Um caminho é [bc]4-c5-b6-c7-b8(grab)
.
11)
12345678
a @....g.D
b ......#$
c .......#
d .....h.. -> 1
A parede extra não muda nada, [bc]4-c5-b6-c7-b8(grab)
ainda é uma solução.
fonte
@
uma entrada válida?Respostas:
soluções anteriores (parte delas) podem ser encontradas no contêiner de rodapé no link tio (essas provavelmente são mais legíveis)
JavaScript (Node.js) ,
883436411360.345311 bytesExperimente online!
Explicação -
em vez de passar do jogador para o dinheiro, fui do estojo para o @. acho que deveria ser mais rápido, porque sei quando parar de procurar (alcançar o @) e, quando você procura dinheiro, precisa sempre se mexer até cobrir todos os pontos (e as maneiras de alcançá-los). então o algo é bem simples assim - a principal função
g.map((r,y)=>[...r].map((c,x)=>A+=c=="$"&&P(g,x,y)),A=0)|A
: encontre dinheiro -> se você o encontrou -> comece a procurar o jogador -> se você o encontrou -> incremente A agora vamos ao localizador de caminho conhecido como P,if(/[.$]/.test(c=(g[y]||[])[x]))
apenas verifique se a célula atual é "especial" -> nesse caso, queremos retornar se for um jogador. casos especiais: @ # (monstro)for(;i--;) if(/^[a-zA-Z*&]$/.test(C=(g[y+~-(i/3)]||0)[x+i%3-1])) -> if my neighbor is a monster {if(m[C])return false -> and it already was in the previous turn - this path is not value M[C]=1} -> if not just add it to the neighbors monsters
for(;I--;) if(!p[(X=x+~-(I / 3))+","+(Y=y+I%3-1)]&&P(g,X,Y,M,{...p,[x+","+y]:1}))return true
repita os vizinhos novamente - se eu ainda não estava lá (p é o caminho escolhido) continue path (call P)fonte
I / 3
possui espaço desnecessário. Elimine esse espaço em branco e sua pontuação é realmente324
! (2)return true
pode serreturn 1
(um valor verdadeiro) ereturn false
pode ser simplesmentereturn
(implícitoundefined
, um valor de falsey). (3) O regex^[^.@$#]$
para verificar se não há monstros é mais curto do que^[a-zA-Z*&]$
para verificar se há monstros. Bom trabalho!