The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Games::Literati - For word games like Literati (or Scrabble, or Words With Friends), find the best-scoring solution(s) for a board and hand of tiles.

SYNOPSIS

    use Games::Literati qw/:allGames/;
    literati();
    wordswithfriends();
    scrabble();
    superscrabble();

Example Windows-based one-liner:

    perl -MGames::Literati=literati -e "$Games::Literati::WordList = './mydict.txt'; literati();"

Example linux-based one-liner:

    perl -MGames::Literati=literati -e "$Games::Literati::WordList = '/usr/dict/words'; literati();"

Export Tags

:allGames => literati(), wordswithfriends(), scrabble(), superscrabble()
:configGame => $WordFile, $MinimumWordLength
:infoFunctions => n_rows(), n_cols(), numTilesPerHand(), get_solutions()
:miscFunctions => reduce_hand()

DESCRIPTION

Games::Literati helps you find out all solutions for a given board and tiles. It can be used to play Scrabble (the original 15x15 grid), Super Scrabble (the official 21x21 extended grid), Literati (an old Yahoo! Games 15x15 grid, from which Games::Literati derives its name), and Words With Friends (a newer 15x15 grid). By overriding or extending the package, one could implement other similar letter-tile grids, with customizable bonus placements.

To use this module to play the games, a one-liner such as the following can be used:

        perl -MGames::Literati=literati -e "literati();"

(This will only work if `./wordlist' is in the current directory. Otherwise, see "PUBLIC VARIABLES", below.)

Enter the data prompted then the best 10 solutions will be displayed.

Board Input

The game will prompt you for each row of the board, one row at a time

    row 0:
    row 1:
    ...
    row 14:

And will expect you to enter the requested row's data. It expects one character for each column on the board. Thus, on a standard 15x15 board, it will expect each row to contain 15 characters. The `.' character represents an empty square. Individual letters (in lower case) represent tiles that have already been laid on the board. (Don't worry about indicating wild tiles just yet; that will come momentarily.) An example input row could be:

    .......s.header

After requesting the last row, the Games::Literati will display the board as it received it, and ask you

    Is the above correct?

At this point, it is expecting you to type either `yes' or `no'. If you answer `yes', the game will progress. If you answer `no', it will start over asking for row 0:. If you answer with anything else, it will ask you again if everything is correct.

Once you have entered `yes', Games::Literati will ask you for the coordinates of the any wild tiles already on the board

    wild tiles are at:[Row1,Col1 Row2,Col2 ...]

Row# and Col# are 0-referenced, so the upper left of the board is 0,0, and the lowe right of the standard board is 14,14. Multiple wild tiles are space-separated. If there have not been any wild tiled played yet, just hit ENTER, giving it an empty input. If you have wilds, with one at one-tile diagonally from the upper right and the second two tiles diagonally from the lower-left, you would enter

    1,13 12,2

If your coordinates resolve to an empty tile (.) or a tile that's not on the board, you will be notified:

    Invalid wild tile positions, please re-enter.
    wild tiles are at:[Row1,Col1 Row2,Col2 ...]

Finally, after receiving a valid input for the wilds, Games::Literati will ask you for what tiles are in your hand.

    Enter tiles:

You should enter anywhere from 1 to 7 tiles (for a standard game). Letter tiles should be in lower case; wild tiles are indicated by a question mark `?'.

    ?omment

It is recommended to pre-write everything into a file. and run the program via command-line. See the "SAMPLE TURNS", below.

SAMPLE TURNS

These samples will use input file t, to help ensure the correct input format.

As described above, the first 15 lines represent board situation, followed with "yes", followed by wild tile positions, if none, place a empty line here, then followed by tiles (can be less than 7), use ? to represent wild tiles. Please make sure the last line in your file ends with a full NEWLINE character on your system (it's safest to add a blank line after the list of tiles).

Make sure to put `./wordlist' in the working directory when running the program, or to set $WordFile as described in "PUBLIC VARIABLES", below.

First Turn

Create game file named t, like this:

    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    ...............
    yes

    ?omment
    <file end with a CR>

Run the game from the command line:

    perl -MGames::Literati=literati -e'literati()' < t

The output will be (depending on word list)

    [...]
    using 7 tiles:
    (47)    row 7 become: 'comment' starting at column 1 (BINGO!!!!)
    (47)    row 7 become: 'memento' starting at column 1 (BINGO!!!!)
    (47)    row 7 become: 'metonym' starting at column 1 (BINGO!!!!)
    (47)    row 7 become: 'momenta' starting at column 1 (BINGO!!!!)
    (47)    row 7 become: 'momento' starting at column 1 (BINGO!!!!)
    [...]
    Possible Ten Best Solution 1: row 7 become: 'metonym' starting at column 5 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 2: row 7 become: 'moments' starting at column 6 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 3: row 7 become: 'momenta' starting at column 6 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 4: column 7 become: 'omentum' starting at row 7 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 5: column 7 become: 'memento' starting at row 7 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 6: column 7 become: 'memento' starting at row 1 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 7: row 7 become: 'comment' starting at column 3 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 8: row 7 become: 'omentum' starting at column 7 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 9: row 7 become: 'omentum' starting at column 1 (BINGO!!!!) using 7 tile(s), score 47
    Possible Ten Best Solution 10: column 7 become: 'memento' starting at row 5 (BINGO!!!!) using 7 tile(s), score 47

If you run the same board with the Scrabble engine:

    $ perl -MGames::Literati=scrabble -e'scrabble()' < t

You will get

    [...]
    (76)    row 7 become: 'comment' starting at column 1 (BINGO!!!!)
    (76)    row 7 become: 'memento' starting at column 1 (BINGO!!!!)
    (72)    row 7 become: 'metonym' starting at column 1 (BINGO!!!!)
    [...]
    Possible Ten Best Solution 1: column 7 become: 'memento' starting at row 1 (BINGO!!!!) using 7 tile(s), score 76
    Possible Ten Best Solution 2: column 7 become: 'momento' starting at row 1 (BINGO!!!!) using 7 tile(s), score 76
    Possible Ten Best Solution 3: row 7 become: 'metonym' starting at column 5 (BINGO!!!!) using 7 tile(s), score 76
    Possible Ten Best Solution 4: row 7 become: 'momenta' starting at column 1 (BINGO!!!!) using 7 tile(s), score 76
    [...]

Intermediate Turn

For most turns, you input file the t containing a partially populated game, such as:

    ...............
    ...............
    ...............
    .......c.......
    ......ai.......
    .......s.header
    .......t....r..
    ...jurors..soup
    .......o....p.h
    .upsilon.f..pea
    .......speering
    .........s..n.e
    .........t..g..
    .........e.....
    ........broils.
    yes
    7,8 10,14 7,14
    eurmsss
    <file end with a CR>

Run the game from the command line:

    perl -MGames::Literati=literati -e'literati()' < t

The output will be (depending on word list)

    [....]
    using 7 tiles:
    using 6 tiles:
    (9)     row 3 become: 'cussers' starting at column 8
    (9)     row 12 become: 'russets' starting at column 4
    using 5 tiles:
    (8)     row 3 become: 'cruses' starting at column 8
    (8)     row 3 become: 'curses' starting at column 8

    [...]
    Possible Ten Best Solution 1: column 3 become: 'susses' starting at row 10  using 5 tile(s), score 24
    Possible Ten Best Solution 2: column 3 become: 'serums' starting at row 10  using 5 tile(s), score 24
    [...]

If you run the same board with the Scrabble engine:

    perl -MGames::Literati=scrabble -e'scrabble()' < t

You will get

    [...]
    Possible Ten Best Solution 1: row 14 become: 'embroils' starting at column 6  using 2 tile(s), score 36
    Possible Ten Best Solution 2: row 6 become: 'stems' starting at column 6  using 4 tile(s), score 23
    Possible Ten Best Solution 3: column 2 become: 'spumes' starting at row 8  using 5 tile(s), score 22
    [...]

Good luck!:)

PUBLIC FUNCTIONS

literati([min[, max]])
wordswithfriends([min[, max]])
scrabble([min[, max]])
superscrabble([min[, max]])

These functions execute each of the games. As shown in the "SYNOPSIS" and "SAMPLE TURNS", each turn generally requires just one call to the specific game function. Each function implements the appropriate 15x15 (or 20x20 for superscrabble) grid of bonus scores.

There are two optional arguments to the game functions:

min

The minimum number of tiles to play, which defaults to 1. If you want to only allow your computer player (ie, the Games::Literati module) to play 3 or more tiles, you would set min=3.

If you specify 0 or negative, the magic of perl will occur, and it will internally use the default of min=1.

max

The maximum number of tiles to play, which defaults to all the tiles in the given hand. If you want to restrict your computer player to play 5 or fewer tiles, you would set max=5. It will check to ensure that max is bounded by the numTilesPerHand()..

If you want to specify max, you must also specify a min.

If you specify max less than min, Games::Literati will not play any tiles.

Thus, specifying literati(3,5) will restrict the computer Literati player to using 3, 4, or 5 tiles on this turn.

n_rows()
n_cols()

Returns number of rows or columns for the most recent game type

numTilesPerHand()

Returns number of tiles in a full hand for the most recent game type

get_solutions()

Returns a hash, whose elements are described in the example below

    %solutions = get_solutions();

    # equivalent to

    %solutions = (
        $key => {                   # [string]: the string that is printed;
                                    #           it's a really bad idea for the key, but it keeps things
                                    #           consistent with the old %Games::Literati::solutions keys
            word => $word,          # [string]: the word being played
            tiles_used => $ntiles,  # [number]: the _number_ of tiles used
            score => $score,        # [number]: the score (equivalent to $Games::Literati::solutions{$key})
            direction => $dir,      # [string]: either 'column' or 'row'
            row => $row,            # [number]: the row number for the start of the word (0-based)
            col => $col,            # [number]: the column number for start of the word (0-based)
            bingo => $flag,         # [boolean]: whether this word was a BINGO or not
            tiles_this_word => $tiles_this_word,
                                    # [string]: Shows the tiles for this word, both those from the board and
                                    #           those from your hand.  Useful for determining placement of wild
                                    #           tiles
            tiles_consumed => $consumed,
                                    # [string]: Shows the tiles from your hand that were used for this play
                                    #           (a subset of the tiles from tiles_this_word), which can be used
                                    #           to remove the tiles from your hand that were played this turn
        },
        ...                         # repeat for other solutions
    );
reduce_hand( $hand_tiles, $played_tiles )

Returns the new hand tiles, with the played tiles removed.

    print reduce_hand( "rstlnec", "lest");  # prints "rnc"
DEPRECATED: find(\%args) or find($args)

Finds possible valid words, based on the hashref provided. When playing the automated game using the above functions, this is not needed, but it is provided to give you access to a function similar to the internal function, but it outputs extra information to the user.

\%args or $args

A reference to a hash containing the keys letters, re, and internal.

$args->{letters}

This is the list of letters available to play.

$args->{re}

This is a string which will be evaluated into a perl regular expression that is evaluated to determine. Note: this requres the full regex syntax, so use '/c.t/' to indicate you are looking for valid letters to put between a `c' and a `t'.

$args->{internal}

(Boolean) If set to a true value, find() will be quiet (not print to standard output) and will return an array-reference of possible solutions. If false, find() will print suggested words to STDOUT.

Note: The find() function is not under active development, and changes to the internal function might not be replicated to this public function. (It is documented and left exportable to be backward compatible with the original Games::Literati 0.01 release.)

PUBLIC VARIABLES

These variables are exportable, so can be fully qualified as %Games::Literati::WordFile, or if included in the export list when you use the module, you can reference them directly, as

    use Games::Literati qw/literati $WordFile/;
    $WordFile = '/usr/share/dict/words';
$WordFile

The $WordFile points to a text document, which lists one valid word per line.

The variable defaults to './wordfile'. (in version 0.01, that was the only value, and there was no variable.)

You may change the default wordfile by setting this variable to the path to find the list.

    $Games::Literati::WordFile = '/usr/dict/words';

Sources for $WordFile

  • Your OS may include a builtin dictionary (such as /usr/dict/words or /usr/share/dict/words). Beware: these often have numbers or punctuation (periods, hyphens), which may interfere with proper functioning

  • ENABLE (Enhanced North American Benchmark Lexicon): a public-domain list with more than 173,000 words, available at a variety of locations, including in an old google code repository as "enable1.txt" The ENABLE dictionary is used by a variety of online tools, and is the primary source for the official Words With Friends dictionary.

  • Anthony Tan has delved into the Words With Friends app, and has compared their internal list to the original ENABLE list at http://www.greenworm.net/notes/2011/05/02/words-friends-wordlist

If you want to use one of the lists from a website, you will need to download the list to a file, and set $WordFile to the path to your downloaded list.

%valid

For each word that Games::Literati parses from the $WordList file, it will set $valid{word} to 1.

$MinimumWordLength

Default = 2. This is used when parsing the dictionary file (during var_init) to ignore words that are too short. Most of these games don't allow single-letter words ("I", "a").

BUGS AND FEATURE REQUESTS

Please report any bugs or feature requests thru the web interface at https://github.com/pryrt/Games-Literati/issues.

A simple interface (with examples) for play your own custom grid is in the works. Studying the source code may point you in the right direction if you want a custom grid before the customization features are made public.

AUTHOR

Chicheng Zhang <chichengzhang AT hotmail.com> wrote the original code.

Peter C. Jones <petercj AT cpan.org> is the current maintainer, and has added various features and made bug fixes.

travis build status Coverage Status

LICENSE AND COPYRIGHT

Copyright (c) 2003, Chicheng Zhang. Copyright (C) 2016,2019,2020 by Peter C. Jones

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.