Plugin/Wordle: colorize ouput and add wordlists

This commit is contained in:
Pragmatic Software 2024-03-16 16:14:07 -07:00
parent c62b4d1c35
commit bde06990fe
No known key found for this signature in database
GPG Key ID: CC916B6E3C84ECCE
10 changed files with 1141643 additions and 56 deletions

63737
data/wordle/american Normal file

File diff suppressed because it is too large Load Diff

429393
data/wordle/american-insane Normal file

File diff suppressed because it is too large Load Diff

63363
data/wordle/british Normal file

File diff suppressed because it is too large Load Diff

63698
data/wordle/canadian Normal file

File diff suppressed because it is too large Load Diff

200095
data/wordle/french Normal file

File diff suppressed because it is too large Load Diff

150689
data/wordle/german Normal file

File diff suppressed because it is too large Load Diff

101975
data/wordle/italian Normal file

File diff suppressed because it is too large Load Diff

68589
data/wordle/spanish Normal file

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,8 @@ sub initialize($self, %conf) {
help => 'Wordle game! Guess target word by submitting words for clues about which letters belong to the word!',
subref => sub { $self->wordle(@_) },
);
$self->{datadir} = $self->{pbot}->{registry}->get_value('general', 'data_dir');
}
sub unload($self) {
@ -24,17 +26,42 @@ sub unload($self) {
}
use constant {
USAGE => 'Usage: wordle start [word length] | custom <word> <channel> | guess <word> | letters | show | giveup',
USAGE => 'Usage: wordle start [length [wordlist]] | custom <word> <channel> [wordlist] | guess <word> | letters | show | giveup',
NO_WORDLE => 'There is no Wordle yet. Use `wordle start` to begin a game.',
DEFAULT_LENGTH => 5,
MIN_LENGTH => 3,
MAX_LENGTH => 10,
WORDLIST => '/usr/share/dict/words',
MIN_LENGTH => 3,
MAX_LENGTH => 22,
LETTER_CORRECT => 1,
LETTER_PRESENT => 2,
LETTER_INVALID => 3,
};
my %wordlists = (
default => '/wordle/american',
american => '/wordle/american',
insane => '/wordle/american-insane',
british => '/wordle/british',
canadian => '/wordle/canadian',
french => '/wordle/french',
german => '/wordle/german',
italian => '/wordle/italian',
spanish => '/wordle/spanish',
);
my %color = (
correct => "\x0301,03",
correct_a => "\x0303,03",
present => "\x0301,07",
present_a => "\x0307,07",
invalid => "\x0301,15",
reset => "\x0F",
);
sub wordle($self, $context) {
my @args = $self->{pbot}->{interpreter}->split_line($context->{arguments});
@ -52,7 +79,7 @@ sub wordle($self, $context) {
return NO_WORDLE;
}
return $self->show_wordle($channel);
return $self->show_wordle($channel, 1);
}
when ('giveup') {
@ -67,8 +94,8 @@ sub wordle($self, $context) {
}
when ('start') {
if (@args > 1) {
return "Invalid arguments; Usage: wordle start [word length]";
if (@args > 2) {
return "Invalid arguments; Usage: wordle start [word length [wordlist]]";
}
if (defined $self->{$channel}->{wordle} && $self->{$channel}->{correct} == 0) {
@ -85,17 +112,24 @@ sub wordle($self, $context) {
$length = $args[0];
}
return $self->make_wordle($channel, $length);
my $wordlist = $args[1] // 'default';
if (not exists $wordlists{$wordlist}) {
return 'Invalid wordlist; options are: ' . (join ', ', sort keys %wordlists);
}
return $self->make_wordle($channel, $length, undef, $wordlist);
}
when ('custom') {
if (@args != 2) {
return "Usage: wordle custom <word> <channel>";
if (@args < 2 || @args > 3) {
return "Usage: wordle custom <word> <channel> [wordlist]";
}
my $custom_word = $args[0];
my $custom_channel = $args[1];
my $length = length $custom_word;
my $custom_word = $args[0];
my $custom_channel = $args[1];
my $custom_wordlist = $args[2];
my $length = length $custom_word;
if ($custom_word !~ /[a-z]/) {
return "Word must be all lowercase and cannot contain numbers or symbols.";
@ -113,9 +147,15 @@ sub wordle($self, $context) {
return "There is already a Wordle underway! Use `wordle show` to see the current progress or `wordle giveup` to end it.";
}
my $result = $self->make_wordle($custom_channel, $length, uc $custom_word);
my $wordlist = $custom_wordlist // 'default';
if ($result !~ /^Wordle:/) {
if (not exists $wordlists{$wordlist}) {
return 'Invalid wordlist; options are: ' . (join ', ', sort keys %wordlists);
}
my $result = $self->make_wordle($custom_channel, $length, uc $custom_word, $wordlist);
if ($result !~ /Guess/) {
return $result;
}
@ -129,7 +169,7 @@ sub wordle($self, $context) {
command => 'wordle',
keyword => 'wordle',
checkflood => 1,
message => "$context->{nick} started a custom $result",
message => "$result (started by $context->{nick})",
};
$self->{pbot}->{interpreter}->add_message_to_output_queue($custom_channel, $message, 0);
@ -162,19 +202,7 @@ sub wordle($self, $context) {
return NO_WORDLE;
}
my $result = 'Good/unknown letters: ';
foreach my $letter (sort keys $self->{$channel}->{letters}->%*) {
if ($self->{$channel}->{letters}->{$letter} == LETTER_CORRECT) {
$result .= "*$letter* ";
} elsif ($self->{$channel}->{letters}->{$letter} == LETTER_PRESENT) {
$result .= "?$letter? ";
} elsif ($self->{$channel}->{letters}->{$letter} == 0) {
$result .= "$letter ";
}
}
return $result;
return $self->show_letters($channel);
}
default {
@ -183,12 +211,15 @@ sub wordle($self, $context) {
}
}
sub load_words($self, $length) {
if (not -e WORDLIST) {
die "Wordle database `" . WORDLIST . "` not available. Set WORDLIST to a valid location of a wordlist file.\n";
sub load_words($self, $length, $wordlist = 'default') {
print "datadir: $self->{datadir}; wordlist = $wordlist; path = $wordlists{$wordlist}\n";
$wordlist = $self->{datadir} . $wordlists{$wordlist};
if (not -e $wordlist) {
die "Wordle database `" . $wordlist . "` not available. Set WORDLIST to a valid location of a wordlist file.\n";
}
open my $fh, '<', WORDLIST or die "Failed to open Wordle database.";
open my $fh, '<', $wordlist or die "Failed to open Wordle database.";
my %words;
@ -205,9 +236,9 @@ sub load_words($self, $length) {
return \%words;
}
sub make_wordle($self, $channel, $length, $word = undef) {
sub make_wordle($self, $channel, $length, $word = undef, $wordlist = 'default') {
eval {
$self->{$channel}->{words} = $self->load_words($length);
$self->{$channel}->{words} = $self->load_words($length, $wordlist);
};
if ($@) {
@ -227,7 +258,7 @@ sub make_wordle($self, $channel, $length, $word = undef) {
}
$self->{$channel}->{wordle} = \@wordle;
$self->{$channel}->{guesses} = [];
$self->{$channel}->{guess} = '';
$self->{$channel}->{correct} = 0;
$self->{$channel}->{guess_count} = 0;
$self->{$channel}->{letters} = {};
@ -236,13 +267,37 @@ sub make_wordle($self, $channel, $length, $word = undef) {
$self->{$channel}->{letters}->{$letter} = 0;
}
push $self->{$channel}->{guesses}->@*, '? ' x $self->{$channel}->{wordle}->@*;
$self->{$channel}->{guess} = $color{invalid};
$self->{$channel}->{guess} .= ' ? ' x $self->{$channel}->{wordle}->@*;
$self->{$channel}->{guess} .= $color{reset};
return "Wordle: " . $self->show_wordle($channel) . " (Guess the word! Legend: X not in word; ?X? wrong position; *X* correct position)";
return $self->show_wordle($channel) . " Guess the word! Legend: $color{invalid}X $color{reset} not in word; $color{present}X$color{present_a}?$color{reset} wrong position; $color{correct}X$color{correct_a}*$color{reset} correct position";
}
sub show_wordle($self, $channel) {
return join ' -> ', $self->{$channel}->{guesses}->@*;
sub show_letters($self, $channel) {
my $result = 'Letters: ';
foreach my $letter (sort keys $self->{$channel}->{letters}->%*) {
if ($self->{$channel}->{letters}->{$letter} == LETTER_CORRECT) {
$result .= "$color{correct}$letter$color{correct_a}*";
$result .= "$color{reset} ";
} elsif ($self->{$channel}->{letters}->{$letter} == LETTER_PRESENT) {
$result .= "$color{present}$letter$color{present_a}?";
$result .= "$color{reset} ";
} elsif ($self->{$channel}->{letters}->{$letter} == 0) {
$result .= "$letter ";
}
}
return $result . "$color{reset}";
}
sub show_wordle($self, $channel, $with_letters = 0) {
if ($with_letters) {
return $self->{$channel}->{guess} . "$color{reset} " . $self->show_letters($channel);
} else {
return $self->{$channel}->{guess} . "$color{reset}";
}
}
sub guess_wordle($self, $channel, $guess) {
@ -258,11 +313,6 @@ sub guess_wordle($self, $channel, $guess) {
$self->{$channel}->{guess_count}++;
if ($self->{$channel}->{guess_count} == 1) {
# remove initial "? ? ? ? ?"
shift $self->{$channel}->{guesses}->@*;
}
my @guess = split //, $guess;
my @wordle = $self->{$channel}->{wordle}->@*;
@ -280,13 +330,13 @@ sub guess_wordle($self, $channel, $guess) {
}
}
my @result;
my $result = '';
my $correct = 0;
for (my $i = 0; $i < @wordle; $i++) {
if ($guess[$i] eq $wordle[$i]) {
$correct++;
push @result, "*$guess[$i]*";
$result .= "$color{correct} $guess[$i]$color{correct_a}*";
$self->{$channel}->{letters}->{$guess[$i]} = LETTER_CORRECT;
} else {
my $present = 0;
@ -303,10 +353,10 @@ sub guess_wordle($self, $channel, $guess) {
}
if ($present) {
push @result, "?$guess[$i]?";
$result .= "$color{present} $guess[$i]$color{present_a}?";
$self->{$channel}->{letters}->{$guess[$i]} = LETTER_PRESENT;
} else {
push @result, "$guess[$i]";
$result .= "$color{invalid} $guess[$i] ";
if ($self->{$channel}->{letters}->{$guess[$i]} == 0) {
$self->{$channel}->{letters}->{$guess[$i]} = LETTER_INVALID;
@ -315,16 +365,14 @@ sub guess_wordle($self, $channel, $guess) {
}
}
push $self->{$channel}->{guesses}->@*, join ' ', @result;
$self->{$channel}->{guess} = $result;
if ($correct == length $guess) {
$self->{$channel}->{correct} = 1;
my $guesses = $self->{$channel}->{guess_count};
return "Correct in $guesses guess" . ($guesses != 1 ? 'es! ' : '! ') . $self->show_wordle($channel);
return $self->show_wordle($channel) . " Correct in $guesses guess" . ($guesses != 1 ? 'es! ' : '! ');
} else {
return $self->show_wordle($channel);
return $self->show_wordle($channel, 1);
}
}

View File

@ -25,8 +25,8 @@ use PBot::Imports;
# These are set by the /misc/update_version script
use constant {
BUILD_NAME => "PBot",
BUILD_REVISION => 4717,
BUILD_DATE => "2024-03-15",
BUILD_REVISION => 4718,
BUILD_DATE => "2024-03-16",
};
sub initialize {}