Multiplicación visual larga

28

Hay una buena manera de realizar una multiplicación larga para dos enteros sin tener que hacer nada más que contar, que ocasionalmente se comparte en Internet. Escribe los dígitos de cada número como un grupo de líneas inclinadas, con los dos números en un ángulo de 90 grados. Luego, simplemente puede contar las intersecciones en las columnas separadas que surgen. Un diagrama probablemente aclarará esto. Aquí hay un ejemplo para calcular 21 * 32:

ingrese la descripción de la imagen aquí

Si buscas en Google "multiplicación larga visual / gráfica" encontrarás muchos más ejemplos.

En este desafío, debe generar estos diagramas utilizando el arte ASCII. Para el mismo ejemplo, la salida se vería así:

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

Probablemente sea más fácil descubrir las reglas de construcción para estos a partir de algunos ejemplos (ver más abajo), pero aquí algunos detalles:

  • Los segmentos que se intersectan son X, los segmentos no intersectantes de las líneas son /o \.
  • Debe haber exactamente un segmento después de las intersecciones más externas.
  • Debe haber exactamente un segmento entre las intersecciones que pertenecen a diferentes dígitos. Si hay cero dígitos, estos resultarán en segmentos consecutivos /o \.
  • Debe admitir cualquier entrada positiva (al menos hasta un límite razonable como 2 16 o 2 32 ), y cualquier dígito desde 0hasta 9. Sin embargo, puede suponer que no hay 0s ni iniciales ni finales .
  • No debe imprimir espacios en blanco iniciales extraños ni líneas vacías iniciales o finales.
  • Puede imprimir espacios en blanco al final, pero no debe exceder el cuadro delimitador alineado con el eje del diagrama.
  • Opcionalmente, puede imprimir una nueva línea final.
  • Puede elegir en qué orden tomar los dos números de entrada. Sin embargo, debe admitir números arbitrarios para cualquier orientación, por lo que no puede elegir algo como "El número más grande se da primero".
  • Si está tomando la entrada como una cadena, puede usar cualquier separador sin dígitos entre los dos números.

Puede escribir un programa o función, tomando la entrada a través de STDIN (o la alternativa más cercana), argumento de línea de comando o argumento de función y generando el resultado a través de STDOUT (o la alternativa más cercana), el valor de retorno de la función o el parámetro de función (out).

Este es el código de golf, gana la respuesta más corta (en bytes).

Ejemplos

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
fuente
¿Una función con 2 parámetros de cadena o solo una sola cadena y tengo que dividirla en mi código?
edc65
@ edc65 Dos cadenas o incluso dos parámetros enteros están bien.
Martin Ender

Respuestas:

1

Pyth - 79 bytes

Una traducción de la respuesta de @ AlexeyBurdin. Probablemente se pueda jugar mucho más al golf.

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

Toma la entrada como dos números, nueva línea separada. Explicación próximamente.

Pruébelo en línea aquí .

Maltysen
fuente
4

pitón, 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])

Creo que es bastante legible para los humanos.
Verificación:

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
fuente
1
Solo unos pocos campos de golf rápidos: reversedes lo mismo [::-1], puede colocar el contenido del bucle for en una línea para ahorrar sangría, len(a)+len(b)es más corto que sum(map(len,[a,b])), no lo use xrangeen el golf, el espacio ) forpuede eliminarse, y ya que está usando python2, puede combinar espacios y pestañas en sangría.
Maltysen
Muchas gracias. Esto da 22 bytes. Pero no creo que sea el más corto. No codifico pyth pero he visto programas de 31 bytes ... Por cierto, 303 es el recuento cuando cada 4 espacios se reemplaza por una pestaña en realidad.
Alexey Burdin
Aquí, pude obtener 276de golf sintáctico simple: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen
Además, ¿le importa si traduzco su programa a Pyth y lo publico como una respuesta separada?
Maltysen
1
Puede configurar e=enumerateal principio para golf 4 caracteres
sagiksp
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])

Las expresiones son bastante largas, así que creo que hay bastante margen de mejora, pero de todos modos ...

Toma entradas separadas por espacios a través de STDIN, p. Ej.

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

Hay un posible espacio final en algunas líneas, pero A+B-2garantiza que todos los espacios finales estén dentro del cuadro delimitador.

Sp3000
fuente
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())));}

Formateada para facilitar la lectura, la función en 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())));
    }
}

El OR bit a bit era solo por diversión, pero la suma también funcionaría.

Carl Walsh
fuente
1

JavaScript ( ES6 ) 271

Estoy seguro de que hay una solución que construye la salida fila por fila, jugando con las coordenadas matemáticas y x, y (x + y == k, xy == k ...). Pero todavía no puedo clavarlo.

Así que aquí hay una solución que simplemente dibuja las líneas una por una.

Ejecute el fragmento en Firefox para probar.

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
fuente
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
         / \
  • la función itera un solo bucle y usa algunas geometricks y ascii trifling.
Abr001am
fuente
¿Qué es la ---48de?
LegionMammal978
@ LegionMammal978 a veces escribo cosas y luego olvido incluso por qué lo puse allí: D, de todos modos, estoy ocupado haciendo otra cosa, cuando termino, te recuerdo; (¿este código va bien en su compilador)?
Abr001am
@ LegionMammal978 aquí, el contenido de la matriz en un índice específico (real) se resta a 48 antes de que disminuya, restando 48 para esperar un carácter nulo y luego disminuir paso a paso hacia adelante en el bucle (o hacia atrás como patrón
ASCII
48 es la representación ascii de "0"
Abr001am
1
Ahora veo, funciona así ...)-- - 48)....
LegionMammal978
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);}

INTENTALO

Abr001am
fuente
Parece que hay columnas de espacios después de cada carácter, y faltan los segmentos finales que no se cruzan en los extremos inferiores. También estás usando los dígitos en orden inverso.
Martin Ender
@ MartinBüttner imaginar que alguien está haciendo esto en la luna y u observación por telescopio, que es la forma en que debe percibir el diagrama (-joking-i ll ajusto esto más adelante)
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")

Pruébalo en línea!

Nick Kennedy
fuente
0

Jalea , 58 bytes

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

Pruébalo en línea!

Explicación

Un programa completo que toma los dos números como una lista de dos enteros y devuelve una cadena.

Enlace auxiliar 1: rotar la matriz

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

Enlace auxiliar 2: generar las plantillas de fila y columna

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

Enlace 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
fuente