level calculation
[engit/Iron-Munger.git] / lib / IronMunger / Calculate.pm
CommitLineData
ac04ccd9 1package IronMunger::Calculate;
2
3use strict;
4use warnings;
66bdbe82 5use List::Util qw(min);
38827ef4 6use autobox;
38efa3f1 7use autobox::DateTime::Duration;
f79d4b5c 8use signatures;
67e9aef2 9
a7b549f9 10use Sub::Exporter -setup => {
11 exports => [
69941ee3 12 qw(successful_sequential_posts days_remaining_to_post level_for_post_count)
a7b549f9 13 ]
14};
15
66bdbe82 16sub day_diff ($dt1, $dt2) {
17 $dt1 = $dt1->at if $dt1->isa('IronMunger::Post');
18 $dt2 = $dt2->at if $dt2->isa('IronMunger::Post');
19 $dt1->delta_days($dt2)->delta_days;
20}
21
38efa3f1 22sub check_post_gap ($aperture, $days, @posts) {
66bdbe82 23 return scalar @posts if @posts <= $aperture;
38efa3f1 24 my @next_post = splice(@posts, 0, $aperture);
e1738c74 25 if (day_diff(DateTime->now, $next_post[-1]) > $days) {
26 while (@next_post && day_diff(DateTime->now, $next_post[-1]) > $days) {
27 pop @next_post;
28 }
29 return scalar(@next_post);
30 }
38efa3f1 31 my $success = $aperture;
67e9aef2 32 foreach my $post (@posts) {
66bdbe82 33 if (day_diff($next_post[0],$post) > $days) {
34 return $success;
35 }
67e9aef2 36 $success++;
37 shift(@next_post);
38 push(@next_post, $post);
39 }
40 return $success;
41}
38efa3f1 42
a51e36e5 43sub check_time_remaining ($aperture, $days, @posts) {
e1738c74 44 my @consider = @posts > $aperture ? @posts[0 .. $aperture - 1] : @posts;
45 foreach my $cand (reverse @consider) {
46 my $days_ago = day_diff(DateTime->now, $cand);
47 return $days - $days_ago if $days > $days_ago;
48 }
49 return $days;
a51e36e5 50}
51
a7b549f9 52sub check_both ($check, @posts) {
66bdbe82 53 return min(
a7b549f9 54 $check->(1, 10, @posts), # 10 days between posts
55 $check->(4, 32, @posts), # 4 posts within any given 32 days
38efa3f1 56 );
57}
ac04ccd9 58
a7b549f9 59sub successful_sequential_posts (@posts) {
60 return check_both(\&check_post_gap, @posts);
61}
62
38827ef4 63sub days_remaining_to_post (@posts) {
a7b549f9 64 return check_both(\&check_time_remaining, @posts);
65}
66
69941ee3 67sub level_for_post_count($count) {
68 return 'paper' if $count < 4;
69 return 'stone' if $count < 12;
70 return 'bronze' if $count < 36;
71 return 'iron';
72}
73
ac04ccd9 741;