From 59b5f61de336b2e3dc117efdf5015c9ce3a84616 Mon Sep 17 00:00:00 2001 From: Pragmatic Software Date: Wed, 24 Apr 2019 23:04:09 -0700 Subject: [PATCH] Spinach: Rename Stats.pm and Statskeeper.pm --- PBot/Plugins/Spinach.pm | 9 +- PBot/Plugins/Spinach/Rank.pm | 215 +++++++++++++++++++ PBot/Plugins/Spinach/Stats.pm | 306 ++++++++++++---------------- PBot/Plugins/Spinach/Statskeeper.pm | 171 ---------------- 4 files changed, 351 insertions(+), 350 deletions(-) create mode 100644 PBot/Plugins/Spinach/Rank.pm delete mode 100644 PBot/Plugins/Spinach/Statskeeper.pm diff --git a/PBot/Plugins/Spinach.pm b/PBot/Plugins/Spinach.pm index 4cc7fd7a..96c9aa43 100644 --- a/PBot/Plugins/Spinach.pm +++ b/PBot/Plugins/Spinach.pm @@ -30,8 +30,8 @@ $Data::Dumper::Useqq = 1; use PBot::HashObject; -use PBot::Plugins::Spinach::Statskeeper; use PBot::Plugins::Spinach::Stats; +use PBot::Plugins::Spinach::Rank; sub new { Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref $_[1] eq 'HASH'; @@ -63,8 +63,8 @@ sub initialize { $self->{metadata} = PBot::HashObject->new(pbot => $self->{pbot}, name => 'Spinach Metadata', filename => $self->{metadata_filename}); $self->load_metadata; - $self->{stats} = PBot::Plugins::Spinach::Statskeeper->new(filename => $self->{stats_filename}); - $self->{statscmd} = PBot::Plugins::Spinach::Stats->new(pbot => $self->{pbot}, channel => $self->{channel}, filename => $self->{stats_filename}); + $self->{stats} = PBot::Plugins::Spinach::Stats->new(filename => $self->{stats_filename}); + $self->{rankcmd} = PBot::Plugins::Spinach::Rank->new(pbot => $self->{pbot}, channel => $self->{channel}, filename => $self->{stats_filename}); $self->create_states; $self->load_questions; @@ -854,7 +854,7 @@ sub spinach_cmd { } when ('rank') { - return $self->{statscmd}->rank($arguments); + return $self->{rankcmd}->rank($arguments); } default { @@ -2044,6 +2044,7 @@ sub showfinalscore { if ($i == 4) { $mentions = "Honorable mentions: $mentions"; } + $self->{stats}->update_player_data($player_id, $player_data); $i--; next; } elsif ($i == 3) { diff --git a/PBot/Plugins/Spinach/Rank.pm b/PBot/Plugins/Spinach/Rank.pm new file mode 100644 index 00000000..9724fafc --- /dev/null +++ b/PBot/Plugins/Spinach/Rank.pm @@ -0,0 +1,215 @@ +#!/usr/bin/env perl + +# 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/. + +package PBot::Plugins::Spinach::Rank; + +use warnings; +use strict; + +use FindBin; +use lib "$FindBin::RealBin/../../.."; + +use PBot::Plugins::Spinach::Stats; + +sub new { + Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref $_[1] eq 'HASH'; + my ($class, %conf) = @_; + my $self = bless {}, $class; + $self->initialize(%conf); + return $self; +} + +sub initialize { + my ($self, %conf) = @_; + $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); + $self->{channel} = $conf{channel} // Carp::croak("Missing channel reference to " . __FILE__); + $self->{filename} = $conf{filename} // 'stats.sqlite'; + $self->{stats} = PBot::Plugins::Spinach::Stats->new(filename => $self->{filename}); +} + +sub sort_generic { + my ($self, $key) = @_; + if ($self->{rank_direction} eq '+') { + return $b->{$key} <=> $a->{$key}; + } else { + return $a->{$key} <=> $b->{$key}; + } +} + +sub print_generic { + my ($self, $key, $player) = @_; + return undef if $player->{games_played} == 0; + return "$player->{nick}: $player->{$key}"; +} + +sub sort_bad_lies { + my ($self) = @_; + if ($self->{rank_direction} eq '+') { + return $b->{questions_played} - $b->{good_lies} <=> $a->{questions_played} - $a->{good_lies}; + } else { + return $a->{questions_played} - $a->{good_lies} <=> $b->{questions_played} - $b->{good_lies}; + } +} + +sub print_bad_lies { + my ($self, $player) = @_; + return undef if $player->{games_played} == 0; + my $result = $player->{questions_played} - $player->{good_lies}; + return "$player->{nick}: $result"; +} + +sub sort_mentions { + my ($self) = @_; + if ($self->{rank_direction} eq '+') { + return $b->{games_played} - $b->{times_first} - $b->{times_second} - $b->{times_third} <=> + $a->{games_played} - $a->{times_first} - $a->{times_second} - $a->{times_third}; + } else { + return $a->{games_played} - $a->{times_first} - $a->{times_second} - $a->{times_third} <=> + $b->{games_played} - $b->{times_first} - $b->{times_second} - $b->{times_third}; + } +} + +sub print_mentions { + my ($self, $player) = @_; + return undef if $player->{games_played} == 0; + my $result = $player->{games_played} - $player->{times_first} - $player->{times_second} - $player->{times_third}; + return "$player->{nick}: $result"; +} + +sub rank { + my ($self, $arguments) = @_; + + my %ranks = ( + highscore => { sort => sub { $self->sort_generic('high_score', @_) }, print => sub { $self->print_generic('high_score', @_) }, title => 'high score' }, + lowscore => { sort => sub { $self->sort_generic('low_score', @_) }, print => sub { $self->print_generic('low_score', @_) }, title => 'low score' }, + avgscore => { sort => sub { $self->sort_generic('avg_score', @_) }, print => sub { $self->print_generic('avg_score', @_) }, title => 'average score' }, + goodlies => { sort => sub { $self->sort_generic('good_lies', @_) }, print => sub { $self->print_generic('good_lies', @_) }, title => 'good lies' }, + badlies => { sort => sub { $self->sort_bad_lies(@_) }, print => sub { $self->print_bad_lies(@_) }, title => 'bad lies' }, + first => { sort => sub { $self->sort_generic('times_first', @_) }, print => sub { $self->print_generic('times_first', @_) }, title => 'first place' }, + second => { sort => sub { $self->sort_generic('times_second', @_) }, print => sub { $self->print_generic('times_second', @_) }, title => 'second place' }, + third => { sort => sub { $self->sort_generic('times_third', @_) }, print => sub { $self->print_generic('times_third', @_) }, title => 'third place' }, + mentions => { sort => sub { $self->sort_mentions(@_) }, print => sub { $self->print_mentions(@_) }, title => 'mentions' }, + games => { sort => sub { $self->sort_generic('games_played', @_) }, print => sub { $self->print_generic('games_played', @_) }, title => 'games played' }, + questions => { sort => sub { $self->sort_generic('questions_played', @_) }, print => sub { $self->print_generic('questions_played', @_) }, title => 'questions played' }, + goodguesses => { sort => sub { $self->sort_generic('good_guesses', @_) }, print => sub { $self->print_generic('good_guesses', @_) }, title => 'good guesses' }, + badguesses => { sort => sub { $self->sort_generic('bad_guesses', @_) }, print => sub { $self->print_generic('bad_guesses', @_) }, title => 'bad guesses' }, + deceptions => { sort => sub { $self->sort_generic('players_deceived', @_) }, print => sub { $self->print_generic('players_deceived', @_) }, title => 'players deceived' }, + ); + + my @order = qw/highscore lowscore avgscore first second third mentions games questions goodlies badlies deceptions goodguesses badguesses/; + + if (not $arguments) { + my $result = "Usage: rank [-] [offset] or rank [-]; available keywords: "; + $result .= join ', ', @order; + $result .= ".\n"; + $result .= "Prefix with a dash to invert sort.\n"; + return $result; + } + + $arguments = lc $arguments; + + if ($arguments =~ s/^([+-])//) { + $self->{rank_direction} = $1; + } else { + $self->{rank_direction} = '+'; + } + + my $offset = 1; + if ($arguments =~ s/\s+(\d+)$//) { + $offset = $1; + } + + if (not exists $ranks{$arguments}) { + $self->{stats}->begin; + my $player_id = $self->{stats}->get_player_id($arguments, $self->{channel}, 1); + my $player_data = $self->{stats}->get_player_data($player_id); + + if (not defined $player_id) { + $self->{stats}->end; + return "I don't know anybody named $arguments."; + } + + my $players = $self->{stats}->get_all_players($self->{channel}); + my @rankings; + + foreach my $key (@order) { + my $sort_method = $ranks{$key}->{sort}; + @$players = sort $sort_method @$players; + + my $rank = 0; + my $stats; + my $last_value = -1; + foreach my $player (@$players) { + $stats = $ranks{$key}->{print}->($player); + + if (defined $stats) { + my ($value) = $stats =~ /[^:]+:\s+(.*)/; + $rank++ if $value ne $last_value; + $last_value = $value; + } else { + $rank++ if lc $player->{nick} eq $arguments; + } + + last if lc $player->{nick} eq $arguments; + } + + if (not $rank) { + push @rankings, "$ranks{key}->{title}: N/A"; + } else { + if (not $stats) { + push @rankings, "$ranks{$key}->{title}: N/A"; + } else { + $stats =~ s/[^:]+:\s+//; + push @rankings, "$ranks{$key}->{title}: #$rank ($stats)"; + } + } + } + + my $result = "$player_data->{nick}'s rankings: "; + $result .= join ', ', @rankings; + $self->{stats}->end; + return $result; + } + + $self->{stats}->begin; + my $players = $self->{stats}->get_all_players($self->{channel}); + + my $sort_method = $ranks{$arguments}->{sort}; + @$players = sort $sort_method @$players; + + my @ranking; + my $rank = 0; + my $last_value = -1; + foreach my $player (@$players) { + my $entry = $ranks{$arguments}->{print}->($player); + 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; + } + } + + my $result; + + if (not scalar @ranking) { + if ($offset > 1) { + $result = "No rankings available for $self->{channel} at offset #$offset.\n"; + } else { + $result = "No rankings available for $self->{channel} yet.\n"; + } + } else { + $result = "Rankings for $ranks{$arguments}->{title}: "; + $result .= join ', ', @ranking; + } + + $self->{stats}->end; + return $result; +} + +1; diff --git a/PBot/Plugins/Spinach/Stats.pm b/PBot/Plugins/Spinach/Stats.pm index 7d7aa220..22a03f92 100644 --- a/PBot/Plugins/Spinach/Stats.pm +++ b/PBot/Plugins/Spinach/Stats.pm @@ -9,13 +9,12 @@ package PBot::Plugins::Spinach::Stats; use warnings; use strict; -use FindBin; -use lib "$FindBin::RealBin/../../.."; +use DBI; +use Carp qw(shortmess); -use PBot::Plugins::Spinach::Statskeeper; +my $debug = 0; sub new { - Carp::croak("Options to " . __FILE__ . " should be key/value pairs, not hash reference") if ref $_[1] eq 'HASH'; my ($class, %conf) = @_; my $self = bless {}, $class; $self->initialize(%conf); @@ -24,192 +23,149 @@ sub new { sub initialize { my ($self, %conf) = @_; - $self->{pbot} = $conf{pbot} // Carp::croak("Missing pbot reference to " . __FILE__); - $self->{channel} = $conf{channel} // Carp::croak("Missing channel reference to " . __FILE__); $self->{filename} = $conf{filename} // 'stats.sqlite'; - $self->{stats} = PBot::Plugins::Spinach::Statskeeper->new(filename => $self->{filename}); } -sub sort_generic { - my ($self, $key) = @_; - if ($self->{rank_direction} eq '+') { - return $b->{$key} <=> $a->{$key}; - } else { - return $a->{$key} <=> $b->{$key}; +sub begin { + my $self = shift; + + print STDERR "Opening stats SQLite database: $self->{filename}\n" if $debug; + + $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$self->{filename}", "", "", { RaiseError => 1, PrintError => 0 }) or die $DBI::errstr; + + eval { + $self->{dbh}->do(<< 'SQL'); +CREATE TABLE IF NOT EXISTS Stats ( + id INTEGER PRIMARY KEY, + nick TEXT NOT NULL COLLATE NOCASE, + channel TEXT NOT NULL COLLATE NOCASE, + high_score INTEGER DEFAULT 0, + low_score INTEGER DEFAULT 0, + avg_score INTEGER DEFAULT 0, + times_first INTEGER DEFAULT 0, + times_second INTEGER DEFAULT 0, + times_third INTEGER DEFAULT 0, + good_lies INTEGER DEFAULT 0, + players_deceived INTEGER DEFAULT 0, + questions_played INTEGER DEFAULT 0, + games_played INTEGER DEFAULT 0, + good_guesses INTEGER DEFAULT 0, + bad_guesses INTEGER DEFAULT 0 +) +SQL + }; + + print STDERR $@ if $@; +} + +sub end { + my $self = shift; + + print STDERR "Closing stats SQLite database\n" if $debug; + + if(exists $self->{dbh} and defined $self->{dbh}) { + $self->{dbh}->disconnect(); + delete $self->{dbh}; } } -sub print_generic { - my ($self, $key, $player) = @_; - return undef if $player->{games_played} == 0; - return "$player->{nick}: $player->{$key}"; +sub add_player { + my ($self, $nick, $channel) = @_; + + my $id = eval { + my $sth = $self->{dbh}->prepare('INSERT INTO Stats (nick, channel) VALUES (?, ?)'); + $sth->bind_param(1, $nick) ; + $sth->bind_param(2, $channel) ; + $sth->execute(); + return $self->{dbh}->sqlite_last_insert_rowid(); + }; + + print STDERR $@ if $@; + return $id; } -sub sort_bad_lies { - my ($self) = @_; - if ($self->{rank_direction} eq '+') { - return $b->{questions_played} - $b->{good_lies} <=> $a->{questions_played} - $a->{good_lies}; - } else { - return $a->{questions_played} - $a->{good_lies} <=> $b->{questions_played} - $b->{good_lies}; - } +sub get_player_id { + my ($self, $nick, $channel, $dont_create_new) = @_; + + my $id = eval { + my $sth = $self->{dbh}->prepare('SELECT id FROM Stats WHERE nick = ? AND channel = ?'); + $sth->bind_param(1, $nick); + $sth->bind_param(2, $channel); + $sth->execute(); + my $row = $sth->fetchrow_hashref(); + return $row->{id}; + }; + + print STDERR $@ if $@; + + $id = $self->add_player($nick, $channel) if not defined $id and not $dont_create_new; + return $id; } -sub print_bad_lies { - my ($self, $player) = @_; - return undef if $player->{games_played} == 0; - my $result = $player->{questions_played} - $player->{good_lies}; - return "$player->{nick}: $result"; -} +sub get_player_data { + my ($self, $id, @columns) = @_; -sub sort_mentions { - my ($self) = @_; - if ($self->{rank_direction} eq '+') { - return $b->{games_played} - $b->{times_first} - $b->{times_second} - $b->{times_third} <=> - $a->{games_played} - $a->{times_first} - $a->{times_second} - $a->{times_third}; - } else { - return $a->{games_played} - $a->{times_first} - $a->{times_second} - $a->{times_third} <=> - $b->{games_played} - $b->{times_first} - $b->{times_second} - $b->{times_third}; - } -} + my $player_data = eval { + my $sql = 'SELECT '; -sub print_mentions { - my ($self, $player) = @_; - return undef if $player->{games_played} == 0; - my $result = $player->{games_played} - $player->{times_first} - $player->{times_second} - $player->{times_third}; - return "$player->{nick}: $result"; -} - -sub rank { - my ($self, $arguments) = @_; - - my %ranks = ( - highscores => { sort => sub { $self->sort_generic('high_score', @_) }, print => sub { $self->print_generic('high_score', @_) }, title => 'high scores' }, - lowscores => { sort => sub { $self->sort_generic('low_score', @_) }, print => sub { $self->print_generic('low_score', @_) }, title => 'low scores' }, - avgscores => { sort => sub { $self->sort_generic('avg_score', @_) }, print => sub { $self->print_generic('avg_score', @_) }, title => 'average scores' }, - goodlies => { sort => sub { $self->sort_generic('good_lies', @_) }, print => sub { $self->print_generic('good_lies', @_) }, title => 'good lies' }, - badlies => { sort => sub { $self->sort_bad_lies(@_) }, print => sub { $self->print_bad_lies(@_) }, title => 'bad lies' }, - first => { sort => sub { $self->sort_generic('times_first', @_) }, print => sub { $self->print_generic('times_first', @_) }, title => 'first place' }, - second => { sort => sub { $self->sort_generic('times_second', @_) }, print => sub { $self->print_generic('times_second', @_) }, title => 'second place' }, - third => { sort => sub { $self->sort_generic('times_third', @_) }, print => sub { $self->print_generic('times_third', @_) }, title => 'third place' }, - mentions => { sort => sub { $self->sort_mentions(@_) }, print => sub { $self->print_mentions(@_) }, title => 'mentions' }, - games => { sort => sub { $self->sort_generic('games_played', @_) }, print => sub { $self->print_generic('games_played', @_) }, title => 'games played' }, - questions => { sort => sub { $self->sort_generic('questions_played', @_) }, print => sub { $self->print_generic('questions_played', @_) }, title => 'questions played' }, - goodguesses => { sort => sub { $self->sort_generic('good_guesses', @_) }, print => sub { $self->print_generic('good_guesses', @_) }, title => 'good guesses' }, - badguesses => { sort => sub { $self->sort_generic('bad_guesses', @_) }, print => sub { $self->print_generic('bad_guesses', @_) }, title => 'bad guesses' }, - deceptions => { sort => sub { $self->sort_generic('players_deceived', @_) }, print => sub { $self->print_generic('players_deceived', @_) }, title => 'players deceived' }, - ); - - my @order = qw/highscores lowscores avgscores first second third mentions games questions goodlies badlies deceptions goodguesses badguesses/; - - if (not $arguments) { - my $result = "Usage: rank [-] [offset] or rank [-]; available keywords: "; - $result .= join ', ', @order; - $result .= ".\n"; - $result .= "Prefix with a dash to invert sort.\n"; - return $result; - } - - $arguments = lc $arguments; - - if ($arguments =~ s/^([+-])//) { - $self->{rank_direction} = $1; - } else { - $self->{rank_direction} = '+'; - } - - my $offset = 1; - if ($arguments =~ s/\s+(\d+)$//) { - $offset = $1; - } - - if (not exists $ranks{$arguments}) { - $self->{stats}->begin; - my $player_id = $self->{stats}->get_player_id($arguments, $self->{channel}, 1); - my $player_data = $self->{stats}->get_player_data($player_id); - - if (not defined $player_id) { - $self->{stats}->end; - return "I don't know anybody named $arguments."; - } - - my $players = $self->{stats}->get_all_players($self->{channel}); - my @rankings; - - foreach my $key (@order) { - my $sort_method = $ranks{$key}->{sort}; - @$players = sort $sort_method @$players; - - my $rank = 0; - my $stats; - my $last_value = -1; - foreach my $player (@$players) { - $stats = $ranks{$key}->{print}->($player); - - if (defined $stats) { - my ($value) = $stats =~ /[^:]+:\s+(.*)/; - $rank++ if $value ne $last_value; - $last_value = $value; - } else { - $rank++ if lc $player->{nick} eq $arguments; - } - - last if lc $player->{nick} eq $arguments; - } - - if (not $rank) { - push @rankings, "$ranks{key}->{title}: N/A"; - } else { - if (not $stats) { - push @rankings, "$ranks{$key}->{title}: N/A"; - } else { - $stats =~ s/[^:]+:\s+//; - push @rankings, "$ranks{$key}->{title}: #$rank ($stats)"; - } - } - } - - my $result = "$player_data->{nick}'s rankings: "; - $result .= join ', ', @rankings; - $self->{stats}->end; - return $result; - } - - $self->{stats}->begin; - my $players = $self->{stats}->get_all_players($self->{channel}); - - my $sort_method = $ranks{$arguments}->{sort}; - @$players = sort $sort_method @$players; - - my @ranking; - my $rank = 0; - my $last_value = -1; - foreach my $player (@$players) { - my $entry = $ranks{$arguments}->{print}->($player); - 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; - } - } - - my $result; - - if (not scalar @ranking) { - if ($offset > 1) { - $result = "No rankings available for $self->{channel} at offset #$offset.\n"; + if(not @columns) { + $sql .= '*'; } else { - $result = "No rankings available for $self->{channel} yet.\n"; + my $comma = ''; + foreach my $column (@columns) { + $sql .= "$comma$column"; + $comma = ', '; + } } - } else { - $result = "Rankings for $ranks{$arguments}->{title}: "; - $result .= join ', ', @ranking; - } - $self->{stats}->end; - return $result; + $sql .= ' FROM Stats WHERE id = ?'; + my $sth = $self->{dbh}->prepare($sql); + $sth->bind_param(1, $id); + $sth->execute(); + return $sth->fetchrow_hashref(); + }; + print STDERR $@ if $@; + return $player_data; +} + +sub update_player_data { + my ($self, $id, $data) = @_; + + eval { + my $sql = 'UPDATE Stats SET '; + + my $comma = ''; + foreach my $key (keys %$data) { + $sql .= "$comma$key = ?"; + $comma = ', '; + } + + $sql .= ' WHERE id = ?'; + + my $sth = $self->{dbh}->prepare($sql); + + my $param = 1; + foreach my $key (keys %$data) { + $sth->bind_param($param++, $data->{$key}); + } + + $sth->bind_param($param, $id); + $sth->execute(); + }; + print STDERR $@ if $@; +} + +sub get_all_players { + my ($self, $channel) = @_; + + my $players = eval { + my $sth = $self->{dbh}->prepare('SELECT * FROM Stats WHERE channel = ?'); + $sth->bind_param(1, $channel); + $sth->execute(); + return $sth->fetchall_arrayref({}); + }; + print STDERR $@ if $@; + return $players; } 1; diff --git a/PBot/Plugins/Spinach/Statskeeper.pm b/PBot/Plugins/Spinach/Statskeeper.pm deleted file mode 100644 index 3c4d16d4..00000000 --- a/PBot/Plugins/Spinach/Statskeeper.pm +++ /dev/null @@ -1,171 +0,0 @@ -#!/usr/bin/env perl - -# 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/. - -package PBot::Plugins::Spinach::Statskeeper; - -use warnings; -use strict; - -use DBI; -use Carp qw(shortmess); - -my $debug = 0; - -sub new { - my ($class, %conf) = @_; - my $self = bless {}, $class; - $self->initialize(%conf); - return $self; -} - -sub initialize { - my ($self, %conf) = @_; - $self->{filename} = $conf{filename} // 'stats.sqlite'; -} - -sub begin { - my $self = shift; - - print STDERR "Opening stats SQLite database: $self->{filename}\n" if $debug; - - $self->{dbh} = DBI->connect("dbi:SQLite:dbname=$self->{filename}", "", "", { RaiseError => 1, PrintError => 0 }) or die $DBI::errstr; - - eval { - $self->{dbh}->do(<< 'SQL'); -CREATE TABLE IF NOT EXISTS Stats ( - id INTEGER PRIMARY KEY, - nick TEXT NOT NULL COLLATE NOCASE, - channel TEXT NOT NULL COLLATE NOCASE, - high_score INTEGER DEFAULT 0, - low_score INTEGER DEFAULT 0, - avg_score INTEGER DEFAULT 0, - times_first INTEGER DEFAULT 0, - times_second INTEGER DEFAULT 0, - times_third INTEGER DEFAULT 0, - good_lies INTEGER DEFAULT 0, - players_deceived INTEGER DEFAULT 0, - questions_played INTEGER DEFAULT 0, - games_played INTEGER DEFAULT 0, - good_guesses INTEGER DEFAULT 0, - bad_guesses INTEGER DEFAULT 0 -) -SQL - }; - - print STDERR $@ if $@; -} - -sub end { - my $self = shift; - - print STDERR "Closing stats SQLite database\n" if $debug; - - if(exists $self->{dbh} and defined $self->{dbh}) { - $self->{dbh}->disconnect(); - delete $self->{dbh}; - } -} - -sub add_player { - my ($self, $nick, $channel) = @_; - - my $id = eval { - my $sth = $self->{dbh}->prepare('INSERT INTO Stats (nick, channel) VALUES (?, ?)'); - $sth->bind_param(1, $nick) ; - $sth->bind_param(2, $channel) ; - $sth->execute(); - return $self->{dbh}->sqlite_last_insert_rowid(); - }; - - print STDERR $@ if $@; - return $id; -} - -sub get_player_id { - my ($self, $nick, $channel, $dont_create_new) = @_; - - my $id = eval { - my $sth = $self->{dbh}->prepare('SELECT id FROM Stats WHERE nick = ? AND channel = ?'); - $sth->bind_param(1, $nick); - $sth->bind_param(2, $channel); - $sth->execute(); - my $row = $sth->fetchrow_hashref(); - return $row->{id}; - }; - - print STDERR $@ if $@; - - $id = $self->add_player($nick, $channel) if not defined $id and not $dont_create_new; - return $id; -} - -sub get_player_data { - my ($self, $id, @columns) = @_; - - my $player_data = eval { - my $sql = 'SELECT '; - - if(not @columns) { - $sql .= '*'; - } else { - my $comma = ''; - foreach my $column (@columns) { - $sql .= "$comma$column"; - $comma = ', '; - } - } - - $sql .= ' FROM Stats WHERE id = ?'; - my $sth = $self->{dbh}->prepare($sql); - $sth->bind_param(1, $id); - $sth->execute(); - return $sth->fetchrow_hashref(); - }; - print STDERR $@ if $@; - return $player_data; -} - -sub update_player_data { - my ($self, $id, $data) = @_; - - eval { - my $sql = 'UPDATE Stats SET '; - - my $comma = ''; - foreach my $key (keys %$data) { - $sql .= "$comma$key = ?"; - $comma = ', '; - } - - $sql .= ' WHERE id = ?'; - - my $sth = $self->{dbh}->prepare($sql); - - my $param = 1; - foreach my $key (keys %$data) { - $sth->bind_param($param++, $data->{$key}); - } - - $sth->bind_param($param, $id); - $sth->execute(); - }; - print STDERR $@ if $@; -} - -sub get_all_players { - my ($self, $channel) = @_; - - my $players = eval { - my $sth = $self->{dbh}->prepare('SELECT * FROM Stats WHERE channel = ?'); - $sth->bind_param(1, $channel); - $sth->execute(); - return $sth->fetchall_arrayref({}); - }; - print STDERR $@ if $@; - return $players; -} - -1;