Daniel Ruoso

Últimos Posts

Categorias

Arquivo

Nuvem de Tags

14.12.2009  Analog ASCII Clock

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

Postado por autor: ruoso em Perl.   Tags  Perlsnippetperl5.