Multiplicação visual longa

28

Existe uma boa maneira de realizar uma multiplicação longa para dois números inteiros sem ter que fazer nada além de contar, que ocasionalmente é compartilhado na Internet. Você escreve os dígitos de cada número como um monte de linhas inclinadas, com os dois números em um ângulo de 90 graus. Então você pode simplesmente contar as interseções nas colunas separadas que surgirem. Um diagrama provavelmente esclarecerá isso. Aqui está um exemplo para calcular 21 * 32:

insira a descrição da imagem aqui

Se você pesquisar no Google por "multiplicação visual / gráfica longa", encontrará muito mais exemplos.

Neste desafio, você deve gerar esses diagramas usando a arte ASCII. Para o mesmo exemplo, a saída seria assim:

   \ /
    X /
 \ / X /
\ X / X
 X X / \ /
/ X X   X /
 / X \ / X
  / \ X / \
     X X
    / X \
     / \

Provavelmente, é mais fácil descobrir as regras de construção para isso a partir de alguns exemplos (veja abaixo), mas aqui alguns detalhes:

  • Os segmentos de interseção são X, os segmentos sem interseção das linhas são /ou \.
  • Deve haver exatamente um segmento após as interseções mais externas.
  • Deve haver exatamente um segmento entre interseções pertencentes a dígitos diferentes. Se houver zero dígitos, isso resultará em consecutivos /ou \segmentos.
  • Você deve oferecer suporte a qualquer entrada positiva (pelo menos até algum limite razoável, como 2 16 ou 2 32 ), e qualquer dígito de 0até 9. No entanto, você pode supor que não existem 0s iniciais nem finais .
  • Você não deve imprimir espaços em branco iniciais estranhos ou linhas vazias iniciais ou finais.
  • Você pode imprimir o espaço em branco à direita, mas não deve exceder a caixa delimitadora alinhada ao eixo do diagrama.
  • Opcionalmente, você pode imprimir uma única nova linha à direita.
  • Você pode escolher em qual ordem os dois números de entrada. No entanto, você deve suportar números arbitrários para qualquer orientação, para não poder escolher algo como "O número maior é fornecido primeiro".
  • Se você estiver usando a entrada como uma sequência, poderá usar qualquer separador sem dígito entre os dois números.

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).

Este é o código golf, a resposta mais curta (em bytes) vence.

Exemplos

1*1
\ /
 X
/ \

2*61
 \ /
\ X /
 X X /
/ X X /
 / X X /
  / X X /
   / X X
    / X \ /
     / \ X
        X \
       / \

 45*1
         \ /
        \ X
       \ X \
      \ X \
     \ X \
      X \
   \ / \
  \ X
 \ X \
\ X \
 X \
/ \

21001*209
       \ /
        X /
       / X
      / / \
   \ / /   \ /
    X /     X /
 \ / X     / X /
\ X / \   / / X /
 X X   \ / / / X /
/ X \   X / / / X /
 / \ \ / X / / / X /
    \ X / X / / / X /
     X X / X / / / X /
    / X X / X / / / X
     / X X / X / / / \
      / X X / X / /
       / X X / X /
        / X X / X
         / X X / \
          / X X
           / X \
            / \
Martin Ender
fonte
Uma função com 2 parâmetros de string ou apenas uma string e eu tenho que dividi-la no meu código?
edc65 12/06
@ edc65 Duas cadeias ou até dois parâmetros inteiros estão corretos.
Martin Ender

Respostas:

1

Pitão - 79 bytes

Uma tradução da resposta de @ AlexeyBurdin. Provavelmente pode ser jogado muito mais.

AzHmu++Gm1sH]Zd]Z,_zwK+lzlHJmm\ KK .e.eX@J+kY+-Yklz@" \/x"+byZHzjbmjk:d2_1:J1_2

Recebe a entrada como dois números, nova linha separada. Explicação em breve.

Experimente online aqui .

Maltysen
fonte
4

python, 303

def f(s):
    a,b=s.split('*')
    a,b=map(lambda l:reduce(lambda x,y:x+[1]*int(y)+[0],l,[0]),[reversed(a),b])
    n=sum(map(len,[a,b]))
    l=[[' ']*n for i in xrange(n)]
    for i,x in enumerate(a):
        for j,y in enumerate(b):
            l[i+j][j-i+len(a)]=r' \/x'[x+2*y]
    return '\n'.join(''.join(x[2:-1]) for x in l[1:-2])

Eu acho que é legível por humanos.
Verificação:

print '---'
print '\n'.join('"%s"'%x for x in f('21001*209').split('\n'))
print '---'
---
"       \ /            "
"        x /           "
"       / x            "
"      / / \           "
"   \ / /   \ /        "
"    x /     x /       "
" \ / x     / x /      "
"\ x / \   / / x /     "
" x x   \ / / / x /    "
"/ x \   x / / / x /   "
" / \ \ / x / / / x /  "
"    \ x / x / / / x / "
"     x x / x / / / x /"
"    / x x / x / / / x "
"     / x x / x / / / \"
"      / x x / x / /   "
"       / x x / x /    "
"        / x x / x     "
"         / x x / \    "
"          / x x       "
"           / x \      "
"            / \       "
---
Alexey Burdin
fonte
1
Apenas alguns golpes rápidos: reversedé o mesmo que [::-1], você pode colocar o conteúdo do loop for em uma linha para economizar no recuo, len(a)+len(b)é mais curto do que sum(map(len,[a,b])), não use xrangeno golfe, o espaço no ) forpode ser removido e, como você está usando python2, você pode combinar espaços e tabulações no recuo.
Maltysen
Muito obrigado. Isso fornece 22 bytes. Mas acho que não seria o mais curto. Eu não codifico pyth, mas já vi programas de 31 bytes ... Btw, 303 é a contagem quando todos os 4 espaços são substituídos por uma guia, na verdade.
Alexey Burdin
Aqui, eu era capaz de obter 276a partir de golfe sintática simples: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen
Além disso, você se importa se eu traduzir seu programa para Pyth e publicá-lo como uma resposta separada?
Maltysen
1
Você pode definir e=enumerateno início o golfe 4 caracteres
sagiksp 8/17/17
2

Python 3, 205 bytes

L=a,b=[eval("+[0]+[1]*".join("0%s0"%x)[2:])for x in input().split()]
A,B=map(len,L)
for c in range(2,A+B-1):print((" "*abs(c-A)+" ".join(" \/X"[a[i-c]+2*b[i]]for i in range(max(0,c-A),min(c,B))))[1:A+B-2])

As expressões são bastante longas, então acho que há bastante espaço para melhorias, mas enfim ...

Leva a entrada separada por espaço via STDIN, por exemplo

21 32
   \ /
    X /
 \ / X /
\ X / X  
 X X / \ /
/ X X   X /
 / X \ / X 
  / \ X / \
     X X  
    / X \
     / \

Há um possível espaço à direita em algumas linhas, mas A+B-2isso garante que todos os espaços à direita estejam dentro da caixa delimitadora.

Sp3000
fonte
1

C #, 451 bytes

void d(string s){var S=s.Split('*');int X=S[1].Select(c=>c-47).Sum(),Y=S[0].Select(c=>c-47).Sum(),L=9*(X+Y),A=1,B=L/3,i,j;var a=Range(0,L).Select(_=>new int[L]).ToArray();foreach(var c in S[1]){for(i=48;i<c;++i){for(j=-1;j<Y;++j)a[B-j][A+j]=1;A++;B++;}A++;B++;}A=1;B=L/3;foreach(var c in S[0]){for(i=48;i<c;++i){for(j=-1;j<X;++j)a[B+j][A+j]|=2;A++;B--;}A++;B--;}Write(Join("\n",a.Select(r=>Concat(r.Select(n=>@" /\X"[n]))).Where(r=>r.Trim().Any())));}

Formatado para facilitar a leitura, a função no contexto:

using System.Linq;
using static System.Console;
using static System.Linq.Enumerable;
using static System.String;

class VisualMultiply
{
    static void Main(string[] args)
    {
        new VisualMultiply().d("21001*209");

        WriteLine();
    }

    void d(string s)
    {
        var S = s.Split('*');

        int X = S[1].Select(c => c - 47).Sum(), 
            Y = S[0].Select(c => c - 47).Sum(),
            L = 9 * (X + Y),
            A = 1,
            B = L / 3,
            i,
            j;

        var a = Range(0, L).Select(_ => new int[L]).ToArray();

        foreach (var c in S[1])
        {
            for (i = 48; i < c; ++i)
            {
                for (j = -1; j < Y; ++j)
                    a[B - j][A + j] = 1;
                A++;
                B++;
            }
            A++;
            B++;
        }

        A = 1;
        B = L / 3;
        foreach (var c in S[0])
        {
            for (i = 48; i < c; ++i)
            {
                for (j = -1; j < X; ++j)
                    a[B + j][A + j] |= 2;
                A++;
                B--;
            }
            A++;
            B--;
        }

        Write(Join("\n", a.Select(r => Concat(r.Select(n => @" /\X"[n]))).Where(r => r.Trim().Any())));
    }
}

O OR bit a bit era apenas por diversão, mas a adição também funcionaria.

Carl Walsh
fonte
1

JavaScript ( ES6 ) 271

Tenho certeza de que existe uma solução que constrói a saída linha por linha, mexendo nas matemáticas e coordenadas x, y (x + y == k, xy == k ...). Mas ainda não consigo acertar.

Então, aqui está uma solução que simplesmente desenha as linhas uma a uma.

Execute o trecho no Firefox para testar.

F=(a,b)=>( // string parameters
  t=u=0,[for(v of a)t-=~v],[for(v of b)u-=~v],
  r=t+u,o=[...' '.repeat(r*r-r)],
  L=(x,y,n,z,m,c)=>{
    for(i=0;d=n[i++];)
      for(j=0;++x,y+=z,j++<d;)
        for(l=m+1,p=x+y*r-1-r;l--;p+=r-z,o[p-p%r-1]='\n')
          o[p]=o[p]>' '&&o[p]!=c?'X':c
  },
  L(u,0,a,1,u,'/'),
  L(0,u,b,-1,t,'\\'),
  o.join('')
)

// TEST

function test()
{
  O.innerHTML= F(A.value, B.value);
}

test();
<input id=A value=21001> * <input id=B value=209> <button onclick='test()'>-></button>
<pre id=O></pre>

edc65
fonte
1

VC ++ (289)280

t(char*a){int i,j,k,r,c=1,e,A=0,B=0,*C,G[99],f,u;for(C=&A;c+48|(k=(c=(*(a+=c<1))---48)>0);G[2**(C=!(c+6)?&(B+=A):&(++*C))]=k**C);for(i=0;i<B*B;printf("\n%c"+!!j,32+15*((k=(c<(f=G[(c=i/B)+(j=i%B)+A+2]))*(j<f)*(f>A))+4*(r=(!!e*B>c+(e=G[A+j-c]))*(!!e*c>A-e-2)*(e<A)))+13*k*r),i++);

Uso

#include  <stdio.h>
#include  <conio.h>

int t(char*);

int main(void)
{   char a[]="123*45";
    t((char*)a);
    getch();
    return 0;
}

int 
//-------- padded code ------
t(char*a){int i,j,k,r,c=1,e,A=0,B=0,*C,G[99],f,u;memset(G,0,396);for(C=&A;c+48|(k=(c=(*(a+=c<1))---48)>0);G[2**(C=!(c+6)?&(B+=A):&(++*C))]=k**C);for(i=0;i<B*B;printf("\n%c"+!!j,32+15*((k=(c<(f=G[(c=i/B)+(j=i%B)+A+2]))*(j<f)*(f>A))+4*(r=(!!e*B>c+(e=G[A+j-c]))*(!!e*c>A-e-2)*(e<A)))+13*k*r),i++);

//---------------------------
return 0;}

Resultados

       \ /
      \ x /
     \ x x /
      x x x /
   \ / x x x
  \ x / x x \ /
   x x / x \ x /
\ / x x / \ x x /
 x / x x   x x x /
/ x / x \ / x x x /
 / x / \ x / x x x
  / x   x x / x x \
   / \ / x x / x \
      x / x x / \
     / x / x x
      / x / x \
       / x / \
        / x
         / \
  • a função itera um único loop e usa alguns geometricks e ascii insignificantes.
Abr001am
fonte
Para que serve ---48?
usar o seguinte
@ LegionMammal978 às vezes eu escrevo coisas, então esqueço até porque eu as coloquei lá: D de qualquer maneira, estou ocupada fazendo outra coisa, quando terminar, lembrarei mal de você; (esse código funciona bem no seu compilador)?
Abr1
@ LegionMammal978 aqui, o conteúdo da matriz no índice específico (real) é subtraído para 48 antes de diminuir, subtraindo 48 para esperar um caractere nulo próximo e, em seguida, diminui passo a passo no loop (ou para trás como padrão ascii)
Abr001am
48 é a representação ascii de "0"
Abr001am 14/06/2015
1
Eu vejo agora, funciona como ...)-- - 48)....
usar o seguinte
1

Tela , 41 bytes

(A┬{[1}0}┐)
⁷L├X⁷lYø;{³×?³y³-╵x\╋
⁸⤢↔╶╶⁸n

Experimente aqui!

dzaima
fonte
0

C (329 b)

int f(char*a){int i,j,r,k,c,h,o,e=15,m=99,A=0,B=0,*C,L[m][m],G[m],*g=G;for(C=&A;(c=*a-48)+48;C=!(c+6)?&B:&(*C+=(*g++=c+1)),a++);for(i=B-1,j=0;j<(r=A+B-1);i--,j++)for(k=0,o=4*!!((*(g-=!*g))---1);k<=*(C=(h=i<0)?&B:&A);k++)L[abs(i)+k][j+k-2*k*h]+=o/(3*h+1)*e;for(i=0;i<r*r;i++)printf("\n%c"+!!(i%r),((h=L[i/r][i%r])>e*4)?120:h+32);}

TENTE

Abr001am
fonte
Parece que existem colunas de espaços após cada caractere e os segmentos finais sem interseção nas extremidades inferiores estão ausentes. Você também está usando os dígitos na ordem inversa.
Martin Ender
@ MartinBüttner imaginar que alguém está fazendo isso na Lua e u vê-lo por telescópio, que é a maneira que você deve perceber o diagrama (-joking-i vai ajustar isso mais tarde)
Abr001am
0

R , 294 bytes

d=do.call;r=outer;m=d(r,c(Map(function(y,w)d(c,c(lapply(y%/%10^rev(0:log10(y))%%10,function(z)c(0,rep(w,z))),0)),scan(),1:2),`+`))+1;p=matrix(" ",u<-sum(dim(m)),u);p[d(r,c(lapply(dim(m),seq),function(a,b)nrow(m)-a+b+u*(a+b-2)))]=c(" ","\\","/","X")[m];cat(apply(p,1,paste,collapse=""),sep="\n")

Experimente online!

Nick Kennedy
fonte
0

Geléia , 58 bytes

ŒDṙLN‘ƊṚị“\/X ”K€
L‘0xż1xⱮ$F
DÇ€Ḥ2¦+þ/µZJUṖ;J’⁶xⱮżÑṖḊẎḊ$€Y

Experimente online!

Explicação

Um programa completo que pega os dois números como uma lista de dois números inteiros e retorna uma string.

Link auxiliar 1: gire a matriz

ŒD                        | get the diagonals
  ṙ                       | rotate left by
   LN‘Ɗ                   | minus num columns +1
       Ṛ                  | reverse order
        ị“\/X ”           | index into \/X
               K€         | join each with spaces

Link auxiliar 2: gerar os modelos de linha e coluna

L‘0x                      | 0 copied (num digits + 1) times
    ż                     | interleaved with
     1xⱮ$                 | 1 copied as specified by the digits
         F                | flattened

Link principal

D                         | convert to decimal digits
 ǀ                       | call above link for each number
   Ḥ2¦                    | double the second one
      +þ/                 | outer product using +
         µ                | start a new monadic chain
          ZJUṖ;J’         | reversed range counting down
                          | the columns, followed by range
                            counting up the rows (without
                            duplicating 0 in the middle)
                   ⁶xⱮ    | that many spaces (to provide indents)
                      ż   | interleaved with
                       Ñ  | rotated matrix
                        ṖḊẎḊ$€ Y | remove blank rows and columns and join with newlines
Nick Kennedy
fonte