一个简单的DNA模拟器


18

您的代码将永远生成DNA的非常简单的ASCII表示形式。它会以您想要的任何格式将两个数字作为输入:作为列表,作为函数的参数,在stdin等上。

  • I介于0.0到1.0(含)之间的浮点间隔(以秒为单位)
  • 缩放级别Z,从1到64(含)的整数

您的代码将每秒钟将一行输出到stdout或等价的行,从而I产生一个无限的输出,看起来像这样(缩放级别4):

    A
 T-----a
G-------c
 G-----c
    g
 t-----A
a-------T
 c-----G
    T
 A-----t
C-------g
...

具体地,我们的DNA的表示是一对由连字符连接的正弦波,一个由字符acg,和t,其他字符的ACG,和T。如果x是我们当前正在打印的行的0索引编号,则小写波中字符的从0开始的位置由给出(sin(πx / Z) + 1) * Z,而大写波中的字符从0开始的位置由给出(-sin(πx / Z) + 1) * Z,两者都四舍五入(但没有下限)整数。更多细节:

  • 如果两个波浪重叠,则需要从大写波浪开始,交替选择哪个波浪在前面。(从小写波开始,我们会得到一个不存在的双螺旋!)
  • 忽略大小写,A总是与T配对,C总是与G配对,就像在真实的DNA中一样。线对本身应随机选择,并在四种可能性上均匀分布。在代码的连续运行中,对的选择是相同还是不同并不重要。只要输出没有明显的模式并且周期至少在十亿之内,随机选择的统计质量就不成问题了(像RANDU这样有缺陷的PRNG 很好。)
  • 您必须没有尾随空格,或者必须在该缩放级别将每一行都填充到波浪的最大位置(在上面的示例中为九个字符)。出于数学原因,缩放级别1可能有一个可选的附加尾随空格。

由于DNA很小,因此您的代码将需要尽可能短。

更多示例:

缩放等级8:

        T
     C-----g
  A-----------t
 C-------------g
G---------------c
 T-------------a
  T-----------a
     T-----a
        c
     g-----C
  t-----------A
 g-------------C
a---------------T
...

缩放等级2:

  A
T---a
  c
g---C
  G
A---t
  c
a---T
...

缩放级别1(注意前导空格):

 G
 a
 C
 t
...


9
“由于DNA很小,因此您的代码将需要尽可能短。” 真?
TanMath

3
@TanMath您真的需要使用Code-Golf的理由吗?这样的背景故事几乎总是愚蠢的,随它去吧。
Patrick Roberts

我知道@PatrickRoberts,但我只是指出原因,许多代码高尔夫球手都这样做。不要太当真!;)
TanMath

“随机选择”是什么意思?RANDU还好吗?较短的重复序列呢?
KSFT

Answers:


4

Ruby,修订版B 171161字节

固定z = 1的输出将花费10个字节。这是一个特例:如果您以90度观看时,螺旋线实际上是3个字符宽,但是当我们以0度观看时,它的宽度仅为1个字符。 z = 1上的零前导空格不再需要

在计算所需的-字符数时,通过省去括号并在截断前将y.abs乘以2,可以节省一些费用。

最后,我通过使用具有number的幂的复数算法来避免了include Mathsin和需要PIi。复数的虚部与sin x等效,除了它以周期4而不是周期2 * PI重复。为此更改保存的是1个字节或0个字节。

->z,i{x=0
loop{y=z*("i".to_c**x).imag
s=(?-*(y.abs*2)).center z*2+1
s[z-y+0.5]='TGAC'[r=rand(4)]
x!=0&&s[z+y+0.5]='actg'[r]
puts s
sleep i
x+=2.0/z
x>3.99&&x=0}}

Ruby,修订版165字节

这比预期的时间更长。有一些潜在的高尔夫机会有待探索。

include Math
->z,i{x=0
loop{y=z*sin(x)
s=('--'*(y.abs+h=0.5)).center(z*2+1)
s[z+h-y]='TGAC'[r=rand(4)]
x!=0&&s[z+h+y]='actg'[r]
puts s
sleep(i)
x+=PI/z
x>6.28&&x=0}}

在测试程序中注释

include Math
f=->z,i{x=0
  loop{y=z*sin(x)
    s=('--'*(y.abs+h=0.5)).center(z*2+1)  #make a space-padded string of z*2+1 characters, containing enough - signs
    s[z+h-y]='TGAC'[r=rand(4)]            #insert random capital letter, saving index in r
    x!=0&&s[z+h+y]='actg'[r]              #insert small letter. This will normally go on top of the capital as it is done second, but supress for x=0 to make helix
    puts s
    sleep(i)
    x+=PI/z                               #increment x
    x>6.28&&x=0                           #reset x if equal to 2*PI (this proofs against loss of floating point precision, making correct output truly infinite.)
  }
}

Z=gets.to_i
I=gets.to_f
f[Z,I]

看起来不错!一个小问题:缩放级别1有领先的空间。此外,在您的测试程序中I=gets.to_i应该为I=gets.to_f
路加福音

哎呀!没错,Z = 1是一个特例。考虑到我提供的数学,这不是故意的,实际上是规则中的矛盾。我将添加Z = 1的前导空格以使数学保持一致。
路加福音

一般规则中的@Luke不应更改,但确实存在矛盾。据我所知,其他答案也没有考虑。稍后,我将更新我的答案,因为那样会更短。
级圣河在

@Luke已更新,但是这意味着我在Z = 1上同时具有前导空间和尾随空间。我理解这是根据您想要的精神,因此可以,尽管它并非严格根据尾随空格的措辞和Z = 1的示例确定。
圣约翰河

再次糟糕,是的,这很好。对困惑感到抱歉。
路加福音

3

C,294 289 285 283 281 270 265 237 218字节

#include<math.h>
o,i,p,r;char*c="acgtTGCA",d[256]={[0 ...254]='-'};P(w,z)float w;{for(;;poll(0,0,r=w*1e3))p=fabs(sinf(M_PI*i++/z))*z+.5,r=rand()&3,o^=4*!p,printf(p?"%*c%s%c\n":"%*c\n",z-p+1,c[r+o],d+256-p*2,c[r+4-o]);}

或解析来自main的输入的较长版本:

#include<stdlib.h>
#include<math.h>
o,i,p,r;char*c="acgtTGCA",d[256]={[0 ...254]='-'};main(n,v)char**v;{for(;n=strtod(v[2],0);poll(0,0,n=atof(v[1])*1e3))p=fabs(sinf(M_PI*i++/n))*n+.5,r=rand()&3,o^=4*!p,printf(p?"%*c%s%c\n":"%*c\n",n-p+1,c[r+o],d+256-p*2,c[r+4-o]);}

这是一个相当愚蠢的整体实现,并附带了一些printf技巧。它缺少一些内容,使用了K&R语法作为该函数,并且依赖于GCC的范围初始化程序,因此这不是很标准。此外,函数版本仍使用全局变量,因此只能调用一次!

该功能版本带有两个参数;等待(以秒为单位)并缩放。这是它的呼叫者:

#include <stdlib.h>
int main( int argc, const char *const *argv ) {
    if( argc != 3 ) {
        printf( "Usage: %s <delay> <zoom>\n", argv[0] );
        return EXIT_FAILURE;
    }
    const float delay = atof( argv[1] );
    const int zoom = strtod( argv[2], 0 );
    if( delay < 0 || zoom <= 0 ) {
        printf( "Invalid input.\nUsage: %s <delay> <zoom>\n", argv[0] );
        return EXIT_FAILURE;
    }
    P( delay, zoom );
    return EXIT_SUCCESS;
}

运行方式:

./dna <delay> <zoom>
./dna 0.5 8

分解:

// Globals initialise to 0
o,                                 // Ordering (upper/lower first)
i,                                 // Current iteration
p,                                 // Current indent
r;                                 // Current random value
char*c="acgtTGCA",                 // The valid letters
    d[256]={[0 ...254]='-'};       // Line of dashes (for printing)
main(n,v)char**v;{                 // K&R-style main definition (saves 2 bytes)
    // n will be used for Zoom, random number & casting delay
    for(
        ;n=strtod(v[2],0);         // Store zoom
        poll(0,0,n=atof(v[1])*1e3) // After each loop, use poll to delay
                                   // (Use variable to cast delay to int)
    )
        p=fabs(sinf(M_PI*i++/n))*n+.5,   // Calculate separation / 2
        r=rand()&3,                      // Pick random number [0-4)
        o^=4*!p,                         // Reverse order if crossing
        printf(p                         // Print... if not crossing:
                ?"%*c%s%c\n"             //  indent+character+dashes+character
                :"%*c\n",                //  Else indent+character
                n-p+1,                   // Width of indent + 1 for char
                c[r+o],                  // First character
                d+256-p*2,               // Dashes
                c[r+4-o]                 // Second character
        );
}

您可以使用函数代替main(),这样可以节省strtodand 的字节atof
路加福音

@卢克阿酷; 我会节省多少钱……
戴夫

3

C,569个 402 361字节

#include<stdlib.h>
u,l,r,m,n,Z,I,y=0,x=0;main(c,char**v){Z = atoi(v[1]);I=atof(v[2])*1000000;srand(time(0));char *a="ACGTtgca";while(1){r=rand()%4;usleep(I);double s=sin(3.14*x++/Z);u=floor(((-1*s+1)*Z)+0.5);l=floor(((s+1)*Z)+0.5);m=(u<l)?u:l;n=u<l?l:u;char z[n+1];memset(z,' ',n);z[l]=a[r+4];z[u]=a[r];for(y=m+1;y<n;y++)z[y]='-';z[n+1]='\0';printf("%s\n",z);}}

我很快就完成了这个工作,所以我确定我可以做一些其他的事情来降低我的分数,但是我很高兴我能够在第一次尝试时就可以编译并正确运行该程序。

高尔夫版本:

#include<stdio.h>
#include<math.h>
#include<unistd.h>
#include<time.h>
#include<stdlib.h>
u,l,r,m,n,Z,I,y=0,x=0;
main(c,char**v){
   Z = atoi(v[1]);
   I=atof(v[2])*1000000;
   srand(time(0));
   char *a="ACGTtgca";
   while(1){
      r=rand()%4;
      usleep(I);
      double s=sin(3.14*x++/Z);
      u=floor(((-1*s+1)*Z)+0.5);
      l=floor(((s+1)*Z)+0.5);
      m=(u<l)?u:l;
      n=u<l?l:u;
      char z[n+1];
      memset(z,' ',n);
      z[l]=a[r+4];
      z[u]=a[r];
      for(y=m+1;y<n;y++)z[y]='-';
      z[n+1]='\0';
      printf("%s\n",z);
   }
}

更新:我调整了循环,以在一个print语句中打印所有内容,并使用了以下事实:默认情况下,将变量定义为int以节省一些字节。UPDATE2:某些var重命名和一些逻辑缩短以剃除更多的字节。


您需要掌握GCC。它是Linux,但您也可以使用Cygwin在Windows上运行它。变量(如果在程序开始时声明或作为函数参数声明)不需要类型,则假定它们为int。与功能相同。而且我敢肯定,您将不需要那些包含。
水平河圣

1
您也有太多的printfs :-D。1.使用putchar一次打印一个字符,或者2.计算出要打印的内容,然后使用puts打印全部内容。3.弄清楚如何使用带有大复杂表达式的单个printf。无论如何,+ 1。
级圣河在

好的,谢谢您的建议!我将尝试做出一个打印声明。那是个好主意,我相信这会提高我的分数。今天我有空的时候,我会重新考虑这一点。感谢@steveverrill
Danwakeem '16

2

的JavaScript(ES6)241个 244 227 222 231字节

这看起来很有趣-我喜欢ASCII艺术!
刚开始,仍在打高尔夫球...

(I,Z)=>{c=i=0,setInterval(_=>{with(Math)m=sin(PI*i++/Z),a=round(++m*Z),b=round((2-m)*Z),r=random()*4|0,D="TGAC"[r],d="actg"[r],e=a-b,c^=!e,p=" ".repeat(a>b?b:a)+(c?D:d)+"-".repeat(e?abs(e)-1:0)+(e?a>b?d:D:""),console.log(p)},I*1e3)

---编辑:原来我实际上不能将其放在eval()中,否则它将无法访问vars I和Z(因此增加了9个字节)

-感谢user81655 ,节省了6个字节
-感谢戴夫,节省了5个字节

说明

(I,Z)=>{
  c=i=0,                                // clear vars
  setInterval(_=>{                      // repeat

    with(Math)                         
      m=sin(PI*i++ / Z),                // calculate waves
      a=round(++m * Z),
      b=round((2-m) * Z),
      r=random()*4|0,                   // get random amino-acids
      D="TGAC"[r],
      d="actg"[r],
      e=a-b,
      c^=!e,                            // alternate upper/lowercase
      p=                                // prepare output
        " ".repeat(
          a>b ? b : a
        )+(
          c ? D : d
        )+

        "-".repeat(
          e ? abs(e)-1 : 0
        )+(
          e ? a>b ? d : D : ""
        ),

      console.log(p)                    // return output
  },I*1e3)                              // repeat for every 'I' seconds
}

1
您可以使用c^=!e代替来节省另外4个字节c+=a==b(让您%2稍后删除检查)。也-m+2可能是2-m
戴夫

@戴夫-谢谢!您介意解释c ^ =!e的实际作用吗?我从来没有看到过:)
Aᴄʜᴇʀᴏɴғᴀɪʟ

它与c=c^(e==0); 它以您以前添加的相同方式应用XOR。如果您不熟悉XOR,则按位操作:排除OR(维基百科可以正确解释)
Dave
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.