December 2009 Archives

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

About this Archive

This page is an archive of entries from December 2009 listed from newest to oldest.

November 2009 is the previous archive.

January 2010 is the next archive.

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