Analog ASCII Clock

| 2 Comments | No TrackBacks

Today I started the day looking at this post that inspired me to write an ascii analog clock in Perl.

Unlike the linked post, I didn't intend to golf, but rather writing a clean and readable code.

Follows the code:


#!/usr/bin/perl

# besides DateTime, the standard pragmas
use 5.010;
use strict;
use warnings;
use utf8;
use DateTime;

# initialize configuration variables
my $width = 32;
my $height = 32;
my $mark_at = 15;
my $length_m = 12;
my $length_h = 8;
my $length_s = 15;
my $pi = 3.14159265;
my $center_x = int(0.5 + ($width / 2));
my $center_y = int(0.5 + ($height / 2));
my $loop = 1;

# clear the screen and position the cursor in the left top corner
print "\x1b[0;0H\x1b[2J";

# loop the rendering of the clock
while ($loop && sleep 1) {

# create a matrix of the configured height and width with blanks
# I use two spaces because most console fonts have the height with
# twice the width
my $data = [map {[ map { ' ' } 1..$width ]} 1..$height];

# get the date and time in the local time zone
my $now = DateTime->now(time_zone => 'local');
my $hour = $now->hour_12;
my $min = $now->minute;
my $sec = $now->second;

# convert that to degrees for the hands of that clock
my $degree_m = ($min * 6) + 270;
my $degree_h = ($hour * 30) + 270;
my $degree_s = ($sec * 6) + 270;

# see the place sub down there
# place the numbers 1 to 12 around the clock
place($data,($_ * 30) + 270,$mark_at,sprintf("%02d",$_)) for 1..12;

# now the seconds hand
place($data,$degree_m, $_ , '<>') for 0..$length_m;

# the hours hand
place($data,$degree_h, $_ , '::') for 0..$length_h;

# the seconds hand
place($data,$degree_s, $_ , '..') for 0..$length_s;

# mark the center o the clock
$data->[$center_y][$center_x] = 'OO';

# position the cursor in the left top corner
print "\x1b[0;0H\n";

# covert the matrix into a single string and print it
say join "\n", map { join '', @$_ } @$data;
};

# covert degrees and distance into X and Y coords using basic trigonometry
sub vec2xy {
my ($deg, $len) = @_;
return $center_x + int(0.5 + ($len * cos($deg * ($pi/180)))),
$center_y + int(0.5 + ($len * sin($deg * ($pi/180))));
}

# place a string into some degree and distance
sub place {
my ($data, $deg, $len, $txt) = @_;
my ($x,$y) = vec2xy($deg,$len);
$data->[$y][$x] = $txt;
}

No TrackBacks

TrackBack URL: http://daniel.ruoso.com/cgi-bin/mt/mt-tb.cgi/167

2 Comments

Nice clock. I did something quite uglier some time ago: http://www.perlmonks.org/?node_id=440771

Cheers!

It's not really a matter of accuracy (eight digits of pi is plenty for this), but I like to calculate pi with the builtin arctan function

my $pi = 4*atan2(1,1);

or, better yet, just use the one in the Math::Trig module

use Math::Trig qw(pi);

Leave a comment

About this Entry

This page contains a single entry by Daniel Ruoso published on December 14, 2009 2:37 PM.

Differences between agile and traditional methods was the previous entry in this blog.

My quest to SDL in Perl is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.