É o sprint final ... e metade do seu time está doente. Você está trabalhando até tarde, apenas fazendo sua última confirmação do dia, esperando ... por que as luzes se apagaram? Não me lembro do cara da segurança por aí ... oh não! Deixei minhas chaves em casa!
À medida que o horror da situação afunda, você decide que vai escapar .
Resumo da tarefa
Para efetuar sua fuga, você precisa de um plano! No entanto, você sabe que qualquer plano tem uma chance de falhar, e planos diferentes exigem quantidades diferentes de esforço.
Sendo faminto, cansado e engenheiro, você decide escrever um pequeno programa para determinar a melhor maneira de escapar do complexo, equilibrando as preocupações de probabilidade de sucesso e o esforço necessário.
Você faz um mapa do edifício:
#######################
# = #
! = ! <-- window
# ! = # (freedom!)
#################= #
# # = #
# # = #
# # = #
# o ! # # ! = #
##| ! ## # ! = #
#######################
^ ^ ^
me my door ludicrously high shelves
(locked) (climbable)
Para escapar do escritório, você terá que sair do mapa. Aqui você vê que existem 2 janelas ( !
), qualquer uma delas levaria você à liberdade, mas apenas uma delas acessível. Definimos 'fora do mapa' como tendo os pés fora dos limites do mapa
Tipos de células
- empty, you can be here (i.e. the escapee can consume this cell)
# - solid (your desk, your in-tray), you can't be here, but you can stand on it
! - destructible, (co-worker's desk, door, window), you can't be here until you smash it first (turning it into an empty cell)
= - climbable, (fire ladder, filing cabinet, etc.), you can be here
As células originalmente consumidas pelo fugitivo são consideradas vazias.
Especificações de ação
Você tem várias ações possíveis à sua disposição. Eles são definidos por transições de estado simples com alguma probabilidade de sucesso inteiro. Por exemplo, para caminhar, você move uma célula do fugitivo, que representamos com esta transição:
Degrau
1 stp, 100%, espelho
o. o
|. --> |
# #
Os pontos mostram células que devem estar vazias (ou escaláveis, mas não sólidas ou destrutíveis), porque entramos nela ou através dela. O 100% significa que você tem 100% de chance de não se machucar e terminar sua fuga ousada. Todas as probabilidades serão porcentagens inteiras entre 1% e 100%, inclusive. O primeiro diagrama mostra o estado inicial (parado em algo sólido, próximo a algum espaço vazio). O segundo diagrama mostra o estado do terminal (movido para o espaço vazio). Não há requisitos para que células não especificadas (espaços ) à esquerda (estado inicial) sejam algo em particular. Células não especificadas (espaço,
) à direita (estado terminal) deve ser o mesmo de antes (por exemplo, o que estiver atrás do fugitivo ou o que eu estiver andando (seja um espaço vazio ou outro)). ) os diagramas mudam apenas as células de destrutíveis para vazias, nenhuma outra alteração pode ocorrer. "1 stp" significa que custa 1 stp: definimos o "stp" como a quantidade de energia necessária para dar um passo.
"espelho" significa que esta ação tem duas formas. A ação "direita" é mostrada, a ação "esquerda" é um espelho exato, por exemplo:
.o
.|
#
é a forma espelho (esquerda) de
o.
|.
#
A ação direita é chamada "Direita" (por exemplo, "Passo à direita"). A ação esquerda é chamada "Esquerda" (por exemplo, "Etapa à esquerda")
Nestes diagramas, o fugitivo é mostrado por
o
|
em pé (2 unidades de altura) e
%
quando agachado (1 unidade de altura). As células que devem ser sólidas ou destrutíveis são indicadas por um hash #
,. As células que não devem ser sólidas ou destrutíveis são indicadas por um ponto .
. As células que devem ser destrutíveis são indicadas por um estrondo !
. Um espaço vazio recém-criado é mostrado por um sublinhado _
.
x
é um ponto de referência que não se move (não existe, nenhuma restrição sobre o que essa célula deve ser (como um espaço )).
Nota: ignoramos a questão da desaceleração rápida quando você bate no chão e, sim, neste jogo você pode fazer saltos épicos totalmente em escadas)
Degrau
1 stp, 100%, espelho
o. o
|. --> |
x# x#
Descer
1 stp, 100%, espelho
= =
o. --> o
|. |
x= x=
Aleatório
3 stp, 100%, espelho
%. %
x# --> x#
Subir
10 stp, 95%, espelho
o. %
|# --> #
x# x#
Solta
0 stp, 100%
o
| --> o
x. x|
Drop (Suporte)
0 stp, 100%
% o
x. --> x|
Escalar
2 stp, 100%
= o
o --> |
x| x
Crouch
2 stp, 100%
o
| --> %
x# x#
Ficar de pé
4 stp, 100%
. o
% --> |
x# x#
Salto curto
4 stp, 95%, espelho
o.. o
|.. --> |
x# x#
Salto em comprimento
7 pts, 75%, espelho
o... o
|... --> |
x# x#
Pulo alto
12 stp, 90%, espelho
.. o
o. --> |
|
x# x#
Coloque as costas para ele!
20 stp, 80%, espelho
o!. _o
|!. --> _|
x# x#
Soco
8 pts, 90%, espelho
o! o_
| --> |
x# x#
Pontapé
8 pts, 85%, espelho
o o
|! --> |_
x# x#
Carimbo
8 stp, 90%
o o
| --> |
x! x_
Planos
Um plano é uma sequência das ações definidas acima. Por exemplo:
Step Left
High Jump Left
Crouch
Shuffle Left
Shuffle Left
Stand
Long Jump Left
Put your back into it! Left
Step Left
Observe a inclusão das gotas. As regras devem ser definidas para impedir que você faça qualquer coisa, menos cair, mas você ainda precisa planejar!
Qualquer plano tem um esforço necessário, que é a soma dos esforços para cada etapa. Há também uma probabilidade de sucesso, que é o produto das probabilidades de sucesso de cada ação. Exemplo simples:
Step Right: 1stp, 100%
Long Jump Right: 7stp, 75%
Step Right: 1stp, 100%
Stamp: 8stp, 90%
Drop: 0stp, 100%
Drop: 0stp, 100%
Drop: 0stp, 100%
Drop: 0stp, 100%
Step Left: 1stp, 100%
Step Left: 1stp, 100%
High Jump Left: 12stp, 90%
Effort = 1+7+1+8+1+1+12 = 31
Success Probability = 75%*90*90% = 60.75%
Um 'exemplo trabalhado' para o mapa na parte superior da página pode ser encontrado como uma essência .
Entrada
A entrada vem em duas partes, um número inteiro e uma matriz ou sequência de caracteres.
O número inteiro é a probabilidade mínima de sucesso aceitável (em porcentagem). Ele deve ser interpretado como uma porcentagem, portanto 80 significa que seu plano deve ter sucesso com probabilidade não inferior a 80%.
Um mapa válido é um retângulo que inclui o escapado em pé (tamanho mínimo de 1x2) e nenhum símbolo não especificado. Todas as linhas terão o mesmo comprimento. Você pode aceitar a entrada como uma sequência delimitada unidimensional (o delimitador deve ser um único caractere consistente ou um dos pares CRLF e LFCR), como uma matriz unidimensional semelhante ou uma matriz bidimensional. Se o formato de entrada escolhido não indicar a largura ou a altura do mapa de alguma forma, você poderá aceitar argumentos adicionais para eles (você deve declarar isso claramente em sua resposta). Você pode combinar argumentos de linha de comando e entrada padrão, se for adequado (por exemplo, mapa de stdin, probabilidade mínima de sucesso de argv). A seguir, exemplos de mapas válidos e inválidos.
Válido:
o
|
Válido:
# #
! o #
! | #
#########
Inválido (sem fugitivo):
# #
! #
! #
#########
Inválido (o fugitivo sempre começa em pé):
# #
! #
! % #
#########
Inválido (símbolo inválido):
# #
! ~ #
! #
#########
Inválido (não é um retângulo / linhas de comprimento diferente):
# #
! o #
! | #
#########
Você pode assumir que sua entrada é válida (não me importo com o que o seu programa faz se receber uma entrada inválida).
Saída
A saída é texto (ASCII). Pode ser retornado como uma sequência ou impresso na saída padrão. O plano deve ser delimitado por um LF, CRLF ou LFCR. Da mesma forma, deve haver outro LF, CRLF ou LFCR após o esforço necessário. Uma quebra de linha à direita é opcional.
Você deve produzir um plano ideal junto com o esforço necessário, ou "Não há esperança!" se esse plano não existir. Você não precisa gerar a probabilidade de sucesso. Este texto pode ou não ter uma quebra de linha à direita.
Um plano ideal é definido como um plano (veja acima) que exige o mínimo de esforço com pelo menos a probabilidade de sucesso especificada. Observe que os cálculos de probabilidade devem ser exatos; você não pode assumir que o ponto flutuante é bom o suficiente (é por isso que não espero que você os produza). Tentarei projetar casos de teste para testar isso razoavelmente (se você passar por eles e não fizer nenhuma suposição idiota, poderá considerar seu envio válido).
Formato:
Required Effort: <effort>
<plan>
Por exemplo, para a entrada
50
# #
! o #
! | #
#########
Uma saída apropriada seria:
Required Effort: 23
Step Left
Step Left
Step Left
Kick Left
Punch Left
Step Left
Step Left
Step Left
Step Left
A probabilidade de sucesso aqui é de 76,5%.
Para o mesmo mapa, mas com uma probabilidade mínima de sucesso de 80%, você teria que "Colocar as costas nele", o que exigiria mais esforço, mas atenderia aos critérios de probabilidade de sucesso. Se a probabilidade mínima de sucesso for maior que 80%, você precisará pensar um pouco mais (dar um soco ou chutar parte da porta e sair). Se a probabilidade mínima de sucesso fosse de 100%, você teria que imprimir "Não há esperança!"
Exemplos
É possível que haja mais de um plano válido para uma entrada, sua saída não precise ser exatamente isso, mas deve ter o esforço necessário correto e ser um plano válido. Você pode usar o verificador para verificar suas soluções (veja abaixo)
Entrada:
100
o
|
Saída:
Required Effort: 0
Drop
Entrada:
5
# = #
# = !
# = ! ! !
# =#######
# = #
# = o #
# = ! | #
##########
Saída:
Required Effort: 57
Step Left
Kick Left
Step Left
Step Left
Step Left
Climb Up
Climb Up
Climb Up
Climb Up
Climb off Right
High Jump Right
Long Jump Right
Step Right
Drop
Kick Right
Crouch
Shuffle Right
Shuffle Right
Entrada:
60
#########
# ! # #
! ! ! o #
! # ! | #
#########
Saída:
Required Effort: 58
Step Left
Kick Left
Crouch
Shuffle Left
Shuffle Left
Stand
Punch Left
Clamber Up Left
Shuffle Left
Drop (Stand)
Kick Left
Crouch
Shuffle Left
Shuffle Left
Para o mesmo mapa, mas 80%, a saída deve ser:
There is no hope!
Para o mesmo mapa, mas 50%, o esforço necessário se torna 56 com um plano diferente)
Entrada:
50
#######################
# # = #
! # = !
# # = #
###### #####!## =### #
#= ## # = #
#=############# = #
#= = #
#= o = #
#!!| = #
#######################
Saída:
Required Effort: 121
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Step Right
Climb Up
Climb Up
Climb Up
Climb Up
Climb Up
Climb Up
Climb off Right
Long Jump Left
Step Left
Step Left
Stamp
Drop
Drop
Crouch
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Shuffle Left
Stand
Clamber Up Left
Stand
Clamber Up Left
Stand
Step Left
Step Left
Step Left
Step Left
Punch Left
Clamber Up Left
Shuffle Left
Entrada:
66
######
# ###
#o ! !
#| ! !
### ##
######
Saída:
Required Effort: 37
Step Right
Put your back into it! Right
Kick Right
Crouch
Shuffle Right
Shuffle Right
Entrada:
Esta foi projetada para verificar uma série de suposições falsas às quais podemos ser vítimas e, consequentemente, parecer um pouco estranhas
30
###################
# ## # # # # = #
! ## # # # = #
# # # = #
## ############= #
# ## # #= #
# = # #= #
! = # #= #
# = # #= #
#o= ! ==#
#|= ! =#
#!= # ==########==#
# # ! !! =#
# # !! ! = #
# # !!!!#########
# # # #
# # # #
###################
Saída com restrição de chance de sucesso 30:
Required Effort: 199
Long Jump Right
Put your back into it! Right
<snip>
Saída com restrição de chance de sucesso 32:
Required Effort: 200
Long Jump Right
Punch Right
<snip>
Usando o mapa na parte superior como entrada, com probabilidade de restrição de sucesso de 1%, você deve obter um Esforço necessário de 116 (chance de sucesso de ~ 32%, isso levou cerca de 20 segundos para ser executado no meu programa de teste).
Critérios de vitória
Este é o código-golfe, que ganhe o menor código.
Para ser elegível, sua função ou programa deve funcionar e ser capaz de resolver cada um dos casos de teste acima em menos de 30 minutos em uma máquina razoável. Meu solucionador faz cada um em menos de 30 segundos. Se o script de teste (abaixo) for executado em menos de 30 minutos, você certamente estará pronto.
Exemplo Solver, Verificador, Script de Teste e TestCases (com soluções)
O código C # para um solucionador e verificador de solução está disponível aqui como uma essência . A essência também contém file.txt
, que é uma forma legível por máquina (suficiente) das ações descritas acima e é necessária para a execução do programa. Qualquer discrepância entre esse arquivo e as especificações não é intencional.
A essência também contém vários casos de teste (incluindo todos os exemplos acima) e um script do PowerShell para executar automaticamente um envio contra eles. Se o script indicar que um teste específico falhou, você poderá executar OfficeEscapeSolver.exe testcase<n>.txt outputFromYourProgram.txt
para ver mais detalhes. Soluções de exemplo para esses casos de teste estão em outra Gist .
Todo o código é uma bagunça completa (embora não seja destruída), mas você não precisa se afastar muito static void Main(...)
para alterar a quantidade de saída ( fique à vontade para usar essas informações, forneci-as para seu benefício!).
Passar em um caso de teste não significa necessariamente que sua saída esteja bem formada, pois o script e o verificador são muito generosos. Sua saída deve corresponder à especificação acima para que seu envio seja válido.
Se você acha que encontrou um bug com o solucionador ou o script de teste, um erro file.txt
ou uma caixa de teste desonesta, por favor, comente esta postagem ou faça um ping no SE Chat; Provavelmente não notarei nenhuma outra tentativa de comunicação.
Não fornecerei o script de teste no Bash ou no Lote, porque não os conheço, mas fico feliz em incluir uma tradução e escreverei uma versão em C # se as pessoas quiserem.
Post Amble
Tem perguntas? Não demora, pergunte a eles hoje!
Esta tarefa deve exigir esforço , dar aos jogadores sérios algo para afundar os dentes.
Meus agradecimentos a ais523 por seu feedback sobre entrada / saída.
Eu posso fornecer mais casos de teste no arquivo gist se as pessoas quiserem mais (não querem que esta postagem se torne mais) ou se quiserem fornecer algumas próprias.
fonte
Respostas:
Perl 5,
142514641481146914851438 bytesEsse foi um desafio divertido! E, surpreendentemente, parece que eu tenho o código mais curto até agora, um pouco abaixo de 1,5kB! :)
Tenho certeza de que finalmente consegui fazer isso funcionar. O delimitador usado é
:
e existe um preenchimento extra de duas linhas na parte superior e uma coluna de cada lado. Portanto, para sua contribuição de:meu programa levaria: (NB: deve haver dois pontos no final, mas não no começo!)
Eu uso expressões regulares para traduzir de um mapa para outro e resolver com força bruta. No entanto, não adiciono mapas à lista se esse mapa já tiver sido alcançado com menos esforço e maior ou igual probabilidade. Os mapas são removidos da lista quando todos os movimentos possíveis a partir desse ponto estiverem esgotados. O programa termina com êxito quando corresponde a um regex que mostra que eu cheguei ao lado ou ao fundo e termina com "Não há esperança!" quando a lista de mapas estiver esgotada.
Infelizmente, havia uma grande quantidade de eficiência trocada para decolar alguns bytes, portanto a versão para golfe é bastante lenta;) Perl parece achar as avaliações em particular bastante dolorosas.
Sem mais delongas,
Por uma questão de sanidade, aqui está a mesma coisa com novas linhas e alguns comentários:
Já vejo alguns lugares para aparar mais alguns bytes, mas ainda não quero passar por todos os testes. Mais tarde! :)
Edit: Adicionado alguns preenchimentos abaixo, bem como para ajustar sua saída mais exatamente ao escapar pelo chão. Foram removidas algumas das avaliações, para que o código também possa correr mais rápido agora!
Edit: Não estava manipulando escadas e cai muito bem. Ainda não lida bem com escadas ... Tentando consertar isso agora.
fonte
C #,
181414811395 bytesQue trabalho árduo !! Estou realmente bastante satisfeito com isso agora!
Experimente Online
Programa completo, leva entrada para STDIN, saída para STDOUT. Essencialmente, uma reescrita do meu solucionador original, usando um BFS simples e ineficientemente implementado para encontrar o caminho ideal. É razoavelmente rápido, não pode ser muito mais lento que minha outra implementação (ainda não o cronometrei), certamente funciona dentro do prazo. Grande parte do custo é a tabela Ação, que é codificada como valores separados por vírgula, que registram o nome, o mapa 'match / smash' e outras propriedades de cada ação disponível.
Começa lendo na probabilidade mínima de sucesso e no mapa. Em seguida, localiza o fugitivo, remove-o do mapa e cria um 'estado de pesquisa' que contém essas informações. Em seguida, ele executa o BFS, que examina repetidamente o próximo estado devido com o mínimo de esforço (garantindo que ele encontre uma solução ideal). Antes de expandir o nó, ele compara seu esforço e probabilidade de sucesso aos nós anteriores com o mesmo mapa e localização do fugitivo e se rejeita se uma rota melhor já tiver sido encontrada para esse estado. Se sobreviver a isso, ele se adiciona à tabela 'vista' para poder rejeitar o estado posteriormente. Tudo isso é para desempenho, e sem ele o fator de ramificação seria enorme. Em seguida, verifica se o fugitivo está fora do mapa. Se for, então ele vence! Ele rastreia o estado (cada estado anterior é registrado com cada estado) e cria o plano (ao contrário) antes de sair do loop BFS. Caso contrário, ele tenta aplicar todas as ações e adiciona qualquer uma que possa ser aplicada ao
due
antes de classificá-la para obter o estado de menor esforço na próxima iteração.Código formatado e comentado:
fonte