A simple DNA simulator Your code is going to generate a very simple ASCII-art representation of DNA, forever. It will take two numbers as input in any format you want: as a list, as arguments to a function, on stdin, etc.


A floating-point interval I in seconds between 0.0 and 1.0 (inclusive)
A zoom level Z as an integer from 1 to 64 (inclusive)


Your code will print one line to stdout or its equivalent every I seconds, producing an infinite output that looks something like this (for zoom level 4):

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


Specifically, our representation of DNA is a pair of sine waves connected by hyphens, one consisting of the characters a, c, g, and t, the other of the characters A, C, G, and T. If x is the 0-indexed number of the line we're currently printing, the 0-based position of the character in the lowercase wave is given by (sin(πx / Z) + 1) * Z, and in the uppercase wave is given by (-sin(πx / Z) + 1) * Z, both rounded (not floored) to the nearest integer. Further details:


In cases where the two waves overlap, you need to alternate which wave is in the front, starting with the uppercase wave. (Starting with the lowercase wave would give us a double helix that does not exist!)
Ignoring case, A always pairs with T and C always pairs with G, as in real DNA. The pairs themselves should be randomly chosen with a uniform distribution over the four possibilities. It does not matter if the choice of pairs is the same or different on successive runs of your code. The statistical quality of your random choices is not an issue as long as the output has no obvious pattern and a period at least in the billions (flawed PRNGs like RANDU are fine.)
You must either have no trailing spaces or pad every line to the maximum position of the waves at that zoom level (in the example above, nine characters.) Zoom level 1 may have one optional additional trailing space for mathematical reasons.


Because DNA is small, your code will need to be as short as possible.

More examples:

Zoom level 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 level 2:

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


Zoom level 1 (note the leading space):

 G
 a
 C
 t
...
Ruby, Rev B 171 161 bytes

Fixing the output for z=1 cost 10 bytes. It's a special case: the helix is really 3 characters wide if you looked at it at 90 degrees, but as we look at it at 0 degrees it looks only 1 character wide. zero leading spaces on z=1 no longer required

Some savings by eliminating brackets and by multiplying y.abs by 2 before truncation when calculating the number of - characters needed.

Finally, I avoided the include Math (required for sin and PI) by using complex number arithmetic with powers of the number i. The imaginary part of the complex number is equivalent to sin x, except that it repeats with period 4 instead of period 2*PI. Saving for this change was either 1 or 0 bytes.

-&gt;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&amp;&amp;s[z+y+0.5]='actg'[r]
puts s
sleep i
x+=2.0/z
x&gt;3.99&amp;&amp;x=0}}


Ruby, Rev A 165 bytes

This is way longer than expected. There are a few potential golfing opportunities to be explored.

include Math
-&gt;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&amp;&amp;s[z+h+y]='actg'[r]
puts s
sleep(i)
x+=PI/z
x&gt;6.28&amp;&amp;x=0}}


Commented in test program

include Math
f=-&gt;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&amp;&amp;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&gt;6.28&amp;&amp;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]