Linuxdoc Linux Questions
Click here to ask our community of linux experts!
Custom Search
Next Previous Contents

12. Fourth Example: Hearts

Here is the hoary old game of Hearts, written for UNIX systems by Bob Ankeney sometime in the '80's, revised in 1992 by Mike Yang, and currently maintained by Jonathan Badger. Its predecessor was an even older Pascal program by Don Backus of Oregon Software, later updated by Jeff Hemmerling. Originally intended as a multiplayer client, it also works well in single-player mode against computer opponents. The graphics are nice, though the game lacks sophisticated features and the computer players are not particularly strong. All the same, it seems to be the only decent Hearts game available for UNIX and Linux machines even at this late date.

Due to its age and lineage, this package is particularly difficult to build on a Linux system. It requires solving a long and perplexing series of puzzles. It is an exercise in patience and determination.

Before beginning, make certain that you have either the motif or lesstif libraries installed.

xmkmf

make

client.c: In function `read_card':
client.c:430: `_tty' undeclared (first use in this function)
client.c:430: (Each undeclared identifier is reported only once
client.c:430: for each function it appears in.)
client.c: In function `scan':
client.c:685: `_tty' undeclared (first use in this function)
make: *** [client.o] Error 1

These are the culprits in the file client.c:

#ifndef SYSV
        (buf[2] != _tty.sg_erase) && (buf[2] != _tty.sg_kill)) {
 #else
        (buf[2] != CERASE) && (buf[2] != CKILL)) {
#endif

In client.c, add

#define SYSV

at line 39. This will bypass the reference to _tty.

make

client.c:41: sys/termio.h: No such file or directory
make: *** [client.o] Error 1

The include file termio.h is in the /usr/include directory on a Linux system, rather than the /usr/include/sys one, as was the case on older UNIX machines. Therefore, change line 41 of client.c from

#include <sys/termio.h>

to
#include <termio.h>

make

gcc -o hearts -g      -L/usr/X11R6/lib client.o hearts.o select.o connect.o
sockio.o start_dist.o  -lcurses -ltermlib       
/usr/bin/ld: cannot open -ltermlib: No such file or directory
collect2: ld returned 1 exit status
make: *** [hearts] Error 1

Modern Linux distributions use the terminfo and/or termcap database, rather than the obsolete termlib one.

Edit the Makefile.

Line 655:

CURSES_LIBRARIES = -lcurses -ltermlib

changes to:

CURSES_LIBRARIES = -lcurses -ltermcap

make

gcc -o xmhearts -g      -L/usr/X11R6/lib xmclient.o hearts.o select.o
connect.o sockio.o start_dist.o gfx.o  -lXm_s -lXt -lSM -lICE -lXext -lX11
-lPW       
/usr/bin/ld: cannot open -lXm_s: No such file or directory
collect2: ld returned 1 exit status

The main lesstif library is libXm, rather than libXm_s. Therefore, edit the Makefile.

In line 653:

XMLIB = -lXm_s $(XTOOLLIB) $(XLIB) -lPW

changes to:

XMLIB = -lXm $(XTOOLLIB) $(XLIB) -lPW

make

gcc -o xmhearts -g      -L/usr/X11R6/lib xmclient.o hearts.o select.o
connect.o sockio.o start_dist.o gfx.o  -lXm -lXt -lSM -lICE -lXext -lX11 -lPW       
/usr/bin/ld: cannot open -lPW: No such file or directory
collect2: ld returned 1 exit status
make: *** [xmhearts] Error 1

Round up the usual suspects.

There is no PW library. Edit the Makefile.

Line 653:

XMLIB = -lXm $(XTOOLLIB) $(XLIB) -lPW

changes to:

XMLIB = -lXm $(XTOOLLIB) $(XLIB) -lPEX5

(The PEX5 lib comes closest to PW.)

make

rm -f xmhearts
gcc -o xmhearts -g      -L/usr/X11R6/lib xmclient.o hearts.o select.o
connect.o sockio.o start_dist.o gfx.o  -lXm -lXt -lSM -lICE -lXext -lX11 -lPEX5       

The make finally works (hurray!).

Installation:

As root,

[root@localhost hearts]# make install
install -c -s  hearts /usr/X11R6/bin/hearts
install -c -s  xmhearts /usr/X11R6/bin/xmhearts
install -c -s  xawhearts /usr/X11R6/bin/xawhearts
install in . done

Test run:

rehash

(We're running the tcsh shell.)

xmhearts

localhost:~/% xmhearts
Can't invoke distributor!

From README file in the hearts package:

     Put heartsd, hearts_dist, and hearts.instr in the HEARTSLIB
     directory defined in local.h and make them world-accessible.

From the file local.h:

/* where the distributor, dealer and instructions live */

#define HEARTSLIB "/usr/local/lib/hearts"

This is a classic case of RTFM.

As root,

cd /usr/local/lib

mkdir hearts

cd !$

Copy the distributor files to this directory.

cp /home/username/hearts/heartsd .

cp /home/username/hearts/hearts_dist .

cp /home/username/hearts/hearts.instr .

Try another test run.

xmhearts

It works some of the time, but more often than not crashes with a dealer died! message.

The "distributor" and "dealer" scan the hardware ports. We should thus suspect that those programs need root user privileges.

Try, as root,

chmod u+s /usr/local/lib/heartsd

chmod u+s /usr/local/lib/hearts_dist

(Note that, as previously discussed, suid binaries may create security holes.)

xmhearts

It finally works!

Hearts is available from Sunsite.


Next Previous Contents