Multiplication visuelle longue

28

Il existe un bon moyen d'effectuer une longue multiplication pour deux entiers sans avoir à faire autre chose que compter, qui est parfois partagé sur Internet. Vous écrivez les chiffres de chaque nombre sous la forme d'un groupe de lignes inclinées, avec les deux nombres à un angle de 90 degrés. Ensuite, vous pouvez simplement compter les intersections dans les colonnes séparées qui se présentent. Un diagramme clarifiera probablement cela. Voici un exemple de calcul 21 * 32:

entrez la description de l'image ici

Si vous recherchez «multiplication visuelle / graphique longue» sur Google, vous trouverez beaucoup plus d'exemples.

Dans ce défi, vous devez générer ces diagrammes en utilisant l'art ASCII. Pour le même exemple, la sortie ressemblerait à ceci:

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

Il est probablement plus facile de comprendre les règles de construction pour ceux-ci à partir de quelques exemples (voir ci-dessous), mais voici quelques détails:

  • Les segments entrecroisés sont X, les segments non entrecroisés des lignes sont /ou \.
  • Il devrait y avoir exactement un segment après les intersections les plus à l'extérieur.
  • Il devrait y avoir exactement un segment entre les intersections appartenant à des chiffres différents. S'il y a zéro chiffre, il en résultera des segments consécutifs /ou \.
  • Vous devez prendre en charge toute entrée positive (au moins jusqu'à une limite raisonnable comme 2 16 ou 2 32 ) et tous les chiffres de 0à 9. Cependant, vous pouvez supposer qu'il n'y a ni 0art. Premier ni arrière .
  • Vous ne devez pas imprimer d'espaces blancs de début superflus ni de lignes vides de début ou de fin.
  • Vous pouvez imprimer un espace de fin, mais il ne doit pas dépasser la zone de délimitation alignée sur l'axe du diagramme.
  • Vous pouvez éventuellement imprimer une seule nouvelle ligne de fin.
  • Vous pouvez choisir dans quel ordre vous prenez les deux numéros d'entrée. Cependant, si vous devez prendre en charge des nombres arbitraires pour l'une ou l'autre orientation, vous ne pouvez pas choisir quelque chose comme "Le plus grand nombre est donné en premier".
  • Si vous prenez l'entrée comme une chaîne, vous pouvez utiliser n'importe quel séparateur non numérique entre les deux nombres.

Vous pouvez écrire un programme ou une fonction, en prenant une entrée via STDIN (ou l'alternative la plus proche), un argument de ligne de commande ou un argument de fonction et en sortant le résultat via STDOUT (ou l'alternative la plus proche), une valeur de retour de fonction ou un paramètre de fonction (out).

C'est le golf de code, la réponse la plus courte (en octets) l'emporte.

Exemples

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
la source
Une fonction avec 2 paramètres de chaîne ou une seule chaîne et je dois la diviser dans mon code?
edc65
@ edc65 Deux chaînes ou même deux paramètres entiers conviennent.
Martin Ender

Réponses:

1

Pyth - 79 octets

Une traduction de la réponse de @ AlexeyBurdin. Peut probablement être joué beaucoup plus.

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

Prend la saisie sous la forme de deux nombres séparés par un saut de ligne. Explication à venir.

Essayez-le en ligne ici .

Maltysen
la source
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])

Je pense que c'est assez lisible par l'homme.
Vérification:

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
la source
1
Juste quelques golfs rapides: reversedc'est la même chose que [::-1], vous pouvez mettre le contenu de la boucle for sur une seule ligne pour économiser sur l'indentation, len(a)+len(b)est plus court que sum(map(len,[a,b])), ne pas utiliser xrangeau golf, l'espace ) forpeut être supprimé, et puisque vous êtes en utilisant python2, vous pouvez combiner des espaces et des tabulations en retrait.
Maltysen
Merci beaucoup. Cela donne 22 octets. Mais je ne pense pas que ce serait le plus court. Je ne code pas pyth mais j'ai vu des programmes de 31 octets ... Au fait, 303 est le nombre quand chaque 4 espaces est remplacé par un tab.
Alexey Burdin
Ici, j'ai pu obtenir 276du golf syntaxique simple: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen
En outre, cela vous dérange si je traduis votre programme en Pyth et le poste en tant que réponse distincte?
Maltysen
1
Vous pouvez définir e=enumerateau départ 4 golfs
sagiksp
2

Python 3, 205 octets

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

Les expressions sont assez longues, donc je pense qu'il y a pas mal de marge d'amélioration, mais de toute façon ...

Prend l'espace d'entrée séparé via STDIN, par exemple

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

Il y a un espace de fin possible sur certaines lignes, mais A+B-2cela garantit que tous les espaces de fin se trouvent dans le cadre de sélection.

Sp3000
la source
1

C #, 451 octets

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

Formatée pour la lisibilité, la fonction en contexte:

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

L'OR au niveau du bit était juste pour le plaisir, mais l'addition fonctionnerait aussi.

Carl Walsh
la source
1

JavaScript ( ES6 ) 271

Je suis sûr qu'il existe une solution qui construit la sortie ligne par ligne, en jouant avec les mathématiques et les coordonnées x, y (x + y == k, xy == k ...). Mais je ne peux toujours pas le comprendre.

Voici donc une solution qui trace simplement les lignes une par une.

Exécutez l'extrait dans Firefox pour tester.

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
la source
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;}

Résultats

       \ /
      \ x /
     \ x x /
      x x x /
   \ / x x x
  \ x / x x \ /
   x x / x \ x /
\ / x x / \ x x /
 x / x x   x x x /
/ x / x \ / x x 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 fonction itère une seule boucle et utilise des geometricks et ascii trifling.
Abr001am
la source
À quoi ça ---48sert?
LegionMammal978
@ LegionMammal978 parfois j'écris des choses puis j'oublie même pourquoi je l'ai mis là: D de toute façon je suis occupé à faire autre chose, quand je termine, je me souviens mal pour vous; (ce code fonctionne-t-il bien dans votre compilateur)?
Abr001am
@ LegionMammal978 ici, le contenu du tableau à un index spécifique (réel) est soustrait à 48 avant de diminuer, en soustrayant 48 afin d'attendre un caractère nul à venir, puis décrémentez pas à pas en boucle (ou en arrière en tant que modèle ascii)
Abr001am
48 est la représentation ascii de "0"
Abr001am
1
Je vois maintenant, ça fonctionne comme ...)-- - 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);}

ESSAYEZ-LE

Abr001am
la source
Il semble qu'il y ait des colonnes d'espaces après chaque caractère, et les derniers segments sans intersection aux extrémités inférieures sont manquants. Vous utilisez également les chiffres dans l'ordre inverse.
Martin Ender
@ MartinBüttner, imaginez que quelqu'un fait cela sur la lune et que vous le regardez au télescope, c'est ainsi que vous devriez percevoir le diagramme (-joking-je l'ajusterai plus tard)
Abr001am
0

R , 294 octets

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

Essayez-le en ligne!

Nick Kennedy
la source
0

Gelée , 58 octets

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

Essayez-le en ligne!

Explication

Un programme complet qui prend les deux nombres comme une liste de deux entiers et renvoie une chaîne.

Lien d'assistance 1: faire pivoter la matrice

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

Lien d'assistance 2: générer les modèles de ligne et de colonne

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

Lien 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
la source