视觉长乘法


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),以及从0to到的任何数字9。但是,您可能会假设既没有前导0s 也没有尾随s。
  • 您不得打印多余的前导空白或前导或尾随的空行。
  • 您可以打印尾随空格,但不得超出图表的轴对齐边界框。
  • 您可以选择打印单个尾随换行符。
  • 您可以选择两个输入数字的顺序。但是,它必须在任一方向上都支持任意数字,因此您不能选择“先给出较大的数字”之类的内容。
  • 如果将输入作为字符串输入,则可以在两个数字之间使用任何非数字分隔符。

您可以编写程序或函数,通过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两个字符串甚至两个整数参数都可以。
Martin Ender 2015年

Answers:


1

Pyth-79个字节

@AlexeyBurdin的答案的翻译。可以打更多的高尔夫球。

AzHmu++Gm1sH]Zd]Z,_zwK+lzlHJmm\ KK .e.eX@J+kY+-Yklz@" \/x"+byZHzjbmjk:d2_1:J1_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循环的内容放入一行以节省缩进,len(a)+len(b)比短sum(map(len,[a,b])),不要xrange在高尔夫中使用,) for因此可以删除其中的空间,并且使用python2,您可以在缩进中组合空格和制表符。
Maltysen 2015年

非常感谢。这些给出22个字节。但是我认为这不是最短的。我没有编写pyth的代码,但是我看过31字节的程序...顺便说一句,303是每4个空格实际上被制表符替换时的计数。
Alexey Burdin

在这里,我可以276从简单的语法高尔夫球中获得:gist.github.com/Maltysen/e8231c0a9b585e2a4941
Maltysen

另外,您介意我是否将您的程序翻译为Pyth并将其发布为单独的答案?
Maltysen

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 ...)。但是我仍然不能钉牢它。

因此,这里是一个简单地一条一条画线的解决方案。

在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
         / \
  • 该函数迭代一个循环,并使用一些geometryks和ascii修饰。

有什么---48
LegionMammal978

@ LegionMammal978有时我写东西,然后我什至忘了为什么把它放在那里:D无论如何我忙着做别的事情,当我结束时,不记得你了;(此代码在您的编译器中运行得很好吗?)?
Abr001am 2015年

@ LegionMammal978在这里,特定(实际)索引处的数组内容在递减之前要减去48,为了等待即将到来的nil字符减去48,然后逐步
递归

图48是“0”的ASCII表示
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);}

试试吧


似乎每个字符后都有一列空格,并且在底端没有最后的不相交的线段。您还以相反的顺序使用数字。
Martin Ender 2015年

@MartinBüttner想象有人正在月球上做这个,你用望远镜观看,这就是你应该看到的图的方式(开玩笑,我稍后会进行调整)
Abr001am 2015年

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

Helper链接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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.