[comp.sources.x] v08i091: Vpuzzle -- screen destruction program :-)

imp@Solbourne.COM (Warner Losh) (08/22/90)

Submitted-by: imp@Solbourne.COM (Warner Losh)
Posting-number: Volume 8, Issue 91
Archive-name: vpuzzle/part01

	This is a program that will make your X display into one of
those old plastic 16 square puzzle games.  It is quite flexible in the
area of the screen it uses, as well as the number of squares that it
can have on the screen at one time.  It will also fake solving the
puzzle when you abort it, if you desire it.

	Included is a README file, a Imakefile file, a Makefile
generated from the Imakefile, a manual page and the source.  This
program has only been tested on a Solbourne and a Sun 4.  It should,
however, work on any BSD system.

Warner Losh		imp@Solbourne.COM

#!/bin/sh
# shar:	Shell Archiver  (v1.22)
#
#	Run the following text with /bin/sh to create:
#	  Imakefile
#	  Makefile
#	  README
#	  vpuzzle.1
#	  vpuzzle.c
#
sed 's/^X//' << 'SHAR_EOF' > Imakefile &&
X        DEPLIBS = $(DEPXLIB)
XLOCAL_LIBRARIES = $(XLIB)
X  SYS_LIBRARIES =
X
XSimpleProgramTarget(vpuzzle)
SHAR_EOF
chmod 0664 Imakefile || echo "restore of Imakefile fails"
sed 's/^X//' << 'SHAR_EOF' > Makefile &&
X# Makefile generated by imake - do not edit!
X# $XConsortium: imake.c,v 1.51 89/12/12 12:37:30 jim Exp $
X#
X# The cpp used on this machine replaces all newlines and multiple tabs and
X# spaces in a macro expansion with a single space.  Imake tries to compensate
X# for this, but is not always successful.
X#
X
X###########################################################################
X# Makefile generated from "Imake.tmpl" and <Imakefile>
X# $XConsortium: Imake.tmpl,v 1.77 89/12/18 17:01:37 jim Exp $
X#
X# Platform-specific parameters may be set in the appropriate .cf
X# configuration files.  Site-wide parameters may be set in the file
X# site.def.  Full rebuilds are recommended if any parameters are changed.
X#
X# If your C preprocessor doesn't define any unique symbols, you'll need
X# to set BOOTSTRAPCFLAGS when rebuilding imake (usually when doing
X# "make Makefile", "make Makefiles", or "make World").
X#
X# If you absolutely can't get imake to work, you'll need to set the
X# variables at the top of each Makefile as well as the dependencies at the
X# bottom (makedepend will do this automatically).
X#
X
X###########################################################################
X# platform-specific configuration parameters - edit sol.cf to change
X
X# platform:  $XConsortium: sun.cf,v 1.32 89/10/11 18:54:52 jim Exp $
X# operating system:  SunOS 4.0.3
X
X###########################################################################
X# site-specific configuration parameters - edit site.def to change
X
X# site:  $XConsortium: site.def,v 1.21 89/12/06 11:46:50 jim Exp $
X
X            SHELL = /bin/sh
X
X              TOP = .
X      CURRENT_DIR = .
X
X               AR = ar cq
X  BOOTSTRAPCFLAGS =
X               CC = cc
X
X         COMPRESS = compress
X              CPP = /lib/cpp $(STD_CPP_DEFINES)
X    PREPROCESSCMD = cc -E $(STD_CPP_DEFINES)
X          INSTALL = install
X               LD = ld
X             LINT = lint
X      LINTLIBFLAG = -C
X         LINTOPTS = -axz
X               LN = ln -s
X             MAKE = make
X               MV = mv
X               CP = cp
X           RANLIB = ranlib
X  RANLIBINSTFLAGS =
X               RM = rm -f
X     STD_INCLUDES =
X  STD_CPP_DEFINES =
X      STD_DEFINES =
X EXTRA_LOAD_FLAGS =
X  EXTRA_LIBRARIES =
X             TAGS = ctags
X
X    SHAREDCODEDEF = -DSHAREDCODE
X         SHLIBDEF = -DSUNSHLIB
X
X    PROTO_DEFINES =
X
X     INSTPGMFLAGS =
X
X     INSTBINFLAGS = -m 0755
X     INSTUIDFLAGS = -m 4755
X     INSTLIBFLAGS = -m 0664
X     INSTINCFLAGS = -m 0444
X     INSTMANFLAGS = -m 0444
X     INSTDATFLAGS = -m 0444
X    INSTKMEMFLAGS = -g kmem -m 2755
X
X          DESTDIR =
X
X     TOP_INCLUDES = -I$(INCROOT)
X
X      CDEBUGFLAGS = -O
X        CCOPTIONS =
X      COMPATFLAGS =
X
X         SOLTOP = $(TOP)/../Solbourne
X       SOLOILIB = -L$(SOLTOP)/OI -lOI
X      ALLINCLUDES = -I$(SOLTOP)/OI $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES)
X       ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS)
X           CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES)
X        LINTFLAGS = $(LINTOPTS) -DLINT $(ALLDEFINES)
X           LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES)
X        LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS)
X   LDCOMBINEFLAGS = -X -r
X
X        MACROFILE = sol.cf
X           RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut
X
X    IMAKE_DEFINES =
X
X         IRULESRC = $(CONFIGDIR)
X        IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES)
X
X     ICONFIGFILES = $(IRULESRC)/Imake.tmpl $(IRULESRC)/Imake.rules \
X			$(IRULESRC)/Project.tmpl $(IRULESRC)/site.def \
X			$(IRULESRC)/$(MACROFILE) $(EXTRA_ICONFIGFILES)
X
X###########################################################################
X# X Window System Build Parameters
X# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
X
X###########################################################################
X# X Window System make variables; this need to be coordinated with rules
X# $XConsortium: Project.tmpl,v 1.63 89/12/18 16:46:44 jim Exp $
X
X          PATHSEP = /
X        USRLIBDIR = $(DESTDIR)/usr/lib
X           BINDIR = $(DESTDIR)/usr/bin/X11
X          INCROOT = $(DESTDIR)/usr/include
X     BUILDINCROOT = $(TOP)
X      BUILDINCDIR = $(BUILDINCROOT)/X11
X      BUILDINCTOP = ..
X           INCDIR = $(INCROOT)/X11
X           ADMDIR = $(DESTDIR)/usr/adm
X           LIBDIR = $(USRLIBDIR)/X11
X        CONFIGDIR = $(LIBDIR)/config
X       LINTLIBDIR = $(USRLIBDIR)/lint
X
X          FONTDIR = $(LIBDIR)/fonts
X         XINITDIR = $(LIBDIR)/xinit
X           XDMDIR = $(LIBDIR)/xdm
X           AWMDIR = $(LIBDIR)/awm
X           TWMDIR = $(LIBDIR)/twm
X           GWMDIR = $(LIBDIR)/gwm
X          MANPATH = $(DESTDIR)/usr/man
X    MANSOURCEPATH = $(MANPATH)/man
X           MANDIR = $(MANSOURCEPATH)n
X        LIBMANDIR = $(MANSOURCEPATH)3
X      XAPPLOADDIR = $(LIBDIR)/app-defaults
X
X        SOXLIBREV = 4.2
X          SOXTREV = 4.0
X         SOXAWREV = 4.0
X        SOOLDXREV = 4.0
X         SOXMUREV = 4.0
X        SOXEXTREV = 4.0
X
X       FONTCFLAGS = -t
X
X     INSTAPPFLAGS = $(INSTDATFLAGS)
X
X            IMAKE = imake
X           DEPEND = makedepend
X              RGB = rgb
X            FONTC = bdftosnf
X        MKFONTDIR = mkfontdir
X        MKDIRHIER = /bin/sh $(BINDIR)/mkdirhier.sh
X
X        CONFIGSRC = $(TOP)/config
X        CLIENTSRC = $(TOP)/clients
X          DEMOSRC = $(TOP)/demos
X           LIBSRC = $(TOP)/lib
X          FONTSRC = $(TOP)/fonts
X       INCLUDESRC = $(TOP)/X11
X        SERVERSRC = $(TOP)/server
X          UTILSRC = $(TOP)/util
X        SCRIPTSRC = $(UTILSRC)/scripts
X       EXAMPLESRC = $(TOP)/examples
X       CONTRIBSRC = $(TOP)/../contrib
X           DOCSRC = $(TOP)/doc
X           RGBSRC = $(TOP)/rgb
X        DEPENDSRC = $(UTILSRC)/makedepend
X         IMAKESRC = $(CONFIGSRC)
X         XAUTHSRC = $(LIBSRC)/Xau
X          XLIBSRC = $(LIBSRC)/X
X           XMUSRC = $(LIBSRC)/Xmu
X       TOOLKITSRC = $(LIBSRC)/Xt
X       AWIDGETSRC = $(LIBSRC)/Xaw
X       OLDXLIBSRC = $(LIBSRC)/oldX
X      XDMCPLIBSRC = $(LIBSRC)/Xdmcp
X      BDFTOSNFSRC = $(FONTSRC)/bdftosnf
X     MKFONTDIRSRC = $(FONTSRC)/mkfontdir
X     EXTENSIONSRC = $(TOP)/extensions
X
X  DEPEXTENSIONLIB = $(USRLIBDIR)/libXext.a
X     EXTENSIONLIB =  -lXext
X
X          DEPXLIB = $(DEPEXTENSIONLIB)
X             XLIB = $(EXTENSIONLIB) -lX11
X
X      DEPXAUTHLIB = $(USRLIBDIR)/libXau.a
X         XAUTHLIB =  -lXau
X
X        DEPXMULIB =
X           XMULIB = -lXmu
X
X       DEPOLDXLIB =
X          OLDXLIB = -loldX
X
X      DEPXTOOLLIB =
X         XTOOLLIB = -lXt
X
X        DEPXAWLIB =
X           XAWLIB = -lXaw
X
X LINTEXTENSIONLIB = $(USRLIBDIR)/llib-lXext.ln
X         LINTXLIB = $(USRLIBDIR)/llib-lX11.ln
X          LINTXMU = $(USRLIBDIR)/llib-lXmu.ln
X        LINTXTOOL = $(USRLIBDIR)/llib-lXt.ln
X          LINTXAW = $(USRLIBDIR)/llib-lXaw.ln
X
X          DEPLIBS = $(DEPXAWLIB) $(DEPXMULIB) $(DEPXTOOLLIB) $(DEPXLIB)
X
X         DEPLIBS1 = $(DEPLIBS)
X         DEPLIBS2 = $(DEPLIBS)
X         DEPLIBS3 = $(DEPLIBS)
X
X###########################################################################
X# Imake rules for building libraries, programs, scripts, and data files
X# rules:  $XConsortium: Imake.rules,v 1.67 89/12/18 17:14:15 jim Exp $
X
X###########################################################################
X# start of Imakefile
X
X        DEPLIBS = $(DEPXLIB)
XLOCAL_LIBRARIES = $(XLIB)
X  SYS_LIBRARIES =
X
X OBJS = vpuzzle.o
X SRCS = vpuzzle.c
X
X PROGRAM = vpuzzle
X
Xall:: vpuzzle
X
Xvpuzzle: $(OBJS) $(DEPLIBS)
X	$(RM) $@
X	$(CC) -o $@ $(OBJS) $(LDOPTIONS) $(LOCAL_LIBRARIES) $(LDLIBS) $(EXTRA_LOAD_FLAGS)
X
Xinstall:: vpuzzle
X	$(INSTALL) -c $(INSTPGMFLAGS)   vpuzzle $(BINDIR)
X
Xinstall.man:: vpuzzle.man
X	$(INSTALL) -c $(INSTMANFLAGS) vpuzzle.man $(MANDIR)/vpuzzle.n
X
Xdepend::
X	$(DEPEND) -s "# DO NOT DELETE" -- $(ALLDEFINES) -- $(SRCS)
X
Xlint:
X	$(LINT) $(LINTFLAGS) $(SRCS) $(LINTLIBS)
Xlint1:
X	$(LINT) $(LINTFLAGS) $(FILE) $(LINTLIBS)
X
Xclean::
X	$(RM) $(PROGRAM)
X
X###########################################################################
X# common rules for all Makefiles - do not edit
X
Xemptyrule::
X
Xclean::
X	$(RM_CMD) \#*
X
XMakefile::
X	-@if [ -f Makefile ]; then \
X	echo "	$(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \
X	$(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \
X	else exit 0; fi
X	$(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR)
X
Xtags::
X	$(TAGS) -w *.[ch]
X	$(TAGS) -xw *.[ch] > TAGS
X
X###########################################################################
X# empty rules for directories that do not have SUBDIRS - do not edit
X
Xinstall::
X	@echo "install in $(CURRENT_DIR) done"
X
Xinstall.man::
X	@echo "install.man in $(CURRENT_DIR) done"
X
XMakefiles::
X
Xincludes::
X
X###########################################################################
X# dependencies generated by makedepend
X
SHAR_EOF
chmod 0664 Makefile || echo "restore of Makefile fails"
sed 's/^X//' << 'SHAR_EOF' > README &&
XThis is a simple program that I wrote after I saw a MAC screen saver
Xdoing the same thing.  I couldn't figure out how to make it a screen
Xsaver, but it is amusing none the less.
X
XThis program shuffles a display like those old 16 square plastic
Xpuzzles that I played with as a kid.  It will do this to your screen
Xforever, until you hit ^C, or you hit any key on the root menu.  It
Xwill optionally solve the puzzle when it either exhausts its move buffer
X(after about 65356 moves), you hit a key in the root window, or hit ^C
Xin the window that it started in.  Please see the manual for details.
X
XTo make the program, just use xmkmf, then type make.  Or, if you don't
Xhave imake installed, you can compile it:
X	cc -O -o vpuzzle vpuzzle.c -lX11
X
XThis program is know to work against the following servers:
X
X	MIT Sun 3
X	MIT Sun 4
X	Solbourne
X
XIt has been tested and compiled on OS/MP 4.0C and OS/SMP 4.0D from
XSolbourne with X release tape 1.1.  These are both based on SunOS
X4.0.3.  X 1.1 is basically X11 R4.  It has been compiled only on
XX11R4, so some changes may be needed to compile on R3.  It uses
Xstraight Xlib calls, no extended calls, and no toolkit calls.  It
Xshould work in any environment where signals exist.  Please let the
Xauthor know the platforms that you are able to get it to run on.  I'm
Xcurious.  My email address is below.
X
XWarner Losh		imp@Solbourne.COM
SHAR_EOF
chmod 0664 README || echo "restore of README fails"
sed 's/^X//' << 'SHAR_EOF' > vpuzzle.1 &&
X.TH VPUZZLE 1 "15 August 1990"
X.sp
X.SH NAME
Xvpuzzle \- Shuffles your display like on old 16 puzzle.
X.SH SYNOPSIS
X\f3vpuzzle [ -\f2option\f3 ... ]\f1
X.sp
X.SH DESCRIPTION
XThe \f3vpuzzle\f1 
Xshuffles your display around like the old puzzle programs.
X.PP
XIf you use
Xthe
X.B \-solve
Xoption, then the program will undo all the moves that have been done
Xto restote the screen to its original state.  There are three
Xways to signal the program to start solving:
X.IP\(bu
XAllowing the program to make 65364 moves.
X.IP\(bu
XHitting one ^C in the window that started the program
X.IP\(bu
XAny keystroke in the root window.
X.PP
XIf you do not use the
X.B \-solve
Xoption, then you can terminate the program by doing any of the above.
XIn addition, if you are waiting for all the moves to be undone, any of
Xthe above actions will cause the program to quit.
X.sp
X.SH OPTIONS
X\f3vpuzzle\f1 accepts the options listed below:
X.PP
X.TP 8
X.B \-display \f2display\f1
XThis option specifies the display. By default it is
Xthe current machine or the current setting of the DISPLAY variable.
X.PP
X.TP 8
X.B \-border
XThis option indicates that a white border should be drawn around all
Xof the squares of the puzzle.
X.PP
X.TP 8
X.B \-solve
XThis option indicates that the program should try to solve the puzzle,
Xgiven half a chance.
X.PP
X.TP 8
X.B \-numsquares \f2n\f1
XThis option specifies the number of squares in both direction to
Xbe used.  The default is 16.
X.PP
X.TP 8
X.B \-xnumsquares \f2n\f1
XThis option specifies the number of squares horizontally that
Xshould be used.  The default is 16.
X.PP
X.TP 8
X.B \-ynumsquares \f2n\f1
XThis option specifies the number of squares vertically that
Xshould be used.  The default is 16.
X.PP
X.TP 8
X.B \-max \f2n\f1
XThis option specifies the number of pixels that should be used
Xwhen doing the shuffling.  The default is the the screen size.
X.PP
X.TP 8
X.B \-xmax \f2n\f1
XThis option specifies the number of pixels across that should be used 
Xwhen doing the shuffling.  The default is the the screen size.
X.PP
X.TP 8
X.B \-ymax \f2n\f1
XThis option specifies the number of pixels up and down that should be used
Xwhen doing the shuffling.  The default is the the screen size.
X.SH X DEFAULTS
XThis program doesn't use X defaults (for shame).
X.sp
X.SH "SEE ALSO"
X\f3X\f1(1), \f3xpuzzle\f1(1)
X.sp
X.SH BUGS
XThe algorithm to solve the puzzle is too simple.  It just
Xundoes the moves that have been done so far.  It should use the same
Xalgorithm that xpuzzle uses.
X.sp
X.SH COPYRIGHT
XCopyright 1990, Solbourne Computer, Inc.
X.sp
X.SH AUTHORS
XM. Warner Losh (Solbourne)
SHAR_EOF
chmod 0664 vpuzzle.1 || echo "restore of vpuzzle.1 fails"
sed 's/^X//' << 'SHAR_EOF' > vpuzzle.c &&
X/*****************************************************************************/
X/**                Copyright 1990 by Solbourne Computer, Inc		    **/
X/**                           Longmont, Colorado                            **/
X/**                                                                         **/
X/**                           All Rights Reserved                           **/
X/**                                                                         **/
X/**    Permission to use, copy, modify, and distribute this software and    **/
X/**    its documentation  for  any  purpose  and  without  fee is hereby    **/
X/**    granted, provided that the above copyright notice appear  in  all    **/
X/**    copies and that both  that  copyright  notice  and  this  permis-    **/
X/**    sion  notice appear in supporting  documentation,  and  that  the    **/
X/**    name  of  Solbourne  not  be  used  in  advertising  in publicity    **/
X/**    pertaining  to  distribution  of  the software  without specific,    **/
X/**    written prior permission.                                            **/
X/**                                                                         **/
X/**    SOLBOURNE  DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,    **/
X/**    INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND  FITNESS,    **/
X/**    IN  NO  EVENT SHALL SOLBROUNE BE LIABLE FOR ANY SPECIAL, INDIRECT    **/
X/**    OR CONSEQUENTIAL DAMAGES OR  ANY  DAMAGES  WHATSOEVER   RESULTING    **/
X/**    FROM LOSS OF USE,  DATA OR  PROFITS,  WHETHER  IN  AN  ACTION  OF    **/
X/**    CONTRACT, NEGLIGENCE  OR OTHER TORTIOUS ACTION, ARISING OUT OF OR    **/
X/**    IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.          **/
X/*****************************************************************************/
X
X/*
X *	xshuffle.c -- makes your display into one of those 16 square puzzles.
X *
X *	Author		: M. Warner Losh	(imp@Solbourne.COM)
X *	Version		: V01.00
X *	Version date	: Wed Aug 15 10:58:36 1990
X *	Creation date	: Sun Aug  5 10:00:03 1990
X *
X *	Usage:	xshuffle
X *			[-numsquares {number-of-squares}] Num squares both ways
X *			[-xnumsquares {num-squares-x}]	Num squares across
X *			[-ynumsquares {num-squares-y}]	Num squares down
X *			[-display {display}]		Display to use
X *			[-border]			Draw a border
X *			[-solve]			Undo moves at end
X *			[-xmax n]			Width of area
X *			[-ymax n]			Height of area
X *			[-max n]			size of square area
X */
X
X/* Include files */
X
X# include <stdio.h>
X# include <signal.h>
X# include <X11/Xlib.h>
X# include <X11/Xatom.h>
X
X/*
X * Macro Definitions
X */
X
X/* Config parameters. */
X
X#define NUM_SQUARES 16			/* Default numberof squares */
X#define MAX_SOLVE	1024*64		/* Max number of moves saved */
X
X/* Magic numbers */
X#define DOWN 0				/* Move down */
X#define UP 1				/* Move up */
X#define RIGHT 2				/* Move rigth */
X#define LEFT 3				/* Move left */
X
X#define MODE_SCRAMBLE	0		/* We're scrambling now */
X#define MODE_SOLVE	1		/* We're solving now */
X#define MODE_EXIT	2		/* Time to exit */
X
X#define X_FLAG	1			/* X coord specified */
X#define Y_FLAG	2			/* Y coord specified */
X
X/*
X * Variables
X */
Xint moves[MAX_SOLVE];			/* Saved moves. */
Xint cur_move = 0;			/* Current move number */
Xint max_moves = MAX_SOLVE;		/* Max moves to make */
Xint solve = 0;				/* True when we are solving puzzle */
Xint mode = MODE_SCRAMBLE;		/* Mode we are in */
Xint boarder_width = 2;			/* Size of the boarder */
Xint nxsquares = NUM_SQUARES;		/* Number of squares across */
Xint nysquares = NUM_SQUARES;		/* Number of squares veritcally */
Xint speed = 1;				/* How fast to move.  Keep at 1 */
Xint last = -1;				/* What was the last move */
Xint x_size;				/* Size in pixels of square */
Xint y_size;				/* Size in pixels of square */
Xint y_max;				/* Biggest y we have. */
Xint x_max;				/* Biggest x we have. */
Xint x;					/* current X of upper left of blank */
Xint y;					/* Current Y of upper left of blank*/
Xint x_start = 0;			/* Start X location */
Xint y_start = 0;			/* Start Y location */
X
XWindow w_root;				/* Real root window */
XDisplay *dpy;				/* display connection */
XGC mygc;				/* Drawing GC */
XPixmap pm = 0;				/* Pixmap to save first square */
Xunsigned long fg, bg;			/* Foreground and background pixel */
Xunsigned long scr;			/* Screen number */
Xint (*old_handler)();			/* Old Error handler We restore this */
X
X/* Function Declarations */
X
Xint create_pm_handler ();
Xvoid die_usage ();
Xvoid done ();
Xint main ();
Xvoid move_a_square ();
Xvoid move_down ();
Xvoid move_left ();
Xvoid move_right ();
Xvoid move_up ();
Xvoid process_event ();
Xvoid rand_move_a_square ();
Xvoid save_move ();
Xvoid time_to_go();
Xvoid undo_move_a_square ();
Xint unique_match ();
Xvoid usage ();
X
X/**********************************************************************
X *     create_pm_handler () --- This is the handler for the one
X * 				XCreatePixmap request that we have.
X * 				All it does is to set pm to zero.  It
X * 				assumes that the only error it can get
X * 				is from CreatePixmap.  That is the
X * 				reason for the XSyncs around the
X * 				XCreatePixmap.
X * 
X * Arguments:
X * 
X *     dpy		    -i- Display the error happened on
X *     e		    -i- Event that caused us to get called.
X * 
X * Returns:
X * 
X */
X
Xint create_pm_handler (dpy, e)
XDisplay *dpy;
XXErrorEvent *e;
X{
X	pm = 0;
X}    /* end of create_pm_handler () */
X
X/**********************************************************************
X *     time_to_go () --- This function is the signal handler for ^C.
X * 			 It gets called when the user wants to exit.
X * 			 If the user requested solving of the puzzle,
X * 			 then we just bump the mode one.  Otherwise,
X * 			 we set the mode to exit.
X * 
X * Arguments:
X * 
X *     sig	     -i- Signal number that caused us to execute.
X *     code	     -i- Code for that signal
X *     scp	     -i- Signal contexted
X *     addr	     -i- Address of the exception.
X */
X
Xvoid time_to_go (sig, code, scp, addr)
Xint sig;
Xint code;
Xstruct sigcontext *scp;
Xchar *addr;
X{
X	if (solve)
X		mode++;
X	else
X		mode = MODE_EXIT;
X}    /* end of time_to_go () */
X
X/**********************************************************************
X *     done () --- Gets called when we are done.  This function sleeps
X * 		   a while if we just got done solving the puzzle.
X * 		   Then it maps a big window over all of the other
X * 		   windows to force them to repaint.  Then it exits.
X */
X
Xvoid done ()
X{
X	Window w;		/* big window */
X	XSetWindowAttributes att; /* Attributes for the window */
X	Visual visual;		/* Visual info */
X	unsigned long mask;	/* Mask for atributes */
X
X	/*
X	 * If we just got done solving the puzzle, then we wait a
X	 * while.  We also flush all of Xlib's buffers.
X	 */
X	if (solve && cur_move == 0)
X	{
X		if (pm)
X			XCopyArea (dpy, pm, w_root, mygc, 0, 0, x_size, y_size,
X				   x_start, y_start);
X		XSync(dpy, False);
X		sleep (3);
X	}
X
X	/*
X	 * Free the Pixmap if we need to.
X	 */
X	if (pm)
X		XFreePixmap (dpy, pm);
X	
X	/*
X	 * Create an override redirect window, map it over all the
X	 * clients, then unmap it.  This will cause the screen to
X	 * refresh.  Exit when done.
X	 */
X	att.override_redirect = True;
X	att.backing_store = False;
X	att.save_under = False;
X	mask = CWOverrideRedirect | CWBackingStore | CWSaveUnder;
X	visual.visualid = CopyFromParent;
X	w = XCreateWindow (dpy, w_root, 0, 0, 9999, 9999, 0,
X			   DefaultDepth (dpy, scr), InputOutput, &visual,
X			   mask, &att);
X	XMapRaised (dpy, w);
X	XSync(dpy, False);
X	XDestroyWindow(dpy, w);
X	exit(1);
X}    /* end of done () */
X
X/**********************************************************************
X *     main () --- Main routine.
X * 
X * Arguments:
X * 
X *     argc    -i- Num args
X *     argv    -i- args
X */
X
Xint main (argc, argv)
Xint argc;
Xchar **argv;
X{
X	int i;			/* Index for loops */
X	int do_border = False;	/* Draw a border around all the squares */
X	char *display = NULL;	/* Text of display to use. */
X	int max_flag = 0;	/* Flag for what max's are specified. */
X	
X	/*
X	 * Parse the arguments.  This is a real kludge right now, so
X	 * please be kind...
X	 */
X	while (--argc)
X	{
X		if (unique_match(*++argv, "-numsquares", 2))
X		{
X			if (--argc)
X				nysquares = nxsquares = atoi(*++argv);
X			else
X				die_usage ("-numsquares requires another arg");
X			continue;
X		}
X		if (unique_match(*argv, "-display", 2))
X		{
X			if (--argc)
X				display = *++argv;
X			else
X				die_usage ("-display requires another arg");
X			continue;
X		}
X		if (unique_match (*argv, "-xnumsquares", 3))
X		{
X			if (--argc)
X				nxsquares = atoi (*++argv);
X			else
X				die_usage("-xnumsquares requires another arg");
X			continue;
X		}
X		if (unique_match (*argv, "-ynumsquares", 3))
X		{
X			if (--argc)
X				nysquares = atoi (*++argv);
X			else
X				die_usage("-ynumsquares requires another arg");
X			continue;
X		}
X		if (unique_match (*argv, "-border", 2))
X		{
X			do_border = True;
X			continue;
X		}
X		if (unique_match (*argv, "-solve", 2))
X		{
X			solve = 1;
X			continue;
X		}
X		if (unique_match (*argv, "-max", 2))
X		{
X			if (--argc)
X			{
X				max_flag |= X_FLAG | Y_FLAG;
X				x_max = y_max = atoi (*++argv);
X			}
X			else
X				die_usage("-max requires another arg");
X			continue;
X		}
X		if (unique_match (*argv, "-ymax", 3))
X		{
X			if (--argc)
X			{
X				max_flag |= Y_FLAG;
X				y_max = atoi (*++argv);
X			}
X			else
X				die_usage("-ymax requires another arg");
X			continue;
X		}
X		if (unique_match (*argv, "-xmax", 3))
X		{
X			if (--argc)
X			{
X				max_flag |= X_FLAG;
X				x_max = atoi (*++argv);
X			}
X			else
X				die_usage("-xmax requires another arg");
X			continue;
X		}
X		fprintf (stderr,"Unknown option %s\n", *argv);
X		usage();
X	}
X	
X	/*
X	 * Setup the random number seed.
X	 */
X	srand (getpid());
X
X	/*
X	 * Open this display.
X	 */
X	dpy = XOpenDisplay(display); 
X	if (!dpy)
X	{ 
X		fprintf(stderr, "xfroot: Can't open display.\n");
X		exit(1); 
X	}
X
X	/*
X	 * Trap ^C so we can do a refresh
X	 */
X	(void) signal (SIGINT, time_to_go);
X	
X	/*
X	 * Get the id of the root window.  No need for pseudo root
X	 * here becuase we draw on top of everything that is ontop of
X	 * the root.
X	 */
X	w_root = DefaultRootWindow(dpy);
X
X	/*
X	 * Get the default fg and bg colors.
X	 */
X	scr = DefaultScreen(dpy);
X	fg = WhitePixel(dpy, scr);
X	bg = BlackPixel(dpy, scr);
X	
X	/*
X	 * Setup the GC that will let us do the magic.  Key points are
X	 * the drawing mode IncludeInferios.  This is what lets us
X	 * draw on top of things.
X	 */
X	mygc = XCreateGC (dpy, w_root, 0, 0);
X	XSetForeground (dpy, mygc, fg);
X	XSetBackground (dpy, mygc, bg);
X	XSetSubwindowMode (dpy, mygc, IncludeInferiors);
X
X	/*
X	 * OK, find out how big to make things...
X	 */
X	if ((max_flag & X_FLAG) == 0)
X		x_max = DisplayWidth (dpy, scr);
X	if ((max_flag & Y_FLAG) == 0)
X		y_max = DisplayHeight (dpy, scr);
X	x_size = x_max / nxsquares;
X	y_size = y_max / nysquares;
X	x_max = x_size * nxsquares;
X	y_max = y_size * nysquares;
X	
X	/*
X	 * Create the grid.
X	 */
X	if (do_border)
X	{
X		XSetLineAttributes (dpy, mygc, boarder_width, LineSolid,
X				    CapNotLast, JoinMiter);
X		for (i = 0; i <= y_max; i+= y_size)
X			XDrawLine (dpy, w_root, mygc, 0, i, x_max, i);
X		for (i = 0; i <= x_max; i+= x_size)
X			XDrawLine (dpy, w_root, mygc, i, 0, i, y_max);
X	}
X	
X	/*
X	 * Start in the upper left hand corner.
X	 */
X	x = x_start;
X	y = y_start;
X	
X	/*
X	 * Save the upper left hand corner square if we are going to
X	 * solve this later.  We will later assume that if pm is
X	 * non-zero, that it must be freed.  Also, check to make sure
X	 * that we can create this pixmap.  Some servers can't handle
X	 * all pixmap create requests.  We have to do this the hard
X	 * way.  If you know a better way (other than ignoring the
X	 * condition), please let me know at the above address.
X	 */
X	if (solve)
X	{
X		XSync (dpy, False);
X		old_handler = XSetErrorHandler (create_pm_handler);
X		pm = XCreatePixmap (dpy, w_root, x_size, y_size,
X				    DefaultDepth(dpy, scr));
X		XSync (dpy, False);
X		XSetErrorHandler (old_handler);
X		if (pm)
X			XCopyArea (dpy, w_root, pm, mygc, x_start, y_start,
X				   x_size, y_size, 0, 0);
X		else
X			fprintf (stderr, "Warning: Start square not saved.\n");
X	}
X	
X	/*
X	 * Setup the mask of events.  I'm just looking for a key press
X	 * right now.
X	 */
X	XSelectInput (dpy, w_root, KeyPressMask);
X	
X	/*
X	 * Loop forever.  Get a random number, move a square if it
X	 * hasn't been just moved and is also on the screen.
X	 */
X	while (1)
X	{
X		if (mode == MODE_EXIT)
X			done();
X		if (XEventsQueued (dpy, QueuedAfterReading) == 0)
X			move_a_square();
X		else
X			process_event();
X	}		
X}    /* end of main () */
X
X/**********************************************************************
X *     process_event () --- Processes events that we are interested
X * 			    in.  All others are ignored.
X */
X
Xvoid process_event ()
X{
X	XEvent e;		/* Event we are looking at.*/
X
X	/*
X	 * Read the event, and dispatch it.
X	 */
X	XNextEvent(dpy, &e);
X	switch (e.type)
X	{
X	/*
X	 * KeyPress events cause us to go to the next mode.
X	 */
X	case KeyPress:
X		if (solve)
X			mode++;
X		else
X			mode = MODE_EXIT;
X		break;
X		
X	/*
X	 * All XLib clients need to do this.
X	 */
X	case MappingNotify:
X		XRefreshKeyboardMapping (&e);
X		break;
X	}
X}    /* end of process_event () */
X
X/**********************************************************************
X *     move_a_square () --- Moves a square.  Will shuffle it when we
X * 			    are randomizing the screen.  Will
X * 			    unshuffle it when we aren't.
X */
X
Xvoid move_a_square ()
X{
X	if (mode == MODE_SCRAMBLE)
X		rand_move_a_square();
X	else
X		undo_move_a_square();
X}    /* end of move_a_square () */
X
X/**********************************************************************
X *     rand_move_a_square () --- Moves a square randomly.  Updates the
X * 				 current X and Y positions.  Also
X * 				 saves the move.
X */
X
Xvoid rand_move_a_square ()
X{
X	switch ((rand() >> 15) & 3)
X	{
X	case DOWN:			/* Move down */
X		if (last != UP && y - y_size >= 0)
X		{
X			move_down (x,y);
X			y -= y_size;
X			save_move(DOWN);
X		}				
X		break;
X			
X	case UP:			/* Move up */
X		if (last != DOWN && y + y_size < y_max)
X		{
X			move_up (x, y);
X			y += y_size;
X			save_move(UP);
X		}
X		break;
X
X	case RIGHT:			/* Move right */
X		if (last != LEFT && x - x_size >= 0)
X		{
X			move_right (x,y);
X			x -= x_size;
X			save_move(RIGHT);
X		}
X		break;
X
X	case LEFT:			/* Move left */
X		if (last != RIGHT && x + x_size < x_max)
X		{
X			move_left (x, y);
X			x += x_size;
X			save_move(LEFT);
X		}
X		break;
X	}
X}    /* end of rand_move_a_square () */
X
X/**********************************************************************
X *     undo_move_a_square () --- Undoes the latest move that hasn't
X * 				 been undone.
X */
X
Xvoid undo_move_a_square ()
X{
X	switch (moves[--cur_move])
X	{
X	case DOWN:			/* Move down */
X		move_up (x,y);
X		y += y_size;
X		break;
X			
X	case UP:			/* Move up */
X		move_down (x, y);
X		y -= y_size;
X		break;
X
X	case RIGHT:			/* Move right */
X		move_left (x,y);
X		x += x_size;
X		break;
X
X	case LEFT:			/* Move left */
X		move_right (x, y);
X		x -= x_size;
X		break;
X	}
X	if (cur_move <= 0)
X		mode = MODE_EXIT;
X}    /* end of undo_move_a_square () */
X
X/**********************************************************************
X *     save_move () --- Saves the move, iff we are solving this thing
X * 			later.
X * 
X * Arguments:
X * 
X *     move	    -i- Move to save (eg LEFT, RIGHT)
X */
X
Xvoid save_move (move)
Xint move;
X{
X	last = move;
X	if (solve)
X	{
X		moves[cur_move++] = move;
X		if (cur_move >= max_moves)
X			mode = MODE_SOLVE;
X	}
X}    /* end of save_move () */
X
X/**********************************************************************
X *     unique_match () --- Does st match pat for at least len
X * 			   characters?
X * 
X * Arguments:
X * 
X *     st	       -i- String to match.  This is what the user
X * 			   types
X *     pat	       -i- Pattern to match against
X *     len	       -i- Minimum unque length.
X * 
X * Returns:
X * 
X *     SUCCESS	       --- String matches to at least the length
X * 			   requested.
X *     FAILURE	       --- Strings don't match.
X */
X
Xint unique_match (st, pat, len)
Xchar *st;
Xchar *pat;
Xint len;
X{
X	return len <= strlen (st) && strncmp (st, pat, strlen (st)) == 0;
X	
X}    /* end of unique_match () */
X
X/**********************************************************************
X *     move_right () --- Moves the square on the left of the blank
X * 			 square to the right.
X * 
X */
X
Xvoid move_right ()
X{
X	int i;
X	
X	for (i = x - x_size; i < x; i+=speed)
X		XCopyArea (dpy, w_root, w_root, mygc, i, y, x_size, y_size,
X			   i+1,y);
X}    /* end of move_right () */
X
X/**********************************************************************
X *     move_left () --- Moves the square to the right of the blank
X * 			square to the left
X */
X
Xvoid move_left ()
X{
X	int i;
X	
X	for (i = x + x_size; i > x; i-=speed)
X		XCopyArea (dpy, w_root, w_root, mygc, i, y, x_size, y_size,
X			   i-1,y);
X}    /* end of move_left () */
X
X/**********************************************************************
X *     move_up () --- Moves the square below the blank square up.
X */
X
Xvoid move_up ()
X{
X	int i;
X
X	for (i = y + y_size; i > y; i-=speed)
X		XCopyArea (dpy, w_root, w_root, mygc, x, i, x_size, y_size,
X			   x,i-1);
X}
X
X/**********************************************************************
X *     move_down () --- Moves the square above the blank square down.
X */
X
Xvoid move_down ()
X{
X	int i;
X
X	for (i = y - y_size; i < y; i+=speed)
X		XCopyArea (dpy, w_root, w_root, mygc, x, i, x_size, y_size,
X			   x,i+1);
X}
X
X/**********************************************************************
X *     usage () --- Tells the user how to use this program.
X */
X
Xvoid usage ()
X{
X	fprintf (stderr, "xshuffle [-numsuqares n] [-xnumsquares n]\
X[-ynumsquares n]\n\
X	[-display disp] [-noborder] [-solve] [-max n] [-ymax n] [-xmax n]\n");
X	exit(1);
X}    /* end of usage () */
X
X/**********************************************************************
X *     die_usage () --- Prints the error, then calls usage.
X * 
X * Arguments:
X * 
X *     msg	    -i- Message to print.
X */
X
Xvoid die_usage (msg)
Xchar *msg;
X{
X	fprintf (stderr, "%s\n", msg);
X	usage();
X}    /* end of die_usage () */
SHAR_EOF
chmod 0664 vpuzzle.c || echo "restore of vpuzzle.c fails"
exit 0

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.