2015-01-28 22:11:04 +01:00
#!/usr/bin/env perl
2017-03-05 22:33:31 +01:00
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
2015-01-28 22:11:04 +01:00
use warnings ;
use strict ;
use Time::HiRes qw( gettimeofday ) ;
2015-05-23 15:23:37 +02:00
use Time::Duration qw( concise duration ) ;
2015-01-28 22:11:04 +01:00
2018-03-12 16:52:43 +01:00
use lib "." ;
2015-01-28 22:11:04 +01:00
use Scorekeeper ;
use IRCColors ;
my $ nick = shift @ ARGV ;
my $ channel = shift @ ARGV ;
my $ command = shift @ ARGV ;
2015-02-17 10:31:40 +01:00
my $ opt = join ' ' , @ ARGV ;
2015-01-28 22:11:04 +01:00
if ( $ channel !~ /^#/ ) {
print "Sorry, C Jeopardy must be played in a channel. Feel free to join #cjeopardy.\n" ;
exit ;
}
my $ scores = Scorekeeper - > new ;
$ scores - > begin ;
2015-02-12 05:58:16 +01:00
my $ rank_direction = '+' ;
sub sort_correct {
if ( $ rank_direction eq '+' ) {
return $ b - > { lifetime_correct_answers } <=> $ a - > { lifetime_correct_answers } ;
} else {
return $ a - > { lifetime_correct_answers } <=> $ b - > { lifetime_correct_answers } ;
}
}
sub print_correct {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_correct_answers } == 0 ;
return "$player->{nick}: $player->{lifetime_correct_answers}" ;
}
sub sort_wrong {
if ( $ rank_direction eq '+' ) {
return $ a - > { lifetime_wrong_answers } <=> $ b - > { lifetime_wrong_answers } ;
2015-02-13 23:39:20 +01:00
} else {
return $ b - > { lifetime_wrong_answers } <=> $ a - > { lifetime_wrong_answers } ;
2015-02-12 05:58:16 +01:00
}
}
sub print_wrong {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_wrong_answers } == 0 and $ player - > { lifetime_correct_answers } == 0 ;
return "$player->{nick}: $player->{lifetime_wrong_answers}" ;
}
sub sort_ratio {
2015-02-13 23:39:20 +01:00
my $ wrong_a = $ a - > { lifetime_wrong_answers } ? $ a - > { lifetime_wrong_answers } : 1 ;
my $ wrong_b = $ b - > { lifetime_wrong_answers } ? $ b - > { lifetime_wrong_answers } : 1 ;
2015-02-12 05:58:16 +01:00
if ( $ rank_direction eq '+' ) {
2015-02-13 23:39:20 +01:00
return $ b - > { lifetime_correct_answers } / $wrong_b <=> $a->{lifetime_correct_answers} / $ wrong_a ;
2015-02-12 05:58:16 +01:00
} else {
2015-02-13 23:39:20 +01:00
return $ a - > { lifetime_correct_answers } / $wrong_a <=> $b->{lifetime_correct_answers} / $ wrong_b ;
2015-02-12 05:58:16 +01:00
}
}
sub print_ratio {
my $ player = shift @ _ ;
2015-12-23 02:21:04 +01:00
return undef if $ player - > { lifetime_wrong_answers } + $ player - > { lifetime_correct_answers } < 50 ;
2015-02-13 23:39:20 +01:00
my $ wrong = $ player - > { lifetime_wrong_answers } ? $ player - > { lifetime_wrong_answers } : 1 ;
my $ ratio = $ player - > { lifetime_correct_answers } / $ wrong ;
2015-02-12 05:58:16 +01:00
return undef if $ ratio == 0 ;
return sprintf "$player->{nick}: %.2f" , $ ratio ;
}
sub sort_hints {
if ( $ rank_direction eq '+' ) {
return $ a - > { lifetime_hints } <=> $ b - > { lifetime_hints } ;
2015-02-13 23:39:20 +01:00
} else {
return $ b - > { lifetime_hints } <=> $ a - > { lifetime_hints } ;
2015-02-12 05:58:16 +01:00
}
}
sub print_hints {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_hints } == 0 and $ player - > { lifetime_correct_answers } == 0 ;
return "$player->{nick}: $player->{lifetime_hints}" ;
}
sub sort_correctstreak {
if ( $ rank_direction eq '+' ) {
return $ b - > { lifetime_highest_correct_streak } <=> $ a - > { lifetime_highest_correct_streak } ;
} else {
return $ a - > { lifetime_highest_correct_streak } <=> $ b - > { lifetime_highest_correct_streak } ;
}
}
sub print_correctstreak {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_highest_correct_streak } == 0 ;
return "$player->{nick}: $player->{lifetime_highest_correct_streak}" ;
}
2015-05-21 16:35:04 +02:00
sub sort_quickeststreak {
2015-05-23 11:27:08 +02:00
my $ streak_a = $ a - > { lifetime_highest_quick_correct_streak } ? $ a - > { lifetime_highest_quick_correct_streak } : - 1000 ;
my $ streak_b = $ b - > { lifetime_highest_quick_correct_streak } ? $ b - > { lifetime_highest_quick_correct_streak } : - 1000 ;
2015-05-21 16:35:04 +02:00
if ( $ rank_direction eq '+' ) {
2015-05-24 15:19:03 +02:00
return $ streak_b - $ b - > { lifetime_quickest_correct_streak } / ($streak_b / 2 ) <=> $ streak_a - $ a - > { lifetime_quickest_correct_streak } / ($streak_a / 2 ) ;
2015-05-21 16:35:04 +02:00
} else {
2015-05-24 15:19:03 +02:00
return $ streak_a - $ a - > { lifetime_quickest_correct_streak } / ($streak_a / 2 ) <=> $ streak_b - $ b - > { lifetime_quickest_correct_streak } / ($streak_b / 2 ) ;
2015-05-21 16:35:04 +02:00
}
}
sub print_quickeststreak {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_highest_quick_correct_streak } == 0 ;
2015-05-23 15:23:37 +02:00
if ( $ player - > { lifetime_quickest_correct_streak } < 60 ) {
return "$player->{nick}: $player->{lifetime_highest_quick_correct_streak} in " . sprintf ( "%.2fs" , $ player - > { lifetime_quickest_correct_streak } ) ;
} else {
return "$player->{nick}: $player->{lifetime_highest_quick_correct_streak} in " . concise duration $ player - > { lifetime_quickest_correct_streak } ;
}
2015-05-21 16:35:04 +02:00
}
2015-02-12 05:58:16 +01:00
sub sort_wrongstreak {
if ( $ rank_direction eq '+' ) {
return $ a - > { lifetime_highest_wrong_streak } <=> $ b - > { lifetime_highest_wrong_streak } ;
2015-02-13 23:39:20 +01:00
} else {
return $ b - > { lifetime_highest_wrong_streak } <=> $ a - > { lifetime_highest_wrong_streak } ;
2015-02-12 05:58:16 +01:00
}
}
sub print_wrongstreak {
my $ player = shift @ _ ;
return undef if $ player - > { lifetime_highest_wrong_streak } == 0 and $ player - > { lifetime_correct_answers } == 0 ;
return "$player->{nick}: $player->{lifetime_highest_wrong_streak}" ;
}
sub sort_quickest {
if ( $ rank_direction eq '+' ) {
return $ a - > { quickest_correct } <=> $ b - > { quickest_correct } ;
} else {
return $ b - > { quickest_correct } <=> $ a - > { quickest_correct } ;
}
}
sub print_quickest {
my $ player = shift @ _ ;
return undef if $ player - > { quickest_correct } == 0 ;
my $ quickest ;
if ( $ player - > { quickest_correct } < 60 ) {
2015-05-25 20:34:43 +02:00
$ quickest = sprintf ( "%.2fs" , $ player - > { quickest_correct } ) ;
2015-02-12 05:58:16 +01:00
} else {
2015-05-25 20:34:43 +02:00
$ quickest = concise duration ( $ player - > { quickest_correct } ) ;
2015-02-12 05:58:16 +01:00
}
return "$player->{nick}: $quickest" ;
}
if ( lc $ command eq 'rank' ) {
my % ranks = (
2015-05-21 16:35:04 +02:00
correct = > { sort = > \ & sort_correct , print = > \ & print_correct , title = > 'correct answers' } ,
wrong = > { sort = > \ & sort_wrong , print = > \ & print_wrong , title = > 'wrong answers' } ,
quickest = > { sort = > \ & sort_quickest , print = > \ & print_quickest , title = > 'quickest answer' } ,
ratio = > { sort = > \ & sort_ratio , print = > \ & print_ratio , title = > 'correct/wrong ratio' } ,
correctstreak = > { sort = > \ & sort_correctstreak , print = > \ & print_correctstreak , title = > 'correct answer streak' } ,
quickeststreak = > { sort = > \ & sort_quickeststreak , print = > \ & print_quickeststreak , title = > 'quickest correct answer streak' } ,
wrongstreak = > { sort = > \ & sort_wrongstreak , print = > \ & print_wrongstreak , title = > 'wrong answer streak' } ,
hints = > { sort = > \ & sort_hints , print = > \ & print_hints , title = > 'hints used' } ,
2015-02-12 05:58:16 +01:00
) ;
2015-02-17 10:31:40 +01:00
if ( not $ opt ) {
print "Usage: rank [-]<keyword> [offset] or rank [-]<nick>; available keywords: " ;
2015-02-12 05:58:16 +01:00
print join ', ' , sort keys % ranks ;
print ".\n" ;
2015-02-17 10:31:40 +01:00
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" ;
2015-02-12 05:58:16 +01:00
goto END ;
}
$ opt = lc $ opt ;
if ( $ opt =~ s/^([+-])// ) {
$ rank_direction = $ 1 ;
}
2015-02-17 10:31:40 +01:00
my $ offset = 1 ;
if ( $ opt =~ s/\s+(\d+)$// ) {
$ offset = $ 1 ;
}
2015-02-12 05:58:16 +01:00
if ( not exists $ ranks { $ opt } ) {
2015-02-13 23:39:20 +01:00
my $ player_id = $ scores - > get_player_id ( $ opt , $ channel , 1 ) ;
2015-12-23 02:21:04 +01:00
my $ player_data = $ scores - > get_player_data ( $ player_id ) ;
2015-02-13 23:39:20 +01:00
if ( not defined $ player_id ) {
print "I don't know anybody named $opt\n" ;
goto END ;
}
my $ players = $ scores - > get_all_players ( $ channel ) ;
my @ rankings ;
foreach my $ key ( sort keys % ranks ) {
2015-12-23 02:21:04 +01:00
if ( $ key eq 'ratio' && $ player_data - > { lifetime_correct_answers } + $ player_data - > { lifetime_wrong_answers } < 50 ) {
my $ needed_answers = 50 - ( $ player_data - > { lifetime_correct_answers } + $ player_data - > { lifetime_wrong_answers } ) ;
push @ rankings , "$ranks{$key}->{title}: ($needed_answers more answers for rank)" ;
next ;
}
2015-02-13 23:39:20 +01:00
my $ sort_method = $ ranks { $ key } - > { sort } ;
@$ players = sort $ sort_method @$ players ;
my $ rank = 0 ;
2015-02-14 00:36:45 +01:00
my $ stats ;
2015-02-14 23:03:26 +01:00
my $ last_value = - 1 ;
2015-02-13 23:39:20 +01:00
foreach my $ player ( @$ players ) {
2015-05-21 16:35:04 +02:00
next if $ player - > { nick } eq 'lern2play' and $ opt ne 'lern2play' ;
next if $ player - > { nick } eq 'keep2play' and $ opt ne 'keep2play' ;
2015-05-23 11:27:08 +02:00
2015-02-14 00:36:45 +01:00
$ stats = $ ranks { $ key } - > { print } - > ( $ player ) ;
2015-05-23 11:27:08 +02:00
2015-02-14 23:03:26 +01:00
if ( defined $ stats ) {
my ( $ value ) = $ stats =~ /[^:]+:\s+(.*)/ ;
$ rank + + if $ value ne $ last_value ;
$ last_value = $ value ;
2015-05-23 11:27:08 +02:00
} else {
$ rank + + if lc $ player - > { nick } eq $ opt ;
2015-02-14 23:03:26 +01:00
}
2015-05-23 11:27:08 +02:00
2015-02-13 23:39:20 +01:00
last if lc $ player - > { nick } eq $ opt ;
}
2015-05-23 11:27:08 +02:00
if ( not $ rank ) {
push @ rankings , "$ranks{key}->{title}: N/A" ;
2015-02-13 23:39:20 +01:00
} else {
2015-05-23 11:27:08 +02:00
if ( not $ stats ) {
2015-12-23 02:21:04 +01:00
push @ rankings , "$ranks{$key}->{title}: N/A" ;
2015-05-23 11:27:08 +02:00
} else {
$ stats =~ s/[^:]+:\s+// ;
push @ rankings , "$ranks{$key}->{title}: #$rank ($stats)" ;
}
2015-02-13 23:39:20 +01:00
}
}
2015-02-14 00:36:45 +01:00
if ( lc $ nick ne $ opt ) {
2015-12-23 02:21:04 +01:00
print "$player_data->{nick}'s rankings: " ;
2015-02-14 00:36:45 +01:00
} else {
2015-12-23 02:21:04 +01:00
print "Your rankings: " ;
2015-02-14 00:36:45 +01:00
}
2015-02-13 23:39:20 +01:00
print join ', ' , @ rankings ;
print "\n" ;
2015-02-12 05:58:16 +01:00
goto END ;
}
my $ players = $ scores - > get_all_players ( $ channel ) ;
my $ sort_method = $ ranks { $ opt } - > { sort } ;
2015-02-13 23:39:20 +01:00
@$ players = sort $ sort_method @$ players ;
2015-02-12 05:58:16 +01:00
my @ ranking ;
2015-02-17 10:47:28 +01:00
my $ rank = 0 ;
my $ last_value = - 1 ;
2015-02-12 05:58:16 +01:00
foreach my $ player ( @$ players ) {
2015-05-21 16:35:04 +02:00
next if $ player - > { nick } eq 'lern2play' ;
2015-02-14 00:36:45 +01:00
next if $ player - > { nick } eq 'keep2play' ;
2015-02-12 05:58:16 +01:00
my $ entry = $ ranks { $ opt } - > { print } - > ( $ player ) ;
2015-02-17 10:47:28 +01:00
if ( defined $ entry ) {
my ( $ value ) = $ entry =~ /[^:]+:\s+(.*)/ ;
$ 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 ;
}
2015-02-12 05:58:16 +01:00
}
if ( not scalar @ ranking ) {
2015-05-23 11:27:08 +02:00
if ( $ offset > 1 ) {
2015-02-17 10:31:40 +01:00
print "No rankings available for $channel at offset #$offset.\n" ;
} else {
print "No rankings available for $channel yet.\n" ;
}
2015-02-12 05:58:16 +01:00
} else {
2015-02-14 00:36:45 +01:00
print "Rankings for $ranks{$opt}->{title}: " ;
2015-02-12 05:58:16 +01:00
print join ', ' , @ ranking ;
print "\n" ;
}
goto END ;
}
2015-01-28 22:11:04 +01:00
my $ player_nick = $ nick ;
2015-05-21 16:35:04 +02:00
$ player_nick = $ opt if $ opt and lc $ command eq 'score' ;
2015-01-28 22:11:04 +01:00
my $ player_id = $ scores - > get_player_id ( $ player_nick , $ channel , 1 ) ;
if ( not defined $ player_id ) {
print "I don't know anybody named $player_nick\n" ;
goto END ;
}
my $ player_data = $ scores - > get_player_data ( $ player_id ) ;
if ( lc $ command eq 'score' ) {
2015-05-21 16:35:04 +02:00
my $ score = "$player_data->{nick}: " unless lc $ nick eq lc $ player_nick ;
2015-01-28 22:11:04 +01:00
2015-05-21 16:35:04 +02:00
$ score . = "correct: $player_data->{correct_answers}" . ( $ player_data - > { lifetime_correct_answers } > $ player_data - > { correct_answers } ? " [$player_data->{lifetime_correct_answers}]" : "" ) . ", " ;
2015-05-25 20:34:43 +02:00
$ score . = "current correct streak: $player_data->{correct_streak}, " ;
$ score . = "highest correct streak: $player_data->{highest_correct_streak}" . ( $ player_data - > { lifetime_highest_correct_streak } > $ player_data - > { highest_correct_streak } ? " [$player_data->{lifetime_highest_correct_streak}]" : "" ) . ", " ;
$ score . = "quickest correct streak: " ;
$ score . = ( $ player_data - > { highest_quick_correct_streak } > 0 ? "$player_data->{highest_quick_correct_streak} in " . ( concise duration $ player_data - > { quickest_correct_streak } ) : "N/A" ) . ( $ player_data - > { lifetime_highest_quick_correct_streak } > $ player_data - > { highest_quick_correct_streak } ? " [$player_data->{lifetime_highest_quick_correct_streak} in " . ( concise duration $ player_data - > { lifetime_quickest_correct_streak } ) . "]" : "" ) . ", " ;
2015-01-28 22:11:04 +01:00
2015-05-21 16:35:04 +02:00
$ score . = "quickest answer: " ;
2015-02-01 01:41:05 +01:00
if ( $ player_data - > { quickest_correct } == 0 ) {
$ score . = "N/A" ;
} elsif ( $ player_data - > { quickest_correct } < 60 ) {
2015-05-25 20:34:43 +02:00
$ score . = sprintf ( "%.2fs" , $ player_data - > { quickest_correct } ) ;
2015-02-01 01:41:05 +01:00
} else {
2015-05-25 20:34:43 +02:00
$ score . = concise duration ( $ player_data - > { quickest_correct } ) ;
2015-02-01 01:41:05 +01:00
}
2015-05-21 16:35:04 +02:00
$ score . = ", " ;
2015-02-01 01:41:05 +01:00
2015-05-21 16:35:04 +02:00
$ score . = "wrong: $player_data->{wrong_answers}" . ( $ player_data - > { lifetime_wrong_answers } > $ player_data - > { wrong_answers } ? " [$player_data->{lifetime_wrong_answers}]" : "" ) . ", " ;
2015-05-25 20:34:43 +02:00
$ score . = "current wrong streak: $player_data->{wrong_streak}, " ;
$ score . = "highest wrong streak: $player_data->{highest_wrong_streak}" . ( $ player_data - > { lifetime_highest_wrong_streak } > $ player_data - > { highest_wrong_streak } ? " [$player_data->{lifetime_highest_wrong_streak}]" : "" ) . ", " ;
2015-05-25 20:27:24 +02:00
$ score . = "ratio: " ;
my $ wrong = $ player_data - > { wrong_answers } ? $ player_data - > { wrong_answers } : 1 ;
$ score . = sprintf ( "%.2f" , $ player_data - > { correct_answers } / $ wrong ) ;
if ( $ player_data - > { lifetime_correct_answers } > 0 ) {
$ wrong = $ player_data - > { lifetime_wrong_answers } ? $ player_data - > { lifetime_wrong_answers } : 1 ;
$ score . = sprintf ( " [%.2f]" , $ player_data - > { lifetime_correct_answers } / $ wrong ) ;
}
$ score . = ", " ;
2015-01-28 22:11:04 +01:00
2015-05-21 16:35:04 +02:00
$ score . = "hints: $player_data->{hints}" . ( $ player_data - > { lifetime_hints } > $ player_data - > { hints } ? " [$player_data->{lifetime_hints}]" : "" ) . "\n" ;
2015-01-28 22:11:04 +01:00
print $ score ;
} elsif ( lc $ command eq 'reset' ) {
2015-05-21 16:35:04 +02:00
$ player_data - > { correct_answers } = 0 ;
$ player_data - > { wrong_answers } = 0 ;
$ player_data - > { correct_streak } = 0 ;
$ player_data - > { wrong_streak } = 0 ;
$ player_data - > { highest_correct_streak } = 0 ;
$ player_data - > { highest_wrong_streak } = 0 ;
$ player_data - > { hints } = 0 ;
$ player_data - > { correct_streak_timestamp } = 0 ;
$ player_data - > { highest_quick_correct_streak } = 0 ;
$ player_data - > { quickest_correct_streak } = 0 ;
2015-01-28 22:11:04 +01:00
$ scores - > update_player_data ( $ player_id , $ player_data ) ;
print "Your scores for this session have been reset.\n" ;
}
END :
$ scores - > end ;