Category: | Fun Stuff |
Author/Contact Info | Flavio Poletti <flavio@NO-SPAM-PLEASEpolettix.it> |
Description: | Something that any terminal should not miss in their spare time...
A quite simple analog clock in ASCII. I made it for fun in little time, so there's no optimisation (for example, I know better algos to write a line, but I was too lazy to get to my copy of Foley/Van Dam...). You can set the clock size (x and y) on the command line; defaults to 45 x 23. Updated: added screen clearing using one advice from here and fairer input usage. I tested clearing in xterm and cygwin window and it seems to work well. |
#!/usr/bin/perl use strict; use warnings; #This will let me handle the output as a simple matrix. # A simple screen abstraction, actually a long array package Screen; sub new { # Get a Screen of given sizes my ($class, $wx, $wy) = @_; my $self = {_wx => $wx, _wy => $wy, _data => [ ((' ') x $wx , "\n") x $wy ]}; bless $self, $class; } sub _index { # Find index of given coordinate into vector my ($self, $x, $y) = @_; return $x + ($y * (1 + $self->{_wx})); } # Public methods sub inbound { # Test if coordinates are within Screen bounds my ($self, $x, $y) = @_; return ($x >= 0 && $y >= 0 && $x < $self->{_wx} && $y < $self->{_wy +}); } sub set { # Set value $v at given coordinates, with clipping my ($self, $x, $y, $v) = @_; return undef unless $self->inbound($x, $y); $self->{_data}->[$self->_index($x, $y)] = $v; } sub to_string { # Dump Screen onto string return join('', @{$_[0]->{_data}}); } #Back to reality. The main cycle gets a new ASCII clock representation + every second and prints it. package main; use POSIX 'ceil'; my $pi2 = 2 * atan2(0, -1); # Useful to have around my ($wx, $wy) = @ARGV; # Accept sizes from command line while (1) { # Cycle forever, updating each second print "\e[2J", anaclock($wx, $wy); sleep(1); } #Accessor functions. The adjust function rounds numbers to have intege +r matrix indexes; # in the meanwhile, it also performs a translation by 1 cell - please +don't ask me why, # it works :) #The two drawing functions do what they declare. # Round and translate to better fit inside the screen sub adjust {return ceil($_[0] - 1.5);} sub draw_circle { my ($screen, $cx, $cy, $rx, $ry, $c) = @_; my $radius = ($rx > $ry) ? $rx : $ry; my $step = abs(1 / ($radius * $pi2)); for (my $a = 0.0; $a < 2 * $pi2; $a += $step) { $screen->set(adjust($cx + $rx * cos($a)), adjust($cy + $ry * sin($a)), $c); } } sub draw_line { my ($screen, $ax, $ay, $bx, $by, $c) = @_; my ($dx, $dy) = ($bx - $ax, $by - $ay); my ($adx, $ady) = (abs($dx), abs($dy)); my $delta = ($adx > $ady) ? $adx : $ady; $dx /= $delta; $dy /= $delta; for (; $delta > 0; $ax += $dx, $ay += $dy, --$delta) { $screen->set(adjust($ax), adjust($ay), $c); } } #The actual ASCII clock building function. It accepts width and heigth + even # if it increases them by 1 when building the screen- I hope you're re +ally not # going to be annoyed because of this. sub anaclock { my $width = shift || 45; my $height = shift || 23; --$width; --$height; # Too lazy to change code after... my ($rx, $ry) = ($width / 2, $height / 2); my ($cx, $cy) = (1 + $rx, 1 + $ry); # Get a virtual screen to write onto; get it a little larger # to cope with roundups my $screen = Screen->new($width + 1, $height + 1); # Draw the surronding circle draw_circle($screen, $cx, $cy, $rx, $ry, '.'); # Decrease radius to be strictly inside $rx *= 6/8; $ry *= 6/8; # What time is it? my ($sec, $min, $hour) = (localtime(time))[0 .. 2]; # Scale values to get angles. Note that $min is shifted by the # seconds, and $hour is shifted by the minutes. $sec *= $pi2 / 60; $min = ($min * $pi2 + $sec) / 60; $hour = (($hour % 12) * $pi2 + $min) / 12; # Draw lines. According to most clocks, hours are in background and # seconds in foreground. draw_line($screen, $cx, $cy, $cx + $rx * sin($hour) * 2 / 3, $cy - $ry * cos($hour) * 2 / 3, '#'); draw_line($screen, $cx, $cy, $cx + $rx * sin($min), $cy - $ry * cos($min), '+'); draw_line($screen, $cx, $cy, $cx + $rx * sin($sec), $cy - $ry * cos($sec), '.'); # Return a string representation return $screen->to_string(); } |
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: ASCII analog clock
by zentara (Archbishop) on Mar 19, 2005 at 12:59 UTC | |
by polettix (Vicar) on Mar 20, 2005 at 16:24 UTC | |
Re: ASCII analog clock
by chanio (Priest) on Mar 22, 2005 at 04:52 UTC | |
Re: ASCII analog clock
by aubell (Novice) on Mar 30, 2005 at 10:47 UTC |
Back to
Code Catacombs