diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2019-06-09 09:25:14 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-06-09 09:25:14 +0100 |
| commit | 3602f68f35bd8bc9b3632e7bd38225e3dbf66476 (patch) | |
| tree | a5fc00f077350996ba77b3ade815cd6a82395203 | |
| parent | 0a25e39af9e85466956da97808fe589703da2cf0 (diff) | |
| parent | 9232205b74dbb9c02dec10e8dcd50098623057c3 (diff) | |
| download | perlweeklychallenge-club-3602f68f35bd8bc9b3632e7bd38225e3dbf66476.tar.gz perlweeklychallenge-club-3602f68f35bd8bc9b3632e7bd38225e3dbf66476.tar.bz2 perlweeklychallenge-club-3602f68f35bd8bc9b3632e7bd38225e3dbf66476.zip | |
Merge pull request #232 from PerlMonk-Athanasius/new-branch
On branch new-branch
| -rw-r--r-- | challenge-011/athanasius/perl5/ch-1.pl | 75 | ||||
| -rw-r--r-- | challenge-011/athanasius/perl5/ch-2.pl | 78 | ||||
| -rw-r--r-- | challenge-011/athanasius/perl5/ch-3.pl | 327 |
3 files changed, 480 insertions, 0 deletions
diff --git a/challenge-011/athanasius/perl5/ch-1.pl b/challenge-011/athanasius/perl5/ch-1.pl new file mode 100644 index 0000000000..0d502980a0 --- /dev/null +++ b/challenge-011/athanasius/perl5/ch-1.pl @@ -0,0 +1,75 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 011 +========================= + +Challenge #1 +------------ + +Write a script that computes the equal point in the Fahrenheit and Celsius +scales, knowing that the freezing point of water is 32 °F and 0 °C, and that the +boiling point of water is 212 °F and 100 °C. This challenge was proposed by +*Laurent Rosenfeld*. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2019 Perlmonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use utf8; +use Const::Fast; + +const my $FAHRENHEIT_FREEZING => 32; +const my $FAHRENHEIT_BOILING => 212; +const my $CELSIUS_FREEZING => 0; +const my $CELSIUS_BOILING => 100; + +$| = 1; + +MAIN: +{ + # At the equal point, degrees Fahrenheit (f) equal degrees Celsius, so + # f = f × ((212 - 32) / 100) + 32 + # => f × (1 - 9/5) = 32 + # => f = 32 / -4/5 + # = -40. + + my $equal = $FAHRENHEIT_FREEZING / + (1 - (($FAHRENHEIT_BOILING - $FAHRENHEIT_FREEZING) / $CELSIUS_BOILING)); + + printf "\nThe equal point is %3.1f°\n", $equal; + printf "This is %s by conversion from Celsius to Fahrenheit\n", + $equal == c2f($equal) ? 'confirmed' : 'refuted'; + printf "This is %s by conversion from Fahrenheit to Celsius\n", + $equal == f2c($equal) ? 'confirmed' : 'refuted'; +} + +# Convert Celsius to Fahrenheit + +sub c2f +{ + my ($degrees_celsius) = @_; + + return ($degrees_celsius * + (($FAHRENHEIT_BOILING - $FAHRENHEIT_FREEZING) / $CELSIUS_BOILING)) + + $FAHRENHEIT_FREEZING +} + +# Convert Fahrenheit to Celsius + +sub f2c +{ + my ($degrees_fahrenheit) = @_; + + return ($degrees_fahrenheit - $FAHRENHEIT_FREEZING) * + ($CELSIUS_BOILING / ($FAHRENHEIT_BOILING - $FAHRENHEIT_FREEZING)); +} + +################################################################################ diff --git a/challenge-011/athanasius/perl5/ch-2.pl b/challenge-011/athanasius/perl5/ch-2.pl new file mode 100644 index 0000000000..7f6a6c727e --- /dev/null +++ b/challenge-011/athanasius/perl5/ch-2.pl @@ -0,0 +1,78 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 011 +========================= + +Challenge #2 +------------ + +Write a script to create an Indentity Matrix for the given size. For example, if +the size is 4, then create Identity Matrix 4x4. For more information about +*Indentity Matrix*, please read the +[ https://en.wikipedia.org/wiki/Identity_matrix |wiki] page. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2019 Perlmonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use Const::Fast; +use Scalar::Util::Numeric qw( isint ); + +const my $DEFAULT_SIZE => 4; +const my $MAX_SIZE => 39; # Adjust for the target console + +$| = 1; + +MAIN: +{ + my $size = $ARGV[0] // $DEFAULT_SIZE; + my $matrix = identity_matrix($size); + + print "\nIdentity Matrix of size $size:\n"; + print_matrix($matrix); +} + +sub identity_matrix +{ + my ($size) = @_; + + die "Invalid matrix size $size, stopped" + unless isint($size) && $size > 0; + + die "Matrix size $size is too wide to be properly displayed, stopped" + if $size > $MAX_SIZE; + + my $matrix; + + for my $i (0 .. $size - 1) + { + $matrix->[$i][$_] = ($i == $_) ? 1 : 0 for 0 .. $size - 1; + } + + return $matrix; +} + +sub print_matrix +{ + my ($matrix) = @_; + my $size = scalar @$matrix; + + if ($size == 1) + { + print '[', $matrix->[0][0], "]\n"; + } + else + { + print '|', join( ' ', $matrix->[$_]->@* ), "|\n" for 0 .. $size - 1; + } +} + +################################################################################ diff --git a/challenge-011/athanasius/perl5/ch-3.pl b/challenge-011/athanasius/perl5/ch-3.pl new file mode 100644 index 0000000000..8b9fed40ed --- /dev/null +++ b/challenge-011/athanasius/perl5/ch-3.pl @@ -0,0 +1,327 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 011 +========================= + +Challenge #3 +------------ + +Using [ https://openweathermap.org/current |Open Weather Map API], write a +script to fetch the current weather for an arbitrary city. Note that you will +need to sign up for Open Weather Map's free tier and then wait a couple hours +before your API key will be valid. This challenge was proposed by *Joelle +Maslak*. The API challenge is *optional* but would love to see your solution. + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2019 Perlmonk Athanasius # +#--------------------------------------# + +use strict; +use warnings; +use utf8; +use Const::Fast; +use DateTime; +use Getopt::Long; +use JSON; +use LWP::UserAgent (); + +const my $API_KEY => '22314778a05bf583f56cda402fce02eb'; +const my $TIMEOUT => 30; # seconds +const my $URL => 'http://api.openweathermap.org/data/2.5/weather?q='; +const my $URL_ID => 'http://api.openweathermap.org/data/2.5/weather?id='; +const my $S_PER_MIN => 60; +const my $MIN_PER_H => 60; +const my $S_PER_HR => $S_PER_MIN * $MIN_PER_H; +const my $ABSZERO_C => -273.15; +const my $ABSZERO_F => -459.67; +const my $K_PER_F => 9 / 5; +const my $USAGE => "\nUsage: perl $0 --city <string> --country <string>\n" . + " or perl $0 --city_id <positive integer>\n" . + " or perl $0 --help\n"; + +$| = 1; + +MAIN: +{ + my ($city_id, $city, $country, $help, $response); + + GetOptions + ( + 'city_id=i' => \$city_id, + 'city=s' => \$city, + 'country=s' => \$country, + 'help' => \$help, + + ) or die $USAGE; + + die $USAGE if $help || + !(defined $city_id || (defined $city && defined $country)); + + $response = get_weather($city_id, $city, $country); + + if ($response->is_success) + { + report($city_id, $city, $country, $response); + } + else + { + die "\nError: ", $response->status_line, "\n"; + } +} + +sub get_weather +{ + my ($city_id, $city, $country) = @_; + + my $url = defined($city_id) ? "$URL_ID$city_id" : "$URL$city,$country"; + $url .= "&APPID=$API_KEY"; + my $ua = LWP::UserAgent->new(timeout => $TIMEOUT); + my $resp = $ua->get($url); + + return $resp; +} + +sub report +{ + my ($city_id, $city, $country, $response) = @_; + + my $json = JSON->new->allow_nonref; + my $weather = $json->decode($response->{_content}); + my $location = defined($city_id) ? "city with ID $city_id" : + "$city, $country"; + + print "\nDetails of the current weather for $location:\n"; + + report_location($weather); + report_weather ($weather); + report_temps ($weather); + report_snow ($weather); + report_rain ($weather); + report_wind ($weather); + report_pressure($weather); + report_times ($weather); +} + +sub report_location +{ + my ($weather) = @_; + my $city = $weather->{name}; + my $country = $weather->{sys}{country}; + my $id = $weather->{id}; + my $latitude = $weather->{coord}{lat}; + $latitude = sprintf "%.2f°%s", abs($latitude), + ($latitude < 0 ? 'S' : 'N') if defined $latitude; + my $longitude = $weather->{coord}{lon}; + $longitude = sprintf "%.2f°%s", abs($longitude), + ($longitude < 0 ? 'W' : 'E') if defined $longitude; + + if (defined $city || defined $country || defined $id || defined $latitude || + defined $longitude) + { + print "\nLocation\n"; + printf " City: %s\n", $city // 'N/A'; + printf " Country code: %s\n", $country // 'N/A'; + printf " City ID: %d\n", $id // 'N/A'; + printf " Latitude: %s\n", $latitude // 'N/A'; + printf " Longitude: %s\n", $longitude // 'N/A'; + } +} + +sub report_weather +{ + my ($weather) = @_; + my $description = $weather->{weather}[0]{description}; + my $summary = $weather->{weather}[0]{main}; + $summary .= ' (' . $description . ')' if defined $summary && + defined $description; + my $cloudiness = $weather->{clouds}{all}; + $cloudiness .= '%' if defined $cloudiness; + my $humidity = $weather->{main}{humidity}; + $humidity .= '%' if defined $humidity; + my $visibility = $weather->{visibility}; + $visibility = commify($visibility) . ' m' if defined $visibility; + + if (defined $summary || defined $cloudiness || defined $humidity || + defined $visibility) + { + print "\nWeather\n"; + printf " Summary: %s\n", $summary // 'N/A'; + printf " Cloudiness: %s\n", $cloudiness // 'N/A'; + printf " Humidity: %s\n", $humidity // 'N/A'; + printf " Visibility: %s\n", $visibility // 'N/A'; + } +} + +sub report_temps +{ + my ($weather) = @_; + + my $min = $weather->{main}{temp_min}; + $min = sprintf("%2.0f°C (%.0f°F)", k2c($min), k2f($min)) if defined $min; + my $max = $weather->{main}{temp_max}; + $max = sprintf("%2.0f°C (%.0f°F)", k2c($max), k2f($max)) if defined $max; + my $cur = $weather->{main}{temp}; + $cur = sprintf("%2.0f°C (%.0f°F)", k2c($cur), k2f($cur)) if defined $cur; + + if (defined $min || defined $max || defined $cur) + { + print "\nTemperatures\n"; + printf " Minimum: %s\n", $min // 'N/A'; + printf " Maximum: %s\n", $max // 'N/A'; + printf " Current: %s\n", $cur // 'N/A'; + } +} + +sub report_snow +{ + my ($weather) = @_; + my $snow_1h = $weather->{snow}{'1h'}; + $snow_1h .= ' mm' if defined $snow_1h; + my $snow_3h = $weather->{snow}{'3h'}; + $snow_3h .= ' mm' if defined $snow_3h; + + if (defined $snow_1h || defined $snow_3h) + { + print "\nSnow\n"; + printf " Volume (1 hr): %s\n", $snow_1h // 'N/A'; + printf " Volume (3 hr): %s\n", $snow_3h // 'N/A'; + } +} + +sub report_rain +{ + my ($weather) = @_; + my $rain_1h = $weather->{rain}{'1h'}; + $rain_1h .= ' mm' if defined $rain_1h; + my $rain_3h = $weather->{rain}{'3h'}; + $rain_3h .= ' mm' if defined $rain_3h; + + if (defined $rain_1h || defined $rain_3h) + { + print "\nRain\n"; + printf " Volume (1 hr): %s\n", $rain_1h // 'N/A'; + printf " Volume (3 hr): %s\n", $rain_3h // 'N/A'; + } +} + +sub report_wind +{ + my ($weather) = @_; + my $speed = $weather->{wind}{speed}; + $speed = sprintf("%.1f m/s", $speed) if defined $speed; + my $direction = $weather->{wind}{deg}; + $direction = sprintf("%d°", $direction) if defined $direction; + + if (defined $speed || defined $direction) + { + print "\nWind\n"; + printf " Speed: %s\n", $speed // 'N/A'; + printf " Direction: %s\n", $direction // 'N/A'; + } +} + +sub report_pressure +{ + my ($weather) = @_; + my $pressure = $weather->{main}{pressure}; + $pressure = commify($pressure) . ' hPa' if defined $pressure; + my $sea_level = $weather->{main}{sea_level}; + $sea_level = commify($sea_level) . ' hPa' if defined $sea_level; + my $grnd_level = $weather->{main}{grnd_level}; + $grnd_level = commify($grnd_level) . ' hPa' if defined $grnd_level; + + if (defined $pressure || defined $sea_level || defined $grnd_level) + { + print "\nAir pressure\n"; + printf " Sea level: %s\n", $pressure if defined $pressure; + printf " Sea level: %s\n", $sea_level if defined $sea_level; + printf " Ground level: %s\n", $grnd_level if defined $grnd_level; + } +} + +sub report_times +{ + my ($weather) = @_; + my $seconds = $weather->{timezone}; + my ($current, $sunrise, $sunset, $timezone); + + if (defined $seconds) + { + $timezone = DateTime::Duration->new(seconds => $seconds); + $current = DateTime->from_epoch(epoch => $weather->{dt}); + + if (defined $current) + { + $current->add_duration($timezone); + $current = $current->hms . ', ' . $current->ymd; + } + + $sunrise = DateTime->from_epoch(epoch => $weather->{sys}{sunrise}); + + if (defined $sunrise) + { + $sunrise->add_duration($timezone); + $sunrise = $sunrise->hms . ', ' . $sunrise->ymd; + } + + $sunset = DateTime->from_epoch(epoch => $weather->{sys}{sunset}); + + if (defined $sunset) + { + $sunset->add_duration($timezone); + $sunset = $sunset->hms . ', ' . $sunset->ymd; + } + + my $hours = abs int ($seconds / $S_PER_HR); + my $minutes = abs int(($seconds % $S_PER_HR) / $S_PER_MIN); + $timezone = sprintf "UTC%s%02d:%02d", (($seconds < 0) ? '-' : '+'), + $hours, $minutes; + } + + if (defined $timezone || defined $current || defined $sunrise || + defined $sunset) + { + print "\nTimes (local)\n"; + printf " Timezone: %s\n", $timezone // 'N/A'; + printf " Current: %s\n", $current // 'N/A'; + printf " Sunrise: %s\n", $sunrise // 'N/A'; + printf " Sunset: %s\n", $sunset // 'N/A'; + } +} + +# Convert temperature in Kelvin to degrees Celsius + +sub k2c +{ + my ($kelvin) = @_; + + return $kelvin + $ABSZERO_C; +} + +# Convert temperature in Kelvin to degrees Fahranheit + +sub k2f +{ + my ($kelvin) = @_; + + return ($kelvin * $K_PER_F) + $ABSZERO_F; +} + +# Separate groups of 3 digits (in the integer part of a number) with commas + +sub commify +{ + my ($string) = @_; + + # Regex from perlfaq5: "How can I output my numbers with commas added?" + + return $string =~ s/(^\d+?(?=(?>(?:\d{3})+)(?!\d))|\G\d{3}(?=\d))/$1,/gr; +} + +################################################################################ |
