diff --git a/modules/cjeopardy/QStatskeeper.pm b/modules/cjeopardy/QStatskeeper.pm index c7438c35..32726a51 100644 --- a/modules/cjeopardy/QStatskeeper.pm +++ b/modules/cjeopardy/QStatskeeper.pm @@ -209,4 +209,16 @@ sub add_wrong_answer { } } +sub get_all_questions { + my ($self) = @_; + + my $qdatas = eval { + my $sth = $self->{dbh}->prepare('SELECT * FROM QStats'); + $sth->execute(); + return $sth->fetchall_arrayref({}); + }; + print STDERR $@ if $@; + return $qdatas; +} + 1; diff --git a/modules/cjeopardy/cjeopardy_qstats.pl b/modules/cjeopardy/cjeopardy_qstats.pl index 66416e49..05267c21 100755 --- a/modules/cjeopardy/cjeopardy_qstats.pl +++ b/modules/cjeopardy/cjeopardy_qstats.pl @@ -8,7 +8,6 @@ use Time::Duration qw(duration concise); use POSIX 'strftime'; use QStatskeeper; -use IRCColors; my $command = shift @ARGV; my $opt = join ' ', @ARGV; @@ -16,8 +15,190 @@ my $opt = join ' ', @ARGV; $command = '' if not defined $command; $opt = '' if not defined $opt; +my $rank_direction = '+'; + +sub sort_correct { + if ($rank_direction eq '+') { + return $b->{correct} <=> $a->{correct}; + } else { + return $a->{correct} <=> $b->{correct}; + } +} + +sub print_correct { + my $qdata = shift @_; + return undef if $qdata->{correct} == 0; + return "$qdata->{id} ($qdata->{correct})"; +} + +sub sort_wrong { + if ($rank_direction eq '+') { + return $b->{wrong} <=> $a->{wrong}; + } else { + return $a->{wrong} <=> $b->{wrong}; + } +} + +sub print_wrong { + my $qdata = shift @_; + return undef if $qdata->{wrong} == 0; + return "$qdata->{id} ($qdata->{wrong})"; +} + +sub sort_wrongstreak { + if ($rank_direction eq '+') { + return $b->{highest_wrong_streak} <=> $a->{highest_wrong_streak}; + } else { + return $a->{highest_wrong_streak} <=> $b->{highest_wrong_streak}; + } +} + +sub print_wrongstreak { + my $qdata = shift @_; + return undef if $qdata->{highest_wrong_streak} == 0; + return "$qdata->{id} ($qdata->{highest_wrong_streak})"; +} + +sub sort_hints { + if ($rank_direction eq '+') { + return $b->{hints} <=> $a->{hints}; + } else { + return $a->{hints} <=> $b->{hints}; + } +} + +sub print_hints { + my $qdata = shift @_; + return undef if $qdata->{hints} == 0; + return "$qdata->{id} ($qdata->{hints})"; +} + +sub sort_quickest { + if ($rank_direction eq '+') { + return $a->{quickest_answer_time} <=> $b->{quickest_answer_time}; + } else { + return $b->{quickest_answer_time} <=> $a->{quickest_answer_time}; + } +} + +sub print_quickest { + my $qdata = shift @_; + return undef if $qdata->{quickest_answer_time} == 0; + if ($qdata->{quickest_answer_time} < 60) { + return "$qdata->{id} (" . sprintf("%.02fs", $qdata->{quickest_answer_time}) . ")"; + } else { + return "$qdata->{id} (" . (concise duration $qdata->{quickest_answer_time}) . ")"; + } +} + +sub sort_longest { + if ($rank_direction eq '+') { + return $b->{longest_answer_time} <=> $a->{longest_answer_time}; + } else { + return $a->{longest_answer_time} <=> $b->{longest_answer_time}; + } +} + +sub print_longest { + my $qdata = shift @_; + return undef if $qdata->{longest_answer_time} == 0; + if ($qdata->{longest_answer_time} < 60) { + return "$qdata->{id} (" . sprintf("%.02fs", $qdata->{longest_answer_time}) . ")"; + } else { + return "$qdata->{id} (" . (concise duration $qdata->{longest_answer_time}) . ")"; + } +} + +sub sort_average { + if ($rank_direction eq '+') { + return $a->{average_answer_time} <=> $b->{average_answer_time}; + } else { + return $b->{average_answer_time} <=> $a->{average_answer_time}; + } +} + +sub print_average { + my $qdata = shift @_; + return undef if $qdata->{average_answer_time} == 0; + if ($qdata->{average_answer_time} < 60) { + return "$qdata->{id} (" . sprintf("%.02fs", $qdata->{average_answer_time}) . ")"; + } else { + return "$qdata->{id} (" . (concise duration $qdata->{average_answer_time}) . ")"; + } +} + if (lc $command eq 'rank') { - print "QStats rankings coming soon.\n"; + my %ranks = ( + correct => { sort => \&sort_correct, print => \&print_correct, title => 'correct answers' }, + wrong => { sort => \&sort_wrong, print => \&print_wrong, title => 'wrong answers' }, + wrongstreak => { sort => \&sort_wrongstreak, print => \&print_wrongstreak, title => 'wrong answer streak' }, + hints => { sort => \&sort_hints, print => \&print_hints, title => 'hints used' }, + quickest => { sort => \&sort_quickest, print => \&print_quickest, title => 'quickest answer time' }, + longest => { sort => \&sort_longest, print => \&print_longest, title => 'longest answer time' }, + average => { sort => \&sort_average, print => \&print_average, title => 'average answer time' }, + ); + + if (not $opt) { + print "Usage: rank [-] [offset] or rank [-]; available keywords: "; + print join ', ', sort keys %ranks; + print ".\n"; + print "Prefixing the keyword or nick with a dash will invert the sort direction for each category. Specifying an offset will start ranking at that offset.\n"; + exit; + } + + my $qstats = QStatskeeper->new; + $qstats->begin; + + $opt = lc $opt; + + if ($opt =~ s/^([+-])//) { + $rank_direction = $1; + } + + my $offset = 1; + if ($opt =~ s/\s+(\d+)$//) { + $offset = $1; + } + + if (not exists $ranks{$opt}) { + print "Ranking specific questions coming soon.\n"; + $qstats->end; + exit; + } + + my $qdatas = $qstats->get_all_questions(); + + my $sort_method = $ranks{$opt}->{sort}; + @$qdatas = sort $sort_method @$qdatas; + + my @ranking; + my $rank = 0; + my $last_value = -1; + foreach my $qdata (@$qdatas) { + my $entry = $ranks{$opt}->{print}->($qdata); + if (defined $entry) { + my ($value) = $entry =~ /\((.*)\)$/; + $rank++ if $value ne $last_value; + $last_value = $value; + next if $rank < $offset; + push @ranking, "#$rank $entry" if defined $entry; + last if scalar @ranking >= 15; + } + } + + if (not scalar @ranking) { + if ($offset > 1) { + print "No rankings available at offset #$offset.\n"; + } else { + print "No rankings available yet.\n"; + } + } else { + print "Rankings for $ranks{$opt}->{title}: "; + print join ', ', @ranking; + print "\n"; + } + + $qstats->end; } elsif ($command =~ m/^\d+$/) { my $qstats = QStatskeeper->new; $qstats->begin;