Basit bir DNA simülatörü


18

Kodunuz sonsuza dek çok basit bir ASCII-art DNA temsili oluşturacaktır. İstediğiniz herhangi bir biçimde girdi olarak iki sayı alır: bir liste olarak, bir işleve bağımsız değişken olarak, stdin'de vb.

  • ISaniye cinsinden kayan nokta aralığı 0,0 ile 1,0 (dahil)
  • Z1 - 64 (dahil) arasında bir tam sayı olarak zoom seviyesi

Kodunuz, stdout'a veya eşdeğerine her Isaniye bir satır yazdırarak , şuna benzer sonsuz bir çıktı üretir (yakınlaştırma düzeyi 4 için):

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

Spesifik olarak, DNA eden temsili, tire ile bağlı sinüs dalgası bir çift bir karakterden oluşan a, c, gve t, karakter diğer A, C, Gve T. Eğer xşu anda baskı konum hattının 0 endeksli bir sayıdır, küçük dalga karakter 0 esaslı konum ile verilir (sin(πx / Z) + 1) * Z, ve büyük dalga ile verilir (-sin(πx / Z) + 1) * Z, her iki yuvarlatılmış en yakın (değil katlı) tamsayı. Daha fazla ayrıntı:

  • İki dalganın üst üste geldiği durumlarda, büyük dalgadan başlayarak hangi dalganın ön tarafta olduğunu değiştirmeniz gerekir. (Küçük dalga ile başlayarak bize bir çift sarmal verecek yok !)
  • Olgu göz ardı edilirse, A her zaman T ve C ile çiftler, gerçek DNA'da olduğu gibi G ile çiftler. Çiftlerin kendileri dört olasılık üzerinde eşit dağılımlı rastgele seçilmelidir. Kod seçiminizin ardışık çalışmalarında çift seçiminin aynı veya farklı olması önemli değildir. Çıktının belirgin bir deseni ve en azından milyarlarca ( RANDU gibi kusurlu PRNG'ler) süresi olmadığı sürece, rastgele seçimlerinizin istatistiksel kalitesi bir sorun değildir. iyidir.)
  • Sondaki boşluklarınız olmamalı veya her satırı o yakınlaştırma düzeyindeki dalgaların maksimum konumuna kadar doldurmalısınız (yukarıdaki örnekte dokuz karakter). Yakınlaştırma düzeyi 1, matematiksel nedenlerden dolayı bir adet isteğe bağlı ek son boşluk içerebilir.

DNA küçük olduğu için kodunuzun mümkün olduğunca kısa olması gerekir.

Daha fazla örnek:

Zoom seviyesi 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
...

Zoom seviyesi 2:

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

Zoom seviyesi 1 (önde gelen boşluğa dikkat edin):

 G
 a
 C
 t
...


9
"DNA küçük olduğu için kodunuzun mümkün olduğunca kısa olması gerekir." Gerçekten mi?
TanMath

3
@TanMath Code-Golf için gerçekten bir nedene mi ihtiyacınız var? Backstories neredeyse her zaman böyle saçma, sadece onunla git.
Patrick Roberts

@PatrickRoberts Biliyorum, ama bunun neden ne kadar aptalca olduğunu, bir çok golfçünün yaptığını gösteriyordum. Çok ciddiye alma! ;)
TanMath

"Rastgele seçilen" ne anlama geliyor? RANDU iyi mi? Daha kısa bir tekrarlama sırası ne olacak?
KSFT

Yanıtlar:


4

Ruby, Rev B 171 bayt

Çıktıyı z = 1 için sabitlemek 10 bayta mal olur. Bu özel bir durum: 90 dereceye bakarsanız sarmal gerçekten 3 karakter genişliğinde, ancak 0 dereceye baktığımızda sadece 1 karakter genişliğinde görünüyor. z = 1 üzerinde sıfır önde gelen boşluk artık gerekli değil

Gerekli karakter sayısını hesaplarken köşeli parantezleri ortadan kaldırarak ve kesme işleminden önce y.abs değerini 2 ile çarparak biraz tasarruf edin.

Son olarak, sayı güçleriyle karmaşık sayı aritmetiği kullanarak include Math( sinve için gerekli PI) kaçındım i. Karmaşık sayının hayali kısmı sin x'e eşittir, tek fark periyot 2 * PI yerine 4 periyodu ile tekrar eder. Bu değişiklik için tasarruf 1 veya 0 bayt oldu.

->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, Rev A 165 bayt

Bu beklenenden çok daha uzun. Keşfedilecek birkaç potansiyel golf fırsatı var.

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

Test programına yorum yaptı

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]

İyi görünüyor! Küçük bir sorun: yakınlaştırma düzeyi 1 için önde gelen bir alan var. Ayrıca, test programınızda I=gets.to_iolmalıdır I=gets.to_f.
Luke

Tüh! Haklısın Z = 1 özel bir durum. Bu kasıtlı değildi ve aslında verdiğim matematik verilen kurallarda bir çelişki. Matematiği tutarlı hale getirmek için Z = 1 için önde gelen alanı ekleyeceğim.
Luke

@ Genel kurallarda luke değiştirilmemeli, ama gerçekten de bir çelişki vardı. Anlayabildiğim kadarıyla, diğer cevaplar da bunu düşünmedi. Cevabımı daha sonra güncelleyeceğim, çünkü bu şekilde daha kısa olacak.
Level River St

@ Luke güncellendi, ancak Z = 1'de hem önde gelen alanım hem de sondaki alanım olduğu anlamına geliyor. Bunun ne istediğinizin ruhuna göre olduğunu anlıyorum ve bu nedenle Tamam, ancak sondaki boşluklara ve Z = 1 örneğine göre değil.
Level River St

Tekrar tekrar, evet bu iyi. Karışıklık için özür dilerim.
Luke

3

Cı, 294 289 285 283 281 270 265 237 218 bayt

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

Veya girişi anadan ayrıştıran daha uzun sürüm:

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

Bu bazı aptalca hileler ile oldukça aptal bir uygulama, bazı eksik içerir, fonksiyon için K&R sözdizimi kullanır ve GCC aralık başlatıcıları dayanır, bu yüzden bu çok standart değil. Ayrıca fonksiyon sürümü hala global kullanıyor, bu yüzden sadece bir kez çağrılabilir!

İşlev sürümü 2 parametre alır; bekleyin (saniye cinsinden) ve yakınlaştırın. İşte bunun için bir arayan:

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

Olarak çalıştırmak:

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

Yıkmak:

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

Ana (), size bayt kurtaracak olan yerine bir işlevi kullanmak için izin konum strtodve atof.
Luke

@ Ah Ah havalı; Ne kadar tasarruf ettiğini göreceğim ...
Dave

3

Cı, 569 402 361 bayt

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

Puanımı düşürmek için yapabileceğim başka şeyler olduğundan eminim, bu yüzden oldukça hızlı bir şekilde çırpıldım, ancak ilk denemede düzgün bir şekilde derlemek ve çalıştırmak için bu programı aldığım için mutluyum.

Golf sürüm:

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

GÜNCELLEME: Her şeyi bir print deyiminde basmak için döngüyü ayarladım ve bazı baytları tıraş etmek için değişkenlerin varsayılan olarak int olarak tanımlandığı gerçeğini kullandım. GÜNCELLEME2: Birkaç bayt tıraş etmek için bazı yeniden adlandırma ve bazı mantık kısaltma.


GCC'yi ele geçirmeniz gerekiyor. Linux ama Cygwin ile pencerelerde de çalıştırabilirsiniz. Değişkenler (programın başında veya işlev bağımsız değişkenleri olarak bildirildiyse) bir türe gerek yoktur, int olarak varsayılırlar. Fonksiyonlar için de aynı şey geçerli. Ve eminim bu içeriğe ihtiyacınız olmayacak.
Level River St

1
Ayrıca çok fazla printfs var :-D. Ya 1. tek seferde bir karakter yazdırmak için putchar kullanın ya da 2. ne yazdırmak istediğinizi düşünün ve ardından hepsini koyar. 3. İçinde büyük karmaşık bir ifade bulunan tek bir printf'in nasıl kullanılacağını öğrenir. Her neyse, +1.
Level River St

Tamam, öneriler için teşekkürler! Tek bir baskı bildirimi yapmaya çalışacağım. Bu iyi bir fikir ve eminim puanımı artıracaktır. Bugün biraz zamanım olduğunda bunu ben düzeltirim. Teşekkürler @steveverrill
Danwakeem

2

JavaScript (ES6) 241 244 227 222 231 bayt

Bu ilginç görünüyordu - ASCII sanatını seviyorum!
Daha yeni başladı, hala golf oynamaya devam ediyor ...

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

--- EDIT: aslında eval () koymak olamaz çıkıyor - aksi takdirde I ve Z vars erişemez (yani 9 bayt ekler)

- user81655 sayesinde 6 bayt
kaydedildi - Dave sayesinde 5 bayt kaydedildi

açıklama

(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
Sen kullanarak başka 4 bayt kurtarabilecek c^=!eyerine c+=a==b(kaldırmak sağlar %2çeki sonrası). Ayrıca -m+2olabilir 2-m!
Dave

@Dave - teşekkürler! C ^ =! E'nin gerçekte ne yaptığını açıklar mısınız? Bunu daha önce hiç görmedim :)
16:16

Aynı c=c^(e==0); bir XOR'u daha önce eklemiş olduğunuz şekilde uygular. XOR'a aşina değilseniz, bu biraz yönlü bir işlemdir: eXclusive OR (wikipedia bunu doğru bir şekilde açıklayabilir)
Dave
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.