Difference between revisions of "Implementations/Libraries/Perl"

From Geohashing
imported>Relet
(Created page with "== Lazy Geohasher == {{30w compliant|partial=1}} If you'd rather just stay at home and wait for a geohash to come to you (or perhaps have some other reason to participate in [[Ge...")
(No difference)

Revision as of 07:52, 10 April 2012

Lazy Geohasher

This implementation IS PARTIALLY 30W-compliant.

If you'd rather just stay at home and wait for a geohash to come to you (or perhaps have some other reason to participate in Geohash Hacking), there's a perl script which will search for combinations of times and DOW Jones opening prices to find when you could win the much coveted Couch Potato Geohash or Cubicle Geohash award. Just put in the ranges of values for the stock market and the time you want to wait for, and watch those CPU cycles fly! -- thaniel.drake@gmail.com.

30w compliance statement: This code does not use live data. Users are expected to determine from the date of the Geohash which opening value is relevant for their locale.

Disclaimer: The author humbly requests that you do not manipulate the Dow Jones Industrial Average to ensure that a geohash collides with your address. The author accepts no responsibility for any resulting financial instability you cause by such manipulations.

Here is an improved implementation which sorts results by great-circle distance. Distance cutoff, length of search, and dollar spread searched may be adjusted at the command line. Days may be a positive integer count of days following today or a comma-separated list of %F datespecs. Same 30W caveats apply.

This implementation IS PARTIALLY 30W-compliant.
#!/usr/bin/perl -w
require 5.9.2;

use Digest::MD5 qw(md5);
use POSIX qw(strftime);
use Math::Trig qw(deg2rad great_circle_distance);

die "usage: $0 lat lon orig-dow [spread] [days] [max-km]" unless @ARGV >= 3;
my ($lat, $lon, $orig, $spread, $days, $max_km) = @ARGV;
my ($g_lat, $g_lon) = map { int } $lat, $lon;
$spread ||= 500; $days ||= 7; $max_km ||= 1;

sub geohash { map { $_ / 2**64 } unpack("Q>Q>", md5(shift)) }
sub genday {
    my $date = shift;
    for (($orig - $spread) * 100 .. ($orig + $spread) * 100) {
        my $dow = sprintf("%.2f", $_ / 100);
        ($f_lat, $f_lon) = map { substr($_, 1) } geohash("$date-$dow");
        $gh{"$date-$dow"} = [$g_lat . $f_lat, $g_lon . $f_lon];
    }
}

if ($days =~ /^\d{4,}-\d{2}-\d{2}/) { genday($_) for split(/,/, $days) }
else { genday(strftime("%F", localtime(time + 86400 * $_))) for (1...$days) }

sub d2r { deg2rad($_[0]), deg2rad(90 - $_[1]) }
sub gdist { great_circle_distance(d2r($lat, $lon), d2r(@{$_[0]}), 6378) }

printf "%s -> %f,%f (%.3fkm)\n", $_->[0], @{$gh{$_->[0]}}, $_->[1] for
    sort { $a->[1] <=> $b->[1] }
        grep { $_->[1] < $max_km }
            map { [$_, gdist($gh{$_})] } keys %gh;

For discussion of the actual algorithm stuff hiding in there, please see the next section.