¿Golpeará el rayo?

31

Un láser dispara un haz recto en una de las cuatro direcciones ortogonales, indicado por <>^v. Determine si alcanzará el objetivo Oen una cuadrícula rectangular.

Cada uno de estos golpeará (Verdadero):

.....
...O.
.....
...^.
.....

>O.
...

v....
O....

...........
...........
O.........<
...........

Estos extrañarán (Falso):

......
......
.^..O.

......
.....>
O.....
......
......


.O.
...
.v.

.....<.
..O....

Entrada: una cuadrícula rectangular de ., al menos 2x2, con exactamente un objetivo Oy un láser de los cuales es uno <>^v. Las líneas pueden ser una lista de cadenas, una matriz 2D o una lista anidada de caracteres, o una sola cadena separada por una nueva línea con una nueva línea final opcional.

Salida : un valor de verdad constante si el rayo láser alcanza el objetivo, y un valor de falsedad constante si falla.

Consideraré los envíos que no usan expresiones regulares (o una coincidencia de cadenas basada en patrones incorporados) como una categoría separada. Si coloca (no regex)después del nombre del idioma, su respuesta aparecerá por separado en la tabla de clasificación.

xnor
fuente
8
Relacionado
VisualMelon
66
Esperaba que incluyeras espejos con /y \ . Tal vez para otra pregunta ...
vsz
2
@Mego ... lo que hace que este desafío sea mucho más simple y permite enfoques muy diferentes.
Martin Ender
2
@Mego no estoy de acuerdo; según esa lógica, el desafío de hello world es un duplicado de docenas de otros desafíos al mismo tiempo. De todos modos, gracias por notificarme sobre el poder que tengo ahora para cerrar / volver a abrir los desafíos de golf de código, no estaba al tanto de eso.
Aditsu
55
@Mego Aunque esta pregunta es un caso especial de la otra, no creo que sea un engaño porque las respuestas usan enfoques totalmente diferentes. Sobre esa pregunta, todos calculan el camino que toma el haz. Los portales pueden mover la ruta de un lugar a otro, lo que no parece permitir un acceso directo, y los reflectores son difíciles de manejar. Las respuestas aquí en su mayoría verifican o coinciden alguna propiedad de la cadena de entrada. Claro, puede copiar una respuesta de trazado de ruta del otro desafío y eliminar los bits adicionales, pero este método es excesivo y ofrece una solución innecesariamente larga.
xnor

Respuestas:

27

Caracoles , 19 bytes

\>|\<l|\^u|\vd).,\O

La especificación para este se puede implementar lo más literalmente posible, sin necesidad de pensar.

Feersum
fuente
66
¿Puedes agregar una explicación de cómo funciona esto?
Financia la demanda de Mónica
55
@QPaysTaxes Hasta que el feersum lo logre, con suerte esto ayudará: Snails es un lenguaje de coincidencia de patrones 2D. udlrestablece la dirección del caracol en arriba / abajo / izquierda / derecha. |funciona como lo hace en expresiones regulares y )no necesita un paréntesis abierto coincidente. Entonces, el código se traduce directamente como "Encuentra uno v<>^y establece la dirección de manera apropiada, luego trata de encontrar una O en esa dirección".
FryAmTheEggman
Sí, lo que dijo Eggman. La única otra cosa es que ,es como la *expresión regular.
Feersum
13

Retina, 56 52 42 38 31 30 bytes

Guardado 1 byte gracias a @ MartinBüttner

O.*<|>.*O|[vO](.*¶)[^O]*[O^]\1

Abusa de las propiedades de los rectángulos. Requiere entrada para tener una nueva línea final.

Pruébalo en línea

Explicación

Esto funciona en tres partes:

  • Pareo >
  • Pareo <
  • Coincidencia ^y vesto se debe a que la lógica ^y la vrealidad son las mismas, solo los personajes.

Validar <

Esto es simple:

O.*<

Esto coincide con O, opcionalmente seguido por caracteres que no son de nueva línea, luego un<

Validar >

Esto es muy similar a la forma anterior, excepto al revés. Primero >se empareja a, luego elO

Validar ^yv

Esto fue difícil de jugar al golf y la publicidad de la entrada siempre fue válida. Primero, hacemos coincidir si es vo un O:

[vO]

Si es un ^, el primer personaje que se encuentre debe ser un O. Entonces, esto coincide con el primer personaje que coincide. A continuación contamos la cantidad de .s que lo siguen hasta la nueva línea:

(.*\n)

A continuación, esto puede ir en dos partes, cubriré la primera:

Entonces, primero, hacemos coincidir hasta lo siguiente O, usando:

[^O]*O

Esto opcionalmente hace coincidir todos los no Ocaracteres hasta que Ose encuentra un, si esto es exitoso, entonces continúa ... si no, entonces sucede lo siguiente ...

Ahora, intenta encontrar el ^uso:

[^^]*\^

^es un carácter especial en regex, por lo que debe escaparse. [^^]coincide con todos los caracteres excepto ^, esto funciona igual que el anterior, si esto tiene éxito, entonces sucede lo siguiente ...

Entonces, ahora, uno de los anteriores ha coincidido con éxito, \1comprueba y ve si el grupo de captura de antes (.*\n), este grupo de captura almacenó la cantidad de .s que había después de vo Oantes, por lo que ahora \1solo comprueba si la cantidad de puntos en el mismo.

Downgoat
fuente
Puede guardar un byte usando en lugar de \n(Retina puede manejar el código fuente en ISO 8859-1.)
Martin Ender
@ MartinBüttner pensó que solo estaba \ n en reemplazos, ¡gracias por el consejo!
Downgoat
no, funciona en cualquier parte del código fuente. Después de dividir el archivo en líneas, lo primero que hace Retina es reemplazarlo por todas partes, antes de realizar cualquier análisis posterior.
Martin Ender
9

Java (no regex), 413 412 246 242 212 211 209 198 bytes

Competir en desafíos de golf con Java tiene menos sentido que participar en la carrera de Fórmula 1 en bicicleta, pero no siempre estoy pensando lo que tiene sentido.

Aquí está mi solución Java extremadamente larga versión Golfed

boolean l(char[][]w){int[]t={},l={};for(int y=0;y<w.length;y++)for(int x=0;x<w[0].length;x++){if(w[y][x]=='O')t=new int[]{x,y};if(w[y][x]=='<')l=new int[]{x,y,1};if(w[y][x]=='>')l=new int[]{x,y,2};if(w[y][x]=='v')l=new int[]{x,y,3};if(w[y][x]=='^')l=new int[]{x,y,4};};return(l[2]==1&&l[1]==t[1]&&l[0]>t[0])||(l[2]==2&&l[1]==t[1]&&l[0]<t[0])||(l[2]==3&&l[0]==t[0]&&l[1]<t[1])||(l[2]==4&&l[0]==t[0]&&l[1]>t[1]);}

y sin golf

boolean l(char[][] w) {
    int[] t = {}, l = {};
    for (int y = 0; y < w.length; y++)
        for (int x = 0; x < w[0].length; x++) {
            if (w[y][x] == 'O')
                t = new int[] { x, y };
            if (w[y][x] == '<')
                l = new int[] { x, y, 1 };
            if (w[y][x] == '>')
                l = new int[] { x, y, 2 };
            if (w[y][x] == 'v')
                l = new int[] { x, y, 3 };
            if (w[y][x] == '^')
                l = new int[] { x, y, 4 };
        }
    ;
    return (l[2] == 1 && l[1] == t[1] && l[0] > t[0])
            || (l[2] == 2 && l[1] == t[1] && l[0] < t[0])
            || (l[2] == 3 && l[0] == t[0] && l[1] < t[1])
            || (l[2] == 4 && l[0] == t[0] && l[1] > t[1]);
}

Parece que todo mi concepto estaba mal, aquí está mi solución más corta

boolean z(char[][]w){int x=0,y=0,i=0,a=w.length,b=w[0].length;for(;w[y][x]!=79;)if(++y==a){y=0;x++;}for(;i<(a<b?b:a);)if(i<b&w[y][i]==(i<x?62:60)|i<a&w[i][x]==(i++<y?'v':94))return 1<2;return 1>2;}

y versión sin golf

oolean z(char[][] w) {
        int x = 0, y = 0, i = 0, a = w.length, b = w[0].length;
        for (; w[y][x] != 79;)
            if (++y == a) {
                y = 0;
                x++;
            }
        for (; i < (a < b ? b : a);)
            if (i < b & w[y][i] == (i < x ? 62 : 60) | i < a
                    & w[i][x] == (i++ < y ? 'v' : 94))
                return 1 < 2;
        return 1 > 2;
    }

EDITAR Reescribí el código para buscar 'O', ahora contiene un solo bucle, es mucho más corto, y también utilicé la sugerencia de @Frozn para reemplazar algunos de los caracteres con sus valores ascii.

Como resultado, otros 30 bytes muerden el polvo.

Otra sugerencia de @Frozn, y estamos un par de bytes más cerca de la solución Python

Otra reescritura suelta un bucle y combina dos sentencias if

usuario902383
fuente
1
+1 Sin embargo, puedes eliminar el espacio entre returny (para guardar un byte. El espacio no es necesario cuando el valor de retorno está entre paréntesis (o comillas para cadenas). Fuente de los consejos de golf de código Java
Kevin Cruijssen
@KevinCruijssen no ahorra mucho, pero gracias :)
user902383
Supongo que cada poquito (o debería decir byte) ayuda. ;) Además, no creo que Java gane un desafío de código de golf de todos modos. Sin embargo, todavía me gusta hacer desafíos de código de golf en Java, especialmente porque actualmente estoy trabajando con Java en el trabajo.
Kevin Cruijssen
Puede reemplazar los caracteres por su valor ASCII: 'O' = 79, '>' = 62, '<' = 60, '^' = 94. Para 'v' es 118 pero eso no acorta el código.
Frozn
@Frozn como dijo Kevin, en cada byte cuenta.
user902383
7

MATL (sin expresión regular), 26 25 24 22 bytes

'>v<^'XJymfX!tZpYswJm)

Pruébalo en línea!

Versión modificada para todos los casos de prueba.

Explicación

        % Implicitly grab input
'>v<^'  % String literal indicating the direction chars
XJ      % Store in the J clipboard
y       % Copy the input from the bottom of the stack
m       % Check to see which of the direction chars is in the input. The
        % result is a 1 x 4 logical array with a 1 for the found direction char
f       % Get the 1-based index into '>v<^' of this character
X!      % Rotate the input board 90 degrees N times where N is the index. This
        % Way we rotate the board so that, regardless of the direction char,
        % the direction char should always be BELOW the target in the same column
t       % Duplicate
Zp      % Determine if any elements are prime ('O' is the only prime)
Ys      % Compute the cumulative sum of each column
w       % Flip the top two stack elements
J       % Grab '>v<^' from clipboard J
m       % Create a logical matrix the size of the input where it is 1 where
        % the direction char is and 0 otherwise
)       % Use this to index into the output of the cumulative sum. If the 
        % direction char is below 'O' in a column, this will yield a 1 and 0 otherwise
        % Implicitly display the result
Suever
fuente
@LuisMendo Ahora para descubrir cómo deshacerse de élJ
Suever
No sé MATL, así que esta puede ser una pregunta tonta, pero ¿por qué 0 es primo?
Neil
3
@Neil Es letra 'O', no número 0. El código ASCII para la carta 'O'es79
Luis Mendo,
Ugh, supongo que aún me habrían engañado si hubieras estado buscando números impares.
Neil
5

CJam (sin expresiones regulares), 25

Las versiones anteriores estaban mal, esto tendrá que hacer por ahora:

q~_z]{'.-HbI%}f%[HF].&~+,

Pruébalo en línea

Explicación:

q~         read and evaluate the input (given as an array of strings)
_z         copy and transpose
]          put the original grid and transposed grid in an array
{…}f%      map the block to each grid (applying it to each string in each grid)
  '.-      remove all dots (obtaining a string of 0 to 2 chars)
  Hb       convert to base H=17, e.g. ">O" -> 62*17+79=1133
  I%       calculate modulo I=18
[HF]       make an array [17 15]
.&         set-intersect the first array (mapped grid) with 17 and 2nd one with 15
~+         dump and concatenate the results
,          get the array length

Probé algunas fórmulas matemáticas para distinguir entre cadenas "buenas" y "malas", y para cada tipo de fórmula intenté conectar varios números. Terminé con lo HbI%anterior.

Las cadenas "buenas" para la cuadrícula original son "> O" y "O <" y dan el resultado 17
cadenas "buenas" para la cuadrícula transpuesta son "vO" y "O ^" y dan el resultado 15
"malas" las cadenas para ambas cuadrículas son: ">", "<", "^", "v", "O", "", "O>", "Ov", "<O", "^ O" y dan los resultados 8, 6, 4, 10, 7, 0, 1, 3, 1, 3

aditsu
fuente
3

Python 3 (sin expresiones regulares), 184 bytes.

¡Hurra por hackear eval!

def f(a,o=0,d={},q=''):
 for r in a:
  i=0
  for c in r:d[c]=o,i;i+=1;q=(c,q)[c in'O.']
  o+=1
 z,y=d['O'];e,j=d[q];return eval("z%se and y%sj"%(('><'[q<'v'],'=='),('==',q))[q in'><'])
Morgan Thrapp
fuente
3

TSQL (sqlserver 2012) (sin expresiones regulares), 358 bytes

DECLARE @ varchar(1000)=
'......'+ CHAR(13)+CHAR(10)+
'......'+ CHAR(13)+CHAR(10)+
'...0..'+ CHAR(13)+CHAR(10)+
'...^..'+ CHAR(13)+CHAR(10)
;

WITH C as(SELECT
number n,SUBSTRING(@,number,1)a,1+min(IIF(SUBSTRING(@,number,1)=char(13),number,99))over()m
FROM master..spt_values
WHERE'P'=type and
SUBSTRING(@,number,1)in('>','<','^','v','0',char(13)))SELECT
IIF(c.n%c.m=d.n%c.m and c.a+d.a in('0^','v0')or
c.n/c.m=d.n/c.m and c.a+d.a in('>0','0<'),1,0)FROM c,c d
WHERE c.n<d.n and char(13)not in(c.a,d.a)

Tuve que usar el cambio de línea funky en la declaración para obligar a la versión en línea a ejecutarlo (la asignación de valores a las variables de entrada no afecta el cálculo de la longitud de todos modos)

Pruébalo en línea!

t-clausen.dk
fuente
2

JavaScript (ES6), 78 bytes

s=>s.match(`>.*O|O.*<|(?=v)([^]{${l=s.search`\n`+1}})+O|(?=O)([^]{${l}})+\\^`)

Regexp por supuesto. Resultó ser similar en principio a la respuesta de Ruby.

Neil
fuente
2

Ruby, 71 55 54 bytes

Solución Regex, lo que significa que probablemente Retina o Perl la superen fácilmente.

Devuelve un número de índice (verdadero) si hay una coincidencia.

Ahora con un truco similar a la respuesta de Retina @Downgoat, haciendo coincidir las vigas hacia abajo y hacia arriba al mismo tiempo.

->m{m=~/>\.*O|O\.*<|(?=[vO])(.{#{??+m=~/\n/}})+[O^]/m}
Tinta de valor
fuente
2

JavaScript (ES6) (sin expresión regular), 126 bytes

s=>([n,o,l,r,u,d]=[..."\nO<>^"].map(c=>1+s.indexOf(c)),l>o&l-o<n&l%n>o%n||r&&r<o&o-r<n&r%n<o%n||u>o&u%n==o%n||d&&d<o&d%n==o%n)

Donde \nrepresenta el carácter literal de nueva línea.

Neil
fuente
2

Clojure (sin expresiones regulares), 293 bytes

(defn z[f](let[v(sort(keep-indexed(fn[i v](if(some #{v}[\v\>\<\^\O])[(if(= v\O)\& v)i]))f))l(+(.indexOf f"\n")1)d((nth v 1)0)q((nth v 1)1)p((nth v 0)1)r(=(quot p l)(quot q l))i(> q p)](cond(= d\^)(and i(=(mod(- q p)l)0))(= d\v)(and(not i)(=(mod(- p q)l)0))(= d\>)(and(not i)r):else(and i r))))

No se siente bien Solución directa, encontrar el índice de los caracteres correspondientes y calcular si están en la misma línea.

Puedes probarlo aquí https://ideone.com/m4f2ra

acantilado
fuente
2

Python (sin expresiones regulares), 105 bytes

def f(s):t=s.strip('.\n');return not['\n'in t,len(t)%(s.find('\n')+1)!=1,1]['>O<vO^'.find(t[0]+t[-1])//3]

devuelve verdadero o falso

Primero, tiras '.' y '\ n' desde los extremos para que los caracteres de interés, '0 <> v ^', sean el primer y el último carácter.

'>O<vO^'.find(t[0]+t[-1])//3- comprueba si los caracteres son un arreglo potencialmente válido. Evalúa a 0 para '> O' o 'O <', a 1 para 'vO' o 'O ^', y a -1 para cualquier otra cosa.

'\n'in t- comprueba si los caracteres están en filas diferentes,
len(t)%(s.find('\n')+1)!=1- comprueba si están en columnas diferentes, y
1- es el valor predeterminado

Los notinvierte el resultado seleccionado de la lista, por lo que la returnexpresión es equivalente a:

t[0]+t[-1] in '>0<' and '\n' not in t or t[0]+t[-1] in 'vO^' and len(t)%(s.find('\n')+1)==1
RootTwo
fuente
2

Julia (sin expresiones regulares), 98

a->(c=rotr90(a,findlast("i1Q/",sum(a-46)));
    f(n)=find(any(c.!='.',n));b=c[f(2),f(1)];
    (b'*b)[1]==97)

Función que opera en una matriz de caracteres, normalizando por rotación, eliminando filas y columnas que contienen solo puntos mediante indexación de rango y finalmente verificando la ubicación de 'O' teniendo en cuenta si el resto b es un vector de columna o fila usando la multiplicación de matrices.

Pruébalo en línea

mschauer
fuente
1

Python 2 (sin expresión regular), 268 bytes

import numpy
def q(i):
 s=numpy.asmatrix(i)
 for n in s:
  n=n.tolist()[0]
  try:
   a=n.index("0")
   if n.index(">")<a or n.index("<")>a:return 1
  except:0
 for n in range(len(i)):
  c=[x[0] for x in s[:,n].tolist()]
  try:
   a=c.index("0")
   if c.index("v")<a or c.index("^")>a:return 1
  except:0
 return 0

Los valores de verdad y falsedad devueltos por la función son 1 y 0, respectivamente.

Todavía no he tenido la oportunidad de jugar al golf. Honestamente, no tengo muchas esperanzas para este ...

Cualquier sugerencia sería muy apreciada!

Daniel
fuente
1

C # (sin expresión regular), 282 bytes

bool F(char[,]b){int k=0,l=1,m=1,n=0,o=0;for(int x=0;x<b.GetLength(0);x++)for(int y=0;y<b.GetLength(1);y++){char i=b[x,y];if(i=='O'){k=x;l=y;}if(new[]{'<','>','^','v'}.Contains(i)){m=x;n=y;o=i;}}return(o==60&&k==m&&l<n)||(o==62&&k==m&&l>n)||(o==94&&l==n&&k<m)||(o==118&&l==n&&k>m);}

Funciona como la versión de Java, pero se transpila y reduce

Ampliado (Explicación incluida):

bool F(char[,] b)
{
    // declare variables for goal x, goal y, laser x, laser y, and laser direction respectively (laser direction is char code for directions)
    int k = 0, l = 0, m = 0, n = 0, o = 0;
    // go through each cell
    for (int x = 0; x < b.GetLength(0); x++)
    {
        for (int y = 0; y < b.GetLength(1); y++)
        {
            // get cell contents
            char i = b[x, y];
            // set goal position if goal
            if (i == 'O')
            {
                k = x;
                l = y;
            }
            // set laser position and direction if laser
            if (new[]{ '<', '>', '^', 'v' }.Contains(i))
            {
                m = x;
                n = y;
                o = i;
            }
        }
    }
    // check everything is on the same line and in right direction
    return (o == 60 && k == m && l < n) ||
           (o == 62 && k == m && l > n) ||
           (o == 94 && l == n && k < m) ||
           (o == 118 && l == n && k > m);
}
RedLaser
fuente
0

C (ANSI) (sin expresión regular), 237 bytes

#define l b[1][i]
main(i,b,c,d,x,y,z,p)char **b;{for(y=z=i=0,x=1;z<2&&(l==10?x=0,++y:1);i++,x++)if(l>46){if(l!=79)p=l;if(!z++)c=x,d=y;}i--;x--;z=(c==x)*((p=='v')*(l==79)+(p==94)*(l==p))+(d==y)*((p==60)*(l==p)+(p==62)*(l==79));return z;}

Expandido:

#define l b[1][i]
main(i,b,c,d,x,y,z,p)char **b;{
    for(y=z=i=0,x=1;z<2&&(l==10?x=0,++y:1);i++,x++)
        if(l>46){if(l!=79)p=l;if(!z++)c=x,d=y;}
    i--;x--;
    z=(c==x)*((p=='v')*(l==79)+(p==94)*(l==p))+(d==y)*((p==60)*(l==p)+(p==62)*(l==79));
    printf("%i\n",z);
    return z;
}

Creo que tomé un enfoque decentemente diferente aquí en comparación con las implementaciones de Java o C #. Obtuve coordenadas de la 'O' y la flecha ((c, d) y (x, y)) y luego las comparé para ver si la flecha apuntaba en la dirección correcta.

Devuelve 0 si es falso y 1 si es verdadero

dj0wns
fuente
0

Grime v0.1 , 31 bytes

n`\>.*a|a.*\<|\v/./*/a|a/./*/\^

No es una solución muy interesante. Imprime 1para casos verdaderos y 0para casos falsos. Pruébalo en línea!

Explicación

Simplemente buscamos en el rectángulo de entrada un patrón de tamaño mínimo (n × 1 o 1 × n) que contenga el láser y el objetivo en el orden correcto. La n`bandera hace que el intérprete imprima el número de coincidencias, de las cuales siempre habrá como máximo una. El resto de la línea consta de cuatro patrones separados por| caracteres, lo que significa un OR lógico: un rectángulo coincide si coincide con uno de los patrones. Los patrones funcionan de la siguiente manera:

\>.*a    Literal ">", horizontal row of any chars, one alphabetic char
a.*\<    One alphabetic char, horizontal row of any chars, literal "<"
\v/./*/a Literal "v", on top of vertical column of any chars, on top of one alphabetic char
a/./*/\^ One alphabetic char, on top of vertical column of any chars, on top of literal "^"
Zgarb
fuente