Files
Arquivotheca.SunOS-4.1.4/games/tool/boggletool/boggle.c
seta75D ff309bfe1c Init
2021-10-11 18:37:13 -03:00

767 lines
18 KiB
C

#ifndef lint
static char sccsid[] = "@(#)boggle.c 1.1 94/10/31 Copyr 1985 Sun Micro";
#endif
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
/*
* main.c: main routine and general windows routines
*/
#include <suntool/tool_hs.h>
#include <suntool/menu.h>
#include <suntool/wmgr.h>
#include <sunwindow/cms.h>
#include <sunwindow/win_ioctl.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <ctype.h>
#include <stdio.h>
#include "defs.h"
#include "images.h"
static short icon_data[256] = {
#include <images/boggle.icon>
};
mpr_static(boggle_pr, 64, 64, 1, icon_data);
struct icon boggle_icon = {
TOOL_ICONWIDTH, TOOL_ICONHEIGHT, 0,
{0, 0, TOOL_ICONWIDTH, TOOL_ICONHEIGHT},
&boggle_pr, {0, 0, 0, 0}, 0, 0, 0
};
struct timeval flashdelay = {0, 10000};
static bog_sigwinch(),
bog_selected(),
sigwinch_handler();
static char tool_name[] = "boggletool";
#define DEFDICT "/usr/games/boggledict" /* dictionary */
char board[16];
int setupboard = 0;
char *cubeletters[16] = { /* the boggle cubes */
"forixb", "moqabj", "gurilw", "setupl",
"cmpdae", "acitao", "slcrae", "romash",
"nodesw", "hefiye", "onudtk", "tevign",
"anedvz", "pinesh", "abilyt", "gkyleu"
};
#define BOG_RESTARTTIMER (caddr_t)1 /* restart the timer */
#define BOG_EXIT (caddr_t)2 /* quit bogtool */
#define BOG_RESTARTGAME (caddr_t)3 /* restart the game */
#define BOG_GIVEUP (caddr_t)4 /* human gives up */
struct menuitem bogmenu_items[] = {
MENU_IMAGESTRING, "Restart Game", BOG_RESTARTGAME,
MENU_IMAGESTRING, "Restart Timer", BOG_RESTARTTIMER,
MENU_IMAGESTRING, "Give Up", BOG_GIVEUP,
MENU_IMAGESTRING, "Quit", BOG_EXIT
};
struct menu b_menu = {
MENU_IMAGESTRING, "Boggle",
sizeof(bogmenu_items) / sizeof(struct menuitem),
bogmenu_items, NULL, NULL
};
struct menu *bog_menu = &b_menu;
boggletool_main(argc, argv)
int argc;
char **argv;
{
char **tool_attrs = NULL, *getenv();
int quit();
long atol();
extern sand_delay;
if (tool_parse_all(&argc, argv, &tool_attrs, tool_name) == -1) {
tool_usage(tool_name);
exit(1);
}
dictionary = DEFDICT;
while (--argc) {
++argv;
if (**argv == '+') {
while (*(*argv)++ == '+')
reuse++;
} else if (isdigit(**argv)) {
sand_delay = compute_delay(atol(*argv));
if (sand_delay <= 0) {
fprintf(stderr, "Playing time cannot be negative!\n");
exit(1);
}
} else if (isalpha(**argv)) {
if (strlen(*argv) != 16)
usage();
strncpy(board, *argv, 16);
setupboard = 1;
} else if (**argv == '-') {
if (*(++(*argv)) == 'd') {
if (*(++(*argv)) != '\0') {
dictionary = *argv;
} else if (argc > 1) {
dictionary = *(++argv);
argc--;
} else {
usage();
}
} else {
usage();
}
} else {
usage();
}
}
tool = tool_make(WIN_NAME_STRIPE, 1,
WIN_LABEL, tool_name,
WIN_ATTR_LIST, tool_attrs,
WIN_ICON, &boggle_icon, 0);
if (tool == NULL) {
fprintf(stderr, "Couldn't create tool!\n");
exit(1);
}
tool_free_attribute_list(tool_attrs);
state = INSTRUCTIONS;
initboggle();
bogsw = tool_createsubwindow(tool, "", -1, -1);
initbogsw();
signal(SIGWINCH, sigwinch_handler);
signal(SIGINT, quit);
signal(SIGQUIT, quit);
signal(SIGTERM, quit);
tool_install(tool);
tool_select(tool, 0);
signal(SIGWINCH, SIG_IGN);
tool_destroy(tool);
killchild();
exit(0);
}
usage()
{
fprintf(stderr, "Usage: bogtool [+[+]] [playing-time-in-minutes] [16-letter-string] -d dictionary\n");
exit(1);
}
killchild()
{
if (childpid > 0) {
kill(childpid, SIGINT);
while (wait(0) > 0)
;
childpid = 0;
close(pfd[0]);
close(pfd[1]);
}
}
static
quit()
{
tool_done(tool);
}
#define TOOL_ADDWIDTH (2 * tool_borderwidth(tool))
#define TOOL_ADDHEIGHT (tool_borderwidth(tool) + tool_stripeheight(tool))
static
sigwinch_handler()
{
int miny;
struct rect r;
if ((tool->tl_flags & TOOL_ICONIC) == 0 && (win_getuserflags(tool->tl_windowfd) & WMGR_ICONIC) == 0) {
miny = DISPLAY_BOTTOM;
win_getrect(tool->tl_windowfd, &r);
if (miny % fontheight != 0)
miny += fontheight - (miny % fontheight);
if (r.r_width < DISPLAY_RIGHT + TOOL_ADDWIDTH) {
if (r.r_height < DISPLAY_BOTTOM + miny + fontheight + TOOL_ADDHEIGHT) {
r.r_width = DISPLAY_RIGHT + BOARD_SPACING + 10 * fontwidth + TOOL_ADDWIDTH;
r.r_height = DISPLAY_BOTTOM + BOARD_SPACING + TOOL_ADDHEIGHT;
win_setrect(tool->tl_windowfd, &r);
return;
} else {
r.r_width = DISPLAY_RIGHT + TOOL_ADDWIDTH;
win_setrect(tool->tl_windowfd, &r);
return;
}
} else if (r.r_height < DISPLAY_BOTTOM + TOOL_ADDHEIGHT) {
if (r.r_width < DISPLAY_RIGHT + BOARD_SPACING + 10 * fontwidth + TOOL_ADDWIDTH) {
r.r_width = DISPLAY_RIGHT + BOARD_SPACING + 10 * fontwidth + TOOL_ADDWIDTH;
r.r_height = DISPLAY_BOTTOM + BOARD_SPACING + TOOL_ADDHEIGHT;
win_setrect(tool->tl_windowfd, &r);
return;
} else {
r.r_height = DISPLAY_BOTTOM + BOARD_SPACING + TOOL_ADDHEIGHT;
win_setrect(tool->tl_windowfd, &r);
return;
}
}
}
tool_sigwinch(tool);
}
initbogsw()
{
struct inputmask im;
register x, y, triwidth, triheight;
bogwin = pw_open(bogsw->ts_windowfd);
bogsw->ts_io.tio_handlesigwinch = bog_sigwinch;
bogsw->ts_io.tio_selected = bog_selected;
input_imnull(&im);
win_setinputcodebit(&im, MS_LEFT);
win_setinputcodebit(&im, MS_MIDDLE);
win_setinputcodebit(&im, MS_RIGHT);
win_setinputcodebit(&im, LOC_MOVEWHILEBUTDOWN);
win_setinputcodebit(&im, LOC_WINEXIT);
im.im_flags |= IM_ASCII;
im.im_flags |= IM_NEGEVENT;
win_setinputmask(bogsw->ts_windowfd, &im, 0, WIN_NULLLINK);
bogwin->pw_prretained = NULL;
if ((bogfont = pw_pfsysopen()) == NULL) {
fprintf(stderr, "Couldn't open font!\n");
exit(1);
}
tri_left_pr = mem_create(fontwidth, fontheight, 1);
tri_right_pr = mem_create(fontwidth, fontheight, 1);
triheight = make_even(0.625 * (double)fontheight);
triwidth = triheight / 2;
for (x = 0; x < triwidth; x++) {
for (y = x; y <= triheight - x; y++) {
pr_put(tri_right_pr, x + 1, y + (fontheight - triheight) / 2, 1);
pr_put(tri_left_pr, triwidth - x, y + (fontheight - triheight) / 2, 1);
}
}
}
make_even(c)
double c;
{
int lower;
lower = (int) c;
if (lower % 2 != 0)
lower--;
if (c - (double)lower <= (double)(lower + 2) - c) {
return(lower);
} else {
return(lower + 2);
}
}
startdisplay()
{
freehumanwords();
cwordlen = 0;
scrolled = 0;
}
startboggle(draw)
int draw;
{
genboard();
startdisplay();
starttimer();
startwordfind();
if (draw)
drawbog();
}
static
bog_sigwinch()
{
struct rect r;
win_getsize(bogsw->ts_windowfd, &r);
if (!rect_equal(&r, &bogrect)) {
pw_damaged(bogwin);
pw_donedamaged(bogwin);
bogwidth = r.r_width;
bogheight = r.r_height;
if (bogwin->pw_prretained != NULL)
pr_destroy(bogwin->pw_prretained);
bogwin->pw_prretained = mem_create(bogwidth, bogheight, 1);
switch (state) {
case INSTRUCTIONS:
askinstr();
break;
case CONFIRM_INSTR:
printinstr();
break;
case PLAYING:
drawbog();
break;
case GAMEOVER:
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_SRC, 0, 0, 0);
drawboard();
drawtimer();
displaylists();
break;
}
} else {
pw_damaged(bogwin);
pw_repairretained(bogwin);
pw_donedamaged(bogwin);
}
}
static
bog_selected(data, ibits, obits, ebits, timer)
caddr_t data;
int *ibits, *obits, *ebits;
struct timeval **timer;
{
struct inputevent ie;
if (*ibits & (1 << bogsw->ts_windowfd)) {
if (input_readevent(bogsw->ts_windowfd, &ie) < 0) {
fprintf(stderr, "input_readevent failed!\n");
exit(1);
}
process_input(&ie);
}
if (childactive && state == PLAYING) {
if (*ibits && (1 << fromchild)) {
if (!readchild()) {
close(pfd[0]);
close(pfd[1]);
childactive = 0;
}
}
}
if (state == PLAYING) {
if (movesand()) {
stoptimer = 1;
timeisup(1);
}
}
if (stoptimer) {
timer = NULL;
stoptimer = 0;
}
*ibits = *obits = *ebits = 0;
if (setchildbits) {
childactive++;
setchildbits = 0;
}
if (childactive && state == PLAYING)
*ibits |= (1 << fromchild);
*ibits |= (1 << bogsw->ts_windowfd);
}
process_input(ie)
struct inputevent *ie;
{
int x, y;
char *word, *mouseonword();
if (isascii(ie->ie_code)) {
if (win_inputnegevent(ie))
return;
switch (state) {
case INSTRUCTIONS:
if (ie->ie_code == 'y' || ie->ie_code == 'Y' || ie->ie_code == '?') {
printinstr();
state = CONFIRM_INSTR;
} else {
state = PLAYING;
startboggle(1);
}
break;
case CONFIRM_INSTR:
if (isupper(ie->ie_code)) {
state = PLAYING;
startboggle(1);
}
break;
case PLAYING:
if (feedback_w > 0) { /* remove feedback from isduplicate() */
pw_write(bogwin, feedback_x, feedback_y, feedback_w, fontheight, PIX_NOT(PIX_DST), NULL, 0, 0);
feedback_w = 0;
}
if (isalpha(ie->ie_code))
addchar(ie->ie_code);
else if (ie->ie_code == '\n' || ie->ie_code == '\r' || ie->ie_code == '\t' || ie->ie_code == ' ')
newline();
else if (ie->ie_code == '\177' || ie->ie_code == '\010')
deletechar();
else if (ie->ie_code == '\025')
deleteline();
else
flash(1);
break;
case GAMEOVER:
if (isupper(ie->ie_code)) {
state = PLAYING;
startboggle(1);
}
break;
}
} else if (ie->ie_code == MS_RIGHT) {
if (win_inputposevent(ie))
domenu(ie);
} else if (ie->ie_code == MS_LEFT || ie->ie_code == MS_MIDDLE || ie->ie_code == LOC_MOVEWHILEBUTDOWN) {
if (laststr[0] != '\0') {
word = mouseonword(ie->ie_locx, ie->ie_locy);
if (word == NULL)
unshowword();
else if (strcmp(laststr, word))
unshowword();
}
if (ie->ie_locx > DISPLAY_RIGHT || ie->ie_locy > DISPLAY_BOTTOM) {
if (win_inputposevent(ie)) {
word = mouseonword(ie->ie_locx, ie->ie_locy);
if (word != NULL && strcmp(word, laststr)) {
if (laststr[0] != '\0')
unshowword();
showcubes(word);
}
} else {
unshowword();
}
}
} else if (ie->ie_code == LOC_WINEXIT) {
unshowword();
}
}
domenu(ie)
struct inputevent *ie;
{
struct menuitem *m_item;
m_item = menu_display(&bog_menu, ie, bogsw->ts_windowfd);
if (m_item != NULL) {
switch (m_item->mi_data) {
case BOG_RESTARTTIMER:
if (state != PLAYING)
break;
starttimer();
drawtimer();
break;
case BOG_EXIT:
if (wmgr_confirm(bogsw->ts_windowfd, "Press the left mouse button to confirm Quit. To cancel, press the right mouse button now."))
tool_done(tool);
break;
case BOG_RESTARTGAME:
state = PLAYING;
startboggle(1);
break;
case BOG_GIVEUP:
if (state != PLAYING)
break;
state = GAMEOVER;
stoptimer = 1;
timeisup(0);
}
}
}
drawbog()
{
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_SRC, 0, 0, 0);
drawboard();
drawtimer();
drawtypein();
}
static
drawboard()
{
char *b = board;
int row, column, x, y;
for (column = 0; column < 4; column++) {
for (row = 0; row < 4; row++) {
x = row * (TILE_WIDTH + BOARD_SPACING) + BOARD_BASELEFT;
y = column * (TILE_WIDTH + BOARD_SPACING) + BOARD_BASETOP;
pw_write(bogwin, x, y, TILE_WIDTH, TILE_WIDTH,
PIX_SRC, &tile_pr, 0, 0);
if (*b == 'q') {
pw_write(bogwin, x + FIRST_LETTER_X_OFFSET,
y + LETTER_Y_OFFSET, LETTER_WIDTH,
LETTER_HEIGHT, PIX_SRC,
letters['q'-'a'], 0, 0);
pw_write(bogwin, x + SECOND_LETTER_X_OFFSET,
y + LETTER_Y_OFFSET, LETTER_WIDTH,
LETTER_HEIGHT, PIX_SRC, &small_u_pr,
0, 0);
} else {
pw_write(bogwin, x + CENTER_LETTER_X_OFFSET,
y + LETTER_Y_OFFSET, LETTER_WIDTH,
LETTER_HEIGHT, PIX_SRC,
letters[*b - 'a'], 0, 0);
}
b++;
}
}
}
/*
* addchar: handle a typed character; make sure this part of word is in
* the grid
*/
addchar(c)
char c;
{
cword[cwordlen] = c;
cword[cwordlen + 1] = '\0';
if (!checkword(cword, cwordlen + 1)) { /* be sure word is in grid */
flash(1);
return;
}
drawcursor(); /* erase cursor */
if ((!scrolled && cwordlen >= MAXWORDLEN) || /* scroll it */
(scrolled && cwordlen - scrolled + 1 >= MAXWORDLEN)) {
if (!scrolled)
scrolled++;
scrolled += MAXWORDLEN - SCROLL_OVERLAP;
pw_write(bogwin, leftmargin, typein_y, fontwidth * MAXWORDLEN, fontheight, PIX_SRC, NULL, 0, 0);
pw_write(bogwin, leftmargin, typein_y, fontwidth, fontheight, PIX_SRC, tri_left_pr, 0, 0);
pw_text(bogwin, leftmargin + fontwidth, typein_y + fontoffset, PIX_SRC, bogfont, &cword[scrolled]);
typein_x = leftmargin + (cwordlen - scrolled) * fontwidth + fontwidth;
}
pw_char(bogwin, typein_x, typein_y + fontoffset, PIX_SRC, bogfont, c);
typein_x += fontwidth;
drawcursor(); /* replace cursor */
cwordlen++;
}
/*
* newline: handle a typed newline; make sure word is in dictionary
* and hasn't already been entered; insert into list; move
* cursor on display
*/
newline()
{
if (cwordlen == 0)
return;
if (cwordlen < 3) {
flash(1);
return;
}
cword[cwordlen] = '\0';
if (isduplicate(cword)) { /* already entered this word */
flash(1);
return;
}
if (!verify(cword)) { /* isn't in the dictionary */
flash(1);
return;
}
addhumanword(cword, leftmargin, typein_y);
cwordlen = 0;
drawcursor(); /* erase cursor */
if (scrolled) { /* unscroll word if it is scrolled */
char buf[MAXWORDLEN];
strncpy(buf, cword, MAXWORDLEN - 1);
buf[MAXWORDLEN - 1] = '\0';
pw_text(bogwin, leftmargin, typein_y + fontoffset, PIX_SRC, bogfont, buf);
pw_write(bogwin, leftmargin + (MAXWORDLEN - 1) * fontwidth,
typein_y, fontwidth, fontheight, PIX_SRC, tri_right_pr, 0, 0);
scrolled = 0;
}
(void) nextscreenpos(&leftmargin, &typein_x, &typein_y); /* move cursor to new line */
removefeedback(typein_x, typein_y); /* remove feedback address from word which was here (if wrapped) */
pw_write(bogwin, typein_x, typein_y, MAXWORDLEN * fontwidth, /* erase any previous word */
fontheight, PIX_SRC, NULL, 0, 0);
drawcursor(); /* replace cursor */
}
/*
* deletechar: handle a backspace from user
*/
deletechar()
{
if (cwordlen > 0) {
drawcursor(); /* erase cursor */
if (scrolled && cwordlen == scrolled + 2) { /* unscroll */
if (cwordlen <= MAXWORDLEN) { /* word will still be scrolled */
scrolled = 0;
pw_write(bogwin, leftmargin, typein_y, fontwidth * MAXWORDLEN, fontheight, PIX_SRC, NULL, 0, 0);
cword[--cwordlen] = '\0';
pw_text(bogwin, leftmargin, typein_y + fontoffset, PIX_SRC, bogfont, cword);
typein_x = leftmargin + cwordlen * fontwidth;
} else { /* word no longer scrolled */
scrolled -= MAXWORDLEN - SCROLL_OVERLAP;
pw_write(bogwin, leftmargin, typein_y, fontwidth * MAXWORDLEN, fontheight, PIX_SRC, NULL, 0, 0);
pw_write(bogwin, leftmargin, typein_y, fontwidth, fontheight, PIX_SRC, tri_left_pr, 0, 0);
cword[--cwordlen] = '\0';
pw_text(bogwin, leftmargin + fontwidth, typein_y + fontoffset, PIX_SRC, bogfont, &cword[scrolled]);
typein_x = leftmargin + (cwordlen - scrolled) * fontwidth + fontwidth;
}
} else { /* handle a non-scrolled word */
typein_x -= fontwidth;
pw_write(bogwin, typein_x, typein_y, fontwidth, fontheight, PIX_SRC, NULL, 0, 0);
cwordlen--;
}
drawcursor(); /* redraw cursor */
}
}
/*
* deleteline: handle a line kill from user
*/
deleteline()
{
if (cwordlen > 0) {
drawcursor(); /* erase cursor */
typein_x = leftmargin;
pw_write(bogwin, typein_x, typein_y, fontwidth * cwordlen,
fontheight, PIX_SRC, NULL, 0, 0);
drawcursor(); /* redraw cursor */
cwordlen = 0;
scrolled = 0;
}
}
genboard()
{
int i, j;
if (setupboard)
return;
for (i = 0; i < 16; i++)
board[i] = 0;
for (i = 0; i < 16; i++) {
j = random() % 16;
while (board[j] != 0)
j = (j + 1) % 16;
board[j] = cubeletters[i][random() % 6];
}
}
/*
* nextscreenpos: determine where on the screen the next word goes
*/
nextscreenpos(lm, x, y)
int *lm, *x, *y; /* current left margin, x, and y; gets changed to new value */
{
int full = 0;
if (*x < 0 || *y < 0) { /* display is blank; move to first position */
*y = DISPLAY_BOTTOM;
if (*y % fontheight != 0)
*y += fontheight - (*y % fontheight);
if (*y + fontheight > bogheight) {
*y = 0;
*lm = *x = DISPLAY_RIGHT + BOARD_SPACING;
} else {
*lm = *x = 0;
}
return(0);
}
*x = *lm;
*y += fontheight;
if (*y + fontheight > bogheight) {
*lm = *x += fontwidth * (MAXWORDLEN + 1);
if (*lm + 10 * fontwidth > bogwidth) {
*y = DISPLAY_BOTTOM; /* wrap to beginning of screen */
if (*y % fontheight != 0)
*y += fontheight - (*y % fontheight);
if (*y + fontheight > bogheight) {
*lm = *x = DISPLAY_RIGHT + BOARD_SPACING;
*y = 0;
} else {
*lm = *x = 0;
}
full = 1;
} else if (*x > DISPLAY_RIGHT + BOARD_SPACING) {
*y = 0;
} else {
*y = DISPLAY_BOTTOM;
if (*y % fontheight != 0)
*y += fontheight - (*y % fontheight);
}
}
return(full);
}
askinstr()
{
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_SRC, 0, 0, 0);
pw_text(bogwin, 0, fontoffset, PIX_SRC, bogfont, "Would you like instructions? ");
pw_write(bogwin, 29 * fontwidth, 0, fontwidth, fontheight, PIX_NOT(PIX_DST), NULL, 0, 0);
}
#define INSTRLEN 15
char *instr[INSTRLEN] = {
" The object of Boggle (TM Parker Bros.) is to find as many words as",
"possible in a 4 by 4 grid of letters within a certain time limit. Words",
"may be formed from any sequence of 3 or more adjacent letters in the grid.",
"The letters may join horizontally, vertically, or diagonally. Normally,",
"no letter in the grid may be used more than once in a word. If boggletool",
"is invoked with a numeric argument, it is taken to be the time limit (in",
"minutes). A single + on the command line removes the restriction that",
"letters may be used only once, and two + signs allow a letter to be con-",
"sidered adjacent to itself as well as its neighbors.",
" Boggletool displays a random grid of letters and an hourglass to mark",
"the remaining time. Enter words separated by newlines, using the DEL key",
"or the line-kill character (^U) to correct mistakes. When your time is",
"up, the computer will display a list of words it found from the online",
"dictionary.",
" Type any capital letter to begin."
};
printinstr()
{
int y;
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_SRC, 0, 0, 0);
for (y = 0; y < INSTRLEN; y++)
pw_text(bogwin, 0, y * fontheight + fontoffset, PIX_SRC, bogfont, instr[y]);
}
timeisup(c)
int c;
{
if (c)
flash(3);
state = GAMEOVER;
comparelists();
feedback_w = 0;
displaylists();
}
flash(times)
int times;
{
while (times--) {
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_NOT(PIX_DST), 0, 0, 0);
select(0, 0, 0, 0, &flashdelay);
pw_write(bogwin, 0, 0, bogwidth, bogheight, PIX_NOT(PIX_DST), 0, 0, 0);
if (times)
select(0, 0, 0, 0, &flashdelay);
}
}