Wizualne długie mnożenie

28

Jest to dobry sposób na wykonanie długiego mnożenia dla dwóch liczb całkowitych bez konieczności robienia niczego poza liczeniem, które od czasu do czasu są udostępniane w Internecie. Cyfry każdej liczby zapisujesz jako wiązkę ukośnych linii, z dwiema liczbami pod kątem 90 stopni. Następnie możesz po prostu policzyć skrzyżowania w oddzielnych kolumnach, które się pojawiają. Schemat prawdopodobnie to wyjaśni. Oto przykład obliczania 21 * 32:

wprowadź opis zdjęcia tutaj

Jeśli wyszukujesz w Google „wizualne / graficzne długie mnożenie”, znajdziesz o wiele więcej przykładów.

W tym wyzwaniu musisz wygenerować te diagramy przy użyciu grafiki ASCII. W tym samym przykładzie dane wyjściowe wyglądałyby tak:

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

Prawdopodobnie najłatwiej jest obliczyć reguły konstrukcyjne dla nich z kilku przykładów (patrz poniżej), ale tutaj kilka szczegółów:

  • Przecinające się segmenty to Xnie przecinające się segmenty linii to /lub \.
  • Powinien znajdować się dokładnie jeden segment za najbardziej zewnętrznymi skrzyżowaniami.
  • Pomiędzy skrzyżowaniami należącymi do różnych cyfr powinien znajdować się dokładnie jeden segment. Jeśli są cyfry zerowe, będą to kolejne /lub \segmenty.
  • Musisz wesprzeć wszelkie pozytywne dane wejściowe (przynajmniej do pewnego rozsądnego limitu, takiego jak 2 16 lub 2 32 ), oraz wszelkie cyfry od 0do 9. Możesz jednak założyć, że nie ma ani początku, ani końca 0.
  • Nie wolno drukować obcych początkowych białych znaków ani początkowych lub końcowych pustych linii.
  • Można wydrukować końcowe białe znaki, ale nie mogą one przekraczać wyrównanego do osi obwiedni.
  • Możesz opcjonalnie wydrukować jedną końcową linię nowego wiersza.
  • Możesz wybrać, w jakiej kolejności wziąć dwie liczby wejściowe. Jednak musi obsługiwać dowolne liczby dla obu orientacji, więc nie można wybrać czegoś w rodzaju „Najpierw podawana jest większa liczba”.
  • Jeśli bierzesz dane wejściowe jako ciąg, możesz użyć dowolnego niecyfrowego separatora między dwiema liczbami.

Możesz napisać program lub funkcję, pobierając dane wejściowe przez STDIN (lub najbliższą alternatywę), argument wiersza poleceń lub argument funkcji i wypisując wynik przez STDOUT (lub najbliższą alternatywę), wartość zwracaną funkcji lub parametr funkcji (wyjściowej).

To jest kod golfowy, wygrywa najkrótsza odpowiedź (w bajtach).

Przykłady

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
źródło
Funkcja z 2 parametrami ciągu lub tylko jednym ciągiem i muszę podzielić go w kodzie?
edc65
@ edc65 Dwa łańcuchy lub nawet dwie liczby całkowite są w porządku.
Martin Ender

Odpowiedzi:

1

Pyth - 79 bajtów

Tłumaczenie odpowiedzi @ AlexeyBurdin. Prawdopodobnie można grać w golfa o wiele więcej.

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

Pobiera dane wejściowe jako dwie liczby oddzielone znakiem nowej linii. Wyjaśnienie już wkrótce.

Wypróbuj online tutaj .

Maltysen
źródło
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])

Myślę, że jest wystarczająco czytelny dla człowieka.
Weryfikacja:

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
źródło
1
Tylko kilka szybkich golfów: reversedjest to samo [::-1], co: możesz umieścić zawartość pętli for w jednej linii, aby zaoszczędzić na wcięciach, len(a)+len(b)jest krótszy niż sum(map(len,[a,b])), nie używaj xrangew golfie, ) formożna usunąć miejsce, a ponieważ jesteś za pomocą python2 możesz łączyć spacje i tabulatory z wcięciem.
Maltysen
Dzięki wielkie. Daje to 22 bajty. Ale nie sądzę, żeby był najkrótszy. Nie koduję pyta, ale widziałem 31-bajtowe programy ... Btw, 303 to liczba, w której każde 4 spacje są zastępowane tabulatorem.
Alexey Burdin
Tutaj udało mi się uzyskać 276proste składanie w
Maltysen
Czy masz coś przeciwko, że przetłumaczę twój program na Pyth i opublikuję go jako osobną odpowiedź?
Maltysen
1
Możesz ustawić e=enumeratena początku golfa 4 znaki
sagiksp
2

Python 3, 205 bajtów

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

Wyrażenia są dość długie, więc myślę, że jest sporo miejsca na ulepszenia, ale w każdym razie ...

Oddziela przestrzeń wejściową przez STDIN, np

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

W niektórych liniach jest możliwe spacje końcowe, ale A+B-2zapewnia, że ​​wszystkie spacje końcowe znajdują się w obwiedni.

Sp3000
źródło
1

C #, 451 bajtów

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

Sformatowana pod kątem czytelności, funkcja w kontekście:

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

Bitowe OR było po prostu dla zabawy, ale dodawanie też by działało.

Carl Walsh
źródło
1

JavaScript ( ES6 ) 271

Jestem pewien, że istnieje rozwiązanie, które buduje dane wyjściowe rząd po rzędzie, bawiąc się współrzędnymi matematycznymi i x, y (x + y == k, xy == k ...). Ale nadal nie mogę tego zrobić.

Oto rozwiązanie, które po prostu rysuje linie jeden po drugim.

Uruchom fragment w przeglądarce Firefox, aby go przetestować.

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
źródło
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++);

Stosowanie

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

Wyniki

       \ /
      \ x /
     \ x x /
      x x x /
   \ / x x x
  \ x / x x \ /
   x x / x \ x /
\ / x x / \ x x /
 x / x x   x x x /
/ x / x \ / x x x /
 / x / \ x / x x x
  / x   x x / x x \
   / \ / x x / x \
      x / x x / \
     / x / x x
      / x / x \
       / x / \
        / x
         / \
  • funkcja iteruje jedną pojedynczą pętlę i używa drobiazgów geometrycznych i ascii.
Abr001am
źródło
Co to jest ---48za?
LegionMammal978
@ LegionMammal978 czasami piszę rzeczy, a potem zapominam, nawet dlaczego to tam umieściłem: D i tak jestem zajęty robieniem czegoś innego, kiedy skończę, źle pamiętam dla ciebie; (czy ten kod działa dobrze w twoim kompilatorze)?
Abr001am
@ LegionMammal978 tutaj, zawartość tablicy o określonym (rzeczywistym) indeksie jest odejmowana do 48, zanim ulegnie zmniejszeniu, odejmując 48, aby poczekać na nadchodzący znak zero, a następnie zmniejszać się krok po kroku w pętli (lub wstecz jako wzór ascii)
Abr001am
48 to ascii przedstawienie „0”
Abr001am
1
Rozumiem teraz, działa jak ...)-- - 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);}

SPRÓBUJ

Abr001am
źródło
Wygląda na to, że po każdej postaci znajdują się kolumny spacji i brakuje końcowych nie przecinających się segmentów na dolnych końcach. Używasz także cyfr w odwrotnej kolejności.
Martin Ender,
@ MartinBüttner wyobraź sobie, że ktoś robi to na Księżycu, a ty oglądasz to przez teleskop, w taki sposób powinieneś postrzegać schemat (-żartuję-dostosuję to później)
Abr001am
0

R , 294 bajty

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

Wypróbuj online!

Nick Kennedy
źródło
0

Galaretka , 58 bajtów

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

Wypróbuj online!

Wyjaśnienie

Pełny program, który bierze dwie liczby jako listę dwóch liczb całkowitych i zwraca ciąg znaków.

Łącze pomocnicze 1: obróć matrycę

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

Łącze pomocnicze 2: wygeneruj szablony wierszy i kolumn

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

Główny 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
źródło