Sistema hidráulico ASCII


19

Introdução

Considere uma grade de caracteres f A\/como

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

Onde:

  • f representa uma torneira que derrama um fluxo de água para baixo
  • A bifurca o fluxo de água acima, então exatamente metade vai para a esquerda e exatamente metade vai para a direita
  • \ desloca o fluxo de água acima para a direita em uma unidade
  • / desloca o fluxo de água acima para a esquerda em uma unidade
  • as combinações \/criam uma calha com capacidade infinita que coleta as correntes de água acima dela
  • [space] é um espaço vazio do que a água pode se mover

A partir disso, podemos imaginar o caminho que a água ( *) seguiria ao sair das torneiras e cair nas calhas ou fora da área da grade:

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

Assumindo que as 3 torneiras produzem a mesma quantidade de água, uma de cada vez, podemos ver que

  • Toda a água da primeira torneira vai para a calha mais baixa.
  • Metade da água da segunda torneira vai para a calha inferior e a outra metade é dividida entre a calha inferior e caindo da grade.
  • Um quarto da água da terceira torneira vai para a calha inferior, um quarto cai na parte inferior da grade, um quarto entra na calha superior e um quarto cai da grade para a direita.

A partir disso, podemos dizer que (1 + 3/4 + 1/4 + 1/4) / 3 = 75%a água é capturada pelas valas e (1/4 + 1/4 + 1/4) / 3 = 25%cai da rede.

Desafios

Você pode concluir um ou todos esses desafios relacionados a esta configuração de fluxo de água ASCII. Todos eles são golfe de código, a resposta mais curta para cada desafio é o vencedor. A resposta aceita será a pessoa que concluir a maioria dos desafios, com o comprimento total do código como desempate.

Desafio 1
Escreva um programa que produza a fração de água que flui para as calhas de uma determinada grade. A saída do exemplo acima seria simplesmente 0.75.

Desafio 2
Escreva um programa que, dado uma grade, desenhe *os lugares nos locais em que a água flui, como fiz acima. Você não deve substituir nada além de caracteres de espaço e a grade não deve mudar de tamanho. Então, para algo como

 f
/A

nada precisa ser feito, pois, embora a água flua em ambos os lados do A, ela não pode ser desenhada para a esquerda sem remover a /e não pode ser desenhada para a direita sem aumentar a grade 2 × 2.

Desafio 3 (Atualizado)
Escreva um programa que inclua dois números inteiros não negativos, o T total e o valor para manter K (T> = K). Gere e desenhe uma grade com exatamente uma ftal que, quando essa torneira derramar T unidades de água, exatamente K fluirá para as calhas. Se for impossível fazer isso em uma grade finita para um par específico (T, K), em seguida, imprima 'Impossível'.

Esclarecimentos (aplicáveis ​​a todos os desafios)

  • A entrada pode ser via stdin, ou um arquivo, ou mesmo uma chamada de função na representação de string da grade. Apenas torne óbvio como executar diferentes entradas.
  • A saída deve ir para stdout.
  • \Ae A/e AAsão também por declínios como seria de esperar.
  • Uma grade w por h sempre será um retângulo bem formatado de caracteres w * h sem contar novas linhas. Não haverá espaços à direita ausentes nem ocorrências de *.
  • As dimensões da grade podem ser tão pequenas quanto 1 × 1 e arbitrariamente grandes. (Arbitrariamente grande dentro da razão, int.maxValue ou similar é um limite aceitável. O mesmo vale para T e K.)
  • Um fluxo acima de um fflui direto através dele.
  • As torneiras podem estar em qualquer lugar, não apenas na linha superior.
  • A sempre divide a quantidade de água derramada exatamente ao meio.

Nota: Coisas como /Ae //são perfeitamente válidas. A água não fluir livremente entre os caracteres (embora para desafio 2 não há espaço suficiente para desenhá-lo).

Então, na configuração

ff

/A

O ffluxo da esquerda desce, bate no /e muda para a esquerda. O ffluxo da direita flui para baixo, bate no A, metade vai para a direita e metade vai para a esquerda entre o Ae o /.

por exemplo

 ff
 **
*/A*
** *
** *

3
+1 bom desafio. Quanto desafio 3, a grade na parte superior não seria uma resposta válida porque tem 3 fs
edc65

@ edc65 Ah, boa captura!
Hobbies de Calvin


2
Para o segundo desafio, você precisa especificar como lidar com as entradas, como /Ase a água caísse na A. Para todos os desafios, seria bom esclarecer se isso \Aé um problema. Para o terceiro desafio, deve- Ase supor que 3 unidades que caem em uma divisão se dividam 1.5 / 1.5(para que a entrada seja realmente um único número racional) ou é 2 / 1, nesse caso, qual lado recebe o 2?
Peter Taylor

11
@PeterTaylor Thanks. Eu esclareci esses pontos. Eu acho que T e K podem ser carros alegóricos, mas eu os mantenho inteiros por simplicidade. (Mas se T = 3 não atingiu um A, em seguida, ambos os lados se obter 1,5 Cabe ao codificador para se certificar de precisão flutuante não é um problema..)
de Calvino Hobbies

Respostas:


3

Todos os desafios C # 690bytes (416bytes + 274bytes)

Desafios 1 e 2 C # 579 446 416bytes

Este é um programa completo que deve fazer os Desafios 1 e 2, praticamente. Ele lê as linhas de entrada do stdin até receber uma linha vazia. Ele imprime o resultado do Desafio 2 e, em seguida, o resultado do Desafio 1. Usa a classe decimal .NET para evitar possíveis erros de arredondamento.

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 golfe:

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);
    }
}

Execução de teste (com falta de espaços à direita que prometo estar lá):

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

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

Desafio 3 C # 274bytes

Este é um programa completo que deve completar Desafio 3. Eu um conseguiu salvar 6bytes por escrever meu próprio analisador inteiro para ler a entrada em vez de Spliting um ReadLinee usando 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 golfe:

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"));
    }
}

Execução de teste (novamente com falta de espaços à direita, que prometo estar lá):

32 17
 f
AA
/ /
 A
/ /
 A
/ /
 A
/ /
AA
/ /

3

Antes de tudo, tenho uma pergunta sobre o desafio. Como não tenho reputação suficiente para comentar sobre a questão, estou escrevendo aqui:

  • Qual é o comportamento de /A(água que flui em A), //(água que flui no lado direito) e variações desse princípio? A água flui para o primeiro "ponto livre" ao lado ou flui "abaixo" do vizinho?

Apenas uma tentativa simples, pode ser simplificada (o que farei depois editando este post).

Edit: Segunda versão, um pouco menor. Eu optei por uma abordagem diferente: em vez de procurar cada célula para verificar o que está vindo do topo e dos lados, começo pelas torneiras e "fluo" para baixo com recursão.

Javascript, 226 bytes (Desafio 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 (Desafio 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 (Desafio 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)};

Como usar

Forneça uma representação bidimensional do mapa. Aqui está o exemplo fornecido na pergunta:

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

Resultado

Desafio 1: Ele simplesmente criará uma caixa de diálogo (alerta) com o resultado (0,75 no exemplo acima).

Desafio 2: Ele modificará diretamente o mapa. Devo imprimi-lo? Em caso afirmativo, o console.log é aceito? como uma saída válida?

Desafio 1 + 2: Ambos acima combinados, obviamente ...


A água continua fluindo entre os personagens como se estivesse abraçando as linhas das Abarras. Eu esclareci isso na pergunta.
Hobbies de Calvin

A pergunta afirmaOutput must go to stdout.
user80551

Você especificou como formato de entrada que você fornece uma matriz de cadeias de caracteres de um por linha, mas lembre-se de que pode indexar str[0]em cadeias. Isso seria uma matriz de seqüências de caracteres em vez de uma matriz de matrizes de caracteres.
tomsmeding 22/07

11
user80551 Obrigado, não sei por que isso escapou da minha mente. Vou atualizar meu código o mais rápido possível. @tomsmeding Sim, funciona para a minha resposta do desafio 1. Mas, para o desafio 2, estou modificando diretamente a entrada e você não pode modificar um caractere em uma string usando str [i], daí o uso de uma matriz de matrizes.
refreshfr

2

Python 3, 186 bytes (Desafio 3)

Peguei a idéia da grade da resposta do VisualMelon . A função deve imprimir uma grade válida para stdout para T e K arbitrariamente grandes, desde que seja possível (grade de tamanho finito), é claro.

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)

Como usar

Chame a cfunção com a quantidade total e a quantidade a serem mantidas como argumentos.

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

>>> c(6, 2)
Impossible
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.