O usuário CarpetPython publicou uma nova visão sobre esse problema, que coloca um foco muito maior nas soluções heurísticas, devido ao aumento do espaço de pesquisa. Pessoalmente, acho que esse desafio é muito melhor do que o meu, então considere tentar esse!
Vector racing é um jogo viciante que pode ser jogado com uma caneta e uma folha de papel quadriculado. Você desenha uma pista arbitrária no papel, define um começo e um fim e depois dirige seu carro de tamanho pontual de maneira baseada em turnos. Chegue ao fim o mais rápido possível, mas tome cuidado para não acabar em uma parede!
The Track
- O mapa é uma grade bidimensional, onde cada célula possui coordenadas inteiras.
- Você move nas células da grade.
- Cada célula da grade faz parte da trilha ou é uma parede.
- Exatamente uma célula da trilha é a coordenada inicial.
- Pelo menos uma célula de rastreamento é designada como objetivo. A aterrissagem em qualquer um deles completa a corrida. Várias células de objetivo não estão necessariamente conectadas.
Dirigindo o carro
Seu carro começa em uma determinada coordenada e com vetor de velocidade (0, 0)
. Em cada turno, você pode ajustar cada componente da velocidade ±1
ou deixá-lo como está. Em seguida, o vetor de velocidade resultante é adicionado à posição do seu carro.
Uma imagem pode ajudar! O círculo vermelho era sua posição no último turno. O círculo azul é sua posição atual. Sua velocidade é o vetor do círculo vermelho ao azul. Nesse turno, dependendo de como você ajusta sua velocidade, você pode mover-se para qualquer um dos círculos verdes.
Se você cair em uma parede, você perde imediatamente.
Sua tarefa
Você adivinhou: escreva um programa que, dado uma pista de corrida como entrada, leve o carro a uma das células do gol no menor número de curvas possível. Sua solução deve ser capaz de lidar razoavelmente bem com trilhas arbitrárias e não ser otimizada especificamente para os casos de teste fornecidos.
Entrada
Quando seu programa é chamado, leia a partir de stdin :
target
n m
[ASCII representation of an n x m racetrack]
time
target
é o número máximo de turnos que você pode fazer para concluir a faixa e time
o orçamento total de tempo para a faixa, em segundos (não necessariamente inteiro). Veja abaixo os detalhes sobre o tempo.
Para a faixa delimitada por nova linha, os seguintes caracteres são usados:
#
- paredeS
- o começo*
- um objetivo.
- todas as outras células da via (estrada)
Todas as células fora da n x m
grade são implicadas em paredes.
A origem das coordenadas está no canto superior esquerdo.
Aqui está um exemplo simples:
8
4.0
9 6
###...***
###...***
###...***
......###
S.....###
......###
Usando indexação baseada em 0, a coordenada inicial seria (0,4)
.
Após cada movimento, você receberá mais informações:
x y
u v
time
Onde x
, y
, u
, v
são todos os inteiros baseados em 0. (x,y)
é sua posição atual e (u,v)
sua velocidade atual. Observe que x+u
e / ou y+v
pode estar fora dos limites.
time
é o que resta do seu orçamento de tempo, em segundos. Sinta-se livre para ignorar isso. Isso é apenas para participantes que realmente querem levar sua implementação ao limite de tempo.
Quando o jogo terminar (porque você caiu em uma parede, saiu dos limites, excedeu as target
curvas, ficou sem tempo ou atingiu a meta), você receberá uma linha vazia.
Saída
Para cada turno, escreva para stdout :
Δu Δv
onde Δu
e Δv
são cada uma de -1
, 0
, 1
. Isso será adicionado (u,v)
para determinar sua nova posição. Apenas para esclarecer, as instruções são as seguintes
(-1,-1) ( 0,-1) ( 1,-1)
(-1, 0) ( 0, 0) ( 1, 0)
(-1, 1) ( 0, 1) ( 1, 1)
Uma solução ideal para o exemplo acima seria
1 0
1 -1
1 0
Observe que o controlador não se conecta ao stderr ; portanto, você pode usá-lo para qualquer tipo de saída de depuração necessária ao desenvolver seu bot. Por favor, remova / comente qualquer saída desse tipo no código enviado.
Seu bot pode levar meio segundo para responder a cada turno. Para turnos que demoram mais, você terá um orçamento de tempo (por faixa) de target/2
segundos. Sempre que uma curva demorar mais de meio segundo, o tempo adicional será subtraído do seu orçamento de tempo. Quando seu orçamento de tempo chegar a zero, a corrida atual será abortada.
Novo: Por razões práticas, tenho que definir um limite de memória (já que a memória parece ser mais limitadora do que o tempo para tamanhos razoáveis de faixas). Portanto, terei que abortar qualquer execução de teste em que o piloto use mais de 1 GB de memória, conforme medido pelo Process Explorer como bytes privados .
Pontuação
Há uma referência de 20 faixas. Para cada faixa:
- Se você completar a faixa, sua pontuação é o número de movimentos necessários para alcançar uma célula de objetivo dividida por
target
. - Se você ficar sem tempo / memória ou não atingir a meta antes do
target
término dos turnos ou você cair em uma parede / fora dos limites a qualquer momento, sua pontuação será2
. - Se o seu programa não é determinístico, sua pontuação é a média acima de 10 corridas nessa faixa (por favor, indique isso na sua resposta).
Sua pontuação geral é a soma das pontuações individuais das faixas. Menor pontuação ganha!
Além disso, todo participante pode (e é fortemente encorajado a) fornecer uma faixa de referência adicional , que será adicionada à lista oficial. As respostas anteriores serão reavaliadas, incluindo esta nova faixa. Isso é para garantir que nenhuma solução seja adaptada muito de perto aos casos de teste existentes e para dar conta de casos extremos interessantes que eu poderia ter esquecido (mas que você pode perceber).
Quebra de gravata
Agora que já existe uma solução ideal, esse provavelmente será o principal fator para a pontuação dos participantes.
Se houver um empate (devido a várias respostas resolverem todas as faixas da melhor maneira ou de outra forma), adicionarei casos de teste adicionais (maiores) para romper o empate. Para evitar qualquer viés humano ao criar esses desempatadores, eles serão gerados de maneira fixa:
- Aumentarei o comprimento do lado
n
em10
comparação com a última faixa gerada dessa maneira. (Eu posso pular tamanhos se eles não quebrarem a gravata.) - A base é este gráfico vetorial
- Isso será rasterizado na resolução desejada usando esse trecho do Mathematica .
- O início está no canto superior esquerdo. Em particular, será a célula mais à esquerda da linha superior da extremidade da pista.
- O objetivo está no canto inferior direito. Em particular, será a célula mais à direita da linha mais baixa do final da pista.
- A
target
vontade4*n
.
A trilha final do benchmark inicial já foi gerada assim, com n = 50
.
O controlador
O programa que testa as submissões está escrito em Ruby e pode ser encontrado no GitHub junto com o arquivo de benchmark que utilizarei. Há também um exemplo de bot chamado randomracer.rb
lá, que simplesmente escolhe movimentos aleatórios. Você pode usar sua estrutura básica como ponto de partida para o seu bot ver como a comunicação funciona.
Você pode executar seu próprio bot em um arquivo de trilha de sua escolha da seguinte maneira:
ruby controller.rb track_file_name command to run your racer
por exemplo
ruby controller.rb benchmark.txt ruby randomracer.rb
O repositório também contém duas classes Point2D
e Track
. Se o seu envio estiver escrito em Ruby, fique à vontade para reutilizá-los para sua conveniência.
Opções de linha de comando
Você pode adicionar opções de linha de comando -v
, -s
, -t
antes do nome de arquivo do benchmark. Se você deseja usar vários comutadores, também é possível, por exemplo -vs
,. Isto é o que eles fazem:
-v
(detalhado): use isso para produzir um pouco mais de saída de depuração do controlador.
-s
(silencioso): se você preferir manter o controle de sua posição e velocidade e não se importar com o orçamento de tempo, pode desativar essas três linhas de saída a cada turno (enviadas para sua apresentação) com esta bandeira.
-t
(faixas): permite selecionar faixas individuais a serem testadas. Por exemplo -t "1,2,5..8,15"
, testaria apenas as faixas 1, 2, 5, 6, 7, 8 e 15. Muito obrigado ao Ventero por esse recurso e pelo analisador de opções.
Sua submissão
Em resumo, inclua o seguinte na sua resposta:
- Sua pontuação.
- Se você estiver usando aleatoriedade, indique isso, para que eu possa calcular sua pontuação em várias execuções.
- O código para o seu envio.
- A localização de um compilador ou intérprete gratuito para o seu idioma preferido, executado em uma máquina Windows 8.
- Instruções de compilação, se necessário.
- Uma sequência de linhas de comando do Windows para executar seu envio.
- Se o seu envio exige a
-s
bandeira ou não. - (opcionalmente) Uma nova faixa solucionável que será adicionada ao benchmark. Eu determinarei um razoável
target
para sua faixa manualmente. Quando a faixa for adicionada à referência, eu a editarei com sua resposta. Reservo-me o direito de solicitar uma faixa diferente (caso você adicione uma faixa desproporcionalmente grande, inclua arte ASCII obscena na faixa etc.). Quando adiciono o caso de teste ao conjunto de benchmarks, substituirei a trilha na sua resposta por um link para a trilha no arquivo de benchmark para reduzir a confusão nesta postagem.
Como você pode ver, testarei todos os envios em uma máquina Windows 8. Se não houver absolutamente nenhuma maneira de fazer o seu envio ser executado no Windows, também posso experimentar uma VM do Ubuntu. Isso será consideravelmente mais lento, portanto, se você deseja maximizar o limite de tempo, verifique se o seu programa é executado no Windows.
Que o melhor motorista surja vetorial!
Mas eu quero jogar!
Se você quiser experimentar o jogo para ter uma idéia melhor, existe esta implementação . As regras usadas lá são um pouco mais sofisticadas, mas é semelhante o suficiente para ser útil, eu acho.
Entre os melhores
Última atualização: 01/09/2014, 21:29 UTC
Faixas de referência: 25
Tamanhos de desempatador: 290, 440
- 6.86688 - Kuroi Neko
- 8.73108 - user2357112 - segundo envio
- 9.86627 - nneonneo
- 10.66109 - user2357112 - 1º envio
- 12.49643 - Ray
- 40.0759 - pseudônimo117 (probabilístico)
Resultados detalhados do teste . (As pontuações para envios probabilísticos foram determinadas separadamente.)