Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Binary Clock

by Legg83 (Novice)
on Dec 29, 2002 at 09:07 UTC ( [id://222890]=perlquestion: print w/replies, xml ) Need Help??

Legg83 has asked for the wisdom of the Perl Monks concerning the following question:

Its been awhile since I've played with perl, and I've fogotten everything more or less.

I want to make a script that does the same thing as the binary clock on thinkgeek. I just want to do this so I can get back into perl, and probably learn new things on the way.

http://www.thinkgeek.com/cubegoodies/lights/59e0/action/

Thats the link to the binary clock.

I want the script to have an output like so:

              **
8             **

           **          **
4          **          **

     **             **
2    **             **

  **       ** **    ** **
1 **       ** **    ** **

  HH HH    MM MM    SS SS
which would read the time for: 12:59:35

I'm not sure how to loop it so it happens exactly every second, and I'm not sure how to have it refresh in the same area... removing astericks when they arn't needed, and adding them when they are. Also, how can I get the solid rectangle rather than the asterick?

Can someone push me in the right direction?

Thanks

edited: Sun Dec 29 18:39:53 2002 by jeffa - removed excessive whitespace from <pre> area

Replies are listed 'Best First'.
Re: Binary Clock
by tachyon (Chancellor) on Dec 29, 2002 at 10:39 UTC

    How about:

    use POSIX 'strftime'; my $clear = $^O =~ m/Win32/ ? 'cls' : 'clear'; while ( 1 ) { system $clear; @digits = split '', strftime("%H%M%S", localtime); print ' ', @digits, "\n ------"; for my $bin ( 8,4,2,1 ) { print "\n$bin "; for my $digit ( @digits ) { $digit >= $bin ? do {$digit -= $bin; print "\052"} : print + "\117" ; # print $bin & $digit ? 1 : 0; # could use binary and to s +elect } } sleep 1; } # this will show you all the possible octal char codes you might like +to use printf "\\%03o\t %s\n", $_, chr for 40..255;

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: Binary Clock
by bart (Canon) on Dec 29, 2002 at 14:58 UTC
    Try this on for size.
    my $time = sprintf '%02d0%02d0%02d', (localtime)[2, 1, 0]; for my $mask (8, 4, 2, 1) { print " "; for my $d (split //, $time) { print $d & $mask ? '## ' : ' '; } print "\n $mask "; for my $d (split //, $time) { print $d & $mask ? '## ' : ' '; } print "\n\n"; } print " HH HH MM MM SS SS\n";
    This does a one-time printing job for the current time.

    As you appear to want to run this in a loop, and display the result in a terminal window, you'll likely will have to dig into ANSI codes. You can change foreground and background colors, which may allow you to just print colored spaces. There are also control codes to move the cursor to any place on the screen.

    A quick Goolge search brought me to this page, which might just contain enough info to make it do what you want: VT-100 Escape Codes

    OK, let's test it.

    #!/usr/local/bin/perl -w my $old = ''; print "\e[2J"; while(1){ print "\e[1;1H"; my $time = sprintf '%02d0%02d0%02d', (localtime)[2, 1, 0]; if($time eq $old) { sleep 1; redo; } $old = $time; for my $mask (8, 4, 2, 1) { print " "; for my $d (split //, $time) { print $d & $mask ? "\e[7m \e[m " : ' '; } print "\n $mask "; for my $d (split //, $time) { print $d & $mask ? "\e[7m \e[m " : ' '; } print "\n\n"; } print " HH HH MM MM SS SS\n"; sleep 1; }
    Blimey, it works.

    Update: Fixed bug in fetching time always with 2 digits.

Re: Binary Clock
by jpfarmer (Pilgrim) on Dec 29, 2002 at 09:34 UTC
    As far as making the clock update exactly every second, I would probabaly just insert a sleep 1 in the program and call it close enough. In order to make the clock increment exactly on the second, you'd have to figure out how long the code took then sleep for 1 second minus that time. That just seems like too much work to me.

    As for updating the clock, why not just clear the screen and redraw it? The Perl Cookbook suggests doing $clock = `clear`; and then just print $clear; whenever you want to clear the screen. It also provides a longer way, although its advantage isn't clear to me at this moment:
    use Term::Cap; $OSPEED = 9600; eval { require POSIX; my $termios = POSIX::Termios->new(); $termios->getattr; $OSPEED = $termios->getospeed; }; $terminal = Term::Cap->Tgetent({OSPEED=>$OSPEED}); $terminal->Tputs('cl', 1, STDOUT);
    For some general framework, look at what I did here:
    $clear = `clear`; while (1){ print $clear; $time = localtime(); print "$time\n"; sleep 1; $l++; }
    It provides a fairly smoothly incrementing clock. You should be able to do something similar with the more complex output you're talking about. Notice how I'm just clearing the screen and redrawing the clock each time?

    And finally, as far as using blocks, why not just use extended ASCII code 219, which is a block character, in place of the asterisks? Hope this helps!
Re: Binary Clock
by Juerd (Abbot) on Dec 29, 2002 at 17:07 UTC

    A *real* geek clock would of course be:

    perl -e'printf "%b\n", time while sleep 1'
    But that might be a little too geeky...

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

      For those trying not to go quite so totally geek, a slightly less extreme clock might be something along the lines of:

      #!/usr/bin/perl -w use strict; $| = 1; # Set $nice_to_nongeeks true # to use dual-format display # for those not yet fluent in binary. my $nice_to_nongeeks = 1; while (1) { my @time_components = localtime(time); my $datestring = "The current time is: " . join ( ':', unpack( "B*", pack( "C", $time_components[2] ) ), unpack( "B*", pack( "C", $time_components[1] ) ), unpack( "B*", pack( "C", $time_components[0] ) ) ); if ($nice_to_nongeeks) { $datestring .= ' (' . join ( ':', substr('00' . $time_components[2], -2), substr('00' . $time_components[1], -2), substr('00' . $time_components[0], -2) ) . ')'; } # Append to the string its length in backspace # characters so as to overwrite its previous output. # (There may perhaps be some terminals where # this might not work, however.) $datestring .= "\b" x length($datestring); print($datestring); sleep(1); }

      (I thought the idea of a binary clock was cool, but didn't like represent-each-digit-as-binary approach, thinking the represent-each-component-as-binary was a little more true to the idea.)

      Enjoy.

      Update: Modified code to force time components in dual-display mode to 2 digits.

Re: Binary Clock
by CountZero (Bishop) on Dec 30, 2002 at 09:46 UTC

    If you don't care about burning machinecycles, you can just put the program in an eternal loop, outputting the things you want at a much faster rate than once a second (just drop the sleep 1): if the present output did not change from the previous output, the screen would seem not to have changed at all, although of course, it was refreshed with the same pattern as before.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://222890]
Approved by Courage
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2024-04-25 07:38 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found