ASCII Waterworks

19

Introducción

Considere una cuadrícula de los caracteres f A\/como

f  f  f  
      A  
   A / \ 
\ /     A
    A \/ 
   /     
 \/         

dónde:

  • f representa un grifo que vierte una corriente de agua hacia abajo
  • A bifurca la corriente de agua arriba, así que exactamente la mitad va hacia la izquierda y exactamente la mitad va hacia la derecha
  • \ desplaza la corriente de agua arriba a la derecha en una unidad
  • / desplaza la corriente de agua arriba a la izquierda por una unidad
  • Las combinaciones \/crean un canal con capacidad infinita que recoge las corrientes de agua por encima
  • [space] es un espacio vacío del que el agua puede moverse

A partir de esto, podemos imaginar el camino *que tomaría el agua ( ) a medida que sale de los grifos y cae en los canales o fuera del área de la cuadrícula:

f  f  f    <-- first second and third faucets
*  * *A* 
* *A*/ \*
\*/ *  *A  <-- a '*' is not drawn to the right of this A because it would be out of the 9×7 bounds
 * *A*\/   <-- upper trough
 **/ *   
 \/  *     <-- lower trough

Suponiendo que las 3 llaves emiten la misma cantidad de agua, una por vez, podemos ver que

  • Toda el agua del primer grifo va al canal inferior.
  • La mitad del agua del segundo grifo va al canal inferior y la otra mitad se divide entre el canal inferior y se cae de la red.
  • Un cuarto del agua del tercer grifo va al canal inferior, un cuarto cae del fondo de la rejilla, un cuarto entra al canal superior y un cuarto cae de la rejilla a la derecha.

De esto podemos decir que (1 + 3/4 + 1/4 + 1/4) / 3 = 75%el agua es atrapada por los canales y se (1/4 + 1/4 + 1/4) / 3 = 25%cae de la red.

Desafíos

Puede completar cualquiera o todos estos desafíos relacionados con esta configuración de flujo de agua ASCII. Todos son códigos de golf, la respuesta más corta para cada desafío es el ganador. La respuesta aceptada será la persona que complete la mayoría de los desafíos, con una longitud total de código como desempate.

Desafío 1
Escriba un programa que genere la fracción de agua que fluye hacia los canales para una red determinada. El resultado del ejemplo anterior sería simplemente 0.75.

Desafío 2
Escriba un programa que, dada una cuadrícula, dibuje los *'s en los lugares donde fluye el agua como lo hice anteriormente. No debe sobrescribir nada además de los caracteres de espacio y la cuadrícula no debe cambiar el tamaño. Entonces para algo como

 f
/A

no es necesario hacer nada ya que, aunque el agua fluye a ambos lados de la A, no se puede arrastrar hacia la izquierda sin quitar la /y no se puede dibujar hacia la derecha sin agrandar la cuadrícula de 2 × 2.

Desafío 3 (actualizado)
Escriba un programa que tome dos enteros no negativos, la T total y la cantidad para mantener K (T> = K). Genere y dibuje una cuadrícula con exactamente una de ftal manera que cuando ese grifo vierta T unidades de agua, exactamente K fluirá hacia los canales. Si es imposible hacer esto en una cuadrícula finita para un par particular (T, K), entonces envíe 'Imposible'.

Aclaraciones (se aplican a todos los desafíos)

  • La entrada puede ser a través de stdin, o un archivo, o incluso una llamada de función en la representación de cadena de la cuadrícula. Simplemente haz que sea obvio cómo ejecutar diferentes entradas.
  • La salida debe ir a stdout.
  • \Ay A/y AAson también depresiones como era de esperar.
  • Una cuadrícula w por h siempre será un rectángulo bien formateado de caracteres w * h sin contar nuevas líneas. No habrá espacios finales faltantes ni ocurrencias de *.
  • Las dimensiones de la cuadrícula pueden ser tan pequeñas como 1 × 1 y arbitrariamente grandes. (Arbitrariamente grande dentro de lo razonable, int.maxValue o similar es un límite aceptable. Lo mismo ocurre con T y K.)
  • Una corriente sobre una ffluye a través de ella.
  • Los grifos pueden estar en cualquier lugar, no solo en la fila superior.
  • A siempre divide la cantidad de agua que se vierte exactamente por la mitad.

Nota: Cosas como /Ay //son perfectamente válidas. El agua no fluya libremente entre los personajes (aunque para el desafío 2 no hay suficiente espacio para dibujar).

Entonces, en la configuración

ff

/A

La fcorriente izquierda se derrama, golpea /y se desplaza a la izquierda. El derecho fcorriente se derrama, golpea el A, la mitad va a la derecha y la otra mitad va a la izquierda entre el Ay el /.

p.ej

 ff
 **
*/A*
** *
** *
Pasatiempos de Calvin
fuente
3
+1 Buen desafío. En cuanto al desafío 3, la cuadrícula en la parte superior no sería una respuesta válida porque tiene 3 fs
edc65
@ edc65 Ah, buena captura!
Calvin's Hobbies
2
Para el segundo desafío, debe especificar cómo manejar la entrada, como /Asi el agua cae sobre el A. Para todos los desafíos, sería bueno aclarar si se \Atrata de una depresión. Para el tercer desafío, ¿deberían Asuponerse que 3 unidades que caen sobre un se dividen 1.5 / 1.5(por lo que la entrada es realmente un único número racional) o es 2 / 1, en cuyo caso, qué lado recibe el 2?
Peter Taylor
1
@PeterTaylor Gracias. He aclarado esos puntos. Supongo que T y K podrían ser flotadores, pero los mantengo enteros por simplicidad. (Pero si T = 3 no alcanzaron un Aentonces ambas partes no consiguen 1,5 Está hasta el codificador para asegurarse de que la precisión de flotación no es un problema..)
Calvin Aficiones

Respuestas:

3

Todos los desafíos C # 690bytes (416bytes + 274bytes)

Retos 1 y 2 C # 579 446 416bytes

Este es un programa completo que debería hacer los desafíos 1 y 2, casi. Lee líneas de entrada de stdin hasta que recibe una línea vacía. Imprime el resultado del Desafío 2, y luego el resultado del Desafío 1. Utiliza la clase decimal .NET para evitar errores de redondeo.

using C=System.Console;class P{static void Main(){decimal u,t=0,f=0;string c,z="";for(decimal[]n=null,o;(c=C.ReadLine())!="";z+='\n'){int s=c.Length,i=s,e;o=n;n=new decimal[s];for(o=o??n;i-->0;n[i]+=(e&2)*u/2){e=c[i]%13;u=o[i]/(e<1?2:1);if(e%8<1)if(i>0)if(c[i-1]%7<3)t+=u;else n[i-1]+=u;if(e<2)if(i<s-1)if(c[i+1]%2>0)t+=u;else n[i+1]+=u;if(e>9){u++;f++;}}for(;++i<s;)z+=c[i]<33&n[i]>0?'*':c[i];}C.WriteLine(z+t/f);}}

Menos golfizado:

using C=System.Console;
class P
{
    static void Main()
    {
        decimal u,t=0,f=0;
        string c,z="";

        for(decimal[]n=null,o;(c=C.ReadLine())!="";z+='\n')
        {
            int s=c.Length,i=s,e;
            o=n;
            n=new decimal[s];
            for(o=o??n;i-->0;n[i]+=(e&2)*u/2)
            {
                e=c[i]%13;
                u=o[i]/(e<1?2:1);

                if(e%8<1)
                    if(i>0)
                        if(c[i-1]%7<3)t+=u;
                        else n[i-1]+=u;
                if(e<2)
                    if(i<s-1)
                        if(c[i+1]%2>0)t+=u;
                        else n[i+1]+=u;
                if(e>9)
                {
                    u++;
                    f++;
                }
            }
            for(;++i<s;)
                z+=c[i]<33&n[i]>0?'*':c[i];
        }

        C.WriteLine(z+t/f);
    }
}

Prueba de funcionamiento (con la falta de espacios finales que prometo que están allí):

f  f  f
      A
   A / \
\ /     A
    A \/
   /
 \/

f  f  f
*  * *A*
* *A*/ \*
\*/ *  *A
 * *A*\/
 **/ *
 \/  *
0.75

Desafío 3 C # 274bytes

Este es un programa completo que debe completar Desafío 3. conseguido salvar un 6bytes escribiendo mi propio analizador número entero de leer la entrada en lugar de Spliting una ReadLiney usar long.Parse;

using C=System.Console;class P{static void Main(){long t=-1,f=t,k;for(;f<0;)for(f=t,t=0;(k=C.Read())>47;)t=t*10+k-48;var r="Impossible\n";for(k=t;k<t*f;)k*=2;if(f<1||(k/f)*f==k)for(r=" f \n";t>0&t<f;t-=(t/f)*f)r+=((t*=2)<f?" ":"A")+"A \n/ /\n";C.Write(r+(t<f?"":"AAA\n"));}}

Menos golfizado:

using C=System.Console;
class P
{
    static void Main()
    {
        long t=-1,f=t,k;
        for(;f<0;)
            for(f=t,t=0;(k=C.Read())>47;)
                t=t*10+k-48;

        var r="Impossible\n";
        for(k=t;k<t*f;)
            k*=2;
        if(f<1||(k/f)*f==k)
            for(r=" f \n";t>0&t<f;t-=(t/f)*f)
                r+=((t*=2)<f?" ":"A")+"A \n/ /\n";
        C.Write(r+(t<f?"":"AAA\n"));
    }
}

Prueba de ejecución (de nuevo con la falta de espacios finales que prometo que están allí):

32 17
 f
AA
/ /
 A
/ /
 A
/ /
 A
/ /
AA
/ /
VisualMelon
fuente
3

En primer lugar, tengo una pregunta sobre el desafío. Como no tengo suficiente reputación para comentar la pregunta, la escribo aquí:

  • ¿Cuál es el comportamiento de /A(agua que fluye en A), //(agua que fluye en el lado derecho) y las variaciones de este principio? ¿Fluye el agua al primer "punto libre" en el costado o fluye "debajo" de su vecino?

Solo un simple intento, se puede simplificar muuuucho (lo que haré más adelante editando esta publicación).

Editar: segunda versión, un poco más pequeña. Fui por un enfoque diferente: en lugar de buscar cada celda para verificar lo que viene de arriba y de los lados, empiezo desde los grifos y "fluyo" hacia abajo con recursividad.

Javascript, 226 bytes (Desafío 1)

function f(c){function h(b,a,d,e){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"==e||"A"==e?g+=d:h(b,a+1,d,"\\"):"/"==c[b][a]?"\\"==e||"A"==e?g+=d:h(b,a-1,d,"/"):"A"==c[b][a]?"A"==e||"\\"==e||"/"==e?g+=d:(h(b,a-1,d/2,"A"),h(b,a+1,d/2,"A")):h(b+1,a,d,c[b][a]))}for(var g=0,m=0,k=0;k<c.length;k++)for(var l=0;l<c[k].length;l++)"f"==c[k][l]&&(h(k+1,l,1),m++);alert(g/m)};

Javascript, 204 bytes (desafío 2)

function f(c){function e(b,a,d){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"!=d&&"A"!=d&&e(b,a+1,"\\"):"/"==c[b][a]?"\\"!=d&&"A"!=d&&e(b,a-1,"/"):"A"==c[b][a]?"A"!=d&&"\\"!=d&&"/"!=d&&(e(b,a-1,"A"),e(b,a+1,"A")):(" "==c[b][a]&&(c[b][a]="*"),e(b+1,a,c[b][a])))}for(var g=0;g<c.length;g++)for(var h=0;h<c[g].length;h++)"f"==c[g][h]&&e(g+1,h)};

Javascript, 238 bytes (Desafío 1 + 2)

function f(c){function h(b,a,d,e){b<c.length&&0<=a&&a<c[0].length&&("\\"==c[b][a]?"/"==e||"A"==e?g+=d:h(b,a+1,d,"\\"):"/"==c[b][a]?"\\"==e||"A"==e?g+=d:h(b,a-1,d,"/"):"A"==c[b][a]?"A"==e||"\\"==e||"/"==e?g+=d:(h(b,a-1,d/2,"A"),h(b,a+1,d/2,"A")):(" "==c[b][a]&&(c[b][a]="*"),h(b+1,a,d,c[b][a])))}for(var g=0,m=0,k=0;k<c.length;k++)for(var l=0;l<c[k].length;l++)"f"==c[k][l]&&(h(k+1,l,1),m++);alert(g/m)};

Cómo utilizar

Proporcione una representación bidimensional del mapa. Aquí está el ejemplo proporcionado en la pregunta:

var input = [["f"," "," ","f"," "," ","f"," "," "],[" "," "," "," "," "," ","A"," "," "],[" "," "," ","A"," ","/"," ","\\"," "],["\\"," ","/"," "," "," "," "," ","A"],[" "," "," "," ","A"," ","\\","/"," "],[" "," "," ","/"," "," "," "," "," "],[" ","\\","/"," "," "," "," "," "," "]];
f(input);

Salida

Desafío 1: simplemente creará un cuadro de diálogo (alerta) con el resultado (0,75 para el ejemplo anterior).

Desafío 2: modificará directamente el mapa. ¿Debo imprimirlo? Si es así, ¿se acepta console.log? como una salida válida?

Desafío 1 + 2: Ambos anteriores combinados, obviamente ...

refreshfr
fuente
El agua sigue fluyendo entre los personajes como si estuviera abrazando las líneas de Alas barras. Lo he aclarado en la pregunta.
Aficiones de Calvin
La pregunta diceOutput must go to stdout.
user80551
Usted especificó como formato de entrada que debe dar una matriz de cadenas de un carácter por fila, pero tenga en cuenta que puede indexar str[0]en cadenas. Eso sería una matriz de cadenas en lugar de una matriz de matrices de caracteres.
tomsmeding
1
user80551 Gracias, no sé por qué se me pasó por la cabeza. Actualizaré mi código lo antes posible. @tomsmeding Sí, funciona para mi respuesta al desafío 1. Pero para el desafío 2, estoy modificando directamente la entrada y no puedes modificar un carácter en una cadena usando str [i], de ahí el uso de una matriz de matrices.
refreshfr
2

Python 3, 186 bytes (Desafío 3)

Tomé la idea de la cuadrícula de la respuesta de VisualMelon . La función debe imprimir una cuadrícula válida en stdout para T y K arbitrariamente grandes, siempre que sea posible (cuadrícula de tamaño finito), por supuesto.

from fractions import*
def c(T,K):
 p=print;g=gcd(T,K);K//=g;T//=g
 if T&(T-1):p('Impossible')
 else:
  p(' f ')
  while T-1:
   T//=2;p('A/'[K<T]+'A \n///')
   if K>=T:K-=T
  p('AAA'*K)

Cómo utilizar

Llame a la cfunción con la cantidad total y la cantidad para mantener como argumentos.

>>> c(24, 9)
 f 
/A 
///
AA 
///
AA 
///

>>> c(6, 2)
Impossible
Cianogenoide
fuente