Verificación de una serpiente ASCII horizontal


22

Recientemente ha habido un par de desafíos de serpientes mascotas ASCII (por ejemplo, aquí )

            0 0               
  0        0 0 000            
00 0     00       000 0      0
    000 0            0 0   00 
       0                000   

Este desafío es tomar una serpiente mascota horizontal generada aleatoriamente (altura de cinco líneas, longitud de 30) y verificar que:

  • Cada columna tiene solo uno 0
  • Cada uno 0está "conectado" al 0antes y al después (separados verticalmente por 0 o 1 línea solamente)

El resultado final puede ser trueo 1si la serpiente es válida, falseo 0si la serpiente no es válida

Editar — Aclaración

Asumir la entrada:

  • Es una cuerda
  • Contiene solo '', '0' y '\ n'
  • Tiene exactamente 30 caracteres en cada línea.
  • Tiene exactamente 5 líneas

Es decir, verificar si la serpiente está conectada y que no hay caracteres extraviados. No es necesario validar el "lienzo" en el que se imprime la serpiente.


44
Hola y bienvenidos a PPCG :) Este es un buen desafío para una primera publicación, pero probablemente quieras agregar más casos de prueba que atrapen serpientes excepcionales. Probablemente también quieras decidir si la serpiente tiene que estar representada por ceros o si puede ser cualquier personaje. En el futuro, considere usar el sandbox . Buena suerte :)
FryAmTheEggman

55
¿Se toma esto como una picadura? ¿O se puede ingresar como una matriz 2d?
JSchiff

66
¿Se garantiza que la entrada consta de 0 y espacios? ¿Que cada línea tiene una longitud de 30? ¿Que hay 5 líneas?
xnor

99
Dado que este es un problema de decisión, ¿qué tal en truthy/falseylugar de hacerlo true/false?
Jonathan Allan

3
@JSchiff ¿Estoy seguro de que una serpiente Bytes?
MarioDS

Respuestas:


14

JavaScript (ES2018), 62 54 bytes

s=>!/0(.{30}|.{60,62}(.{31})*)0|( .{30}){4} /s.test(s)

La entrada es una sola cadena:

  • sin arrastrar nueva línea
  • contener solo espacio, '0' y '\ n'
  • 30 caracteres cada línea, 5 líneas, 154 caracteres en total

Indicador ssignifica que un punto coincide con cualquier cosa (incluyendo '\ n'). Esta característica actualmente es compatible con Chrome 63+, Opera 50+, Safari 11.1+, basada en la tabla de compatibilidad . Puede probar esta función con estos navegadores compatibles. Obtendrá una excepción al cargar la página si su navegador no admite esta función.

Cómo funciona:

  • Sin columna sin 0:
    • no coinciden /( .{30}){4} /
  • No hay dos 0s en una columna:
    • no coinciden /0.{30}(.{31})*0/
  • No 0no se conecta a sus vecinos:
    • no coinciden /0.{60}(.{31})*0/,/0.{62}(.{31})*0/

Combina todas estas expresiones regulares, y finalmente obtendrás esta.

Gracias a Martin Ender señalar que hacer un solo !operador puede ahorrar 8 bytes.


8

SnakeEx , 51 bytes

Este es obviamente el lenguaje correcto para la tarea. : ^ D

s:({c<L>}{c<R>}0[(<R> <L>)(<L> <R>)_?])%{30}
c:0 *$

Coincide con la entrada completa si es una serpiente válida; no coincide si no es así. Pruébalo aquí!

Explicación

SnakeEx es un lenguaje de coincidencia de patrones 2D . Un programa consiste en una lista de definiciones para "serpientes", que se arrastran alrededor de los caracteres coincidentes de entrada, cambian de dirección y generan otras serpientes. En nuestro programa, definimos dos serpientes, syc .

Comenzaremos cporque es más simple. Su definición es 0 *$, que debería ser bastante legible si conoce regex: match 0, seguido de cero o más espacios, seguido del borde de la cuadrícula. El problema principal aquí: esta coincidencia puede proceder en cualquier dirección. Vamos a usarc tanto hacia arriba como hacia abajo desde la serpiente, para verificar que no haya 0s adicionales en cada columna.

Ya por la serpiente principal s. Toma la forma (...)%{30}, que significa "hacer coincidir el contenido de los paréntesis 30 veces", una vez para cada uno 0en la serpiente. Hasta aquí todo bien. ¿Qué va dentro de los paréntesis?

{c<L>}

Esto genera una nueva cserpiente, giró a la izquierda 90 grados. La dirección es relativa a la sdirección de la serpiente, por lo que la nueva serpiente se mueve hacia la parte superior de la cuadrícula (la serpiente principal se mueve hacia la derecha). La cserpiente comprueba que la celda de la cuadrícula actual es una 0y que cada celda de arriba es un espacio. Si falla, toda la partida falla. Si tiene éxito, continuamos con

{c<R>}

que hace lo mismo, solo giró a la derecha (hacia la parte inferior de la cuadrícula).

Tenga en cuenta que estos engendros no afectan la posición del puntero de coincidencia en la serpiente principal. Son un poco como lookaheads en regex. (¿Tal vez aquí podríamos llamarlos "lookbesides"?) Entonces, después de verificar que estamos apuntando a a 0y que el resto de la columna contiene solo espacios, necesitamos hacer coincidir 0:

0

Ahora el puntero de coincidencia está en el carácter a la derecha de 0. Necesitamos verificar tres opciones diferentes: la serpiente se inclina hacia abajo, la serpiente se inclina hacia arriba o la serpiente se endereza. Para esto, podemos usar una expresión OR:

[...]

Dentro de nuestro quirófano, tenemos tres posibilidades:

(<R> <L>)

Gire a la derecha, haga coincidir un espacio y gire a la izquierda nuevamente (ángulos de serpiente hacia abajo).

(<L> <R>)

Gire a la izquierda, combine un espacio y gire a la derecha nuevamente (la serpiente se inclina hacia arriba).

_?

Haga coincidir cero o uno con guiones bajos. Como no hay guiones bajos en la entrada, esta siempre será una coincidencia vacía (la serpiente va en línea recta).

Después de hacer coincidir una de las tres opciones anteriores, el puntero de coincidencia debe apuntar a la 0en la siguiente columna, listo para coincidir nuevamente con la expresión entre paréntesis.


2

CJam , 35 34 bytes

{z_{'0e=1=}%:*\'0f#2ew::-[W0X]-!*}

Pruébalo en línea! La entrada es una matriz rectangular de matrices de caracteres. Asume que la entrada solo contiene y0 .

Explicación:

{z_{'0e=1=}%:*\'0f#2ew::-[W0X]-!*}   Function taking a character matrix:
 z                                      Transpose.
   {      }%                            Consider whether each row
      e=                                  contains
        1=                                exactly one
    '0                                    of the character '0'.
            :*                            This must be true for every row.
                  #                     Next, find the position
               '0                         of the character '0'
                 f                        at every row
  _           \                           in the original input.
                       :-               Find the differences between
                      :                   each
                   2                      pair
                    ew                    of adjacent elements (in other words, compute
                                            the increments).
                                        For the snake to be valid, this array of increments
                                            must only contain {0, 1, -1}, so
                              -         Remove from this list
                         [   ]            the elements
                          W                 -1,
                           0                0,
                            X               and 1,
                               !          and then check whether the array is empty.
                                *       The previous code tested two different properties
                                          of the matrix; they both must be true for a
                                          valid snake.

2

05AB1E , 18 bytes

ζDε0k}¥Ä2‹sεþg}ìPΘ

Pruébalo en línea!

Explicación

ζ                    # transpose
 D                   # duplicate
  ε  }               # for each row in the first copy (column of input)
   0k                # get the index of the first 0
      ¥Ä             # calculate absolute delta's
        2‹           # check that each is less than 2
          sε  }      # for each row in the second copy (column of input)
            þg       # calculate the length of the string with non-digits removed
               ì     # concatenate the lists
                P    # calculate product
                 Θ   # truthify (turn false values to 0)

2

Cáscara , 12 bytes

Dependiendo de las aclaraciones de las reglas, puede tener 11 bytes o 13 bytes .

±Λ=;1Ẋ×≈mηfT

Pruébalo en línea!

La entrada es una lista de líneas que contienen solo espacios y ceros; Si se requiere una sola cadena, anteponga al programa para dividir en líneas. El enlace TIO ya lo hace para mayor claridad. La salida es 0 o 1; Si cualquier valor falso y verdadero está bien, el± se puede eliminar.

Explicación

±Λ=;1Ẋ×≈mηfT  Implicit input: a list of lines.
           T  Transpose into list of columns.
        m     For each column,
         ηf   get list of indices of truthy elements.
              In Husk, whitespace characters are falsy and other are truthy,
              so this gets us the indices of 0s on each column.
     Ẋ        For each adjacent pair of these index lists,
      ×       for all pairs drawn from the two lists,
       ≈      give 1 if they differ by at most 1, otherwise 0.
              For each adjacent pair, this produces a list of 1s and 0s.
 Λ            Do all of these lists
  =;1         equal [1]? Return either 0 or 30 (length of the outer list + 1).
±             Signum; convert to 0 or 1.

La idea es usar ×≈para garantizar que (a) todas las columnas contengan exactamente un 0, y (b) sus posiciones difieran en como máximo uno. Como ejemplo, considere la entrada de 8 columnas

0  0  0 
 000 0  
  00   0

Primero, lo mηfTtransforma en la lista de listas de índice

[[1],[2],[2,3],[1,2,3],[],[2],[1],[3]]

Luego Ẋ×≈da

[[1],[1,1],[1,1,0,1,1,1],[],[],[1],[0]]

Cada uno 1corresponde a un par de índices que difieren en a lo sumo 1, y cada uno 0corresponde a un par que no. Cada resultado es [1]exactamente igual cuando ambas listas tienen un índice, y los índices difieren en a lo sumo 1.


2

Python 2 , 71 bytes

f=lambda s:s[1]<' 'or'0'in s[::31]in' %s '%s[1::31]in'%6s'%0*2*f(s[1:])

Pruébalo en línea!

Toma la entrada como una cadena multilínea. Caso de pruebas de Bubbler .

La primera columna se extrae como s[::31]y la segunda comos[1::31] , y se verifica su validez. Recurrimos al seliminar el primer carácter, haciendo que se verifiquen pares sucesivos de columnas.

La verificación de dos columnas utiliza el encadenamiento de comparación de Python para incombinar múltiples verificaciones:

  • '0'in s[::31] comprueba que la primera columna tiene al menos uno 0
  • s[::31]in' %s '%s[1::31]comprueba que la primera columna es una subcadena de los emparedados de la segunda columna entre dos espacios, lo que garantiza que la posición de la columna 0haya cambiado como máximo un espacio
  • ' %s '%s[1::31]in'%6s'%0*2comprueba que la segunda columna contiene como máximo una 0.

El final *f(s[1:])también obliga a que el caso recursivo sea verdadero.


Ahora que lo pienso, Python es un lenguaje increíble para estos desafíos de "serpientes". : P
MoustacheMoses

2

C (gcc) ,246 245 232 215 212 bytes

#define F)exit(1);
#define L for(i=l=0;i<30;i++)
#define X b[7][i]
char b[8][31];k,j,l;main(i){for(;j++<5;){gets(b);L{if(i[*b]>47){if(X++F memset(b[j+1]+i-1,l=1,3);}else if(!X&b[j][i]F}k+=!!l;}if(k<5 F L if(!X F}

Pruébalo en línea!

Pensé que tomaría mi lenguaje favorito para esto (aunque, como puedo ver en las muchas otras entradas más pequeñas, probablemente no sea lo ideal para este tipo de desafío) y C lo que podría manejar. El enfoque del programa para el problema es relativamente sencillo, solo que con una gran cantidad de byte. toma la serpiente en stdin y da su resultado en el valor de retorno de main (por lo tanto, el código de salida;según lo solicitado en el problema 0 indica una serpiente inválida y 1 válido aunque para un código de salida que es extrañocomo es típico para los códigos de salida 0 es una serpiente válida y 1 es una serpiente no válida). Con las macros expandidas y un bonito espacio en blanco, se parece más a lo siguiente:

char b[8][31];l,j,k;                           //Declares a buffer to work in, initialized all to 0; l j and k default to int and as globals are init to 0
main(i) {                                      //This is run no-args, so argc is 1 and the undeclared type defaults to int.
  for (; j++ < 5;) {                           //Iterating over each row, 1-indexed for convenience accessing the buffer
    gets(b);                                   //Reads into b[0] because of stack array decl layout
    for (i = l = 0; i < 30; i++) {             //j and l both init each time we begin this overall loop
      if (i[*b] > 47) {                        //Did we read a zero?
        if(b[7][i]++) exit(1);                 //If the snake already had a zero in this column, fail out
        memset(b[j+1] + i-1, l = 1, 3);        //Expect them on the next row in the columns left and right of this one (also set l)
      } else if (!b[7][i] & b[j][i]) exit(1);  //If we didn't read a zero, and we had reason to expect one this row, and there wasn't already a zero in this column, fail out
    }
    k+=!!l;                                    //Adds 1 to k iff l is nonzero 
  } if (k < 5) exit(1);                        //If less than 5 rows had zeroes in them, fail out
  for(i = l = 0 ; i < 30; i++) {               //l isn't relevant in this loop but saves some bytes when sharing a macro with the other horizontal loop
    if(!b[7][i]) exit(1);                      //If any columns didn't have zeroes, fail out
  }                                            //Else, snake is valid. main default returns 0.
}

Las líneas de entrada se leen en la primera fila del búfer, las siguientes cinco son para rastrear qué lugares se espera (leer: debe) tener ceros en la fila después de cada uno actual, y la última es para rastrear si un cero ya ha sido leído en una columna dada, en cualquier fila. El programa procesa cada fila a su vez.

No es nada robusto ( gets()es solo el comienzo) y la entrada debe contener todos los espacios relevantes (sin espacios en blanco finales, por ejemplo), y gcc arroja advertencias y notas sobre la funcionalidad stdlib que se deja implícitamente declarada y así sucesivamente, pero, C la vida.

También se supone que la cabeza de la serpiente no necesita estar en la fila central, y que una serpiente válida debe tener al menos un cero en cada fila (es decir, no hay filas de todos los espacios en las 5 filas de entrada). Si este último no es un requisito, se puede acortar un poco; en ese caso , todo lo que tenga que ver con ky len el programa se puede reducir o reemplazar con menos bytes de código.

Gracias al usuario202729 por aprox. 26 bytes guardados.



Puede omitir el espacio entre #define Fy )por -1 byte.
usuario202729

Además, debido a que la entrada solo tiene \n(10), <space>(32) y 0(48), puede verificar ==48con >47(-1 byte). / Puede eliminar ={0}cuando inicialice bsi la variable es global. Del mismo modo, haga un parámetro kglobal y iun (sin tipo -> int) de main(en lugar de argccuál es 1).
user202729

¡Gracias! Editado antes de ver las últimas sugerencias; Voy a tictac mi camino a través de ellos (que icomo argces genio). Los primeros borradores de este eran más de 400 bytes; Me tomó el tiempo suficiente para arrastrarlo a mis objetivos personales de 300 y luego 256, por lo que es muy posible que haya más formas de reducirlo.
SevenStarConstellation

Decidí hacer k, jy ltodos los globales para ahorrar en tener intdeclaraciones separadas , luego me di cuenta de que los valores predeterminados me permitirían dejar el tipo completamente. ¡Gracias de nuevo!
SevenStarConstellation

1

MATL , 18 17 bytes

32>&fun30=wd|2<vA

La entrada es una matriz de caracteres 2D. Cualquier personaje no espacial puede ser usado para la serpiente.

Pruébalo en línea!

Explicación

32>      % Implicit input. Transform non-space into 1, space into 0
&f       % Push vector of row indices and vector of column indices of nonzeros
u        % Unique: vector of deduplicated entries
n        % Length
30=      % Does it equal 30? (*)
w        % Swap. Moves vector of row indices to top
d|       % Absolute consecutive differences
2<       % Is each value less than 2? (**)
v        % Concatenate results (*) and (**) vertically
A        % All: true if all entries are nonzero. Implicit display

1
La especificación implica que las longitudes de línea son 30, por lo que creo que puede guardar algunas.
Jonathan Allan

@JonathanAllan ¡Gracias! Estoy usando un30=para verificar que todos los índices de columna son diferentes, y ninguna de las 30 columnas está vacía. Tal vez pueda probar eso más directamente, pero no veo cómo
Luis Mendo


1

Jalea , 19 bytes

Zn⁶T€L€=1$$;FIỊ$$$Ạ

Pruébalo en línea!

-2 bytes gracias al Sr. Xcoder

Explicación

Zn⁶T€L€=1$$;FIỊ$$$Ạ  Main Link
Z                    Transpose the matrix of characters
                         (string -> list of chars in Jelly)
 n⁶                  != " " (vectorizing)
   T€                For each column, get (row) indices of snake parts
     L€=1$$          For each index list, is its length 1? (that is, exactly one snake part per column)
           ;     $   Append (helper part)
            FIỊ$$    helper part:
            F        flatten index list
             I       get increments/forward differences
              Ị      are the values insignificant? (|z| <= 1)
                  Ạ  Are these all true?

La entrada es como una lista de cadenas


@ Mr.Xcoder Huh falla, problemas de representación de cadenas Jelly jaja. arreglado desangrando el 1 byte
HyperNeutrino

1

Jalea , (14? *) 13 bytes

Zn⁶T€z-IỊ0-¦Ȧ

Un enlace monádico que toma una lista de cinco cadenas *, cada una de longitud 30 que consiste en espacios y cualquier otro carácter (p. Ej. 0 S), y devuelve un número entero (1 si una serpiente se define, 0 de lo contrario)

* Si la entrada debe ser una sola cadena (lista de caracteres), añada a para dividir la cadena en los avances de línea.

Pruébalo en línea!

¿Cómo?

Zn⁶T€z-IỊ0-¦Ȧ - Link: list of lists of characters, Lines
Z             - transpose the lines -> columns
  ⁶           - literal space character
 n            - not equal? -> 0 where there were spaces and 1 where there were "0"s
   T€         - truthy indices for each -> e.g. [0,0,1,0,0] -> [3] or [0,1,1,0,0] -> [2,3]
              -                           note: [0,0,0,0,0] -> []
      -       - literal minus one
     z        - transpose with filler (-1) -> {valid: a single list of heights {top:1,...,bottom:5}
              -                              invalid: list of >1 lists, some of which contain -1
              -                                       ...OR an empty list (no 0s in the input at all)}
       I      - differences -> {up:-1; down:1; flat:0; invalid:-6,-5,...,-2,2,...4}
        Ị     - insignificant (abs(z)<=1) -? {up/down/flat:1; invalid:0}
           ¦  - sparse application///
         0    - ...action: literal zero
          -   - ...to indices: [-1] -> make penultimate list into a zero (when one exists)
            Ȧ - any & all -> when flattened:{empty or contains a 0:0; otherwise:1}

Ah, pensé que había probado todos los casos extremos, gracias por el aviso; tendrá que abordar más tarde.
Jonathan Allan

@LuisMendo heh y al arreglar eso salvé tres, ¡así que gracias de nuevo!
Jonathan Allan

... uh, pero presenté otro. Arreglado por otros 3 :(
Jonathan Allan

Sin embargo, no es un mal recuento de bytes :-)
Luis Mendo

1

Stax , 20 bytes CP437

Å┴m▐◘5)ît╢V¼≥+╝╜►º½ê

24 bytes cuando está desempaquetado,

LM{'0|Ic%vChm:-{Jh!f%29=

¡Ejecute y depure en línea!

Puede que no sea el mejor golfizado, pero creo que el método es novedoso e interesante.

Explicación

LM                          Load the input string as a 2d array of characters, and transpose it

  {         m               Map array with block
   '0|I                     Get all indices of substring "0"
       c%vC                 Map to nothing if the indices are not unique
           h                Otherwise map to the unique index

             :-             Take pairwise difference

               {   f        Filter array with block
                Jh!         Only keep 0, 1 and -1

                    %29=    Check whether the final array has exactly 29 elements

1

J , 38, 37 30 bytes

-8 bytes gracias a FrownyFrog

[:($e.~[:(-:*)2-/\])@:I.'0'=|:

Pruébalo en línea!


1
Qué tal [:(-:*)2-/\, verifique si todas las diferencias son −1, 0 o 1.
FrownyFrog

@FrownyFrog Sí, ¡es mucho mejor! ¡Gracias!
Galen Ivanov

@ FrownyFrog Hmm, no me di cuenta de eso. Intentaré arreglarlo. Gracias por señalar eso.
Galen Ivanov

1
[:(#@{.=[:(-:*)2-/\])@:I.'0'=|:
FrownyFrog

1
Oh, esto también funciona[:($e.~[:(-:*)2-/\])@:I.'0'=|:
FrownyFrog

1

Jalea , 16 bytes

Zµi€”0IỊ;ċ€⁶=4ƊẠ

Pruébalo en línea!

Asume que la cadena de entrada siempre contendrá solo espacios y ceros. Toma la entrada como una lista de cadenas (cada una representa una línea) y genera 1 si es verdadero, 0 de lo contrario.

Explicación

Zµi€”0IỊ;ċ€⁶=4ƊẠ | Monadic full program.
Z                | Transpose.
 µ               | Start a new monadic chain.
  i€”0           | Retrieve the first index of 0 in each column.
      IỊ         | Check whether their increments are insignificant (element-wise).
        ;     Ɗ  | Append the result of the following:
         ċ€⁶     | In each list of characters, count the occurrences of a space.
            =4   | Check whether they equal 4 (returns a boolean array).
               Ạ | All. Check whether all the elements are truthy.

0

Python 2 , 141 bytes

lambda g:(lambda a:all(map(len,a)+[-2<x-y<2 for b in[sum(a,[])]for x,y in zip(b,b[1:])]))([[i for i in range(5)if"0"==r[i]]for r in zip(*g)])

Pruébalo en línea!

La entrada es una cuadrícula de caracteres.


0

Python 2 y Python 3 , 122 120 119 bytes

lambda s:s.count('0')<31and all(s[i-31*(i>30):31*(i<124)-~i:31].strip(' ')for i,x in enumerate(s,1)if' '<x)and' '<s[62]

Pruébalo en línea!

El formato de entrada es una cadena de longitud 154 (5 x 30 caracteres, 4 líneas nuevas):

'''
            0 0               
  0        0 0 000            
00 0     00       000 0      0
    000 0            0 0   00 
       0                000   '''[1:] # to exclude starting newline

Si la cabeza no tiene que ser la fila central

El requisito de la cabeza de la fila central estaba en el desafío original, pero descubrí que no es el caso aquí (al menos no se menciona explícitamente).

Python 2 y Python 3 , 124 123 bytes

lambda s:s.count('0')<31and all(s[i-31*(i>30):31*(i<124)-~i:31].strip(' ')for i,x in enumerate(s,1)if' '<x)and'0'in s[::31]

Pruébalo en línea!


Editar:

  • Se redujeron 2 bytes cambiando iguales (== ) en desigualdades para cada código.
  • Encontró errores en la versión menos limitante y la revisó. (Afortunadamente no es demasiado terrible, por lo que podría mantener todas las versiones de longitud similar.) Puede ver casos de prueba adicionales en los últimos dos enlaces TIO.
  • Encontré un byte colgante en las soluciones de Py2, lo que hizo que el all()truco no tuviera sentido en Py3, por lo que fusionó ambas versiones.

0

Excel (VBA), 68 bytes

Usando la ventana Inmediato, Cell[A6]como salida.

[A1:AD5]="=CHOOSE(ROUND(RAND()+1,),0,"""")":[A6]="=COUNT(A1:AD5)=30"





0

Pitón 3 , 197 bytes

En el símbolo del sistema do verify.py<snake.txto en bash do cat snake.txt | python verify.py. Dóndesnake.txt está un archivo que contiene una serpiente para verificar?

Si la serpiente es correcta, no se generará nada. Si no es correcto, Python generará un error de índice.

import sys
s=sys.stdin.read().split("\n")
x=0
exec('t,y="",0\nwhile y<5:t+=s[y][x];y+=1\ns+=[t];x+=1;'*30)
s=list(map(lambda l:len(l.rstrip()),s))
while y<35:"ee"[abs(s[y]-s[y+1])];y+=2

Oh, no noté que mi salida tenía que ser verdadera o falsa. ¿El código de error devuelto cuenta?
MoustacheMos

Golfizado 12 bytes.
MoustacheMoses
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.