Візуальне довге множення


28

Існує хороший спосіб виконати довге множення двох цілих чисел, не роблячи нічого, крім підрахунку, який час від часу ділиться в Інтернеті. Цифри кожного числа ви записуєте як купу нахилених ліній, з двома числами під кутом 90 градусів. Тоді ви можете просто порахувати перехрестя в окремих стовпцях, що виникають. Діаграма, ймовірно, прояснить це. Ось приклад для розрахунку 21 * 32:

введіть тут опис зображення

Якщо ви перейдете на Google для "візуального / графічного довгого множення", ви знайдете набагато більше прикладів.

У цьому виклику ви повинні генерувати ці діаграми, використовуючи арт. ASCII. У цьому ж прикладі результат буде виглядати так:

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

Напевно, найпростіше з’ясувати правила побудови для них з деяких прикладів (див. Нижче), але ось деякі деталі:

  • Пересічні сегменти - Xце непересічні відрізки ліній /або \.
  • Після самих зовнішніх перехрестів має бути рівно один відрізок.
  • Між перехрестями, що належать до різних цифр, має бути рівно один відрізок. Якщо є нульові цифри, це призведе до послідовних /або \сегментів.
  • Ви повинні підтримувати будь-які позитивні дані (принаймні, до певного розумного обмеження, наприклад 2 16 або 2 32 ), і будь-які цифри від 0до 9. Однак, ви можете припустити, що немає ні провідних, ні кінцевих 0с.
  • Ви не повинні друкувати сторонні пробіли або провідні чи кінцеві порожні рядки.
  • Ви можете надрукувати пробіли пробілу, але він не повинен перевищувати вікно діаграми, що вирівнюється по осі.
  • Ви необов'язково можете надрукувати один зворотний рядок.
  • Ви можете вибрати, в якому порядку ви берете два вхідні номери. Однак ви повинні підтримувати довільні числа для будь-якої орієнтації, тому ви не можете вибрати щось на кшталт "Більше число задається першим".
  • Якщо ви приймаєте введення як рядок, ви можете використовувати будь-який нецифровий роздільник між двома номерами.

Ви можете написати програму або функцію, взявши введення через STDIN (або найближчу альтернативу), аргумент командного рядка або аргумент функції та вивівши результат через STDOUT (або найближчу альтернативу), значення повернення функції або параметр функції (out).

Це код гольфу, найкоротша відповідь (у байтах) виграє.

Приклади

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 \
            / \

Функція з двома рядковими параметрами або лише одна одна рядок, і я повинен розділити її у своєму коді?
edc65

@ edc65 Двома рядками або навіть двома цілими параметрами добре.
Мартін Ендер

Відповіді:


1

Pyth - 79 байт

Переклад відповіді @ Олексія Бурдіна. Можливо, може бути гольф набагато більше.

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

Вводиться як два числа, розділені новою лінією. Пояснення найближчим часом.

Спробуйте його онлайн тут .


4

пітон, 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])

Я думаю, що це достатньо читабельно для людини.
Підтвердження:

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 \      "
"            / \       "
---

1
Лише кілька швидких гольфів: reversedте саме [::-1], що ви можете помістити вміст циклу for в один рядок, щоб заощадити на відступі, len(a)+len(b)коротше sum(map(len,[a,b])), не використовуйте xrangeв гольфі, місце в ньому ) forможна видалити, і оскільки ви використовуючи python2, ви можете комбінувати пробіли та вкладки в відступі.
Малтісен

Велике спасибі Це дає 22 байти. Але я не думаю, що це було б найкоротшим. Я не кодую pyth, але я бачив 31- байтні програми ... Btw, 303 - це кількість, коли фактично кожен 4 пробіл замінюється вкладкою.
Олексій Бурдін

Тут мені вдалося дістатися 276з простого синтаксичного гольфу: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Мальтісен

Також ви не заперечуєте, якщо я перекладу вашу програму на Pyth і опублікую її як окрему відповідь?
Малтісен

1
Ви можете встановити e=enumerateна старті в гольф 4 символи
sagiksp

2

Python 3, 205 байт

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

Вирази досить довгі, тому я думаю, що є достатньо місця для вдосконалення, але все одно ...

Займає розділений простір вводу через STDIN, наприклад

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

На деяких лініях можливий пробіл, але це A+B-2гарантує, що всі проміжки проміжку знаходяться в межах обмежувального поля.


1

C #, 451 байт

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

Відформатована для читабельності, функція в контексті:

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

Побіт АБО був просто для розваги, але доповнення теж буде працювати.


1

JavaScript ( ES6 ) 271

Я впевнений, що існує рішення, яке будує вихідний рядок за рядком, співпадаючи з математикою та x, y координатами (x + y == k, xy == k ...). Але я все одно не можу це зробити.

Тож ось рішення, яке просто малює лінії по черзі.

Запустіть фрагмент у Firefox для тестування.

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>


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

Використання

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

Результати

       \ /
      \ x /
     \ x x /
      x x x /
   \ / x x x
  \ x / x x \ /
   x x / x \ x /
\ / x x / \ x x /
 x / x x   x x x /
/ x / x \ / x x x /
 / x / \ x / x x x
  / x   x x / x x \
   / \ / x x / x \
      x / x x / \
     / x / x x
      / x / x \
       / x / \
        / x
         / \
  • функція повторює одну певну петлю і використовує деякі геометричні елементи та дрібниці.

Для чого ---48?
LegionMammal978

@ LegionMammal978 іноді я пишу речі, то я забуваю навіть, чому я це помістив: D все одно я зайнятий тим, що роблю щось інше, коли я закінчу, погано пам’ятаю тебе; (чи добре цей код іде у вашому компіляторі)?
Апр001ам

@ LegionMammal978 тут вміст масиву в конкретному (фактичному) індексі віднімається до 48 до його зменшення, віднімаючи 48, щоб дочекатися наступного символу нуля, а потім зменшення крок за кроком вперед у циклі (або назад, як шаблон ascii)
Abr001am

48 - представлення ascii "0"
Abr001am

1
Я бачу зараз, це працює так ...)-- - 48)....
LegionMammal978


0

C (329 б)

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

СПРОБУЙ ЦЕ


Здається, що після кожного символу є стовпці пробілів, а кінцеві непересічні сегменти на нижніх кінцях відсутні. Ви також використовуєте цифри у зворотному порядку.
Мартін Ендер

@ MartinBüttner уявити , що хто - то робить це на Місяці і і дивитися його з допомогою телескопа, що S, як ви повинні сприймати діаграму (-joking-я буду коректувати , що пізніше)
Abr001am

0

R , 294 байти

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

Спробуйте в Інтернеті!


0

Желе , 58 байт

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

Спробуйте в Інтернеті!

Пояснення

Повна програма, яка приймає два числа як список двох цілих чисел і повертає рядок.

Посилання 1 для помічника: повернути матрицю

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

Посилання помічника 2: генеруйте шаблони рядків та стовпців

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

Головна посилання

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.