O modo de piloto automático

10

Um helicóptero que começa no canto superior esquerdo está descendo (em um espaço 2D, para os fins desta pergunta) em direção ao solo. Possui um modo de piloto automático e um modo manual.

O modo de piloto automático se comporta da seguinte maneira:

  • Se o espaço diretamente abaixo estiver livre, desça para ele.
  • Caso contrário, mova um passo para a esquerda ou direita, totalmente aleatoriamente. (Ele pode mover várias etapas dessa maneira.)

E continua repetindo esses dois passos até atingir o chão. O modo manual é mais inteligente e encontrará o caminho ideal para o solo, mesmo que isso exija mover-se para cima ou algumas manobras hábeis.

Seu trabalho é determinar se

  1. O piloto automático passará no cenário especificado,
  2. O piloto automático pode falhar no cenário especificado,
  3. O piloto automático falhará, mas o modo manual passará ou
  4. Ambos os modos falharão (não há caminho válido para o solo).

Entrada

  • Dado o cenário como uma matriz 1d ou 2d não vazia, usando dois caracteres diferentes para representar espaços livres e bloqueados. Pontuação opcional.
  • Opcional: dimensões da matriz

Resultado

Um dos quatro caracteres predefinidos indicando qual dos casos ocorreu.

Dados de amostra

Usando 0 (vazio) e 1 (bloqueado) na entrada, 1 2 3 4 na saída (conforme numerado acima)

0 0 0 0
0 1 0 0
0 0 0 1
1 1 0 0

Resultado: 1

0 0 1 0
1 0 0 1
0 0 0 0
0 1 1 0
0 0 0 1

Saída: 2(o helicóptero encontrará o 1 na quarta linha e é possível que ele se prenda no final da linha 5, se estiver no modo de piloto automático)

0 0 0 1 0
0 1 1 0 0
0 1 0 0 0
0 0 0 1 0
1 1 1 1 0

Saída: 3(Isso requer mover para cima, para que o piloto automático falhe)

1 0 0
0 0 0

Resultado: 4

0 0 0 0 1
1 1 1 0 0
1 0 0 1 0
0 1 0 0 0
0 0 1 1 1

Resultado: 4

ghosts_in_the_code
fonte
@ MartinBüttner Concluído. Como nota lateral, você prefere que as pessoas publiquem na sandbox ou publiquem diretamente e seus erros foram corrigidos? A segunda opção é mais simples, portanto, a menos que haja algum incentivo para não fazê-lo, não consigo imaginar por que seguiria a opção um.
ghosts_in_the_code
7
Pessoalmente, prefiro o sandbox, porque ele dá às pessoas mais tempo para pensar em possíveis erros, brechas ou casos de teste ausentes antes que as pessoas comecem a trabalhar no desafio. Se alguém postar uma resposta antecipada a um desafio defeituoso, você não poderá corrigi-lo sem invalidar as respostas existentes.
Martin Ender
Além disso - as entradas são sempre caracteres, ou podem ser booleanos / inteiros / etc? E saída - isso pode ser inteiro ou é necessário que seja um caractere?
Não que Charles

Respostas:

1

Ruby, 259

Eu me diverti muito com isso. Obrigado! desafios da tendem a ser excelentes divertidos com desafios interessantes. Isso pressupõe que "caracteres" na pergunta possam ser números inteiros.

Eu acho que os principais pontos de melhoria aqui são:

  1. A criação de r
  2. O horrível abuso ternário na terceira linha provavelmente pode ser transformado em algo mais medonho, mas terser algo.
->a,h,w{f=->l,s=0,y=[0]{r=w-2<s%w ?w:1,1>s%w ?w:-1,w
v=(l ?r+[-w]:a[s+w]==0?[w]:r).map{|d|a[m=s+d]==0&&!y[m]?m:p}-q=[p]
a[s]>0?q:s/w>h-2?8:v[0]?v.map{|o|f[l,y[o]=o,y]}.flatten-q :r.any?{|i|a[s+i]<1}?p: !0}
g=f[p]
[8,g[0]&&g.all?,g.any?,f[8].any?,!p].index !p}

Sem Golfe (um pouco desatualizado, mas bem próximo):

# a is a one-dimensional array of 0s and 1s, h is height, w is width
->a,h,w{
  # f recursively walks the array and returns true/false/nil for each path.
  #    True means we can reach ground.
  #    False means we are stuck in a local minimum and cannot escape
  #    Nil means we reached a local dead-end and need to backtrack.
  # l: {true=>"manual", false=>"autopilot"}
  # s: the position index
  # y: an array of booleans - true-ish means we've visited that square before
  #         (this is to prevent infinite loops, esp in manual mode)
  f=->l,s=0,y=[0]{
    # d: all the legal deltas from s (maximally, that's [1,-1,w,-w], aka [LRDU])
    # r: but the right and left get tricky on the edges, so let's pre-calculate those
    #    we'll default to "down" if "left" or "right" are illegal
    r=[w-2<s%w ?w:1,1>s%w ?w:-1]
    # if manual, [LRDU]; if auto, and you can go down, [D]. else, [LR] 
    d=l ?r+[w,-w]:a[s+w]==0?[w]:r
    # v: the legal deltas that you can go to from s (that is, unvisited and unblocked)
    v=d.map{|d|a[m=s+d]==0&&!y[m]?m:p}-[p]


    a[s]>0 ? [p]     # if we're currently blocked, return [nil] (this is only the case when a[0]==1)
      : s/w>h-2 ? !p # if we're at the bottom, return true
        : v[0] ?     # if we have a place to go....
        v.map{|o|f[l,y[o]=o,y]}.flatten-[p] # recurse with each step.
                                            # y[o]=o is a neat trick to make y[o] truthy and return o
          : r.any?{|i|a[s+i]==0} ? # otherwise, we have nowhere to go. If we could visit left/right, but have already been there
            p                      #    this is not a dead-end - return nil to remove this path
            : !!p                  # If we have a true dead-end (auto-mode with a local minimum), false
  }
  # g is the auto flight
  g=f[p]
  # finally, choose the first "true" out of:
  # 0: always 8.  Cuz why not 8?
  # 1: there is at least one auto path, and all are truthy
  # 2: any auto path is truthy
  # 3: any manual path is truthy
  # 4: true
  [8,g[0]&&g.all?,g.any?,f[!p].any?,!p].index !p
}
Não que Charles
fonte