Visuelle lange Multiplikation

28

Es gibt eine gute Möglichkeit, eine lange Multiplikation für zwei ganze Zahlen durchzuführen, ohne etwas anderes zu tun als zu zählen, was gelegentlich im Internet geteilt wird. Sie schreiben die Ziffern jeder Zahl als Bündel von schrägen Linien, wobei sich die beiden Zahlen in einem Winkel von 90 Grad befinden. Dann können Sie einfach die Schnittpunkte in den einzelnen Spalten zählen, die entstehen. Ein Diagramm wird dies wahrscheinlich verdeutlichen. Hier ist ein Beispiel für die Berechnung 21 * 32:

Bildbeschreibung hier eingeben

Wenn Sie für "visuelle / grafische lange Multiplikation" googeln, finden Sie viel mehr Beispiele.

In dieser Herausforderung müssen Sie diese Diagramme mit ASCII-Grafik erstellen. Für dasselbe Beispiel würde die Ausgabe folgendermaßen aussehen:

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

Es ist wahrscheinlich am einfachsten, die Konstruktionsregeln für diese anhand einiger Beispiele herauszufinden (siehe unten), aber hier einige Details:

  • Sich Xüberschneidende Segmente sind /oder sich nicht überschneidende Segmente der Linien \.
  • Nach den äußersten Kreuzungen sollte genau ein Segment vorhanden sein.
  • Zwischen den Schnittpunkten, die zu verschiedenen Ziffern gehören, sollte genau ein Segment liegen. Wenn es Nullstellen gibt, führen diese zu aufeinanderfolgenden /oder \Segmenten.
  • Sie müssen jede positive Eingabe (mindestens bis zu einer angemessenen Grenze wie 2 16 oder 2 32 ) und alle Ziffern von 0bis unterstützen 9. Sie können jedoch davon ausgehen, dass es weder führende noch nachfolgende 0s gibt.
  • Sie dürfen keine überflüssigen führenden Leerzeichen oder führende oder nachfolgende Leerzeilen drucken.
  • Sie können nachgestellte Leerzeichen drucken, diese dürfen jedoch das achsenausgerichtete Begrenzungsfeld des Diagramms nicht überschreiten.
  • Sie können optional eine einzelne nachgestellte Zeile drucken.
  • Sie können wählen, in welcher Reihenfolge Sie die beiden Eingabenummern nehmen. Sie müssen jedoch für beide Ausrichtungen beliebige Zahlen unterstützen, damit Sie nicht die Option "Die größere Zahl wird zuerst vergeben" auswählen können.
  • Wenn Sie Eingaben als Zeichenfolge verwenden, können Sie ein beliebiges nicht-stelliges Trennzeichen zwischen den beiden Zahlen verwenden.

Sie können ein Programm oder eine Funktion schreiben, indem Sie eine Eingabe über STDIN (oder die nächstgelegene Alternative), ein Befehlszeilenargument oder ein Funktionsargument vornehmen und das Ergebnis über STDOUT (oder die nächstgelegene Alternative), einen Funktionsrückgabewert oder einen Funktionsparameter (out) ausgeben.

Dies ist Code Golf, die kürzeste Antwort (in Bytes) gewinnt.

Beispiele

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
quelle
Eine Funktion mit 2 String-Parametern oder nur einem einzigen String und ich muss ihn in meinem Code aufteilen?
edc65,
@ edc65 Zwei Zeichenfolgen oder sogar zwei Ganzzahlparameter sind in Ordnung.
Martin Ender

Antworten:

1

Pyth - 79 Bytes

Eine Übersetzung von @ AlexeyBurdins Antwort. Kann wahrscheinlich viel mehr golfen werden.

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

Nimmt die Eingabe als zwei Zahlen, getrennt durch Zeilenumbrüche. Erklärung folgt in Kürze.

Probieren Sie es hier online aus .

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

Ich denke, es ist genug für Menschen lesbar.
Nachprüfung:

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
quelle
1
Nur ein paar schnelle Golfer: reversedist das Gleiche wie [::-1], Sie können den Inhalt der for-Schleife in eine Zeile setzen, um Einrückung zu sparen, len(a)+len(b)ist kürzer als sum(map(len,[a,b])), nicht xrangezum Golfen verwenden, der Platz ) forkann entfernt werden, und da Sie sind Mit python2 können Sie Leerzeichen und Tabulatoren in Einrückungen kombinieren.
Maltysen,
Vielen Dank. Dies ergibt 22 Bytes. Aber ich denke nicht, dass es das kürzeste wäre. Ich codiere Pyth nicht, aber ich habe 31-Byte-Programme gesehen ... Übrigens, 303 ist die Zählung, wenn alle 4 Leerzeichen tatsächlich durch einen Tabulator ersetzt werden.
Alexey Burdin
Hier konnte ich 276vom einfachen syntaktischen Golfen ausgehen: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen
Macht es Ihnen auch etwas aus, wenn ich Ihr Programm in Pyth übersetze und es als separate Antwort poste?
Maltysen
1
Sie können e=enumeratezu Beginn Golf 4 Zeichen
einstellen
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])

Die Ausdrücke sind ziemlich lang und ich denke, es gibt eine Menge Raum für Verbesserungen, aber trotzdem ...

Nimmt die Eingabe durch STDIN getrennt vor, z

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

In einigen Zeilen ist möglicherweise ein Leerzeichen nachgestellt, aber das A+B-2stellt sicher, dass sich alle nachgestellten Leerzeichen innerhalb des Begrenzungsrahmens befinden.

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

Aus Gründen der Lesbarkeit formatiert, die Funktion im Kontext:

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

Das bitweise ODER war nur zum Spaß, aber das Hinzufügen würde auch funktionieren.

Carl Walsh
quelle
1

JavaScript ( ES6 ) 271

Ich bin mir sicher, dass es eine Lösung gibt, die die Ausgabe Zeile für Zeile erstellt und dabei mit Mathe- und XY-Koordinaten spielt (x + y == k, xy == k ...). Aber ich kann es immer noch nicht nageln.

Hier ist also eine Lösung, die die Linien einfach nacheinander zeichnet.

Führen Sie das Snippet zum Testen in Firefox aus.

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

Verwendung

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

Ergebnisse

       \ /
      \ 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
         / \
  • Die Funktion durchläuft eine einzelne Schleife und verwendet einige Geometrie-Tipps und Kleinigkeiten.
Abr001am
quelle
Wofür ist das ---48?
LegionMammal978
@ LegionMammal978 manchmal schreibe ich Dinge, dann vergesse ich sogar, warum ich es dort abgelegt habe: D Trotzdem bin ich damit beschäftigt, etwas anderes zu tun, wenn ich fertig bin, erinnere ich mich nicht mehr an dich; (Geht dieser Code in Ihrem Compiler gut)?
14.
@ LegionMammal978 hier wird der Array-Inhalt an einem bestimmten (tatsächlichen) Index von 48 subtrahiert, bevor er dekrementiert wird, wobei 48 subtrahiert wird, um auf ein Null-Zeichen zu warten, und dann schrittweise in der Schleife vorwärts dekrementiert wird (oder rückwärts als ASCII-Muster)
Abr001am
48 ist die ASCII-Darstellung von "0"
Abr001am
1
Ich verstehe jetzt, wie es funktioniert ...)-- - 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);}

VERSUCH ES

Abr001am
quelle
Es scheint, dass nach jedem Zeichen Spalten mit Leerzeichen vorhanden sind und die letzten sich nicht überschneidenden Segmente an den unteren Enden fehlen. Sie verwenden die Ziffern auch in umgekehrter Reihenfolge.
Martin Ender
Vorstellen @ MartinBüttner jemand tut dies auf dem Mond und u es durch Teleskop beobachten, dass die Art und Weise s sollten Sie das Diagramm wahrnehmen (-joking-i ll einstellen , dass später)
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")

Probieren Sie es online!

Nick Kennedy
quelle
0

Jelly , 58 Bytes

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

Probieren Sie es online!

Erläuterung

Ein vollständiges Programm, das die beiden Zahlen als Liste mit zwei Ganzzahlen verwendet und eine Zeichenfolge zurückgibt.

Hilfslink 1: Matrix drehen

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

Hilfslink 2: Generieren Sie die Zeilen- und Spaltenvorlagen

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

Hauptlink

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
quelle