Визуальное Длинное Умножение


28

Есть хороший способ выполнить длинное умножение для двух целых чисел без необходимости делать что-либо, кроме подсчета, которое иногда используется в интернете. Вы пишете цифры каждого числа в виде ряда наклонных линий с двумя числами под углом 90 градусов. Тогда вы можете просто посчитать пересечения в отдельных столбцах, которые возникают. Диаграмма, вероятно, прояснит это. Вот пример для расчета 21 * 32:

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

Если вы воспользуетесь «визуальным / графическим длинным умножением», вы найдете гораздо больше примеров

В этой задаче вы должны сгенерировать эти диаграммы, используя искусство ASCII. Для того же примера вывод будет выглядеть так:

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

Вероятно, проще всего выяснить правила построения для них из некоторых примеров (см. Ниже), но здесь некоторые детали:

  • Пересекающиеся сегменты X, не пересекаются отрезки линий /или \.
  • Должен быть ровно один сегмент после самых внешних пересечений.
  • Между пересечениями должен быть ровно один сегмент, принадлежащий разным цифрам. Если есть нулевые цифры, это приведет к последовательным /или \сегментам.
  • Вы должны поддерживать любой положительный ввод (по крайней мере, до некоторого разумного предела, например 2 16 или 2 32 ) и любые цифры от 0до 9. Тем не менее, вы можете предположить, что нет ни ведущих, ни конечных 0s.
  • Вы не должны печатать лишние начальные пробелы или начальные или конечные пустые строки.
  • Вы можете напечатать конечный пробел, но он не должен превышать ограничивающий прямоугольник диаграммы.
  • При желании вы можете распечатать один завершающий символ новой строки.
  • Вы можете выбрать, в каком порядке вы берете два входных номера. Однако, вы должны поддерживать произвольные числа для любой ориентации, поэтому вы не можете выбрать что-то вроде «Чем больше число дается первым».
  • Если вы принимаете ввод как строку, вы можете использовать любой нецифровый разделитель между двумя числами.

Вы можете написать программу или функцию, принимая ввод через 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 \
            / \

Функция с 2 строковыми параметрами или только одна строка, и я должен разделить ее в моем коде?
edc65

@ edc65 Две строки или даже два целочисленных параметра подходят.
Мартин Эндер

Ответы:


1

Pyth - 79 байт

Перевод ответа @ AlexeyBurdin. Возможно, можно играть в гольф намного больше.

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, вы можете комбинировать пробелы и табуляции в отступе.
Maltysen

Спасибо большое. Это дает 22 байта. Но я не думаю, что это будет самым коротким. Я не пишу pyth, но я видел 31-байтовые программы ... Кстати, 303 - это счетчик, когда каждые 4 пробела заменяются табуляцией.
Алексей Бурдин

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

Кроме того, вы не возражаете, если я переведу вашу программу на Pyth и опубликую ее как отдельный ответ?
Maltysen

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

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 иногда я пишу что-то, а потом забываю, почему я его туда положил; (этот код хорошо работает в вашем компиляторе)?
Abr001am

@ LegionMammal978 здесь, содержимое массива по определенному (фактическому) индексу вычитается до 48 прежде чем оно уменьшается, вычитая 48, чтобы дождаться приходящего нулевого символа, а затем постепенно
уменьшать

48 - это представление ascii «0»
Abr001am

1
Теперь я вижу, это работает как ...)-- - 48)....
LegionMammal978


0

С (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 представьте, что кто-то делает это на Луне, а вы смотрите это с помощью телескопа, именно так вы должны воспринимать диаграмму (-шучу, я исправлю это позже)
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.