Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

Entries for this challenge will display an animated rotating Lissajous figure. The appearance of 3d rotation occurs as the x parameter is successively phase-shifted in each frame.

Input:

The a and b parameters (as per the wikipedia article) will be specified at the command line, or read from stdin.

Output:

This is , so output will be displayed in a terminal emulator window or equivalent. Output size may be hardcoded, but the Lissajous figure must be at least big enough to fill a 80x24 window.

The animation frame rate will be approximately 50fps. Sleeping for 20ms between each frame is fine, as long as the time to calculate each frame is small compared with the fixed sleep time. If your choice of language cannot calculate quick enough on your chosen platform, then you'll have to calculate the time to sleep dynamically.

Each frame will not be displayed until all calculation for that frame is complete. There is no need to clear the screen between each frame.

The figure will make a full 2*Pi rotation approximately every 4 seconds.

For each frame, a full closed curve must be generated. At least 1000 points must be calculated along the curve. Line-drawing in between points is not necessary.

Points of the curve will be plotted as # characters. The rest of the display area will be blank/whitespace.

This is , so the shortest answer in bytes (deemed acceptable by me) will be the accepted winner one week after this posting.


Ungolfed reference answer.

share|improve this question
1  
Are we allowed to draw it using a graphics-oriented language? –  TheDoctor Apr 30 at 17:18
    
@TheDoctor I was torn on that, but decided to restrict to ascii-art. Perhaps we can do a graphical-output follow-up if this ends up popular. –  DigitalTrauma Apr 30 at 17:23
1  
As with many rotating figures, these figures rotate different ways depending on how you look at them. For example, your answer seems to be rocking back and forth to me. But when I try hard, I can see regular rotation. –  Quincunx Apr 30 at 19:11

5 Answers 5

up vote 7 down vote accepted

Perl - 177

while($d+=.1){print"\e[H\e[2J";$a=0;while(($a+=.01)<4*atan2 1,0){$x=$==40+40*cos$d+$a*$ARGV[0];$y=$==13+13*sin$d+$a*$ARGV[1];print"\e[$y;$x"."H#";}print$/;select($v,$v,$v,.03);}

The coefficients are passed via arguments. The above gif is produced from perl % 2 3

share|improve this answer
    
+1. Nice animated .gif –  DigitalTrauma Apr 30 at 17:11
1  
@DigitalTrauma I have my very own tool for recording screen in X11 –  mniip May 1 at 7:41

C (reference answer - not golfed)

Output with ./lissajous 2 3:

enter image description here

/*
 * lissajous.c
 *
 * Compile with:
 *   cc lissajous.c -lm -o lissajous
 *
 * Usage:
 *   ./lissajous a b
 *
 * a and b are the parameters as described in:
 * http://en.wikipedia.org/wiki/Lissajous_curve
 */

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <unistd.h>

int main (int argc, char **argv) {
    char buffer[25][80];
    double t, p;
    int x, y;
    int a, b;

    if (argc != 3) return 1;

    a = atoi(argv[1]);
    b = atoi(argv[2]);

    for (;;) {
        for (p = 0; p < 2 * M_PI; p += M_PI / 100) {
            memset(buffer, ' ', sizeof(buffer));
            /* Set 1st char of final line to nul.  Then we can printf
             * the whole 2d array as if it were one long 1d buffer.
             * Line wraps at 80 chars are assumed */
            buffer[24][0] = 0;
            for (t = 0; t < 2 * M_PI; t += M_PI / 500) {
                x = 39.5 * (1 + sin(a * t + p));
                y = 11.5 * (1 + sin(b * t)); 
                buffer[y][x] = '#';
            }
            printf("%s\n", &buffer[0][0]);
            usleep(20000);
        }
    }
    return (0);
}

C, 257 bytes

Ok, well I couldn't resist golfing it a bit myself. I think there's a lot more golfing to be done on this though:

#include<math.h>
main(int a,char**v){char x,y,b,d[25][80];double t,p,q=2*M_PI;a=atoi(v[1]);b=atoi(v[2]);for(p=0;memset(d,32,2000);p+=q/100){p=p<q?p:0;d[24][0]=0;for(t=0;t<q;y=11.5*sin(b*t)+12,d[y][x]=35,t+=q/1e3)x=39.5*sin(a*t+p)+40;puts(d);usleep(20000);}}
share|improve this answer
2  
funny how the reference answer is getting upvotes... –  TheDoctor Apr 30 at 17:20
    
@TheDoctor I know, right. Thats why I ended up adding a golfed version, as it didn't feel right to get upvotes for an ungolfed answer. –  DigitalTrauma Apr 30 at 17:24
    
If you're usleeping for 20000ms, why not just sleep for 20s ? –  ace Apr 30 at 20:40
    
@ace usleep(20000)== 20000 micro seconds, not 20000 milli seconds –  DigitalTrauma Apr 30 at 20:41
    
Oops, sorry, my bad. What about usleep(2e4);? –  ace Apr 30 at 20:47

Python 3 - 280

Don't have one of those fancy animated gifs for ya, sorry. Windows console is slow at printing :P

Not sure this meets the 50fps requirement though I'm not sure it's really possible with Python. You can adjust the 1000 on the second line for the amount of points to calculate (the list is output width, output height, points to find, progression per frame (pi*2/n) and starting point). Or you can remove them and specify in the input as well.

import math as m
a,b,w,h,p,r,t=list(map(int,input().split()))+[79,24,1000,100,0]
while 1:v,z=w/2,h/2;d=[[int(m.sin(a*k+t)*v+v),int(m.sin(b*k)*z+z)]for k in[m.pi*2/p*l for l in range(p)]];print('\n'.join(''.join([' ','#'][[i,j]in d]for i in range(w))for j in range(h)));t+=m.pi*2/r

MORE IMPORTANT EDIT: Input via stdin, space-separated, newline terminated. Will wait for your input.

EDIT: Screenshot. Changed height to 40 for this one.

Lissajous rendering

share|improve this answer
    
Hmm, it just hangs for me with python 3.2.3 (and 2.7.3) on Ubuntu. I guess I need to dig up a windows VM from somewhere. Or learn python. –  DigitalTrauma Apr 30 at 21:10
    
@DigitalTrauma Hm. I'm running 3.3.2. Strange that it doesn't work though, don't see any platform-specific procedures in my code. –  Trimsty Apr 30 at 21:20
    
Save as lissajous.py, then run python3 lissajous.py 2 3 should be sufficient, right? –  DigitalTrauma Apr 30 at 21:22
    
@DigitalTrauma Oh, oh, sorry. It takes input from stdin, not the args (failed to specify that...oops). Space-separated. –  Trimsty Apr 30 at 21:23
    
Aha - I guess I should have seen input() and guessed that. Works fine now for me with 3.2.3. +1 –  DigitalTrauma Apr 30 at 21:28

C# - 360 352 (cross platform - 332 for Windows only)

Edited after micro-golfing and rounding bug fix + suggestion by Ypnypn

Not exactly a contender at that length - and it's pretty much a verbatim copy of the reference - but oh well. :)

namespace System{class P{static int Main(string[]m){double p=Math.PI*2,a=int.Parse(m[0]),b=int.Parse(m[1]),q,t;for(;;)for(q=0;q<p;q+=p/200){var s=new string(' ',1920).ToCharArray();for(t=0;t<p;t+=p/1000)s[(int)(39.5*Math.Sin(a*t+q)+40)+(int)(11.5*Math.Sin(b*t)+12)*80]='#';Console.SetCursorPosition(0,0);Console.Write(s);Threading.Thread.Sleep(20);}}}}

Memory hog, creating a new array for every refresh - originally (re)used a StringBuilder, but sacrificed it for shortness. But at least the refresh takes less than 1 ms on my old Core2.

After removing some - now length-hurtful - old golfing, thereby reducing it by 8 characters, I tried to get it back to the "poetic" 360 by reverting to double rather than int parsing, and returning to 80*24 instead of 1920. That's still only 359, though - and no other single character addition that I can think of really adds any value to the code. So we'll just stick with 352. :-)

Unrolled (lost the pre-golf code):

namespace System
{
    class P
    {
        static int Main(string[] m)
        {
            double p = Math.PI * 2,
                   a = int.Parse(m[0]),
                   b = int.Parse(m[1]),
                   q, t;

            for (;;)
            {
                for (q = 0; q < p; q += p/200)
                {
                    var s = new string(' ', 1920).ToCharArray();
                    // Alternative - Windows console only:
                    // var s = new char[1920];

                    for (t = 0; t < p; t += p/1000)
                    {
                        s[
                            (int) (39.5*Math.Sin(a * t + q) + 40)
                          + (int) (11.5*Math.Sin(b * t) + 12) * 80
                        ] = '#';
                    }
                    Console.SetCursorPosition(0, 0);
                    Console.Write(s);
                    Threading.Thread.Sleep(20);
                }
            }
        }
    }
}

The Windows console actually accepts outputting a lot of null chars resulting in output that's (graphically) identical to using an actual space character - which allows a few characters less to initialize the character array.

No fancy animation, sorry :-)

share|improve this answer
    
Windows console actually accepts outputting a lot of null chars. Ah perhaps that explains why it doesn't so well with mono on Ubuntu. I don't have windows/.net handy right now, so I'll take your word for it that it works. –  DigitalTrauma Apr 30 at 19:14
    
Just added a screenshot - should make it cross platform, but considering the non-contender status it has already - and the rather "poetic" number of characters, maybe it should just be left as is. :-) –  JimmiTh Apr 30 at 19:19
    
No need for all answers to be cross-platform IMO. If answers are platform-specific, its good to mention the platform, though C# is so well-known that its already obvious. –  DigitalTrauma Apr 30 at 19:25
    
Does using C = Console really save any characters? –  Ypnypn May 1 at 2:21
    
@Ypnypn - not after invading the System namespace, nope. Didn't change it, or look for it, because the self-stated goal was to get to the same 360 characters while still using "proper" char array initialization. Thanks. :-) –  JimmiTh May 1 at 6:28

Python 2.7 - 214

I think I'm going to have another look at this. I have a feeling this can be brought down even further, but it will be hard to hit the Perl byte count. The math seems to be my biggest limitation here.

Warning: may crash whatever terminal you are using. I tested this on the Windows command prompt with lissajous.py 2 3. Because of the quick writing to the command prompt, expect the frames to jump a little bit. This can be mostly resolved (at the cost of speed) by using a greater s in the range(s) and t=2*pi*i.

I don't use \r or \b here purposely because I'm running it on Windows and it would cost extra characters.

from math import*;import sys;a,b=sys.argv[1:];p=s=1920
while p:
 c = [" "]*s
 for i in range(s):
    t=2*pi*i/s;c[int(round((39.5*(1+sin(eval(a)*t+p))))+round(11.5*(1+sin(eval(b)*t)))*80)]="#"
 print ''.join(c)
 p+=.1
share|improve this answer
    
+1 Works on Ubuntu, though the output is a bit jumpy –  DigitalTrauma May 1 at 14:38
    
@DigitalTrauma Yeah the jumpiness is caused by this being a cross platform solution (ie. to work on Windows command prompt). –  grovesNL May 1 at 16:28

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.