pbot/modules/cjeopardy/cjeopardy.pl

213 lines
5.3 KiB
Perl
Raw Normal View History

2014-07-28 06:29:05 +02:00
#!/usr/bin/env perl
2021-07-11 00:00:22 +02:00
# SPDX-FileCopyrightText: 2021 Pragmatic Software <pragma78@gmail.com>
# SPDX-License-Identifier: MIT
License project under MPL2 This patch adds the file LICENSE which is the verbatim copy of the Mozilla Public License Version 2.0 as retreived from https://www.mozilla.org/media/MPL/2.0/index.815ca599c9df.txt on 2017-03-05. This patch also places license headers for the MPL2 type A variant of the license header in the following files: PBot/AntiFlood.pm PBot/BanTracker.pm PBot/BlackList.pm PBot/BotAdminCommands.pm PBot/BotAdmins.pm PBot/ChanOpCommands.pm PBot/ChanOps.pm PBot/Channels.pm PBot/Commands.pm PBot/DualIndexHashObject.pm PBot/EventDispatcher.pm PBot/FactoidCommands.pm PBot/FactoidModuleLauncher.pm PBot/Factoids.pm PBot/HashObject.pm PBot/IRCHandlers.pm PBot/IgnoreList.pm PBot/IgnoreListCommands.pm PBot/Interpreter.pm PBot/LagChecker.pm PBot/Logger.pm PBot/MessageHistory.pm PBot/MessageHistory_SQLite.pm PBot/NickList.pm PBot/PBot.pm PBot/Plugins.pm PBot/Plugins/AntiAway.pm PBot/Plugins/AntiKickAutoRejoin.pm PBot/Plugins/AntiRepeat.pm PBot/Plugins/AntiTwitter.pm PBot/Plugins/AutoRejoin.pm PBot/Plugins/Counter.pm PBot/Plugins/Quotegrabs.pm PBot/Plugins/Quotegrabs/Quotegrabs_Hashtable.pm PBot/Plugins/Quotegrabs/Quotegrabs_SQLite.pm PBot/Plugins/UrlTitles.pm PBot/Plugins/_Example.pm PBot/Refresher.pm PBot/Registerable.pm PBot/Registry.pm PBot/RegistryCommands.pm PBot/SQLiteLogger.pm PBot/SQLiteLoggerLayer.pm PBot/SelectHandler.pm PBot/StdinReader.pm PBot/Timer.pm PBot/Utils/ParseDate.pm PBot/VERSION.pm build/update-version.pl modules/acronym.pl modules/ago.pl modules/c11std.pl modules/c2english.pl modules/c2english/CGrammar.pm modules/c2english/c2eng.pl modules/c99std.pl modules/cdecl.pl modules/cfaq.pl modules/cjeopardy/IRCColors.pm modules/cjeopardy/QStatskeeper.pm modules/cjeopardy/Scorekeeper.pm modules/cjeopardy/cjeopardy.pl modules/cjeopardy/cjeopardy_answer.pl modules/cjeopardy/cjeopardy_filter.pl modules/cjeopardy/cjeopardy_hint.pl modules/cjeopardy/cjeopardy_qstats.pl modules/cjeopardy/cjeopardy_scores.pl modules/cjeopardy/cjeopardy_show.pl modules/codepad.pl modules/compiler_block.pl modules/compiler_client.pl modules/compiler_vm/Diff.pm modules/compiler_vm/cc modules/compiler_vm/compiler_client.pl modules/compiler_vm/compiler_server.pl modules/compiler_vm/compiler_server_vbox_win32.pl modules/compiler_vm/compiler_server_watchdog.pl modules/compiler_vm/compiler_vm_client.pl modules/compiler_vm/compiler_vm_server.pl modules/compiler_vm/compiler_watchdog.pl modules/compiler_vm/languages/_c_base.pm modules/compiler_vm/languages/_default.pm modules/compiler_vm/languages/bash.pm modules/compiler_vm/languages/bc.pm modules/compiler_vm/languages/bf.pm modules/compiler_vm/languages/c11.pm modules/compiler_vm/languages/c89.pm modules/compiler_vm/languages/c99.pm modules/compiler_vm/languages/clang.pm modules/compiler_vm/languages/clang11.pm modules/compiler_vm/languages/clang89.pm modules/compiler_vm/languages/clang99.pm modules/compiler_vm/languages/clangpp.pm modules/compiler_vm/languages/clisp.pm modules/compiler_vm/languages/cpp.pm modules/compiler_vm/languages/freebasic.pm modules/compiler_vm/languages/go.pm modules/compiler_vm/languages/haskell.pm modules/compiler_vm/languages/java.pm modules/compiler_vm/languages/javascript.pm modules/compiler_vm/languages/ksh.pm modules/compiler_vm/languages/lua.pm modules/compiler_vm/languages/perl.pm modules/compiler_vm/languages/python.pm modules/compiler_vm/languages/python3.pm modules/compiler_vm/languages/qbasic.pm modules/compiler_vm/languages/scheme.pm modules/compiler_vm/languages/server/_c_base.pm modules/compiler_vm/languages/server/_default.pm modules/compiler_vm/languages/server/c11.pm modules/compiler_vm/languages/server/c89.pm modules/compiler_vm/languages/server/c99.pm modules/compiler_vm/languages/server/clang.pm modules/compiler_vm/languages/server/clang11.pm modules/compiler_vm/languages/server/clang89.pm modules/compiler_vm/languages/server/clang99.pm modules/compiler_vm/languages/server/cpp.pm modules/compiler_vm/languages/server/freebasic.pm modules/compiler_vm/languages/server/haskell.pm modules/compiler_vm/languages/server/java.pm modules/compiler_vm/languages/server/qbasic.pm modules/compiler_vm/languages/server/tendra.pm modules/compiler_vm/languages/sh.pm modules/compiler_vm/languages/tendra.pm modules/compliment modules/cstd.pl modules/define.pl modules/dice_roll.pl modules/excuse.sh modules/expand_macros.pl modules/fnord.pl modules/funnyish_quote.pl modules/g.pl modules/gdefine.pl modules/gen_cfacts.pl modules/gencstd.pl modules/get_title.pl modules/getcfact.pl modules/google.pl modules/gspy.pl modules/gtop10.pl modules/gtop15.pl modules/headlines.pl modules/horoscope modules/horrorscope modules/ideone.pl modules/insult.pl modules/love_quote.pl modules/man.pl modules/map.pl modules/math.pl modules/prototype.pl modules/qalc.pl modules/random_quote.pl modules/seen.pl modules/urban modules/weather.pl modules/wikipedia.pl pbot.pl pbot.sh It is highly recommended that this list of files is reviewed to ensure that all files are the copyright of the sole maintainer of the repository. If any files with license headers contain the intellectual property of anyone else, it is recommended that a request is made to revise this patch or that the explicit permission of the co-author is gained to allow for the license of the work to be changed. I (Tomasz Kramkowski), the contributor, take no responsibility for any legal action taken against the maintainer of this repository for incorrectly claiming copyright to any work not owned by the maintainer of this repository.
2017-03-05 22:33:31 +01:00
2014-07-28 06:29:05 +02:00
use warnings;
use strict;
use Time::HiRes qw/gettimeofday/;
use Time::Duration qw/duration/;
use Fcntl qw(:flock);
2014-07-28 06:29:05 +02:00
use lib ".";
use IRCColors;
2015-05-23 11:27:53 +02:00
use QStatskeeper;
my $CJEOPARDY_FILE = 'cjeopardy.txt';
my $CJEOPARDY_DATA = 'data/cjeopardy.dat';
my $CJEOPARDY_FILTER = 'data/cjeopardy.filter';
my $CJEOPARDY_HINT = 'data/cjeopardy.hint';
my $CJEOPARDY_SHUFFLE = 'data/cjeopardy.shuffle';
2014-07-28 06:29:05 +02:00
my $TIMELIMIT = 300;
2014-07-28 06:29:05 +02:00
my $channel = shift @ARGV;
my $text = join(' ', @ARGV);
sub encode { my $str = shift; $str =~ s/\\(.)/{sprintf "\\%03d", ord($1)}/ge; return $str; }
sub decode { my $str = shift; $str =~ s/\\(\d{3})/{"\\" . chr($1)}/ge; return $str }
2014-07-28 06:29:05 +02:00
if ($channel !~ /^#/) {
print "Sorry, C Jeopardy must be played in a channel. Feel free to join #cjeopardy.\n";
2014-07-28 06:29:05 +02:00
exit;
}
open my $semaphore, ">", "$CJEOPARDY_DATA-$channel.lock" or die "Couldn't create semaphore lock: $!";
flock $semaphore, LOCK_EX;
my $ret = open my $fh, "<", "$CJEOPARDY_DATA-$channel";
if (defined $ret) {
my $last_question = <$fh>;
my $last_answer = <$fh>;
my $last_timestamp = <$fh>;
2019-06-26 18:34:19 +02:00
if (scalar gettimeofday - $last_timestamp <= $TIMELIMIT) {
my $duration = duration($TIMELIMIT - scalar gettimeofday - $last_timestamp);
2015-01-31 03:40:19 +01:00
print "$color{magneta}The current question is$color{reset}: $last_question";
print "$color{red}You may request a new question in $duration.$color{reset}\n";
close $fh;
exit;
}
close $fh;
}
my $filter_regex;
my $filter_text;
$ret = open $fh, "<", "$CJEOPARDY_FILTER-$channel";
if (defined $ret) {
my $words = <$fh>;
close $fh;
chomp $words;
$filter_text = $words;
$filter_text =~ s/,/, /g;
$filter_text =~ s/, ([^,]+)$/ or $1/;
2017-06-08 04:31:07 +02:00
# print "[Filter active!]\n";
my @w = split /,/, $words;
my $sep = '';
$filter_regex .= '(?:';
foreach my $word (@w) {
$filter_regex .= $sep;
$filter_regex .= $word =~ m/^[a-zA-Z0-9]/ ? '\b' : '\B';
$filter_regex .= quotemeta $word;
$filter_regex .= $word =~ m/[a-zA-Z0-9]$/ ? '\b' : '\B';
$sep = '|';
}
$filter_regex .= ')';
}
my $question_index;
my $shuffles = 0;
NEXT_QUESTION:
if (not length $text) {
$ret = open $fh, "<", "$CJEOPARDY_SHUFFLE-$channel";
if (defined $ret) {
my @indices = <$fh>;
$question_index = shift @indices;
close $fh;
if (not @indices) {
print "$color{teal}(Shuffling.)$color{reset}\n";
shuffle_questions(0);
$shuffles++;
} else {
open my $fh, ">", "$CJEOPARDY_SHUFFLE-$channel" or print "Failed to shuffle questions.\n" and exit;
foreach my $index (@indices) {
print $fh $index;
}
close $fh;
}
} else {
print "$color{teal}(Shuffling!)$color{reset}\n";
$question_index = shuffle_questions(1);
$shuffles++;
}
}
2014-07-28 06:29:05 +02:00
my @questions;
open $fh, "<", $CJEOPARDY_FILE or die "Could not open $CJEOPARDY_FILE: $!";
2014-07-28 06:29:05 +02:00
while (my $question = <$fh>) {
my ($question_only) = map { decode $_ } split /\|/, encode($question), 2;
$question_only =~ s/\\\|/|/g;
2014-07-28 06:29:05 +02:00
next if length $text and $question_only !~ /\Q$text\E/i;
next if defined $filter_regex and $question_only =~ /$filter_regex/i;
2014-07-28 06:29:05 +02:00
push @questions, $question;
}
close $fh;
if (not @questions) {
if (length $text) {
print "No questions containing '$text' found.\n";
} else {
if ($shuffles <= 1) {
goto NEXT_QUESTION;
} else {
print "No questions available.\n";
}
}
2014-07-28 06:29:05 +02:00
exit;
}
if (length $text) {
$question_index = int rand(@questions);
}
my $question = $questions[$question_index];
2014-07-28 06:29:05 +02:00
if (not defined $question) {
goto NEXT_QUESTION;
}
my ($q, $a) = map { decode $_ } split /\|/, encode($question), 2;
2014-07-28 06:29:05 +02:00
chomp $q;
chomp $a;
$q =~ s/\\\|/|/g;
2015-05-23 11:27:53 +02:00
$q =~ s/^(\d+)\) \[.*?\]\s+/$1) /;
my $id = $1;
$q =~ s/\b(this keyword|this operator|this behavior|this preprocessing directive|this escape sequence|this mode|this function specifier|this function|this macro|this predefined macro|this header|this pragma|this fprintf length modifier|this storage duration|this type qualifier|this type|this value|this operand|this many|this|these)\b/$color{bold}$1$color{reset}/gi;
2014-07-28 06:29:05 +02:00
print "$q\n";
open $fh, ">", "$CJEOPARDY_DATA-$channel" or die "Could not open $CJEOPARDY_DATA-$channel: $!";
print $fh "$q\n";
2014-07-28 06:29:05 +02:00
print $fh "$a\n";
print $fh scalar gettimeofday, "\n";
2014-07-28 06:29:05 +02:00
close $fh;
unlink "$CJEOPARDY_HINT-$channel";
2015-05-23 11:27:53 +02:00
my $qstats = QStatskeeper->new;
$qstats->begin;
my $qdata = $qstats->get_question_data($id);
$qdata->{asked_count}++;
$qdata->{last_asked} = gettimeofday;
$qdata->{last_touched} = gettimeofday;
$qdata->{wrong_streak} = 0;
$qstats->update_question_data($id, $qdata);
$qstats->end;
close $semaphore;
=cut
my $hint = `./cjeopardy_hint.pl candide $channel`;
print $hint;
=cut
sub shuffle_questions {
my $return_index = shift @_;
open my $fh, "<", $CJEOPARDY_FILE or die "Could not open $CJEOPARDY_FILE: $!";
my (@indices, $i);
while (<$fh>) {
push @indices, $i++;
}
close $fh;
open $fh, ">", "$CJEOPARDY_SHUFFLE-$channel" or die "Could not open $CJEOPARDY_SHUFFLE-$channel: $!";
while (@indices) {
my $random_index = int rand(@indices);
my $index = $indices[$random_index];
print $fh "$index\n";
splice @indices, $random_index, 1;
if ($return_index and @indices == 1) {
close $fh;
return $indices[0];
}
}
close $fh;
}