Visual Long Multiplication

28

There is a nice way to perform long multiplication for two integers without having to do anything but counting, which occasional gets shared around the internet. You write the digits of each number as a bunch of slanted lines, with the two numbers at a 90 degree angle. Then you can simply count the intersections in the separate columns that arise. A diagram will probably clarify this. Here is an example for calculating 21 * 32:

enter image description here

If you google for "visual/graphical long multiplication" you'll find a lot more examples.

In this challenge, you are to generate these diagrams using ASCII art. For the same example, the output would look like this:

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

It's probably easiest to figure out the construction rules for these from some examples (see below), but here some details:

  • Intersecting segments are X, non-intersecting segments of the lines are / or \.
  • There should be exactly one segment after the outermost intersections.
  • There should be exactly one segment between intersections belonging to different digits. If there are zero-digits, these will result in consecutive / or \ segments.
  • You have to support any positive input (at least up to some reasonable limit like 216 or 232), and any digits from 0 to 9. However, you may assume that there neither leading nor trailing 0s.
  • You must not print extraneous leading whitespace or leading or trailing empty lines.
  • You may print trailing whitespace but it must not exceed the diagram's axis-aligned bounding box.
  • You may optionally print a single trailing newline.
  • You may choose in which order you take the two input numbers. However, it you must support arbitrary numbers for either orientation, so you can't choose something like "The larger number is given first".
  • If you're taking input as a string, you can use any non-digit separator between the two numbers.

You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.

This is code golf, the shortest answer (in bytes) wins.

Examples

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

Posted 2015-06-07T13:24:22.380

Reputation: 184 808

A function with 2 string parameters or just one single string and I have to split it in my code? – edc65 – 2015-06-12T12:30:00.300

@edc65 Two strings or even two integer parameters are fine. – Martin Ender – 2015-06-12T12:39:31.650

Answers

1

Pyth - 79 bytes

A translation of @AlexeyBurdin's answer. Can probably be golfed a lot more.

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

Takes input as two numbers, newline separated. Explanation coming soon.

Try it online here.

Maltysen

Posted 2015-06-07T13:24:22.380

Reputation: 25 023

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

I think it's enough human-readable.
Verification:

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

Posted 2015-06-07T13:24:22.380

Reputation: 844

1Just a few quick golfs: reversed is the same as [::-1], you can put the contents of the for loop into one line to save on indentation, len(a)+len(b) is shorter than sum(map(len,[a,b])), don't use xrange in golfing, the space in ) for can be removed, and since you are using python2, you can combine spaces and tabs in indentation. – Maltysen – 2015-06-07T17:44:28.847

Thanks much. These gives 22 bytes. But I don't think it would be the shortest. I don't code pyth but I've seen 31-byte programs... Btw, 303 is the count when every 4-spaces is replaced by a tab actually. – Alexey Burdin – 2015-06-07T18:05:45.130

Here, I was able to get 276 from simple syntactic golfing: https://gist.github.com/Maltysen/e8231c0a9b585e2a4941

– Maltysen – 2015-06-07T18:09:26.423

Also, do you mind if I translate your program to Pyth and post it as a separate answer? – Maltysen – 2015-06-07T18:10:52.937

This would be great since you actually can. I think reverse coordinate change of (x,y)=(i+j,j-i+len(a)): (i,j)=(smth of x and y) would be more efficient, but just a guess. – Alexey Burdin – 2015-06-07T18:17:34.957

Well I got it, but its no 31 byte answer, :) – Maltysen – 2015-06-07T18:46:20.737

Put the first four lines after the function signature onto the same line with semicolons separating. Should save 3 bytes. Also, remove the space in return '\n' and the space in -1]) for to save 2 more. – mbomb007 – 2015-06-09T18:41:27.550

1You can set e=enumerate at the start to golf 4 chars – sagiksp – 2017-06-08T10:47:07.053

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

The expressions are quite long so I think there's a fair amount of room for improvement, but anyway...

Takes input space-separated via STDIN, e.g.

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

There's a possible trailing space on some lines, but the A+B-2 ensures that all of the trailing spaces are within the bounding box.

Sp3000

Posted 2015-06-07T13:24:22.380

Reputation: 58 729

1

Canvas, 41 bytes

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

Try it here!

dzaima

Posted 2015-06-07T13:24:22.380

Reputation: 19 048

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

Formatted for readability, the function in context:

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

The bitwise OR was just for fun, but addition would work too.

Carl Walsh

Posted 2015-06-07T13:24:22.380

Reputation: 201

1

JavaScript (ES6) 271

I'm sure that there is a solution that builds the output row by row, fiddling with math and x,y coordinates (x+y==k, x-y==k ...). But I still can't nail it.

So here is a solution that simply draws the lines one by one.

Run the snippet in Firefox to test.

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

Posted 2015-06-07T13:24:22.380

Reputation: 31 086

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

Usage

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

Results

       \ /
      \ 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
         / \
  • the function iterates one single loop , and use some geometricks and ascii trifling.

Abr001am

Posted 2015-06-07T13:24:22.380

Reputation: 862

What's the ---48 for? – LegionMammal978 – 2015-06-14T12:56:26.290

@LegionMammal978 sometimes i write things then i forget even why did i put it there :D anyway im busy doing something else, when i finish , ill remember for you ; (does this code go well in your compilater) ? – Abr001am – 2015-06-14T13:12:25.257

@LegionMammal978 here ,array content at specific (actual) index is subtracted to 48 before it decrements , subtracting 48 in order to wait a coming nil character then decrement step by step forward in loop (or backwards as ascii pattern) – Abr001am – 2015-06-14T15:52:10.173

48 is the ascii representation of "0" – Abr001am – 2015-06-14T15:55:03.110

1I see now, it works like ...)-- - 48).... – LegionMammal978 – 2015-06-20T17:23:22.133

0

Jelly, 58 bytes

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

Try it online!

Explanation

A full program that takes the two numbers as a list of two integers and returns a string.

Helper link 1: rotate the matrix

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

Helper link 2: generate the row and column templates

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

Main link

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

Posted 2015-06-07T13:24:22.380

Reputation: 11 829

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

Try it online!

Nick Kennedy

Posted 2015-06-07T13:24:22.380

Reputation: 11 829

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

TRY IT

Abr001am

Posted 2015-06-07T13:24:22.380

Reputation: 862

It seems there are columns of spaces after every character, and the final non-intersecting segments at the bottom ends are missing. You're also using the digits in reverse order. – Martin Ender – 2015-06-09T15:46:17.997

@MartinBüttner imagine someone is doing this on the moon and u watching it by telescope , that s the way you should perceive the diagram (-joking-i ll adjust that later) – Abr001am – 2015-06-09T16:52:09.520