Phép nhân trực quan dài


28

Có một cách hay để thực hiện phép nhân dài cho hai số nguyên mà không phải làm gì ngoài việc đếm, đôi khi được chia sẻ trên internet. Bạn viết các chữ số của mỗi số dưới dạng một loạt các đường xiên, với hai số ở góc 90 độ. Sau đó, bạn có thể chỉ cần đếm các giao điểm trong các cột riêng biệt phát sinh. Một sơ đồ có thể sẽ làm rõ điều này. Đây là một ví dụ để tính toán 21 * 32:

nhập mô tả hình ảnh ở đây

Nếu bạn google cho "nhân dài hình ảnh / đồ họa", bạn sẽ tìm thấy nhiều ví dụ hơn.

Trong thử thách này, bạn phải tạo các sơ đồ này bằng nghệ thuật ASCII. Đối với ví dụ tương tự, đầu ra sẽ như thế này:

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

Có lẽ dễ nhất để tìm ra các quy tắc xây dựng cho những điều này từ một số ví dụ (xem bên dưới), nhưng ở đây một số chi tiết:

  • Các phân đoạn giao nhau là X, các phân đoạn không giao nhau của các dòng là /hoặc \.
  • Cần có chính xác một đoạn sau các giao lộ ngoài cùng.
  • Cần có chính xác một đoạn giữa các giao điểm thuộc các chữ số khác nhau. Nếu có các chữ số 0, chúng sẽ dẫn đến các phân đoạn /hoặc liên tiếp \.
  • Bạn phải hỗ trợ bất kỳ đầu vào tích cực nào (ít nhất là đến một số giới hạn hợp lý như 2 16 hoặc 2 32 ) và bất kỳ chữ số nào từ 0đến 9. Tuy nhiên, bạn có thể cho rằng không có 0s dẫn đầu hay dấu .
  • Bạn không được in các khoảng trắng hàng đầu bên ngoài hoặc các dòng trống hàng đầu hoặc cuối.
  • Bạn có thể in khoảng trắng theo sau nhưng không được vượt quá hộp giới hạn theo trục của sơ đồ.
  • Bạn có thể tùy ý in một dòng mới duy nhất.
  • Bạn có thể chọn theo thứ tự bạn lấy hai số đầu vào. Tuy nhiên, bạn phải hỗ trợ các số tùy ý cho một trong hai hướng, vì vậy bạn không thể chọn thứ gì đó như "Số lớn hơn được đưa ra trước".
  • Nếu bạn đang nhập dữ liệu dưới dạng chuỗi, bạn có thể sử dụng bất kỳ dấu tách không có chữ số nào giữa hai số.

Bạn có thể viết chương trình hoặc hàm, lấy đầu vào qua STDIN (hoặc thay thế gần nhất), đối số dòng lệnh hoặc đối số hàm và xuất kết quả qua tham số STDOUT (hoặc thay thế gần nhất), tham số trả về hàm hoặc tham số hàm (out).

Đây là mã golf, câu trả lời ngắn nhất (tính bằng byte) sẽ thắng.

Ví dụ

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

Một hàm có 2 tham số chuỗi hoặc chỉ một chuỗi đơn và tôi phải chia nó trong mã của mình?
edc65

@ edc65 Hai chuỗi hoặc thậm chí hai tham số nguyên đều ổn.
Martin Ender

Câu trả lời:


1

Pyth - 79 byte

Bản dịch câu trả lời của @ AlexeyBurdin. Có lẽ có thể được chơi golf nhiều hơn nữa.

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

Lấy đầu vào là hai số, dòng mới tách ra. Giải thích đến sớm.

Hãy thử trực tuyến tại đây .


4

trăn, 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])

Tôi nghĩ rằng nó đủ để con người có thể đọc được.
Xác minh:

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
Chỉ cần một vài cú đánh nhanh: reversedcũng giống như [::-1], bạn có thể đặt nội dung của vòng lặp for vào một dòng để tiết kiệm thụt, len(a)+len(b)ngắn hơn sum(map(len,[a,b])), không sử dụng xrangetrong việc đánh gôn, ) forcó thể xóa khoảng trống trong và vì bạn đang bằng cách sử dụng python2, bạn có thể kết hợp các khoảng trắng và tab trong thụt lề.
Maltysen

Cảm ơn nhiều. Chúng cho 22 byte. Nhưng tôi không nghĩ nó sẽ ngắn nhất. Tôi không mã hóa pyth nhưng tôi đã thấy các chương trình 31 byte ... Btw, 303 là số đếm khi mỗi 4 khoảng trống được thay thế bằng một tab thực sự.
Alexey Burdin

Tại đây, tôi đã có thể nhận được 276từ việc chơi golf cú pháp đơn giản: gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen

Ngoài ra, bạn có phiền nếu tôi dịch chương trình của bạn sang Pyth và đăng nó dưới dạng một câu trả lời riêng không?
Maltysen

1
Bạn có thể thiết lập e=enumeratekhi bắt đầu chơi golf 4 ký tự
sagiksp

2

Python 3, 205 byte

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

Các biểu thức khá dài nên tôi nghĩ có một số lượng lớn để cải thiện, nhưng dù sao thì ...

Lấy khoảng cách đầu vào được phân tách bằng STDIN, vd

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

Có một khoảng trống có thể có trên một số dòng, nhưng A+B-2đảm bảo rằng tất cả các khoảng trắng ở trong hộp giới hạn.


1

C #, 451 byte

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

Được định dạng để dễ đọc, chức năng trong ngữ cảnh:

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

Bitwise OR chỉ để cho vui, nhưng bổ sung cũng sẽ hoạt động.


1

JavaScript ( ES6 ) 271

Tôi chắc chắn rằng có một giải pháp xây dựng hàng đầu ra theo hàng, thay đổi tọa độ toán học và x, y (x + y == k, xy == k ...). Nhưng tôi vẫn không thể đóng đinh nó.

Vì vậy, đây là một giải pháp chỉ đơn giản là vẽ từng dòng một.

Chạy đoạn trích trong Firefox để kiểm tra.

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

Sử dụng

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

Các kết quả

       \ /
      \ x /
     \ x x /
      x x x /
   \ / x x x
  \ x / x x \ /
   x x / x \ x /
\ / x x / \ x x /
 x / x x   x x x /
/ x / x \ / x x x /
 / x / \ x / x x x
  / x   x x / x x \
   / \ / x x / x \
      x / x x / \
     / x / x x
      / x / x \
       / x / \
        / x
         / \
  • hàm lặp lại một vòng lặp duy nhất và sử dụng một số phép đo hình học và ascii trifling.

Để làm gì ---48?
LegionMammal978

@ LegionMammal978 đôi khi tôi viết những thứ sau đó tôi quên ngay cả tại sao tôi lại đặt nó ở đó: D dù sao tôi cũng bận làm việc khác, khi tôi hoàn thành, tôi nhớ bạn; (mã này có hoạt động tốt trong trình biên dịch của bạn không)?
Abr001am

@ LegionMammal978 ở đây, nội dung mảng ở chỉ số cụ thể (thực tế) được trừ đi 48 trước khi giảm, trừ 48 để chờ một ký tự không đến rồi giảm dần từng bước trong vòng lặp (hoặc ngược lại theo mẫu ascii)
Abr001am

48 là đại diện ascii của "0"
Abr001am

1
Tôi thấy bây giờ, nó hoạt động như thế nào ...)-- - 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);}

THỬ NÓ


Dường như có các cột khoảng trắng sau mỗi ký tự và các phân đoạn không giao nhau cuối cùng ở cuối cùng bị thiếu. Bạn cũng đang sử dụng các chữ số theo thứ tự ngược lại.
Martin Ender

@ MartinBüttner hãy tưởng tượng ai đó đang làm điều này trên mặt trăng và bạn đang xem nó bằng kính viễn vọng, đó là cách bạn nên cảm nhận sơ đồ (-joking-i sẽ điều chỉnh điều đó sau)
Abr001am

0

R , 294 byte

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

Hãy thử trực tuyến!


0

Thạch , 58 byte

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

Hãy thử trực tuyến!

Giải trình

Một chương trình đầy đủ lấy hai số làm danh sách hai số nguyên và trả về một chuỗi.

Liên kết trợ giúp 1: xoay ma trận

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

Trình trợ giúp liên kết 2: tạo các mẫu hàng và cột

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

Liên kết chính

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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.