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