視覚的な長い乗算


28

カウント以外の何もすることなく、2つの整数の長い乗算を実行する良い方法があります。これは時々インターネット上で共有されます。各数字の数字は、2本の数字が90度の角度になった斜めの線の束として書きます。次に、発生した個別の列の交差点を数えるだけです。これはおそらく図で明らかになります。以下は計算の例です21 * 32

ここに画像の説明を入力してください

「ビジュアル/グラフィックの長い乗算」を検索すると、さらに多くの例が見つかります。

この課題では、ASCIIアートを使用してこれらの図を生成します。同じ例の場合、出力は次のようになります。

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

いくつかの例(以下を参照)からこれらの構成規則を理解するのがおそらく最も簡単ですが、ここでいくつかの詳細を示します。

  • 交差するセグメントはX、ラインの非交差セグメント/または\
  • 最も外側の交差点の後に、ちょうど1つのセグメントがあるはずです。
  • 異なる桁に属する交差点の間に正確に1つのセグメントが存在する必要があります。ゼロ桁がある場合、これらは連続/または\セグメントになります。
  • 正の入力(少なくとも2 16や2 32などの合理的な制限まで)、およびから0までの数字をサポートする必要があります9。ただし、先頭または末尾が存在しないと仮定することもできます0のsます。
  • 余分な先頭の空白や先頭または末尾の空行を印刷しないでください。
  • 末尾の空白を印刷できますが、ダイアグラムの軸に合わせた境界ボックスを超えてはなりません。
  • オプションで、単一の末尾の改行を印刷できます。
  • 2つの入力番号を取得する順序を選択できます。ただし、どちらの方向でも任意の数字をサポートする必要があるため、「大きい数字が最初に与えられる」ようなものは選択できません。
  • 入力を文字列として取得している場合、2つの数字の間に数字以外の区切り文字を使用できます。

プログラムまたは関数を作成し、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つの文字列パラメーターまたは1つの単一の文字列を持つ関数で、コード内で分割する必要がありますか?
edc65

@ edc65 2つの文字列、さらには2つの整数パラメータで十分です。
マーティンエンダー

回答:



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

私はそれが十分に人間が読めると思います。
検証:

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ループの内容をインデントを節約するために1行に入れることができ、len(a)+len(b)より短く、ゴルフにsum(map(len,[a,b]))使用しないxrangeで、スペースを) for削除できます。 python2を使用すると、スペースとタブをインデントで組み合わせることができます。
マルティセン

どうもありがとう。これらは22バイトを与えます。しかし、私はそれが最短になるとは思わない。私はpythをコーディングしていませんが、31バイトのプログラムを見てきました。
アレクセイバーディン

ここでは、276単純な構文ゴルフから得ることができました:gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen

また、プログラムを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())));
    }
}

ビット単位のORは単なる楽しみでしたが、加算も機能します。


1

JavaScript(ES6)271

数学とx、y座標(x + y == k、xy == k ...)をいじって、行ごとに出力を作成するソリューションがあると確信しています。しかし、私はまだそれを釘付けすることはできません。

そこで、ここでは、1行ずつ単純に線を引くソリューションを示します。

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
         / \
  • この関数は1つのループを繰り返し、いくつかのgeometricksとascii triflingを使用します。

何の---48ためですか?
LegionMammal978

@ LegionMammal978時々私は物事を書いて、なぜそこに置いたのかさえ忘れます:Dとにかく何か他のことをするのに忙しいです (このコードはコンパイラでうまくいきますか?)
Abr001am

@ LegionMammal978ここで、特定でアレイ含量は(実際の)インデックスは48に減算される前に、それはその後デクリメントループにおける前進段階(またはASCIIパターンとして後方)来るゼロ文字を待つためには48を引い、デクリメント
Abr001am

48は、「0」のASCII表現です
-Abr001am

1
私は今、それが次のように機能するのを見る...)-- - 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);}

それを試してみてください


すべての文字の後にスペースの列があり、下端の最後の非交差セグメントが欠落しているようです。また、数字を逆の順序で使用しています。
マーティンエンダー

@MartinBüttnerは、誰かが月にこれをやっていて、望遠鏡でそれを見ていると想像します。それが図を認識する方法です(-joking-iは後で調整します)
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

オンラインでお試しください!

説明

2つの整数を2つの整数のリストとして受け取り、文字列を返す完全なプログラム。

ヘルパーリンク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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.