The <prgn> cardwords </prgn> game Tobias Peters cardwords@crosswinds.net m4_include(VERSION) cardwords is a card game for your computer running Linux. You get cards showing letters and can lay words with them crossword-like on the table. This document describes how to compile, install, customize and run the game. Please note that the game is playable but still very alpha. Copyright © 1998 1999 Tobias Peters

The cardwords program including this README is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Introduction

cardwords is a card game for your computer running Linux (it will probably run on other flavors of Unix, too).

This software is in alpha state. It is possible to play a game against the computer or against other players over the net, but it is not very comfortable yet.

cardwords is a client/server based program. The server accepts connections from clients all over the internet and manages the game. One client can authenticate as the owner and that client's user can do some administrative jobs such as deciding to add words to the dictionary of valid words while the others can not. You can play against other people over the internet or against as many computer generated robots as you like. Or against a mix of both.

I want to have different clients in the long run. At the moment there is only a gtk client which requires xwindows with scalable fonts, gtk+ and gtk-- . I would like to have also a text mode client using ncurses or inside emacs.

In the game you get cards showing a character and points. You try to lay words with them on the table in a crossword-like way.

You can customize the game. However, this has currently to be done by editing some text files. I want to have tools for this task in the long run, but for customizing the game now, I will describe the format of the various files concerned in .

These files are

a charset file which contains the characters that can form the words,

one or more dictionary files of valid words,

a file that lists all existing cards,

a file containing information about the card-table,

a file specifying bonus and penalty points for certain actions and (implicitly) the number of cards everybody gets handed out.

This way it is possible to have dictionarys in different languages and use the special characters of that language, but this is currently limited to the latin-1 charset.

Getting, compiling and installing cardwords

You can obtain the latest cardwords source from or from your local sunsite mirror.

You will currently need the gtk+ and gtk-- libraries in order to compile and run cardwords because the only existing client program uses the gtk-- library. and run cardwords.

Modify the Makefile: The Makefile has the following entrys:

BINDIR = $(DESTDIR)/usr/local/bin LIBDIR = $(DESTDIR)/usr/local/lib/games/cardwords CONFDIR = $(DESTDIR)/usr/local/etc LOCALEDIR = $(DESTDIR)/usr/local/share/locale DEFAULT_HOMEDIR = getenv\(\"HOME\"\) # c expression. DEFAULT_PORT = 27037

Adjust these entrys according to your needs. They have the following meaning: BINDIR:

The executable files will be installed into this directory.

LIBDIR:

This directory will contain the charset files, the dictionary files, the card set files, the card-table files and the bonus files.

LOCALEDIR:

This is the directory where translated messages (.mo files) will be stored under LOCALEDIR/locale-abbrev/cardwords.mo .

CONFDIR:

This directory is not used yet. Later it will contain a system wide default configuration. A configuration consists of default values for charset files, the dictionary files, the card set files, the card-table files and the bonus files.

DEFAULT_HOMEDIR:

Unlike the previous ...DIR settings, this has to be a valid c++ expression, with shell escapes. Change it if your system does not set the environment variable HOME to your home directory or if you use a shell that does not use the backslash for quoting single characters.

DEFAULT_PORT:

The default tcp port the server listens to. Change it if this port is already in use on your system. This is unlikely.

Then type make to compile everything and make install to copy the created binaries to the BINDIR. The example files will be copied to the LIBDIR.

Customizing cardwords

cardwords is customized by supplying customized versions of the following files:

The charset file, see .

The dictionary files, see .

The card set file, see .

The card-table file, see .

The bonus file, see .

You can put customized versions of these files anywhere you like and point the client programm to them with the options dialog and then save the options, but I suggest that you put these files either in LIBDIR (if you are the system administrator and these files are of interest for some of your users) or in the .cardwords subdirectory of your home directory.

If you create a french version of these files for example, and all your users speek french as their native language, you should put these files in LIBDIR and make the symlinks default.* point to them.

When you create new versions of these files and make them accessible to other people, you must be careful not to violate anyone's copyright.

Yes, I mean it. It may be possible to customize this game so that it imitates other crossword computer games or real world crossword games. If you create such an customization, and you do not have the copyright for it, you must not distribute it. This does even mean that you must not play a game that is this way customized with other people over the net, because the server sends copies of these files to the clients, and this is an act of distribution and copying.

I rather want to encourage you to be creative and invent your own charsets, card sets, card-tables, bonus and penalty rules etc, and publish them under a free license such as the GPL, BSD, Artistic etc.

The charset file

The charset file has the format

n character 1 equivalents character 2 equivalents character 3 equivalents [...] character n equivalents

where n is the number of different characters on your cards and character i

1 ≤ i ≤ n

equivalents are characters from the computer's charset that this character represents. The character equivalents must not contain white space. This way it is possible to let uppercase and lowercase characters be represented by the same card character. Here is an example charset file for the english language (as distributed in example.charset with cardwords):

26 Aa Bb Cc Dd Ee Ff Gg Hh Ii Jj Kk Ll Mm Nn Oo Pp Qq Rr Ss Tt Uu Vv Ww Xx Yy Zz

The first character that you give in a set of equivalent characters will always be used by the program's output to refer to that card character, while all given characters are recognized in the input.

If you really want to you can also separate lowercase from uppercase characters, and specify only one character on each line. This could make sense in some languages where several words always start with an uppercase letter, but I think it is generally unnecessarily complicated.

You might wonder why you have to specify the characters in a file, A to Z uppercase and lowercase is not too hard to think of, is it? My main motivation to write cardwords was the lack of crossword computer games that featured the german umlauts Ä, Ö and Ü and the ß. While it is common practice to replace these even in german newspaper's crossword puzzles with AE, OE, UE and SS, the result is sometimes ugly. With cardwords, this is no more necessary.

The programs I saw also had hardwired assumptions about the distribution of the characters in the language that fits the english language, but is ridiculous in other languages. This distribution of characters can be customized within the card set file described in .

The dictionary files

You have to use a dictionary file if you want to play against robots. The robots would otherwise have no clue what a valid word is. If you start the server without specifying a dictionary, it will crash currently when a robot tries to make his move. I recommend using a dictionary file. The server sometimes interrupts the connection when a client tries to perform an action that it is not allowed to. If this happens (and remember, the software is alpha, this can happen now) or the connection breaks otherwise, then the remote player is replaced by a robot, even if you started a game with no robots at all.

A dictionary file is just a text file that contains the words that you want the server to allow, like this:

salt pepper collapsible jaw eat so

The words do not need to be sorted in any way. The only restrictions are:

The words must consist of at least 2 characters.

The words must be build up from characters that you put in the charset file. This implies that they must not contain white space.

The cardwords server program can use dictionary files in three different ways:

It is in fact not the server program cardwords_server that makes this distinction, but cardwords_dicbot , which is started by the server and handles all dictionary related tasks like checking the validity of words and finding the best moves for the robots.

As a normal, read-only dictionary. The server could handle several of these, adding all contained words to its internal dictionary, but this is not yet implemented in the client that starts the server.

As a dictionary file that is read when the server starts and to which new words, that are introduced by the owner of the server, will be appended.

As a file that contains words to remove from the internal dictionary. This is not implemented yet, and when it is, you should not add a dictionary file which contains many words you do not want to have and then remove them using a remove-file, because it works very slow. I optimized the internal dictionary to quickly find the best move for a given set of cards (the robots need this), and the result was that removing a word is not only slow, but very slow

O(N)

.

Dictionaries are a source of conflicts between human players. Find a consensus with your players what kinds of words should go into the dictionary before starting the game.

The robots will of course accept any dictionarys that you provide. With a combination of a read-only file and a read write file, you can have a system wide read-only dictionary that everybody agrees on and a writeable personal dictionary where you put your own special words.

You can also use the writeable dictionary to add just a few words to the dictionary in the beginning and let the program add new words as they occur during the game. I recommend this way, it is the conveniest and it ensures that you win the first games against the robots :-).

The card set file

You can decide what cards you want to play with. Each card shows a character and a points value. You can also create special wildcards that can represent any character the player wants. You can create any combinations of characters and point values.

The card set file just lists all existing cards, preceeded by the total number of cards. A card in the file has the following format:

[x #]

where [ and ]

are literal brackets.

x

is a character that is contained in the charset file. This is the character the card shows. For wildcards, this must be a space.

(the space in the middle)

is a literal space. This is required.

#

is an int in decimal, the points of that card.

Clients can restrict the points of the cards to certain values, while the server does not. The only client existing by now restricts the points of cards to the range from -9 to 99. This is because of the space where the points are displayed on the screen is designed to hold two digits, or one digit and the minus sign at maximum. Other clients can have other restrictions.

Here is an example card set file that can be used together with the example charset file:

14 [A 6] [A 6] [A 6] [A 7] [B 2] [B 2] [B 9] [E 1] [E 0] [E -1][K 19] [ 0] [ -2] [ -1]

The card descriptions can be separated from each other by white space. Remember the required space in each card description! The last line in this example shows three wildcards. Theese need two spaces, one to mark it as a wildcard and the other one is the required space.

You might wonder what the sense of the middle space is. cardwords uses exactly this card description format when client and server communicate. Sometimes the meaning of wildcards needs to be specified. This is done by replacing this space with a character with that meaning.

You might want to count the distribution of characters in documents written in your language, in order to create a card set file. You can use cardwords_count to do this. Create cardwords_count by typing make cardwords_count. cardwords_count takes a charset file as argument and parses its standard input. It will ignore all chars that do not occur in the charset file and write the total number of occurrences of every recognized character to its standard output.

I must admit I have no idea if and how the copyright propagates from the document in which you count the characters to the output of cardwords_count, and if you base your card set file on it, to this card set file. I think it could be declared as a derivative work. So, unless you know it better than me, you should use only documents that you wrote entirely yourself or that are in the public domain.

You might also want to set the total number of cards in some relation to the total number of places on the card table.

The card-table file

The card-table is the place where the words are created. Because the words should appear crossword-like, the card-table has a grid of cells where the cards can be put. This grid has always the form of a rectangle, but you can customize its width and height.

You can also give a start condition. This means you can restrict the first word to areas where it touches a certain row of the grid, or a certain column, or even a single cell.

Subsequent new words must then touch existing cards on the card-table.

The format of a card-table file that creates a very simple card-table is

dimensions start condition end tag

where dimensions

have the form width*height, width and height being decimal integers describing the width and height of the grid, * is a literal asterisk;

start condition

has the form (column, row), with the parentheses and the comma being literal parentheses and comma, with column and row being decimal integers. If 0 ≤ column < width, then this column must be touched by the first word on the card-table. If 0 ≤ row < height, then this row must be touched by the first word on the card-table. As you see, valid column and row row numbers start with 0. (0,0) is the upper left corner;

end tag

is a (column, row) pair with at least one of the following conditions:

columnwidth or

rowheight .

I will give some examples of simple card-table files to make it clear what they look like:

A file defining a card-table with width 18, height 10 and no start condition:

18*10 (18,10) (18,10)

A file defining a card-table with width 18, height 10 and a start condition that restricts the first word to touch the rightmost column:

18*10 (17,10) (18,10)

A file defining a card-table with width 18, height 10 and a start condition that restricts the first word to touch the left bottom cell:

18*10 (0,9) (18,10)

But that is not all that can be specified in card-table files. You can set certain attributes of the card-table grid cells:

Cells can be unuseable (blocked). This means, they can not hold a card, and no word can cross them. To block a cell add a line (column, row) B; to the card table file between the start condition line and the end tag line.

Cells can have a points value. All cells have a points value in fact. The default points value is 0. The player who occupies this cell with a card gets these points. To change the points value of a cell add a line (column, row) C points; to the card table file between the start condition line and the end tag line.

Cells can have a letter factor. All cells have a letter factor in fact. The default letter factor is 1. This means that the points of the card that is put there are multiplied by this factor when the points are counted. To change the letter factor of a cell add a line (column, row) L factor; to the card table file between the start condition line and the end tag line.

Cells can have a word factor. All cells have a word factor. The default word factor is 1. This means that the points of the card that is put there and the points of all other cards that form a word together with the card in this cell are multiplied by this factor when the points are counted. To change the word factor of a cell add a line (column, row) W factor; to the card table file between the start condition line and the end tag line.

Multiple attributes of a single cell can be grouped into a single line like (column, row) W word_factor C cell_points; or any other combination. The gtk client does not support more than 2 non-default cell attributes per cell.

You should perhaps only use one cell attribute per cell at maximum, and let most of the cells have their default values in order to not make it too complicated for humans to play the game. Here is the example card-table file as shipped with cardwords:

19*10 (10,11) (0 ,0) B; (0 ,1) B; (1 ,0) B; (17,0) B; (18,0) B; (18,1) B; (0 ,9) B; (1 ,9) B; (0 ,8) B; (18,9) B; (17,9) B; (18,8) B; (10,0) C 5; (10,9) C 5; (1 ,1) W 2; (17,8) L 2; (20,12)

The bonus file

This file has the following format:

There are 2*N+1 pairs int:int with the following restrictions and meanings:

-N:trade_N_score ..:.. -1:trade_1_score 0:pass_score 1:1-bonus ..:.. N:N-bonus

The trade_i_score is added to the player's score when he changes i cards. trade_i_score will usually be ≤ 0.

The pass_score is added to the players score when he passes. Usually <= 0.

1-bonus, ..., N-Bonus are added to the player's score on top of the move count for a move with that many cards.

N is the number of cards every player has got in his hand. N is only implicitly defined in the bonus file and nowhere else.

Here is an example bonus file:

-6:-10 -5:-10 -4:-10 -3:-5 -2:-5 -1:-5 0:-1 1:0 2:0 3:0 4:0 5:5 6:10

This bonus file sets the number of cards in every player's hand to 6. Trading cards and passing results in penalty points, putting 5 or 6 cards simultaneously onto the table results in bonus points.

Running cardwords

This chapter describes how to run cardwords using the gtk client cardwords_gtkclient. The client's user interface urgently needs to be improved, but as long as it is as unfriendly as by now, this chapter will guide you through the program.

While running X, type cardwords_gtkclient, or type the full path of the programm, if the directory where you installed it is not in your PATH environment variable.

After the program starts, you will see a dialog where you can set options.

The option settings

I will now explain this dialog which is divided into several parts: Identity

The fields in this dialog are: Your name:

You have to fill in your name here. This name will show up later in every human player's client programs.

The computer fills your user name in here as a default, but you can change the name.

The name must not contain white space.

Alternative name:

Several human players can participate in the same game. All must have different names. You can give another name here that will be used when your first name is already used by someone else. This way you can avoid the client asking you for another name. (Currently, it will not ask you for another name.)

You can leave this field blank.

The alternative name must not contain white space.

Appearance

The fields in this dialog are: Card width:

Some xwindows programs open a window that is larger than your screen, while other ones use so little room on the screen that you might want to switch to a lesser screen resolution.

This is an attempt to let the user decide how much room the window will occupy, however it is very incomplete. You can only change the size (in pixels) a card will occupy on the screen. This will also change the fonts used inside the cards and card-table cells, but it does not affect the fonts used in other places of the window. And if you have no idea about the width and height of the card-table grid, you will have no clue which values to use here. This has to change in the future.

Card height:

Should be equal or nearly equal to card width, because square cards look best when forming words with them in a crossword way.

Use digits for the columns

You can choose if you want to have coodinates with digits for the columns and characters for the rows or the other way round.

Column indices grow rightwards

If you want the leftmost column to have the least index (`A' or `1'), check this button.

Row indices grow upwards

If you want the bottom-most row to have the least index (`A' or `1'), check this button.

Local server options

The fields in this dialog have the following meaning: Server program:

This is the location where the cardwords_server executable file is installed. If you compiled the program with make and installed it with make install, the computer will fill in the correct location here. You should not change it.

Charset file:

The location of the charset file you want to use for this game, see for an explanation of charset files.

Cardset file:

The location of the cardset file you want to use for this game, see for an explanation of cardset files.

Card-table file:

The location of the card-table file you want to use for this game, see for an explanation of card-table files.

Bonus file:

The location of the bonus file you want to use for this game, see for an explanation of bonus files.

Dictionary file:

The location of a read-only dictionary file you want to use for this game, see for an explanation of dictionary files.

Personal dictionary file:

The location of a dictionary file to which new words that are added during the game will be appended, see for an explanation of dictionary files.

Number of human players:

The number of players who can connect to the server, should be at least 1, because you want to play.

You can choose any number of players you like as long as there are enough cards in the card set so that every player has a full hand of cards at least when the game starts.

Number of robot players:

The number of robot players that the server creates. The robots are named Robot1 ... RobotN.

You can choose any number of robots you like as long as there are enough cards in the card set so that every player has a full hand of cards at least when the game starts.

Number of watchers:

The number of watchers who can connect to the server and observe the game without playing.

You should leave the 0 the computer filled in untouched because logging in as a watcher does not work yet.

Port number:

The number of the tcp port that the server listens to. If you have once started a server and are now trying to start a new one, change it a bit, and exec killall cardwords_server regularly between restarts.

Running servers are sometimes left over when the client exits (remember, it's in alpha state), and a new server usually can not use the same port as another server uses already or has used until a few minutes ago.

Remote server

Here you see a dialog where you can set the host name and port number of the remote cardwords_server.

Set these if you want to connnect to a cardwords_server that is already running somewhere.

Playing the game

You can save all options that you have set or start a local server or connect to a remote server or exit the program by clicking on the appropriate button. Use the `Start a local server'-button if you want to play a game against the computer.

If everything went well, you will now see a window displaying the card-table and some other info.

When all human players have logged on, the game starts.

The game window

You can see the card-table in the upper left area of the window. When most cells in the card-table grid are set to their default values, as I proposed in , the board will appear mostly green. This is because I think card-tables in casinos always have a green surtface (but I have not seen one yet).

Cell attributes different from the default values are displayed inside the cells on a background of a different color. You can recognize cell points by the letter `C', word factors by the letter `W', and letter factors by the letter `L'.

All info about the cell currently under the mouse pointer is shown in the upper right corner of the window.

Below this, there is the score board. It shows whose go it is, how many points and cards every player has, how many points everyone got in the last round, and of course the names of the other players. The column entitled `Type' contains a `H' if this is a human player and an `R' if that player is a robot. When the network connection to a particular player breaks, then this player will become a robot.

One row in the score board is automatically highlighted when the game runs. This line indicates whose go it is.

Below the score board you can see a single line telling you how many cards are left in the pile.

The client can tell you what cards are there at all in the game or what cards can still be in the pile (or in the other players' hands) by opening two windows showing lists. Access these lists via the menu.

And now to the most important thing in this game: How to tell the game what move/trade/pass you want to do next.

On the lowest line in the window you can see the cards in your hand. When you click with the mouse on one of these cards, it usually

Wildcards do not move immediately, the program expects that you type the desired meaning in the keyboard (one character, without return) before it moves the wildcard to the line above your hand.

moves to the line above the hand. I call this line the action selection area.

You use the action selection area to decide whether you move, trade or pass and which card to use. And where to move in the case of a move.

While you can do moves and passes alone with mouse-clicking (except for the wildcards), you might have difficulties trying to trade card(s) this way. That is why I will first tell you about the `keyboard way' to do things in the action selection area in the following subsection:

Composing moves, trades and passes with the action selection area

Let me first describe what you see in the action selection area. The action selection area consists of the following items (from left to right): The current card-table location display:

This display shows the current card-table location. Moves will start at the card-table grid cell with these coordinates.

The order of the coordinate pair (consisting of a character and a number) has a special meaning: Whatever coordinate appears first will be one coordinate of every card that you move. That means you are restricted to a single row or column of the card table with one move.

The restriction is even tighter: There must not be free cells between the cards that you lay on the board in a single move.

There are braces around the coordinate pair whenever the current state of the action selection area is not a move, but a trade or a pass. This happens in either of the following cases:

when there are no cards inside the action selection area. Pressing the OK button in this state will result in a pass.

when the cards would not fit on the card-table if a move started from this location.

when the card table is empty and a move starting from this location would not obeye the start condition.

when the user explicitly wants to trade cards.

In all these cases, when there are braces around the coordinate pair, pressing the OK button while there are cards inside the action selection area will result in trading these cards, or, if there are no cards in the action selection area, pressing the OK button will result in a pass.

The composing area

consists of card cells that contain your cards while you are composing your move or trade. When you want to get rid of a that is already in this area, you can click on it with the mouse or, if it is the last card, remove it with the backspace key.

The direction button:

By pressing this button you can change the direction of your move. The button's label tells you if you are currently composing a horizontal move or a vertical move. Note that the order of the coordinates in the current card-table location display changes accordingly when you press this button.

The OK button

can be pressed when you have finished your action selection.

I will now describe how to use the action selection area via the keyboard:

The action selection area is roughly in two different states: it expects either a coordinate pair or a card specification.

When your go begins, it expects a coordinate pair. If you want to make a move, and I think this is what you want most of the time, you can now change the current card-table location. type in a character and a number, in an order so that the coordinate which is common to all the card destinations of this move comes first.

I avoid speeking of horizontal and vertical here, like "for a horizontal move, type the character coordinate first", because it is (not yet, but very soon) costomizable if you want to use the characters for the columns and the numbers for the rows or vice versa. I think only a dialog field and a value setting is missing now, but I first want to get the program out.

If you do not want to make a move, but rather a trade, you can invalidate the current card-table location by typing the point `.'. The current card-table location will then be shown with braces around and the button that previously held the label vertical or horizontal will be empty.

After typing the current card-table location or invalidating it, the action selection area is in card input mode.

You can then specify the cards that you want to move or trade by first typing their meaning, and in case this is not to uniquely identify any card from your hand because there are cards with the same face value but different points, type in the card's points thereafter. As soon as the program recognizes which card you mean, it will be moved to the composing area.

Specify wildcards by first typing space, then the desired meaning of the wildcard (even when you want to trade the card, in which case the meaning is irrelevant), and, if this was again not enough to identify the wildcard because there are wildcards with different points on your hand, type in the points of the desired card.

You can remove the last card from the composing area by typing the backspace key while in card input mode.

You can change the current card-table location while in card input mode by typing once `.' and then typing the new card-table location.

You can change a move into a trade while in card input mode by twice typing `.': The first `.' sets the state of the action selection area to expecting a new card-table location, the second `.' invalidates the current card-table location.

You can change a trade into a move while in card input mode by typing `.' followed by the new card-table location.

You can change the direction of a move by typing `/'.

Finish your go by typing return.

With the info in the previous subsection, I think you can find out how to do your moves with the mouse. But one thing has not yet been mentioned: You can change the current card-table location with the mouse by clicking in the desired cell in the card-table.

Valid moves and score-counting

The first move has to obeye the start condition, see . Subsequent moves must touch at least one card that is already on the card-table.

All words created by the new move must be valid, ie they have to be contained in the server's dictionary and have to have a length of at least 2 characters.

If a player tries a move that creates a word that is unknown to the server, the owner of the server (the player that started the server) will be asked if he liked to add this word to the dictionary of known words. The player whose move was rejected can try another move or trade or pass, or wait until the owner adds the missing word and then retry the previous move. Players will not be notified about new words. Use an irc client to communicate with the other human players or whatever you like.

When making a move, all cell points of the cells that are being covered by the new cards are directly added to the moving players score. The points of the cards he moves are counted word-wise: for every new word that is being created the points of the new cards are first multiplied with the cell's letter factor. The products are then summed up. The plain points of all cards that have already been on the board before this move are added to this sum. This sum is then subsequently multiplied with every newly occupied cell's word factor. When the sum has been multiplied with each and every of these word factors, the result is also added to the player's points.

The winner is the player with the most points in the end. But the end of the game is just beginning to be implemented. This will change.

Have fun!