Ajuda, estou preso em uma fábrica infinita!


26

Esse desafio é vagamente inspirado no jogo Zachtronics Infinifactory .

Você tem uma visão de cima para baixo de uma grade retangular de transportadores, representada por >v<^. Pode haver células sem transportadores, representadas por espaços. Aqui está um exemplo:

> <vv    <
 v ^ >v v 
  >v^^>vv^
    ^>^ v 
>  v<v  >>
  >v v<^  

Essa configuração é implicitamente cercada por um número infinito de espaços.

Além disso, você recebe as dimensões de uma carga retangular que é colocada nos transportadores no canto superior esquerdo da grade. Sua tarefa é descobrir se a carga pára ou se acaba se movendo em um loop.

Obviamente, é provável que a carga cubra vários transportadores de uma só vez, portanto, aqui estão as regras para determinar a direção da carga em cada etapa:

  1. Transportadores opostos se cancelam. Portanto, se uma carga 3x2 cobrir qualquer uma das seguintes correções (descritas com hífens e tubos para maior clareza), o resultado será o mesmo:

    +---+   +---+   +---+
    |>>^|   |  ^|   |v^^|
    |^<<|   |^  |   |^^v|
    +---+   +---+   +---+
    

    O mesmo vale para estes:

    +---+   +---+   +---+
    |v^<|   |   |   |><>|
    |>>>|   |>> |   |>><|
    +---+   +---+   +---+
    

    Como a posição exata de um transportador embaixo da carga é irrelevante, não importa quais pares você cancela.

    Este cancelamento é aplicado antes das outras regras. Portanto, para as outras regras, só haverá transportadores em no máximo duas direções.

  2. Se a carga não cobrir nenhum transportador (seja porque todos os transportadores cancelam, porque cobre apenas espaços ou porque saiu totalmente da grade), ela pára.
  3. Se a carga cobre mais transportadores de uma direção do que da outra, a carga se move nessa direção. Por exemplo, se uma carga 3x2 cobria o seguinte patch

    >>
    ^>^
    

    moveria para a direita, porque há mais >de ^. Por outro lado, se abrangesse

    >>^
      ^
    

    essa regra não se aplicaria, porque há um empate entre >e ^.

  4. Isso deixa apenas os casos em que há um empate entre as direções adjacentes (um empate entre as direções opostas teria sido cancelado). Nesse caso, a carga continua se movendo ao longo do eixo em que ela já está se movendo. Por exemplo, se uma carga 3x2 em movimento à direita ou esquerda estiver agora cobrindo o trecho

    >>^
    ^  
    

    se moveria para a direita. Se ele chegasse nesse patch subindo ou descendo, agora seria movido para cima. Se esse tipo de conflito ocorrer no primeiro passo da simulação, assuma que a carga estava se movendo para a direita.

Exemplos detalhados

Considere a grade do transportador na parte superior e uma carga 3x2. A seguir, é apresentada uma visualização passo a passo do processo. Cada etapa consiste na grade, com a carga representada por #, uma pequena caixa que mostra os transportadores cobertos pela carga, outra caixa com os transportadores após o cancelamento e a regra que determina para onde a carga se move:

 ###vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <
 ###^ >v v     ###^ >v v      v ^ >v v      v ^ >v v      v ^ >v v      v ^ >v v 
   >v^^>vv^    ###v^^>vv^    ###v^^>vv^     ###^^>vv^      ###^>vv^      >###>vv^
     ^>^ v         ^>^ v     ### ^>^ v      ###^>^ v       ###>^ v        ###^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>    >  v<v  >>
   >v v<^        >v v<^        >v v<^        >v v<^        >v v<^        >v v<^  

+---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+
|> <|  |   |  | v |  | v |  |  >|  |  >|  | >v|  | >v|  |>v^|  |> ^|  |v^^|  | ^^|
| v |  | v |  |  >|  |  >|  |   |  |   |  |   |  |   |  |  ^|  |   |  | ^>|  |  >|
+---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+  +---+

   Rule 3        Rule 4        Rule 3        Rule 4        Rule 4        Rule 3

 ================================================================================

 > <vv    <    > <###   <    > <vv    <
  v ###v v      v ###v v      v ###v v 
   >###>vv^      >v^^>vv^      >###>vv^
     ^>^ v         ^>^ v         ^>^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>
   >v v<^        >v v<^        >v v<^  

+---+  +---+  +---+  +---+  +---+  +---+
|^ >|  |  >|  |vv |  | v |  |^ >|  |  >|
|v^^|  | ^^|  |^ >|  |  >|  |v^^|  | ^^|
+---+  +---+  +---+  +---+  +---+  +---+

   Rule 3        Rule 4        Rule 3

Nesse ponto, a carga entra em um loop entre os dois últimos quadros.

Agora considere uma carga 2x3:

 ##<vv    <    >##vv    <    > <vv    <    > <vv    <    > <vv    <    > <vv    <
 ## ^ >v v      ##^ >v v      ##^ >v v      v ^ >v v      v ^ >v v      v ^ >v v 
 ##>v^^>vv^     ##v^^>vv^     ##v^^>vv^     ##v^^>vv^      ##^^>vv^      >v^^>vv^
     ^>^ v         ^>^ v      ## ^>^ v      ## ^>^ v       ##^>^ v       ##^>^ v 
 >  v<v  >>    >  v<v  >>    >  v<v  >>    >##v<v  >>    > ##<v  >>    > ##<v  >>
   >v v<^        >v v<^        >v v<^        >v v<^        >v v<^        ## v<^  

 +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+
 |> |  |> |    | <|  |  |    |v |  |v |    | >|  | >|    |>v|  |>v|    |  |  |  |
 | v|  | v|    |v |  |v |    | >|  | >|    |  |  |  |    |  |  |  |    | v|  | v|
 |  |  |  |    | >|  |  |    |  |  |  |    |  |  |  |    | v|  | v|    |>v|  |>v|
 +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+    +--+  +--+

   Rule 4        Rule 3        Rule 4        Rule 3        Rule 3        Rule 3

 ================================================================================

 > <vv    <    > <vv    <    > <vv    <
  v ^ >v v      v ^ >v v      v ^ >v v 
   >v^^>vv^      >v^^>vv^      >v^^>vv^
     ^>^ v         ^>^ v         ^>^ v 
 > ##<v  >>    >  v<v  >>    >  v<v  >>
   ## v<^        ## v<^        >v v<^  
   ##            ##            ##
                 ##            ##
                               ##

 +--+  +--+    +--+  +--+    +--+  +--+
 | v|  | v|    |>v|  |>v|    |  |  |  |
 |>v|  |>v|    |  |  |  |    |  |  |  |
 |  |  |  |    |  |  |  |    |  |  |  |
 +--+  +--+    +--+  +--+    +--+  +--+

   Rule 3        Rule 4        Rule 2

Na última etapa, a regra 2 se aplica porque a carga saiu da grade e, portanto, pára e não haverá um loop.

Regras e premissas

Sua entrada será a grade do transportador, conforme descrito acima, juntamente com a largura e a altura da carga. Você pode levar esses três parâmetros em qualquer ordem e formato convenientes. Para a grade, isso significa que você pode ler uma única seqüência de caracteres com linhas separadas por novas linhas ou outros caracteres, ou uma matriz de cadeias de caracteres ou uma matriz de matrizes de caracteres, desde que as células individuais da grade ainda sejam representadas pelos caracteres >v<^e espaços.

Você deve saída um truthy valor se os resultados de instalação em um loop de pelo menos dois quadros ou um Falsas valor se a carga virá para descansar.

Você pode supor que a grade será preenchida com um retângulo com espaços e que a carga se ajustará inicialmente à grade.

Você pode escrever um programa ou função, recebendo entrada via STDIN (ou alternativa mais próxima), argumento da linha de comando ou argumento da função e emitindo o resultado via STDOUT (ou alternativa mais próxima), valor de retorno da função ou parâmetro da função (saída).

Isso é código de golfe, então a resposta mais curta (em bytes) vence.

Casos de teste

Os casos de teste são agrupados por grades.

Grid (2x2):

>v
^<

Width  Height  Loop?
1      1       True
1      2       True
2      1       True
2      2       False

Grid (3x3):

> v

^ <

Width  Height  Loop?
1      1       False
1      2       False
1      3       False
2      1       False
2      2       True
2      3       True
3      1       False
3      2       True
3      3       False

Grid (4x3):

>^>v
v^v 
^ <<

Width  Height  Loop?
2      2       False

Grid (6x5):

>v>v>v
^v^v^v
^v^v^v
^>^>^v
^<<<<<

Width  Height  Loop?
1      1       True
1      2       False
2      1       True
2      2       True
2      4       True
2      5       False
3      1       False
3      2       True
3      3       True
3      5       True
6      2       False
6      3       True
6      5       False

Grid (10x6):

> <vv    <
 v ^ >v v 
  >v^^>vv^
    ^>^ v 
>  v<v  >>
  >v v<^  

Width  Height  Loop?
1      1       False
2      3       False
2      6       False
3      2       True
5      4       False
6      1       True
10     6       False

Como um conjunto adicional de casos de teste, considere que qualquer entrada em que a grade consiste apenas em espaços deve produzir um resultado falso.

Verifiquei todos os casos de teste manualmente, então, deixe-me saber se você acha que cometi um erro.



4
@Fatalize Estou ficando flashbacks Twitch Plays Pokemon ...
undergroundmonorail

"Sua entrada será a grade do transportador, conforme descrito acima, juntamente com a largura e a altura da carga. Você pode levar esses três parâmetros em qualquer ordem e formato conveniente". - isso significa que podemos receber a grade do transportador como uma matriz de matrizes? Ou seja, uma grade 2x2 com [^^/v<]torna - se [[0,1] [0,1];[0,-1] [-1,0]]? Ou você quer dizer que depende de nós se é STDIN, uma entrada de string, uma entrada de array de caracteres, etc, mas ainda precisa estar na forma de ^, v,> e <?
Glen O

@GlenO Você pode pegar uma sequência separada por nova linha (ou outro caractere), uma matriz de seqüências de caracteres ou uma matriz de matrizes de caracteres, mas cada célula ainda deve ser representada pelos caracteres ><^vou por um espaço. Eu vou esclarecer isso.
Martin Ender

Então, o que acontece se a carga entrar em conflito onde a direção continuada não é uma das opções? Ou seja, se estava se movendo para a direita e agora deve escolher entre cima e esquerda.
Joshua Joshua

Respostas:


7

Ruby, 306 298 251 204 198

->g,w,h{m=->y,x,d,v=[]{q=y,x
r=->s{([""]*h+g)[y+h,h].map{|l|(?x*w+l)[x+w,w]}.join.count s}
z=k=r[?v]-r[?^],j=r[?>]-r[?<]
q[d=[d,1,0][j*j<=>k*k]]+=z[d]<=>0
v&[q<<d]!=[]?q!=v[-1]:m[*q,v<<q]}
m[0,0,1]}

Edit: Muito obrigado a Ventero, que encurtou muito o código, aplicando alguns truques incríveis!

Entrada e saída

O código representa uma função ruby ​​que aceita três parâmetros:

  • a grade, representada como uma matriz de cadeias (cada linha é uma cadeia diferente)
  • a largura da carga
  • a altura da carga

Ele retorna 1(na verdade) no caso de haver um loop ou nil(falsy) no caso de a carga descansar.

Testes

Aqui está passando todos os testes de Martin: http://ideone.com/zPPZdR

Explicação

Não há truques inteligentes no código; é uma implementação bastante direta das regras.

No código abaixo, moveé uma função recursiva que faz um movimento de acordo com as regras e:

  • retorna verdade no caso de um loop
  • retorna falso em caso de descanso
  • caso contrário, chama a si mesmo para executar o próximo movimento

Uma versão mais legível está disponível aqui .

Nota: o código golfed passou por várias modificações e não é mais semelhante à versão legível.


Como não importa se há rentradas adicionais além das quatro direções, você r[y>=0&&x>=0&&g[y]&&g[y][x]]+=1deve economizar alguns bytes.
Ventero

Tomei a liberdade de golfe coisas um pouco mais, espero que você não se importa: ideone.com/k69BmH
Ventero

@ Ventero Uau, você fez coisas incríveis no código. Eu nunca teria pensado em transformar o hash em um lambda. Eu estava tentando algumas das minhas idéias para encurtar o programa, mas não estava nem perto do que você fez. Muito obrigado!
Cristian Lupascu

2
Entendi até 200 através ligeiramente mais curto manipulação de índices negativos, acho que vou ficar por aqui por enquanto: ideone.com/k69BmH
Ventero

2
Na verdade, 198: ideone.com/ptKrzf :)
Ventero 17/08/2015

8

Python 2, 207 bytes

def f(L,w,h,u=0,v=0,D=1,S=[]):a,b,c,d=map(`[r[u*(u>0):u+w]for r in L[v*(v>0):v+h]]`.count,"v^><");D=cmp(abs(a-b),abs(c-d))<D;T=u,v,D;return T in S or a-b|c-d and f(L,w,h,u+cmp(c,d)*D,v+cmp(a,b)*0**D,D,S+[T])

Insira a grade como uma lista de linhas, por exemplo

['>v>v>v', '^v^v^v', '^v^v^v', '^>^>^v', '^<<<<<']

seguido pela largura e altura. Retorna 0ou em Trueconformidade.

Explicação

def f(L,          # Grid
      w,h,        # Width, height of cargo
      u=0,v=0,    # Position of top-left of cargo, initially (0, 0)
      D=1,        # Moving left/right = 1, up/down = 0
      S=[]        # Seen (pos, axis) pairs, initially empty
     ):     

     # Arrows under cargo - no need for "".join since we only need to count v^<>
     A = `[r[u*(u>0):u+w]for r in L[v*(v>0):v+h]]`

     # Count for each arrow
     a,b,c,d=map(A.count,"v^><")

     # Golfed form of abs(a-b) < abs(c-d) or (abs(a-b) == abs(c-d) and D == 1)
     D=cmp(abs(a-b),abs(c-d))<D
     T=u,v,D

     return (T in S                # Return True if (pos, axis) previously seen
             or a-b|c-d               # Return 0 if all conveyors cancel
             and f(L,w,h,             # Otherwise, recurse
                   u+cmp(c,d)*D,      # Update u if moving left/right
                   v+cmp(a,b)*0**D,   # Update v if moving up/down
                   D,
                   S+[T]          # Add (pos, axis) to seen
                  )
            )

Você não pode reduzi-lo atribuindo cmpa uma variável?
Blue

É suficiente detectar ciclos verificando as posições já visitadas? Com base na regra 4, o próximo passo também pode ser influenciado pela direção anterior. Portanto, parece possível que você chegue à mesma posição duas vezes, mas não tenha um ciclo, porque se move em direções diferentes com base em diferentes direções anteriores.
Reto Koradi 16/08/2015

@muddyfish Isso seria o ponto de equilíbrio
Sp3000 16/08/2015

@RetoKoradi Esperançosamente corrigido
Sp3000 17/15

Sim, adicionando Dà chave de posição deve fazê-lo.
Reto Koradi 17/08/2015

8

Julia - 394 300 246 214 bytes

f(A,x,y)=(Z=sign;(S,T)=size(A);X=x+1;Y=y+1;G=fill(5,S+2y,T+2x);G[Y:S+y,X:T+x]=A;C=0G;D=1;while C[Y,X]!=D C[Y,X]=D;i,j=sum(i->1-[19 8]i%82%3,G[Y:Y+y-1,X:X+x-1]);D=Z(2i^2-2j^2+(i!=0)D);X+=Z(i+D*i);Y+=Z(j-D*j)end;D^2)

Retorna 1 se a carga fizer um loop e 0 se parar. Não é "estritamente" verdade / falsidade, pois Julia não permite 0 e 1 em contextos booleanos ... mas considero valores xpelos quais bool(x)==truesão verdadeiros e bool(x)==falsefalsos.

A entrada Adeve ter a forma de uma matriz de caracteres. Se você estiver copiando / colando a grade do transportador, precisará inseri-la no formulário apropriado. Para evitar que você precise manipulá-lo manualmente, use o seguinte:

A=foldl(hcat,map(collect,split("""(PASTE GRID HERE)""","\n")))'

Onde, obviamente, (PASTE GRID HERE)deve ser substituído pela própria grade. Verifique novamente os espaços no final de cada linha, para garantir que ele realmente tenha todos os espaços (não verifique se todas as linhas têm o mesmo comprimento). Observe que essa linha não faz parte do código da solução real, apenas uma parte conveniente do código para facilitar o uso do código da solução.

Ungolfed:

function f(A,x,y)
  # Determine size of grid for use later
  (S,T)=size(A)
  # Initialise starting position (performed here to save characters)
  X=x+1
  Y=y+1
  # Create an expanded field that is functionally "spaces" (to provide
  # spaces at edges for the cargo to stop in)
  G=fill(5,S+2y,T+2x)
  # Put the conveyor grid into centre of the expanded field
  G[Y:S+y,X:T+x]=A
  # Create an array storing the most recent movement direction:
  # will use 1=horizontal, -1=vertical, 0=stopped
  C=0G
  # Initialise current direction (same system as C)
  D=1
  # Loop until it finds itself repeating a coordinate/direction pair
  while C[Y,X]!=D
    # Mark current coordinate/direction pair in array
    C[Y,X]=D
    # Determine the net coordinate pairing, stored in two variables
    # for golf purposes *SEE NOTE*
    i,j=sum(i->1-[19 8]i%82%3,G[Y:Y+y-1,X:X+x-1])
    # Determine new movement axis (if D=0, cargo stopped)
    D=sign(2i^2-2j^2+(i!=0)D)
    # Update X or Y depending on signs of D and the appropriate direction
    X+=sign(i+D*i)
    Y+=sign(j-D*j)
  end
  # if D=±1, return 1 (cargo is still moving), otherwise return 0
  return D^2
end

Nota: 1-[19 8]i%82%3foi escolhido para mapear os cinco caracteres possíveis para os pares de coordenadas apropriados pelo método mais eficiente que pude encontrar. Esse também é o motivo do uso de 5 para preencher os espaços ao criar G- é um caractere de um dígito que mapeia [0 0].

Exemplo de uso:

julia> A=foldl(hcat,map(collect,split(""">v>v>v
       ^v^v^v
       ^v^v^v
       ^>^>^v
       ^<<<<<""","\n")))';

julia> f(A,2,1)
true

julia> f(A,3,3)
true

julia> f(A,5,2)
false

f(A,x,y)=é mais curto que f=(A,x,y)->.
Alex A.

@AlexA. - verdade, mas, provavelmente, removerei o f=e tornarei uma função anônima quando terminar de jogar golfe.
Glen O

1
Terá o mesmo comprimento se for uma função nomeada versus uma função anônima quando houver vários parâmetros. f()=versus ()->.
Alex A.
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.