File Coverage

blib/lib/NetHack/NAOdash.pm
Criterion Covered Total %
statement 72 89 80.9
branch 8 22 36.3
condition 10 24 41.6
subroutine 15 18 83.3
pod 2 4 50.0
total 107 157 68.1


line stmt bran cond sub pod time code
1             package NetHack::NAOdash;
2              
3 1     1   21494 use 5.014000;
  1         4  
4 1     1   6 use strict;
  1         1  
  1         21  
5 1     1   5 use warnings;
  1         5  
  1         36  
6 1     1   5 use re '/saa';
  1         2  
  1         96  
7 1     1   821 use parent qw/Exporter/;
  1         332  
  1         6  
8              
9             our $VERSION = '0.003';
10             our @EXPORT_OK = qw/naodash_xlog naodash_user/;
11             our @EXPORT = @EXPORT_OK;
12              
13 1     1   176706 use File::Slurp;
  1         20020  
  1         88  
14 1     1   806 use File::Spec::Functions qw/tmpdir catdir catfile/;
  1         846  
  1         84  
15 1     1   346660 use HTTP::Tiny;
  1         48746  
  1         48  
16 1     1   8 use List::Util qw/max min sum/;
  1         2  
  1         121  
17 1     1   870 use List::MoreUtils qw/uniq/;
  1         24459  
  1         8  
18 1     1   1431 use Text::XLogfile qw/parse_xlogline/;
  1         1007  
  1         1671  
19              
20             sub won_game {
21 1530     1530 0 12683 my %game = @_;
22 1530         19848 $game{death} eq 'ascended'
23             }
24              
25             our @check_subs = (
26             sub { # Combos
27             my %game = @_;
28             return unless won_game %game;
29             $game{align0} //= $game{align};
30             "combo_$game{role}_$game{race}_$game{align0}"
31             },
32              
33             sub { # Achievements
34             my %game = @_;
35             my @achieves = qw/bell gehennom candelabrum book invocation amulet endgame astral ascended luckstone sokoban medusa/;
36             map { $game{achieve} & (1 << $_) ? "achieve_$achieves[$_]" : () } 0 .. $#achieves
37             },
38              
39             sub { # Conducts
40             my %game = @_;
41             return unless won_game %game;
42             my @conducts = qw/foodless vegan vegetarian atheist weaponless pacifist illiterate polypileless polyselfless wishless artiwishless genocideless/;
43             map { $game{conduct} & (1 << $_) ? "conduct_$conducts[$_]" : () } 0 .. $#conducts
44             },
45              
46             sub { # Unofficial conducts
47             my %game = @_;
48             return unless won_game %game;
49             my @uconducts;
50             push @uconducts, 'survivor' if $game{deaths} == 0;
51             push @uconducts, 'boneless' unless $game{flags} & 32;
52             push @uconducts, 'minscore' if $game{points} - 100 * ($game{maxlvl} - 45) == 24_400;
53             map { "uconduct_$_" } @uconducts
54             },
55             );
56              
57             our %sum_subs = (
58             games => sub { 1 },
59             ascensions => sub {
60             my %game = @_;
61             !!won_game %game
62             },
63             totalrealtime => sub {
64             my %game = @_;
65             $game{realtime} // 0
66             },
67             );
68              
69             sub make_attr_sub ($) { ## no critic (ProhibitSubroutinePrototypes)
70 5     5 0 18 my ($attr) = @_;
71             sub {
72 850     850   7447 my %game = @_;
73 850 100       4140 return unless won_game %game;
74 150   33     1533 $game{$attr} // ()
75             },
76 5         26 }
77              
78             our %max_subs = (
79             maxhp => make_attr_sub 'maxhp',
80             maxpoints => make_attr_sub 'points',
81             maxconducts => make_attr_sub 'nconducts',
82             );
83              
84             our %min_subs = (
85             minturns => make_attr_sub 'turns',
86             minrealtime => make_attr_sub 'realtime',
87             );
88              
89             sub naodash_xlog { ## no critic (RequireArgUnpacking)
90 3     3 1 211 my (%args, %exclude, %include);
91 3 100       12 %args = %{shift()} if ref $_[0] eq 'HASH'; ## no critic (Builtin)
  2         7  
92 3   100     6 %exclude = map { $_ => 1 } @{$args{exclude_versions} // []};
  1         4  
  3         20  
93 3   100     6 %include = map { $_ => 1 } @{$args{include_versions} // []};
  1         4  
  3         14  
94 3         104 my ($xlog) = join '', @_;
95 3         21 my %number_subs = (%sum_subs, %max_subs, %min_subs);
96              
97 3         7 my @checks;
98 3         10 my %numbers = map { $_ => [] } keys %number_subs;
  24         49  
99              
100 3         203 for my $logline (split /\n/, $xlog) {
101 255         318 my %game = %{parse_xlogline $logline};
  255         764  
102 255         40310 for (keys %game) {
103 7395 50       15484 delete $game{$_} if $game{$_} eq ''
104             }
105 255 100 100     1983 next if $exclude{$game{version}} || %include && !$include{$game{version}};
      66        
106 170 50       507 next if $game{flags} & 3; # flag 0x01 is wizard mode, 0x02 is explore mode
107 170         1062 push @checks, $_->(%game) for @check_subs;
108 170         522 push @{$numbers{$_}}, $number_subs{$_}->(%game) for keys %number_subs;
  1360         7527  
109             }
110              
111 3         34 $numbers{$_} = sum @{$numbers{$_}} for keys %sum_subs;
  9         120  
112 3         11 $numbers{$_} = max @{$numbers{$_}} for keys %max_subs;
  9         62  
113 3         10 $numbers{$_} = min @{$numbers{$_}} for keys %min_subs;
  6         39  
114 3         8 @checks = uniq map { lc } @checks;
  496         1139  
115              
116 3         178 {checks => [sort @checks], numbers => \%numbers}
117             }
118              
119             my $ht = HTTP::Tiny->new(agent => "NetHack-NAOdash/$VERSION ");
120              
121             sub _get_xlog_from_server {
122 0     0     my ($name) = @_;
123 0           my $ret = $ht->get("http://alt.org/nethack/player-all-xlog.php?player=$name");
124 0 0         die 'Error while retrieving xlogfile from alt.org: ' . $ret->{status} . ' ' . $ret->{reason} . "\n" unless $ret->{success};
125 0           $ret->{content} =~ m{
(.*)
}i;
126             }
127              
128             sub _get_xlog {
129 0     0     my ($name) = @_;
130 0 0 0       return _get_xlog_from_server $name if $ENV{NAODASH_CACHE} && lc $ENV{NAODASH_CACHE} eq 'none';
131 0   0       my $dir = $ENV{NAODASH_CACHE} || catdir tmpdir, 'naodash';
132 0 0 0       mkdir $dir or die "Cannot create cache directory: $!\n" unless -d $dir;
133 0           my $file = catfile $dir, $name;
134 0 0 0       write_file $file, _get_xlog_from_server $name if ! -f $file || time - (stat $file)[9] >= 86_400;
135 0           scalar read_file $file
136             }
137              
138             sub naodash_user { ## no critic (RequireArgUnpacking)
139 0     0 1   my $args = {};
140 0 0         $args = shift if ref $_[0] eq 'HASH';
141 0           my ($name) = @_;
142 0           my $xlog = _get_xlog $name;
143 0 0         die "No xlogfile found for user $name\n" unless defined $xlog;
144 0           naodash_xlog $args, $xlog;
145             }
146              
147             1;
148             __END__