home *** CD-ROM | disk | FTP | other *** search
- /* Notes to Localizers:
- * This program was designed to work specifically with English-language
- * words, but it is possible to adapt it to run in any given language
- * with an 8-bit character set. Making this work with a 16-bit character
- * set would require redefining some basic structures.
- * A level 1 modification will make the game playable in another language:
- * 1) Translate the help file from BAGO.DOC, then recompile into BAGO.HLP.
- * 2) Assign new letters to the dice[][] array with a suitable distribution
- * for your language.
- * 3) Change hardwired strings [use your editor to search for double-
- * quote (") marks] to your language.
- * 4) Check that the string functions such as strupr(), toupper(), and
- * isupper() work properly for your language.
- * 5) You must discard the BAGO.DIC dictionary, but can generate a new
- * one simply by playing the game.
- * 6) Generate bitmaps for any additional characters you need. See the
- * WM_PAINT case of the CubeButton window procedure.
- * A level 2 modification would involve making the suffixing routines work
- * properly in your language.
- * 6) Rewrite AddSuffix().
- * 7) Rewrite RemoveSuffix().
- * 8) May need to rewrite macros isdoub() and isvowel().
- * 9) May wish to rewrite isword(), or discard the function completely.
- * 10) Change AddQu() and RemoveQu() routines if necessary. This is
- * because in English, 'U' always follows 'Q'. You may need to write
- * some of your own routines to do similar things.
- * 11) Be aware that some of the 'reward' bitmaps may be illegal in some
- * countries, or at least illegal for distribution to minors. You
- * may wish to discard this feature.
- *
- * You may freely modify this source at no charge. However, I would be
- * interested in seeing your results if you do.
- */
- /****************************************************************************
-
- PROGRAM: Bago.c
-
- PURPOSE: Boggle game for MicroSoft Windows
-
- Author: Roderick Young. (Pen name H.G. Wrekshun)
-
- FUNCTIONS:
-
- WinMain() - calls initialization function, processes message loop
- BagoInit() - initializes window data and registers window
- BagoWndProc() - processes messages
- About() - processes messages for "About" dialog box
-
- Modifications:
- Q.00.00 Hello, World.
- Q.00.01 First playable game.
- Q.00.02 Added game timer.
- Q.00.03 Added tree structure for dictionary.
- Q.00.04 Added capability to write out dictionary.
- Q.00.05 Added capability to read dictionary. Added Resize function.
- Q.00.06 Converted Egg Timer to its own window.
- Q.00.07 Added dialog box for editing words in dictionary.
- Q.00.08 Added routine to compute suffixes of words.
- Q.00.09 Added Prev and Next to Edit dictionary dialog box
- Q.00.10 Added Delete to Edit dictionary dialog box
- Q.00.11 Added dictionary optimization.
- Q.00.12 Added beep sound at end of game.
- Q.00.13 Converted Egg Timer to autonomous Graphic hourglass window.
- Q.01.00 Added window for computer play.
- Q.01.01 Deleted rarely used -OUS, -ION, -ITY suffixes
- Q.01.02 Added RemoveSuffix. Added Learn mode.
- Q.02.00 Added SearchBoard and psearch for computer word search.
- Q.02.01 Eliminated flicker in updating of computer word list.
- Q.02.02 Improved efficiency of psearch by 34% (killed more branches)
- Q.02.03 Added suffix capability to computer search.
- Words found increased by 44%
- Q.02.04 Changed optimize to use windows global memory.
- Search routine yield made to pass through keystrokes.
- Q.02.05 A fixed bug in search algorithm. Now finding 12% more words,
- search length up to 300% of previous.
- Q.02.06 Checking for word validity added.
- Q.02.07 Processing of Qu cube added. Stored as 'Q' internally.
- Q.02.08 General input routine added. Dictionary cull added.
- Q.02.09 Added Bago Cube font.
- Q.02.10 Added variable difficulty level (smartness). Improved font.
- Q.02.11 Added rack numbers and ability to go back to certain rack.
- Also made general input box set default values.
- Added HELP reference card.
- Q.02.12 Added statistics display and clear statistics.
- Q.02.13 Added load and save rack.
- Q.02.14 Added reset frequencies.
- Fixed problem of input words > 10 characters.
- Q.02.15 Fixed deleting hTreeTop word bug. Edit Dict dialog now
- initializes with a starter word.
- Q.02.16 Avoid reading full dictionary if not enough heap space.
- Avoid learning words if not enough heap space.
- Save rack now includes both player and computer word lists.
- Q.02.17 Question last user word if incomplete. Fix cube spacing
- to work with Bago font on EGA.
- Q.02.18 Computer search aborts when game over.
- A.01.00 First release as Freeware. New ABOUTBOX.
- Prev, Next, Virgin edit no longer blank current word.
- A.01.01 Check for success on all GlobalAlloc.
- Width of Word list boxes now relative to character width.
- FindLeaf checks suffixes as well as root word.
- A.01.02 Save and restore settings from WIN.INI
- 2.00 New version convention. Accelerators added.
- 2.01 Clicking on hourglass now starts new game.
- 3.00 Port to windows 3.0. ES_UPPERCASE added to edit window.
- 3.01 Fixed listbox windows to handle proportional fonts.
- Private profile file is now used.
- 3.02 Added isword() routine to loosely check for bogus words.
- 3.03 Added bitmap of eyes to menu, later to use for rewards.
- 3.04 Added progress box while loading dictionary.
- 3.05 Changed from special font to bitmapped controls for cubes.
- Cubes are still output only.
- 3.06 Moved RackNumber display from main window to title bar.
- 3.07 Added WinHelp file.
- 3.08 Made cube controls work for input. Disable dictionary
- functions during a game.
- 3.09 Automatic prompts to save dictionary in places.
- Progress box added for Cull and Optimize. Some message
- boxes taken out.
- 3.10 Got rid of annoying flash on STOP control. Autodetect
- color/mono and do displays to suit.
- 3.11 Changed InputBox to use DialogBoxParam. With 2.0 version,
- needed to use a global to pass input data.
- 3.12 Added Pic box to display reward pictorals. Release to BBSes.
- 3.13 Fixed bug: main title getting messed up, not static.
- 3.14 Added tabstops so that scores line up right justified.
- 3.15 Added -ERS, -INGS suffixes.
- 3.16 Dict edit bug fixed - deleting leaf w/ no inferiors.
- Added DictChanged flag. Distributed to BBses.
- 3.17 Added rand() when player types, so that computer won't
- always find the same words in a given game.
- 3.18 Feature of showing the path by which a word is formed.
- 3.19 Patch color depth detection to handle Super VGA and above.
- Compute initial sizing of window if none in .INI file.
- Focus set to word list after game (for keyboard-only players)
- TAB moves between list boxes (for KB-only users)
- ****************************************************************************/
-
- #include <ctype.h>
- #include <stdlib.h>
- #include <math.h> /* MUST have this, for drawing egg timer */
- #include <io.h>
- #include <windows.h> /* required for all Windows applications */
- #include "bago.h" /* specific to this program */
-
- /* vowels include Y and W for my purpose */
- #define isvowel(c) (c=='A' || c=='E' || c=='I' || c=='O' || c=='U' || c=='W' || c=='Y')
- /* letters which can be doubled */
- #define isdoub(c) (!isvowel(c) && c!='H' && c!='J' && c!='Q' && c!='W' && c!='X' && c!='Y')
-
- HANDLE hInst; /* current instance of main window */
- HWND hUEdit; /* edit window of words typed by player */
- HWND hUList = NULL; /* listbox for player's words */
- HWND hCList = NULL; /* Computer's word list window */
- HWND hEgg = NULL; /* Handle for Egg Timer window */
- HWND hEnter; /* Enter and STOP keys */
- HWND hStop;
-
- HANDLE hAccTable; /* Handle for Menu accelerator table */
-
- /* All the words in the dictionary are kept in a tree structure. */
- HANDLE hTreeTop; /* the top of the tree containing the words */
-
- HANDLE hCListTop; /* top of tree for list of words computer found */
-
- HCURSOR hHourGlass; /* standard hourglass cursor */
-
- HBITMAP hEyes; /* bitmap of eyes */
- HBRUSH hGrayBrush0, hGrayBrush1, hGrayBrush2;
- /* DEBUG make this a static local later, and pass to functions needing it */
- HANDLE hWord; /* Used by EditWord dialog box. */
- /* Handle to record for word being processed */
-
- /* Global variables for the game */
- /* A master list of the dice and what they look like on each face. */
- char dice[NDICE][7] = {
- {0,'A','A','A','F','R','S'},
- {0,'A','A','F','I','R','S'},
- {0,'A','D','E','N','N','N'},
- {0,'A','E','E','E','E','M'},
- {0,'A','E','E','E','E','R'},
- {0,'A','E','E','G','M','U'},
- {0,'A','E','G','M','N','N'},
- {0,'A','F','I','R','S','Y'},
- {0,'B','J','K','Q','X','Z'},
- {0,'C','C','E','N','S','T'},
- {0,'C','E','I','I','L','T'},
- {0,'C','E','I','L','P','T'},
- {0,'C','E','I','P','S','T'},
- {0,'D','D','H','N','O','T'},
- {0,'D','H','H','L','O','R'},
- {0,'D','H','L','N','O','R'},
- {0,'D','H','L','N','O','R'},
- {0,'E','I','I','I','T','T'},
- {0,'E','M','O','T','T','T'},
- {0,'E','N','S','S','S','U'},
- {0,'F','I','P','R','S','Y'},
- {0,'G','O','R','R','V','W'},
- {0,'I','P','R','R','R','Y'},
- {0,'N','O','O','T','U','W'},
- {0,'O','O','O','T','T','U'} };
-
- /* The playing board. The master dice are shuffled into positions on
- * this board at the start of each game.
- */
- BOARD board[NROWS][NCOLS];
-
- BOOL UseTimer; /* True if games are to be timed */
- BOOL CPlay; /* True if computer play option is enabled */
- BOOL Learn; /* True if computer is to learn words from user */
- BOOL RotCubes; /* True if cubes are to be rotated */
- BOOL Sound; /* True if sound enabled */
- BOOL Rewards; /* True if pictoral rewards are given */
- BOOL Mono; /* True if we are on monochrome display */
-
- BOOL GameOver; /* True if game not presently in play */
-
- int EndTime; /* Game duration in seconds */
- int Smartness; /* Level of challenge */
- int NGames = 0; /* Number of games played */
- int RUScore = 0; /* Running Player score */
- int RCScore = 0; /* Running Computer score */
- int RUWords = 0; /* Running Player # of words found */
- int RCWords = 0; /* Running Computer # of words found */
-
- int RackNumber, NextRackNumber; /* Allows consistent regeneration of racks */
- /* by forcing the RNG initialization */
-
- char NextVal[NROWS][NCOLS]; /* These hold the values of the playing cubes */
- char NextOrient[NROWS][NCOLS]; /* for the next game. This funny scheme is */
- /* needed in order to restore an arbitrary */
- /* game from a file */
-
- BOOL OptimizeFail; /* TRUE if optimize GlobalAlloc failed */
-
- int TScoreWidth; /* Width of the string, "Total Score: " */
- int ListWinWidth; /* Width of User and Computer list boxes */
- int TabStops[3]; /* For list box windows */
-
- CUBELOC CubeStack[NDICE]; /* stack to keep track of cubes picked by user */
- int CubeStackPtr = 0; /* points to first free space in stack */
-
- BOOL DictChanged; /* TRUE if dictionary has changed since loading */
-
- /****************************************************************************
-
- FUNCTION: WinMain(HANDLE, HANDLE, LPSTR, int)
-
- PURPOSE: calls initialization function, processes message loop
-
- COMMENTS:
-
- This will initialize the window class if it is the first time this
- application is run. It then creates the window, and processes the
- message loop until a PostQuitMessage is received. It exits the
- application by returning the value passed by the PostQuitMessage.
-
- ****************************************************************************/
-
- int PASCAL WinMain(hInstance, hPrevInstance, lpszCmdLine, nCmdShow)
- HANDLE hInstance; /* current instance */
- HANDLE hPrevInstance; /* previous instance */
- LPSTR lpszCmdLine; /* command line */
- int nCmdShow; /* show-window type (open/icon) */
- {
- HWND hWnd; /* window handle */
- MSG msg; /* message */
- char ProString[80]; /* Holds profile string */
- int x0, y0, x1, y1;
- int ColorDepth; /* true color depth */
- int VertRes; /* Kludge way to determine EGA/VGA */
- HWND hDesk;
- HDC hDeskDC;
-
- /* find out some system metrics for sizing window and choosing bitmaps */
- hDesk = GetDesktopWindow(); /* any window will do */
- hDeskDC = GetDC(hDesk);
- /* for sizing */
- TScoreWidth = LOWORD(GetTextExtent(hDeskDC, "Total Score: ", 16));
- ListWinWidth = TScoreWidth + LOWORD(GetTextExtent(hDeskDC, "0000", 4))
- + GetSystemMetrics(SM_CXVSCROLL);
- /* find out what kind of monitor we're on */
- ColorDepth = GetDeviceCaps(hDeskDC, PLANES) * GetDeviceCaps(hDeskDC, BITSPIXEL);
- VertRes = GetDeviceCaps(hDeskDC, VERTRES);
- ReleaseDC(hDesk, hDeskDC);
- Mono = (ColorDepth <= 2);
-
- /* must have brushes BEFORE setting window class */
- if (ColorDepth < 3)
- {
- hGrayBrush0 = GetStockObject(WHITE_BRUSH);
- hGrayBrush1 = hGrayBrush0;
- hGrayBrush2 = GetStockObject(BLACK_BRUSH);
- }
- else if (VertRes < 480) /* probably EGA */
- {
- hGrayBrush0 = CreateSolidBrush(GRAY1);
- hGrayBrush1 = hGrayBrush0;
- hGrayBrush2 = CreateSolidBrush(GRAY2);
- }
- else /* assume VGA or better */
- {
- hGrayBrush0 = CreateSolidBrush(GRAY0);
- hGrayBrush1 = CreateSolidBrush(GRAY1);
- hGrayBrush2 = CreateSolidBrush(GRAY2);
- }
-
- if (!hPrevInstance) /* Has application been initialized? */
- if (!BagoInit(hInstance))
- return (NULL); /* Exits if unable to initialize */
-
- hInst = hInstance; /* Saves the current instance */
-
- /* Restore the last position, if any */
- /* if no last position, compute a reasonable size and position */
- if (GetPrivateProfileString("Bago", "Window", "", ProString, 80, BAGOINI))
- sscanf(ProString, "%d %d %d %d", &x0, &y0, &x1, &y1);
- else
- {
- x0 = 5;
- y0 = 5;
- x1 = 5 + 2*GetSystemMetrics(SM_CXFRAME)
- + 5*32 /* cubes */
- + 37 /* egg timer */
- + 140 /* slop around egg timer */
- + 2*ListWinWidth;
- y1 = 5 + 2*GetSystemMetrics(SM_CYFRAME)
- + GetSystemMetrics(SM_CYCAPTION)
- + GetSystemMetrics(SM_CYMENU)
- + 5*32; /* cubes */
- }
-
- hWnd = CreateWindow("Bago", /* window class */
- "Bago", /* window name */
- WS_OVERLAPPEDWINDOW, /* window style */
- x0, /* x position */
- y0, /* y position */
- x1-x0, /* width */
- y1-y0, /* height */
- NULL, /* parent handle */
- NULL, /* menu or child ID */
- hInstance, /* instance */
- NULL); /* additional info */
-
- if (!hWnd) /* Was the window created? */
- return (FALSE);
-
- ShowWindow(hWnd, nCmdShow); /* Shows the window */
-
- while (GetMessage(&msg, /* message structure */
- NULL, /* handle of window receiving the message */
- NULL, /* lowest message to examine */
- NULL)) /* highest message to examine */
- {
- if (!TranslateAccelerator(hWnd, hAccTable, &msg))
- {
- TranslateMessage(&msg); /* Translates virtual key codes */
- DispatchMessage(&msg); /* Dispatches message to window */
- }
- }
- return (msg.wParam); /* Returns the value from PostQuitMessage */
- }
-
-
- /****************************************************************************
-
- FUNCTION: BagoInit(HANDLE)
-
- PURPOSE: Initializes window data and registers window class
-
- COMMENTS:
-
- Sets up a structure to register the window class. Structure includes
- such information as what function will process messages, what cursor
- and icon to use, etc.
-
-
- ****************************************************************************/
-
- BOOL BagoInit(hInstance)
- HANDLE hInstance; /* current instance */
- {
- HANDLE hMemory; /* handle to allocated memory */
- PWNDCLASS pWndClass; /* structure pointer */
- BOOL bSuccess; /* RegisterClass() result */
- OFSTRUCT OfStruct;
-
- /* the reason we alloc instead of just having automatic variable */
- /* is to get the whole structure zeroed out */
- hMemory = LocalAlloc(LPTR, sizeof(WNDCLASS));
- pWndClass = (PWNDCLASS) LocalLock(hMemory);
-
- pWndClass->style = NULL;
- pWndClass->lpfnWndProc = BagoWndProc;
- pWndClass->hInstance = hInstance;
- pWndClass->hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(BAGOICON));
-
- pWndClass->hCursor = LoadCursor(NULL, IDC_ARROW);
- pWndClass->hbrBackground = hGrayBrush0;
- pWndClass->lpszMenuName = MAKEINTRESOURCE(BAGOMENU);
- pWndClass->lpszClassName = (LPSTR) "Bago";
-
- bSuccess = RegisterClass(pWndClass);
-
- if (!bSuccess)
- {
- LocalUnlock(hMemory); /* unlock memory and return it to windows */
- LocalFree(hMemory);
- return(FALSE); /* registering window failed */
- }
-
- /* now register a class for the Egg Timer window */
-
- pWndClass->style = NULL;
- pWndClass->lpfnWndProc = EggWndProc;
- pWndClass->hInstance = hInstance;
- pWndClass->hIcon = NULL;
- pWndClass->hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(BAGOCUR));
- pWndClass->hbrBackground = hGrayBrush1;
- pWndClass->lpszMenuName = (LPSTR) NULL;
- pWndClass->lpszClassName = (LPSTR) "Egg";
-
- bSuccess = RegisterClass(pWndClass);
-
- if (!bSuccess)
- {
- LocalUnlock(hMemory); /* unlock memory and return it to windows */
- LocalFree(hMemory);
- return(FALSE); /* registering window failed */
- }
-
- /* The Progress Box class */
-
- pWndClass->style = NULL;
- pWndClass->lpfnWndProc = ProWndProc;
- pWndClass->hInstance = hInstance;
- pWndClass->hIcon = NULL;
- pWndClass->hCursor = NULL;
- pWndClass->hbrBackground = hGrayBrush1;
- pWndClass->lpszMenuName = NULL;
- pWndClass->lpszClassName = "Pro";
-
- bSuccess = RegisterClass(pWndClass);
-
- if (!bSuccess)
- {
- LocalUnlock(hMemory); /* unlock memory and return it to windows */
- LocalFree(hMemory);
- return(FALSE); /* registering window failed */
- }
-
- /* Cube button class */
-
- pWndClass->style = NULL;
- pWndClass->lpfnWndProc = CubeWndProc;
- pWndClass->hInstance = hInstance;
- pWndClass->hIcon = NULL;
- pWndClass->hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(BAGOCUR));
- pWndClass->hbrBackground = NULL;
- pWndClass->lpszMenuName = NULL;
- pWndClass->lpszClassName = "CubeButton";
-
- bSuccess = RegisterClass(pWndClass);
-
- if (!bSuccess)
- {
- LocalUnlock(hMemory); /* unlock memory and return it to windows */
- LocalFree(hMemory);
- return(FALSE); /* registering window failed */
- }
-
- /* Pictoral display class */
-
- pWndClass->style = NULL;
- pWndClass->lpfnWndProc = PicWndProc;
- pWndClass->hInstance = hInstance;
- pWndClass->hIcon = NULL;
- pWndClass->hCursor = LoadCursor(hInstance, MAKEINTRESOURCE(BAGOCUR));
- pWndClass->hbrBackground = hGrayBrush2;
- pWndClass->lpszMenuName = NULL;
- pWndClass->lpszClassName = "Pic";
-
- bSuccess = RegisterClass(pWndClass);
-
- LocalUnlock(hMemory); /* unlock memory and return it to windows */
- LocalFree(hMemory);
-
- return (bSuccess); /* Returns result of registering the window */
- }
-
- /****************************************************************************
-
- FUNCTION: BagoWndProc(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages
-
- MESSAGES:
-
- WM_CREATE - create window
- WM_PAINT - repaint window
- WM_DESTROY - destroy window
-
- COMMENTS:
-
-
- ****************************************************************************/
-
- long FAR PASCAL BagoWndProc(hWnd, message, wParam, lParam)
- HWND hWnd; /* window handle */
- unsigned message; /* type of message */
- WORD wParam; /* additional information */
- LONG lParam; /* additional information */
- {
- switch (message) {
- case WM_SYSCOMMAND: /* message: command from system menu */
- if (wParam == MN_REWARDS)
- {
- ProcessBagoRewards(hWnd, wParam);
- break;
- }
- else /* Lets Windows process it */
- return (DefWindowProc(hWnd, message, wParam, lParam));
-
- case WM_CREATE: /* message: window being created */
- ProcessBagoCreate(hWnd, wParam, lParam);
- break;
-
- case BAGOM_INIT:
- /* A call to initialize. This is only called once per instance. */
- /* These actions are done here rather than at WM_CREATE message, */
- /* because I want the window to appear immediately, rather than */
- /* have an annoying pause while everything is initializing */
-
- LoadDictionary(hWnd);
- break;
-
-
- case WM_COMMAND: /* process menu selection */
- ProcessBagoCommand(hWnd, wParam, lParam);
- break;
-
- case WM_PAINT:
- ProcessBagoPaint(hWnd);
- break;
-
- case WM_SIZE:
- ProcessBagoSize(hWnd, wParam, lParam);
- break;
-
- case WM_SETFOCUS:
- /* This is in case the player came back from some other task */
- if (!GameOver) SetFocus(hUEdit);
- else
- {
- if (CPlay) SetFocus(hCList); /* so that keyboard only user */
- else SetFocus(hUList); /* can see word paths */
- }
- break;
-
- case BAGOM_CUBEDN:
- /* given when a cube pressed down by player */
- /* wparam contains CUBELOC of cube */
- PushCube(wParam);
- EnableAroundCube(wParam);
- break;
-
- case BAGOM_CUBEUP:
- /* given when a cube popped up by player */
- EnableAroundCube(PopCube());
- break;
-
- case WM_DRAWITEM:
- ProcessBagoDrawItem(hWnd, lParam);
- break;
-
- case BAGOM_ENDGAME:
- /* do not end the game if it is already over */
- if (!GameOver) ProcessBagoEndGame(hWnd);
- break;
-
- case WM_CLOSE: /* message BEFORE window is destroyed */
- ProcessBagoClose(hWnd);
- DestroyWindow(hWnd);
- break;
-
- case WM_DESTROY: /* message: window being destroyed */
- PostQuitMessage(0);
- break;
-
- default: /* Passes it on if unproccessed */
- return (DefWindowProc(hWnd, message, wParam, lParam));
- }
- return (NULL);
- }
-
- /* Return a near pointer to a copy of a far string.
- * Warnings: will die on strings of length > 20.
- * will destroy the near copy of the string on subsequent calls
- */
- char NEAR *FarToNearStr(FarStr)
- LPSTR FarStr;
- {
- static char NEAR NearStr[20];
- char *NearPtr;
- NearPtr = NearStr;
- while (*NearPtr++ = *FarStr++);
- return(NearStr);
- }
-
- /* CubeStackPtr points to first free space in the stack */
- PushCube(cube)
- CUBELOC cube;
- {
- if (CubeStackPtr < NDICE)
- {
- CubeStack[CubeStackPtr] = cube;
- CubeStackPtr++;
- }
- }
-
- /* If the stack is empty, returns a virtual cube whose neighbors cannot */
- /* be in the rack. This is important, as it will be used by the */
- /* EnableAroundCube() routine. This is not a normal type pop routine */
- /* WARNING: returns the element REMAINING on the top of the stack, NOT */
- /* the element that was just popped off */
- CUBELOC PopCube()
- {
- CUBELOC OffBoard;
-
- if (CubeStackPtr > 0) CubeStackPtr--;
- if (CubeStackPtr > 0) return(CubeStack[CubeStackPtr-1]);
- else
- {
- OffBoard.row = -1; OffBoard.col = -1;
- return(OffBoard);
- }
- }
-
- /* This enables or disables all cube windows at once, according to the */
- /* value of the parameter passed. */
- EnableCubes(bEnable)
- BOOL bEnable;
- {
- int row, col;
-
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- {
- EnableWindow(board[row][col].hWindow, bEnable);
- }
- }
-
- /* This enables all neighbors to a cube except those which are */
- /* already pressed down. Any other cubes in the rack are disabled */
- /* If the cube specified is not on the board, all cubes are enabled */
- EnableAroundCube(cube)
- CUBELOC cube;
- {
- int row, col;
-
- if (cube.row < 0 || cube.col < 0)
- EnableCubes(TRUE);
- else
- {
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- {
- if (cube.col==col && cube.row==row) EnableWindow(board[row][col].hWindow, TRUE);
- else if ((cube.col==col-1 || cube.col==col+1 || cube.col==col) &&
- (cube.row==row-1 || cube.row==row+1 || cube.row==row))
- EnableWindow(board[row][col].hWindow, !board[row][col].Uused);
- else
- EnableWindow(board[row][col].hWindow, FALSE);
- }
- }
- }
-
- /* This routine sets up everything for a new game. It scraps any existing */
- /* information in the word list windows, and displays a new board. */
- NewGame(hWnd)
- HWND hWnd;
- {
- int row, col; /* used to step through board array */
- HANDLE hOldBuffer; /* the User's word list */
- static char Title[20]; /* static because will be in title */
-
- GameOver = FALSE;
- CubeStackPtr = 0; /* empty the Cube stack */
-
- /* disallow dictionary menu picks while game in progress */
- EnableMenuItem(GetMenu(hWnd), 2, MF_BYPOSITION | MF_DISABLED | MF_GRAYED);
- DrawMenuBar(hWnd);
-
- /* set up the rack, and report it in title bar */
- RackNumber = NextRackNumber;
- if (RackNumber >= 0)
- sprintf(Title, "Bago - Game #%d", RackNumber);
- else
- /* Some games do not have rack numbers, like restored games */
- strcpy(Title, "Bago");
- /* not using SetWindowText because no rush */
- PostMessage(hWnd, WM_SETTEXT, 0, (LONG)(LPSTR) Title);
-
- /* Now draw the new cubes */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- {
- board[row][col].val = NextVal[row][col];
- board[row][col].orient = NextOrient[row][col];
- board[row][col].Uused = FALSE;
- board[row][col].Cused = FALSE;
- InvalidateRect(board[row][col].hWindow, NULL, FALSE);
- }
- EnableCubes(TRUE);
- EnableWindow(hEnter, TRUE);
- EnableWindow(hStop, TRUE);
- EnableWindow(hUEdit, TRUE);
-
- /* Clear out the old word list from player's edit */
- hOldBuffer = SendMessage(hUEdit, EM_GETHANDLE, 0, 0L);
- if (hOldBuffer) LocalFree(hOldBuffer);
- /* Allocate small buffer - edit control will expand if needed */
- hOldBuffer = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT, USERWORDLEN);
- SendMessage(hUEdit, EM_SETHANDLE, hOldBuffer, 0L);
- ShowWindow(hUEdit, SW_SHOW);
- ShowWindow(hUList, SW_HIDE);
-
- SetFocus(hUEdit); /* direct input to the word list */
-
- /* Clear player's list (it is under the edit window) */
- SendMessage(hUList, LB_RESETCONTENT, 0, 0L);
-
- /* Start game timer if there is one */
- if (hEgg) SendMessage(hEgg, EGGM_START, 0, 0L);
-
- /* If the computer is playing */
- if (CPlay)
- {
- /* clear the computer's list */
- SendMessage(hCList, LB_RESETCONTENT, 0, 0L);
- DestroyLeaf(hCListTop);
- hCListTop = NULL;
- /* start computer search */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- SearchBoard(&board[row][col]);
- }
- }
-
- /* General Input */
- /* Prompt is the prompt string for the input, target output goes to integer
- * OutI if Mode is TRUE, else string goes to OutString
- * Values are returned in OutString and OutI. Note: OutString must have
- * space for 80 characters.
- */
- /* Status is returned as a WORD */
- WORD InputBox(hWnd, Prompt, OutString, OutI, IntMode)
- HWND hWnd;
- LPSTR Prompt;
- LPSTR OutString;
- LPINT OutI;
- BOOL IntMode;
- {
- FARPROC lpInputDiag;
- INPUTSTRUCT InputStruct;
- WORD result; /* either OK or CANCEL */
-
- InputStruct.Prompt = Prompt;
- InputStruct.OutString = OutString; /* default value for input */
- InputStruct.OutI = OutI;
- InputStruct.IntMode = IntMode;
-
- lpInputDiag = MakeProcInstance((FARPROC) InputDiag, hInst);
- result = DialogBoxParam(hInst, MAKEINTRESOURCE(INPUTDIALOG), hWnd, lpInputDiag, (LONG) (LPSTR) &InputStruct);
- FreeProcInstance(lpInputDiag);
- return(result);
- }
-
- /* Tricky use of lParam -> Mode: upon entry, indicates integer or text mode */
- /* Upon exit, indicates the button (OK or CANCEL) pressed */
- BOOL FAR PASCAL InputDiag(hDlg, message, wParam, lParam)
- HWND hDlg;
- unsigned message;
- WORD wParam;
- LONG lParam;
- {
- BOOL TransOK;
- static LPINPUTSTRUCT InputStruct;
-
- switch (message)
- {
- case WM_INITDIALOG: /* message: initialize dialog box */
- InputStruct = (LPINPUTSTRUCT) lParam; /* remember our structure for later */
- SetDlgItemText(hDlg, ID_IMSG, InputStruct -> Prompt);
- SetFocus(GetDlgItem(hDlg, ID_INPUT));
- /* set default value and select entire string */
- SetDlgItemText(hDlg, ID_INPUT, InputStruct -> OutString);
- SendMessage(GetDlgItem(hDlg, ID_INPUT),
- EM_SETSEL, 0, MAKELONG(0, 32767));
- return (FALSE); /* so windows won't arbitrarily set focus */
- break;
- case WM_COMMAND: /* message: received a command */
- switch (wParam)
- {
- case ID_OK:
- if (InputStruct -> IntMode)
- {
- *(InputStruct -> OutI) = GetDlgItemInt(hDlg, ID_INPUT, &TransOK, TRUE);
- if (TransOK) EndDialog(hDlg, wParam);
- }
- else
- {
- GetDlgItemText(hDlg, ID_INPUT, InputStruct -> OutString, 80);
- EndDialog(hDlg, wParam);
- }
- break;
- case ID_CANCEL:
- EndDialog(hDlg, wParam); /* Exits the dialog box */
- break;
- }
- return (TRUE);
- break;
- default:
- return (FALSE); /* Didn't process a message */
- }
- }
-
- /**************** Bago Processing Routines ****************/
-
- /* Creates the egg timer and puts it up on the screen */
- /* Warning: if the egg timer already exists, a second copy will be created */
- HWND CreateEggTimer(hWnd)
- HWND hWnd;
- {
- RECT Rect;
- POINT Point;
- HWND hEgg;
-
- GetClientRect(hWnd, (LPRECT) &Rect);
- Point.x = Rect.left + 280;
- Point.y = Rect.top;
- ClientToScreen(hWnd, &Point);
-
- /* Would like to have WS_THICKFRAME, but that forces the */
- /* resulting window to have an undesirably large minimum size */
- hEgg = CreateWindow("Egg", /* window class */
- "", /* window name */
- WS_POPUP | WS_CAPTION | WS_BORDER | WS_VISIBLE,
- Point.x, /* x position */
- Point.y, /* y position */
- 37, /* width */
- 120, /* height */
- hWnd, /* parent handle */
- NULL, /* no ID for popup window */
- hInst, /* instance */
- NULL); /* additional info */
-
- if (!hEgg)
- MessageBox(hWnd, "Unable to create timer window", "ERROR",
- MB_ICONQUESTION | MB_OK);
-
- return(hEgg);
- }
-
- ProcessBagoCommand (hWnd, wParam, lParam)
-
- HWND hWnd;
- WORD wParam;
- LONG lParam;
- {
- FARPROC lpEditWord; /* proc instance for opening dialog box */
- FARPROC lpProcAbout; /* pointer to the "About" function */
- char OutBuf[80];
- int NewValue;
-
- switch (wParam)
- {
- case MN_DD_GAME + MN_GAM_PLAY:
- NewGame(hWnd);
- break;
-
- case MN_DD_GAME + MN_GAM_END:
- if (UseTimer) PostMessage(hEgg, EGGM_STOP, 0, 0L);
- else PostMessage(hWnd, BAGOM_ENDGAME, 0, 0L);
- break;
-
- case MN_DD_GAME + MN_GAM_STATS:
- ProcessBagoStats(hWnd);
- break;
-
- case MN_DD_GAME + MN_GAM_CSTATS:
- RUScore = 0; RUWords = 0;
- RCScore = 0; RCWords = 0;
- NGames = 0;
- break;
-
- case MN_DD_GAME + MN_GAM_TOURN:
- sprintf(OutBuf, "%d", NextRackNumber);
- if (InputBox(hWnd, "Set Rack Number for Next Game (0 - 32767)",
- OutBuf, &NewValue, TRUE) != ID_CANCEL)
- {
- if (NewValue < 0) NewValue = 0;
- if (NewValue > 32767) NewValue = 32767;
- NextRackNumber = NewValue;
- SetNextRack(NextRackNumber);
- }
- break;
-
- case MN_DD_GAME + MN_GAM_LOAD:
- ProcessBagoGLoad(hWnd);
- break;
-
- case MN_DD_GAME + MN_GAM_SAVE:
- ProcessBagoGSave(hWnd);
- break;
-
- case MN_DD_GAME + MN_GAM_QUIT:
- ProcessBagoClose(hWnd);
- DestroyWindow(hWnd);
- break;
-
- /* Set the computer's skill level */
- case MN_DD_OPTIONS + MN_OPT_LEVEL:
- sprintf(OutBuf, "%d", Smartness);
- if (InputBox(hWnd, "Difficulty (0 - 100)",
- OutBuf, &NewValue, TRUE) != ID_CANCEL)
- {
- if (NewValue < 0) NewValue = 0;
- if (NewValue > 100) NewValue = 100;
- Smartness = NewValue;
- }
- break;
-
- /* Realistically rotated cubes option */
- case MN_DD_OPTIONS + MN_OPT_ROTATE:
- ProcessBagoRotCubes(hWnd, wParam);
- break;
-
- case MN_DD_OPTIONS + MN_OPT_SOUND:
- ProcessBagoSound(hWnd, wParam);
- break;
-
- /* Set game duration */
- case MN_DD_OPTIONS + MN_OPT_GTIME:
- sprintf(OutBuf, "%d", EndTime);
- if (InputBox(hWnd, "Play Time in seconds (30 - 600)",
- OutBuf, &NewValue, TRUE) != ID_CANCEL)
- {
- if (NewValue < 30) NewValue = 30;
- if (NewValue > 600) NewValue = 600;
- EndTime = NewValue;
- }
- break;
-
- /* enable/disable egg timer */
- case MN_DD_OPTIONS + MN_OPT_TIMER:
- ProcessBagoTimer(hWnd, wParam);
- break;
-
- case MN_DD_OPTIONS + MN_OPT_LEARN:
- ProcessBagoLearn(hWnd, wParam);
- break;
-
- /* Enable Computer Play */
- case MN_DD_OPTIONS + MN_OPT_CPLAY:
- ProcessBagoCPlay(hWnd, wParam);
- break;
-
- /* display heap size */
- case MN_DD_OPTIONS + MN_SEL_8:
- sprintf(OutBuf, "Local Heap: %u\nGlobal Heap: %lu", LocalCompact(64000), GlobalCompact(1200000L));
- MessageBox(hWnd, OutBuf, "Mem Free", MB_OK);
- break;
-
- #ifdef ignore
- case MN_DD_OPTIONS + MN_SEL_9:
- /* Test the search algorithm */
- GameOver = FALSE;
- DestroyLeaf(hCListTop);
- hCListTop = NULL;
- DebugCount = 0L;
- /* start computer search */
- for (Debugrow=0; Debugrow < NROWS; Debugrow++)
- for (Debugcol=0; Debugcol < NCOLS; Debugcol++)
- SearchBoard(&board[Debugrow][Debugcol]);
- sprintf(OutBuf, "Iterations: %ld", DebugCount);
- MessageBox(hWnd, OutBuf, "Test PSearch", MB_OK);
- GameOver = TRUE;
- #endif
- break;
-
- case MN_DD_DICT + MN_DIC_LOAD:
- if (!LoadDictionary(hWnd))
- MessageBox(hWnd, "Cannot find "BAGODIC, "Error",
- MB_OK | MB_ICONQUESTION);
- break;
-
- case MN_DD_DICT + MN_DIC_SAVE:
- ProcessBagoSaveDict(hWnd);
- break;
-
- case MN_DD_DICT + MN_DIC_SHOW:
- ProcessBagoShowDict(hWnd);
- InvalidateRect(hUEdit, NULL, TRUE);
- break;
-
- case MN_DD_DICT + MN_DIC_EDIT:
- lpEditWord = MakeProcInstance((FARPROC) EditWord, hInst);
- DialogBox(hInst, MAKEINTRESOURCE(EDITWORDBOX), hWnd, lpEditWord);
- FreeProcInstance(lpEditWord);
- break;
-
- case MN_DD_DICT + MN_DIC_OPT:
- ProcessBagoOptDict(hWnd);
- break;
-
- case MN_DD_DICT + MN_DIC_CULL:
- strcpy(OutBuf, "0");
- if (InputBox(hWnd, "Min Freq on words to KEEP (0-32767)",
- OutBuf, &NewValue, TRUE) == ID_CANCEL)
- break;
- CullDictionary(hWnd, NewValue);
- break;
-
- case MN_DD_DICT + MN_DIC_RFREQ:
- ResetFreqLeaf(hTreeTop);
- break;
-
- case MN_DD_HELP + MN_HLP_REFCARD:
- MessageBox(hWnd,
- "Object of game: To make as many words as possible\n"
- " by following paths through adjacent letters.\n\n"
- "Scoring:\n\n"
- " Word Size\tScore\n"
- " 4 letters\t 1 point\n"
- " 5 letters\t 2 points\n"
- " 6 letters\t 3 points\n"
- " 7 letters\t 5 points\n"
- " 8 or more\t11 points\n\n"
- "Disqualification marks on words:\n\n"
- "(indent)\tFound by both players\n"
- " \"\tDuplicate of word listed earlier\n"
- " <\tLess than 4 letters\n"
- " ?\tNot in rack (check again)\n"
- " -\tNot a word\n\n\n"
- "... select Help -> Index for more details",
- "Reference Card", MB_OK);
- break;
-
- case MN_DD_HELP + MN_HLP_INDEX:
- if (!WinHelp(hWnd, BAGOHLP, HELP_INDEX, 0L))
- MessageBox(hWnd, "Sorry, can't run help.", "Error", MB_OK);
- break;
-
- case MN_DD_HELP + MN_HLP_ABOUT:
- lpProcAbout = MakeProcInstance(About, hInst);
- DialogBox(hInst, /* current instance */
- MAKEINTRESOURCE(ABOUTBOX), /* resource to use */
- hWnd, /* parent handle */
- lpProcAbout); /* About() instance address */
- FreeProcInstance(lpProcAbout);
- break;
-
- case BAGOM_TAB:
- /* This command is so that keyboard-only users can swap between */
- /* lists after a game to see the word paths */
- if (GameOver && CPlay)
- {
- if (GetFocus()==hCList) SetFocus(hUList);
- else SetFocus(hCList);
- }
- break;
-
- case ID_STOP:
- /* Same as the endgame menu pick or accelerator */
- if (UseTimer) PostMessage(hEgg, EGGM_STOP, 0, 0L);
- else PostMessage(hWnd, BAGOM_ENDGAME, 0, 0L);
- break;
-
- case ID_ENTER:
- /* Enter key pressed. If game in progress, send enter to */
- /* the user wordlist, and enable all cubes */
- if (!GameOver) ProcessEnter();
- break;
-
- case ID_USERWORDS:
- /* Randomize slightly so that computer plays differently based */
- /* on how player plays */
- rand();
- break;
-
- case ID_PLIST:
- case ID_CPLAY:
- /* click on word to display path on cubes */
- ProcessBagoPList(hWnd, lParam);
- break;
- }
- }
-
- /* Process a notification message from a list box. */
- /* Presently, this only shows that path (if any) that forms the selected */
- /* word. Process the message that selection changed. */
- ProcessBagoPList(hWnd, lParam)
- HWND hWnd;
- LONG lParam;
- {
- if (HIWORD(lParam)==LBN_SELCHANGE)
- {
- HWND hListBox;
- int SelIndex;
- CUBELOC cube;
- int col, row;
- BOOL found;
- RECT rect;
- char WordSought[80];
- int tStackPtr;
-
- /* clean off any previous path from buttons */
- for (tStackPtr=CubeStackPtr; tStackPtr >= 0; tStackPtr--)
- {
- cube = CubeStack[tStackPtr];
- InvalidateRect(board[cube.row][cube.col].hWindow, NULL, FALSE);
- }
- /* get the requested word */
- hListBox = LOWORD(lParam);
- SelIndex = SendMessage(hListBox, LB_GETCURSEL, 0, 0L);
- if (SelIndex != LB_ERR)
- {
- SendMessage(hListBox, LB_GETTEXT, SelIndex, (LONG)(LPSTR) WordSought);
- TrimWord(WordSought, strlen(WordSought));
- RemoveQu(WordSought);
- /* Find the word on the board */
- found = FALSE;
- for (row=0; row<NROWS; row++)
- {
- for (col=0; col<NCOLS; col++)
- {
- CubeStackPtr = 0;
- if (verify(WordSought, &board[row][col], strlen(WordSought)))
- {
- found = TRUE;
- break;
- }
- }
- if (found) break;
- }
- if (found)
- /* tell main window to go and draw the path */
- {
- rect.left=0; rect.top=0;
- rect.right=32*NCOLS; rect.bottom=32*NROWS;
- InvalidateRect(hWnd, &rect, FALSE);
- }
- }
- }
- }
-
- /* Enter control pressed */
- ProcessEnter()
- {
- CUBELOC cube;
-
- /* pop up any cubes that are selected */
- if (CubeStackPtr > 0)
- while (CubeStackPtr > 0)
- {
- cube = CubeStack[--CubeStackPtr];
- board[cube.row][cube.col].Uused = FALSE;
- InvalidateRect(board[cube.row][cube.col].hWindow, NULL, FALSE);
- }
- EnableCubes(TRUE);
-
- PostMessage(hUEdit, WM_CHAR, '\r', 1L);
- SetFocus(hUEdit);
- }
-
- /* Process WM_DRAWITEM message from STOP and ENTER controls */
- ProcessBagoDrawItem(hWnd, lParam)
- HWND hWnd;
- LPDRAWITEMSTRUCT lParam;
- {
- HDC hDC;
- HBITMAP hBitmap, hOldBitmap;
- HDC hMemoryDC;
-
- hDC = lParam -> hDC;
- switch (lParam -> CtlID)
- {
- case ID_STOP:
- if ((lParam -> itemState) & ODS_SELECTED)
- hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(STOPDNBMP));
- else
- hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(STOPUPBMP));
- hMemoryDC = CreateCompatibleDC(hDC);
- hOldBitmap = SelectObject(hMemoryDC, hBitmap);
- if (hOldBitmap)
- {
- BitBlt(hDC, 0, 0, 32, 32, hMemoryDC, 0, 0, SRCCOPY);
- SelectObject(hMemoryDC, hOldBitmap);
- }
- DeleteObject(hBitmap);
- DeleteDC(hMemoryDC);
- break;
- case ID_ENTER:
- if ((lParam -> itemState) & ODS_SELECTED)
- hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(ENTERDNBMP));
- else
- hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(ENTERUPBMP));
- hMemoryDC = CreateCompatibleDC(hDC);
- hOldBitmap = SelectObject(hMemoryDC, hBitmap);
- if (hOldBitmap)
- {
- BitBlt(hDC, 0, 0, 64, 32, hMemoryDC, 0, 0, SRCCOPY);
- SelectObject(hMemoryDC, hOldBitmap);
- }
- DeleteObject(hBitmap);
- DeleteDC(hMemoryDC);
- break;
- }
- }
-
- /* The only thing that is painted in the main window is the path that */
- /* shows how a word was made. And that feature is only available when */
- /* the game is over */
- ProcessBagoPaint(hWnd)
- HWND hWnd;
- {
- HDC hDC;
- PAINTSTRUCT ps;
- HPEN hPathPen, hOldPen;
- int row, col;
- int tStackPtr;
- CUBELOC cube;
-
- hDC = BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
-
- if (GameOver && CubeStackPtr > 0)
- {
- /* Clear any previous path off the cubes if necessary */
- /* Must do all cubes, in case we are restoring a minimized window */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- UpdateWindow(board[row][col].hWindow);
-
- hPathPen = CreatePen(PS_SOLID, 1, RED);
- if (hPathPen)
- {
- hOldPen = SelectObject(hDC, hPathPen);
- tStackPtr = CubeStackPtr - 1;
- cube = CubeStack[tStackPtr];
- MoveTo(hDC, cube.col*32+16, cube.row*32+16);
- while (tStackPtr > 0)
- {
- cube = CubeStack[--tStackPtr];
- LineTo(hDC, cube.col*32+16, cube.row*32+16);
- }
- SelectObject(hDC, hOldPen);
- DeleteObject(hPathPen);
- }
- /* Note: tell ALL the buttons not to repaint */
- /* it is faster to just validate them all. Selective validation */
- /* of the ones that the path went through may still allow some */
- /* of the buttons to repaint, taking up time */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- ValidateRect(board[row][col].hWindow, NULL);
- }
-
- EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
- }
-
- /* Process the Resize message by sizing the controls and child windows */
- ProcessBagoSize(hWnd, wParam, lParam)
- HWND hWnd;
- WORD wParam;
- LONG lParam;
- {
- MoveWindow(hUEdit, LOWORD(lParam) - 2*ListWinWidth, 0,
- ListWinWidth, HIWORD(lParam), TRUE);
- MoveWindow(hUList, LOWORD(lParam) - 2*ListWinWidth, 0,
- ListWinWidth, HIWORD(lParam), TRUE);
- MoveWindow(hCList, LOWORD(lParam) - ListWinWidth, 0,
- ListWinWidth, HIWORD(lParam), TRUE);
- InvalidateRect(hWnd, NULL, TRUE);
- }
-
- /* Converts all lowercase characters to uppercase, then eliminates any */
- /* characters that are not strictly alphabetic */
- TrimWord(w, len)
- char w[80];
- int len;
- {
- int source = 0, dest = 0;
-
- strupr(w); /* convert to uppercase */
- for (source=0; source < len; source++)
- if (isupper(w[source]))
- w[dest++] = w[source];
-
- w[dest] = NULL;
- }
-
- /* Converts 'Q' in a string to 'QU' */
- AddQu(w)
- char w[];
- {
- char temp[30];
- int source, dest;
- int len;
-
- len = strlen(w);
- dest = 0;
- for (source=0; source<len; source++)
- {
- temp[dest++] = w[source];
- if (w[source] == 'Q')
- temp[dest++] = 'U';
- }
- temp[dest] = NULL;
- strcpy(w, temp);
- }
-
- /* Converts 'QU' in a string to 'Q' */
- RemoveQu(w)
- char w[];
- {
- int source, dest;
- int len;
-
- len = strlen(w);
- dest = 0;
- for (source=0; source<len; source++)
- {
- w[dest++] = w[source];
- if (w[source] == 'Q' && w[source+1] == 'U')
- source++;
- }
- w[dest] = NULL;
- }
-
- /* This procedure is used to add a leaf to the dictionary tree */
- /* Recursive, to match the tree search and sort */
- /* Procedure is more complicated than a normal tree sort because
- * I have chosen to use Windows local heap, instead of direct pointers.
- * This will make the program slower in execution, but the program may
- * be much faster than it needs to be, anyway.
- * If the word is already in the structure, its frequency count is
- * incremented. If not, the word is added to the structure.
- * When a word is added, a back link is made, too, so that the tree
- * may be easily traversed in either direction
- */
- AddLeaf(s, hLeafPtr, freq, suffix, hSuperior)
- char *s;
- HANDLE *hLeafPtr;
- int freq;
- unsigned suffix;
- HANDLE hSuperior; /* handle of superior leaf */
- {
- PDW LeafPtr;
- int comp; /* results of string compare */
-
- if (*hLeafPtr)
- /* A record exists at this handle. Check it. */
- {
- LeafPtr = (PDW) LocalLock(*hLeafPtr);
- if (!(comp = strcmp(s, LeafPtr -> w)))
- /* words are equal, combine the relevant data */
- {
- /* don't want to overflow 16-bit integer */
- if ((LONG) (LeafPtr -> Freq) + freq < 32767L) LeafPtr -> Freq += freq;
- LeafPtr -> Suffix1 |= suffix;
- }
- else
- {
- if (comp < 0)
- /* the new word is less than the word at this leaf */
- {
- AddLeaf(s, &(LeafPtr -> lt), freq, suffix, *hLeafPtr);
- }
- else
- /* the new word is greater than the word at this leaf */
- {
- AddLeaf(s, &(LeafPtr -> gt), freq, suffix, *hLeafPtr);
- }
- }
- LocalUnlock(*hLeafPtr);
- }
- else
- /* No record exists at this handle. Allocate memory and add word */
- {
- *hLeafPtr = LocalAlloc(LMEM_MOVEABLE | LMEM_ZEROINIT,
- sizeof(DW));
- LeafPtr = (PDW) LocalLock(*hLeafPtr);
- strcpy(LeafPtr -> w, s);
- LeafPtr -> Freq = freq;
- LeafPtr -> Suffix1 = suffix;
- LeafPtr -> up = hSuperior;
- LocalUnlock(*hLeafPtr);
- }
- }
-
- /* Relocate a leaf. The assumption is made that hSource is the
- * handle of a valid record, and that this record does not already
- * exist in the tree. hLeafPtr is the target destination for the
- * leaf. If there is already something in hLeafPtr, the routine
- * recursively finds a free place. hSuperior is a handle to the
- * leaf that the up link of hLeafPtr should point to.
- * This routine preserves any existing gt and lt links.
- */
- RelocateLeaf(hSource, hLeafPtr, hSuperior)
- HANDLE hSource, *hLeafPtr, hSuperior;
-
- {
- PDW LeafPtr, Source;
-
- if (*hLeafPtr)
- /* A record exists at this handle. Check it. */
- {
- LeafPtr = (PDW) LocalLock(*hLeafPtr);
- Source = (PDW) LocalLock(hSource);
-
- if (strcmp(Source -> w, LeafPtr -> w) < 0)
- /* the new word is less than the word at this leaf */
- RelocateLeaf(hSource, &(LeafPtr -> lt), *hLeafPtr);
- else
- /* the new word is greater than the word at this leaf */
- RelocateLeaf(hSource, &(LeafPtr -> gt), *hLeafPtr);
-
- LocalUnlock(*hLeafPtr);
- LocalUnlock(hSource);
- }
- else
- /* No record exists at this handle. Put the record here */
- {
- *hLeafPtr = hSource;
- Source = (PDW) LocalLock(hSource);
- Source -> up = hSuperior;
- LocalUnlock(hSource);
- }
- }
-
- /* Similar to AddLeaf. This procedure adds a leaf to a tree, giving
- * first sort priority to frequency, rather than the collating order
- * of the word. This routine is used only to optimize the dictionary;
- * it is not used during normal play of the game. Note that this
- * procedure does not make use of all the pointer fields in the DW
- * record, and uses lt and gt in a different manner than AddLeaf.
- * Count is incremented for each leaf added.
- */
- AddLeafO(hSource, hLeafPtr)
- HANDLE hSource;
- LPHANDLE hLeafPtr;
- {
- LPDW LeafPtr;
- PDW SourcePtr;
-
- if (*hLeafPtr)
- /* A record exists at this handle. Check it. */
- {
- LeafPtr = (LPDW) GlobalLock(*hLeafPtr);
- SourcePtr = (PDW) LocalLock(hSource);
- if (SourcePtr -> Freq == LeafPtr -> Freq)
- /* Frequencies equal, sort on basis of word comparison */
- {
- if (lstrcmp((LPSTR) (SourcePtr -> w), LeafPtr -> w) < 0)
- AddLeafO(hSource, &(LeafPtr -> lt));
- else
- AddLeafO(hSource, &(LeafPtr -> gt));
- }
- else
- {
- if (SourcePtr -> Freq > LeafPtr -> Freq)
- /* the new word is more frequent than the word at this leaf */
- /* we want more frequent to print first so use lt link */
- AddLeafO(hSource, &(LeafPtr -> lt));
- else
- /* the new word is less frequent than the word at this leaf */
- AddLeafO(hSource, &(LeafPtr -> gt));
- }
- LocalUnlock(hSource);
- GlobalUnlock(*hLeafPtr);
- }
- else
- /* No record exists here. Allocate memory and copy entire record */
- {
- *hLeafPtr = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
- (DWORD) sizeof(DW));
- if (*hLeafPtr)
- {
- LeafPtr = (LPDW) GlobalLock(*hLeafPtr);
- SourcePtr = (PDW) LocalLock(hSource);
-
- lstrcpy(LeafPtr -> w, (LPSTR) (SourcePtr -> w));
- LeafPtr -> Freq = SourcePtr -> Freq;
- LeafPtr -> Suffix1 = SourcePtr -> Suffix1;
- LocalUnlock(hSource);
- GlobalUnlock(*hLeafPtr);
- }
- else
- /* Ouch! GlobalAlloc failed! */
- OptimizeFail = TRUE;
- }
- }
-
- /* This procedure will print the entire tree out to a listbox */
- /* Note that hLeafPtr is not passed by reference, as in Addleaf */
- PrintLeaf(hList, hLeafPtr)
- HWND hList;
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- char lbuf[40]; /* local printing buffer */
-
- if (hLeafPtr)
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- PrintLeaf(hList, LeafPtr -> lt); /* print all less than */
- sprintf(lbuf, "%-10s %2d %4.4X \r\n",
- LeafPtr -> w, LeafPtr -> Freq, LeafPtr -> Suffix1);
- SendMessage(hList, LB_INSERTSTRING, -1, (LONG) (LPSTR) lbuf);
- PrintLeaf(hList, LeafPtr -> gt); /* print all greater than */
- LocalUnlock(hLeafPtr);
- }
- }
-
- /* Count the number of leaves below and including the one pointed to */
- /* by hLeafPtr, and return it */
- int CountLeaf(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- int n;
-
- if (!hLeafPtr) return(0);
- else
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- n = CountLeaf(LeafPtr -> lt) + 1 + CountLeaf(LeafPtr -> gt);
- LocalUnlock(hLeafPtr);
- }
- return(n);
- }
-
- /* Similar to PrintLeaf. This procedure copies a leaf and all its
- * inferior leaves into a second tree pointed to by hLeafPtr.
- * Used only to Re-Sort the tree into a different order for optimization
- */
- ReSortLeaf(hSource, hLeafPtr, count, hPro)
- HANDLE hSource;
- LPHANDLE hLeafPtr;
- int *count;
- HWND hPro;
- {
- PDW SourcePtr;
-
- if (hSource && !OptimizeFail)
- /* Quick exit if pointing to null leaf, or GlobalAlloc failed in AddLeafO */
- {
- SourcePtr = (PDW) LocalLock(hSource);
- ReSortLeaf(SourcePtr -> lt, hLeafPtr, count, hPro); /* copy all less than */
- AddLeafO(hSource, hLeafPtr);
- (*count)++;
- SendMessage(hPro, PRO_SETPOS, *count, 0L);
- ReSortLeaf(SourcePtr -> gt, hLeafPtr, count, hPro); /* copy all greater than */
- LocalUnlock(hSource);
- }
- }
-
- /* Leaf handle and all inferiors are copied in sorted order to a linear array.
- * Note that no data is copied; only handles. hSource is the source handle,
- * LinArray is the destination, an array of handles. Index specifies which
- * element of the array to copy to. Index is automatically updated.
- */
- CopyTreeToLin(hSource, LinArray, index)
- HANDLE hSource;
- LPHANDLE LinArray;
- int *index;
- {
- LPDW SourcePtr;
-
- if (hSource)
- {
- SourcePtr = (LPDW) GlobalLock(hSource);
- CopyTreeToLin(SourcePtr->lt, LinArray, index);
- LinArray[*index] = hSource;
- (*index)++;
- CopyTreeToLin(SourcePtr->gt, LinArray, index);
- GlobalUnlock(hSource);
- }
- }
-
- /* Attaches a range of elements in the linear array of handles in
- * such an order that they form a balanced binary tree. first and
- * last are the bounds of the array to output, hLeafPtr is the
- * destination tree, and LinArray is the linear array of handles to
- * output.
- */
- Balance(hLeafPtr, LinArray, first, last)
- HANDLE *hLeafPtr;
- LPHANDLE LinArray;
- int first, last;
- {
- int mid; /* midpoint between ends of segment */
-
- LPDW LeafPtr; /* pointer to record being added */
-
- mid = (first+last)/2;
-
- /* Add the data from the leaf back into the dictionary */
- /* be careful, far to near copying */
- LeafPtr = (LPDW) GlobalLock(LinArray[mid]);
- AddLeaf(FarToNearStr(LeafPtr->w), hLeafPtr, LeafPtr->Freq,
- LeafPtr->Suffix1, NULL);
- GlobalUnlock(LinArray[mid]);
-
- if (first < mid) Balance(hLeafPtr, LinArray, first, mid-1);
- if (mid < last) Balance(hLeafPtr, LinArray, mid+1, last);
- }
-
- /* This procedure will print the entire tree out to the dictionary file */
- /* Note that hLeafPtr is not passed by reference, as in Addleaf */
- /* This is almost the same as the PrintLeaf function, except that */
- /* the tree is printed in storage-order rather than collate-order */
- BOOL PrintDict(hDictFile, hLeafPtr)
- int hDictFile;
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- char lbuf[40]; /* local printing buffer */
- int IOStatus;
- BOOL retval; /* return value */
-
- if (hLeafPtr)
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- sprintf(lbuf, "%-10s %2d %4.4X\r\n",
- LeafPtr -> w, LeafPtr -> Freq, LeafPtr -> Suffix1);
- IOStatus = write(hDictFile, lbuf, strlen(lbuf));
-
- /* return FALSE if error */
- retval = (IOStatus == strlen(lbuf));
-
- /* print all less than */
- if (!PrintDict(hDictFile, (LeafPtr -> lt))) retval = FALSE;
- /* print all greater than */
- if (!PrintDict(hDictFile, (LeafPtr -> gt))) retval = FALSE;
- LocalUnlock(hLeafPtr);
- return(retval);
- }
- }
-
- /* Find the string passed as a parameter in the tree */
- /* If the string is found, a handle to the record is returned */
- /* Else, NULL is returned */
- HANDLE FindLeaf(Word, hLeafPtr)
- char *Word;
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- int comp; /* comparison result from strcmp */
- HANDLE retval; /* return value */
- int nSuffix; /* used for suffixing words */
- char FullWord[13];
- unsigned BitMask;
-
- if (!hLeafPtr) return(NULL);
- else
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- /* 2 character comparison only, for reasons outlined in psearch */
- comp = strncmp(Word, LeafPtr -> w, 2);
- if (comp < 0)
- /* the word is less than the word at this leaf */
- retval = FindLeaf(Word, LeafPtr -> lt);
- else if (comp > 0)
- /* the word is greater than the word at this leaf */
- retval = FindLeaf(Word, LeafPtr -> gt);
- else
- /* comp == 0, we could have a match */
- {
- if (!strcmp(Word, LeafPtr -> w))
- /* exact match */
- retval = hLeafPtr;
- else
- {
- /* must look at both branches */
- retval = FindLeaf(Word, LeafPtr -> lt);
- if (!retval) retval = FindLeaf(Word, LeafPtr -> gt);
- if (!retval && !strncmp(Word, LeafPtr->w, strlen(LeafPtr->w)-1))
- /* Last resort. If enough letters in word match, try suffixes */
- {
- BitMask = 1;
-
- for (nSuffix=ID_FIRSTSUF; nSuffix <= ID_LASTSUF; nSuffix++)
- {
- if (BitMask & (LeafPtr->Suffix1))
- /* if the suffix is legal, try it */
- {
- AddSuffix(LeafPtr->w, nSuffix, FullWord);
- if (!strcmp(Word, FullWord))
- {
- /* matches suffixed word exactly */
- retval = hLeafPtr;
- break;
- }
- }
- BitMask <<= 1; /* move to the next bit */
- }
- }
- }
- }
- LocalUnlock(hLeafPtr);
- return(retval);
- }
- }
-
- /* This is used only in dictionary editing. Finds exact word, ignoring
- * suffixes. Returns the handle of the word. If cannot find word,
- * returns NULL. Otherwise, like FindLeaf()
- */
- HANDLE FindExactLeaf(Word, hLeafPtr)
- char *Word;
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- int comp;
- HANDLE retval;
-
- if (!hLeafPtr) return(NULL);
-
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- comp = strcmp(Word, LeafPtr -> w);
- if (comp < 0)
- retval = FindExactLeaf(Word, LeafPtr -> lt);
- else if (comp > 0)
- retval = FindExactLeaf(Word, LeafPtr -> gt);
- else
- /* exact match */
- retval = hLeafPtr;
-
- LocalUnlock(hLeafPtr);
- return(retval);
- }
-
- /* Follows the lt chain all the way down from the present record
- * and returns the last one. Used to find the least word in
- * a chain.
- */
- HANDLE FindLeast(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- HANDLE retval;
-
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> lt) retval = FindLeast(LeafPtr -> lt);
- else retval = hLeafPtr;
- LocalUnlock(hLeafPtr);
- return(retval);
- }
-
- /* Follows the up chain until it finds a word that is less
- * than the word corresponding to hLeafPtr. If no such word is
- * found, NULL is returned.
- * WARNING: this routine assumes that hLeafPtr != NULL
- */
- HANDLE FindUpLess(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- PDW SuperPtr;
- HANDLE retval;
-
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> up)
- /* if there is a leaf above this one, examine it */
- {
- SuperPtr = (PDW) LocalLock(LeafPtr -> up);
- if (strcmp(SuperPtr -> w, LeafPtr -> w) < 0)
- /* found one */
- retval = LeafPtr -> up;
- else
- /* look at next link up */
- retval = FindUpLess(LeafPtr -> up);
- LocalUnlock(LeafPtr -> up);
- }
- else
- /* there is no superior leaf, return null */
- retval = NULL;
-
- LocalUnlock(hLeafPtr);
- return(retval);
- }
-
- /* Follows the up chain until it finds a word that is greater
- * than the word corresponding to hLeafPtr. If no such word is
- * found, NULL is returned.
- * WARNING: this routine assumes that hLeafPtr != NULL
- */
- HANDLE FindUpGreater(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- PDW SuperPtr;
- HANDLE retval;
-
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> up)
- /* if there is a leaf above this one, examine it */
- {
- SuperPtr = (PDW) LocalLock(LeafPtr -> up);
- if (strcmp(SuperPtr -> w, LeafPtr -> w) > 0)
- /* found one */
- retval = LeafPtr -> up;
- else
- /* look at next link up */
- retval = FindUpGreater(LeafPtr -> up);
- LocalUnlock(LeafPtr -> up);
- }
- else
- /* there is no superior leaf, return null */
- retval = NULL;
-
- LocalUnlock(hLeafPtr);
- return(retval);
- }
-
- /* Follows the gt chain all the way down from the present record
- * and returns the last one. Used to find the greatest word in
- * a chain.
- */
- HANDLE FindGreatest(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- HANDLE retval;
-
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> gt) retval = FindGreatest(LeafPtr -> gt);
- else retval = hLeafPtr;
- LocalUnlock(hLeafPtr);
- return(retval);
- }
-
- /* Finds the previous leaf (collating order) in the tree, and
- * returns a handle to it. If no leaf found, NULL is returned
- * Return value is in this priority:
- * 1. If hLeafPtr is NULL, return NULL
- * 2. If hLeafPtr has a lt link, return the greatest along this chain
- * 3. If hLeafPtr has an up link, and the uplink was a gt link originally,
- * return the uplink.
- * 4. If none of the above, return NULL
- */
- HANDLE FindPrev(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- PDW SuperiorPtr;
- HANDLE retval;
-
- if (!hLeafPtr) return(NULL);
- else
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> lt)
- /* if there is a lt link, look for the greatest along the chain */
- retval = FindGreatest(LeafPtr -> lt);
- else
- /* look higher in the tree to see if there is a lesser word */
- retval = FindUpLess(hLeafPtr);
-
- LocalUnlock(hLeafPtr);
- return(retval);
- }
- }
-
- /* Finds the next leaf (collating order) in the tree, and
- * returns a handle to it. If no leaf found, NULL is returned
- * Return value is in this priority:
- * 1. If hLeafPtr is NULL, return NULL
- * 2. If hLeafPtr has a gt link, return the least along this chain
- * 3. If hLeafPtr has an up link, and the uplink was a lt link originally,
- * return the uplink.
- * 4. If none of the above, return NULL
- */
- HANDLE FindNext(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- PDW SuperiorPtr;
- HANDLE retval;
-
- if (!hLeafPtr) return(NULL);
- else
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if (LeafPtr -> gt)
- /* if there is a greater than link, look for the least along the chain */
- retval = FindLeast(LeafPtr -> gt);
- else
- /* look higher in the tree to see if there is a greater word */
- retval = FindUpGreater(hLeafPtr);
-
- LocalUnlock(hLeafPtr);
- return(retval);
- }
- }
-
- /* Finds a virgin leaf in the tree, and returns the handle. A virgin leaf is
- * one which has never been viewed by the dictionary editor. This function is
- * to aid in finding words which do not yet have suffixes defined.
- */
- HANDLE FindVirgin(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
- HANDLE retval;
-
- if (!hLeafPtr) return(NULL);
- else
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- if ((LeafPtr -> Suffix1) & 0x8000)
- /* this leaf is virgin */
- retval = hLeafPtr;
- else
- {
- /* try the inferior leaves */
- if (!(retval = FindVirgin(LeafPtr -> lt)))
- retval = FindVirgin(LeafPtr -> gt);
- }
- LocalUnlock(hLeafPtr);
- return(retval);
- }
- }
-
- /* This will free up the memory allocated to a leaf, and all leaves further
- * down the tree, whether on the greater-than or less-than side
- * The only time this should be called is to dispose of the entire dictionary
- * tree
- */
- DestroyLeaf(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
-
- if (hLeafPtr)
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- DestroyLeaf(LeafPtr -> lt); /* Destroy all less than */
- DestroyLeaf(LeafPtr -> gt); /* Destroy all greater than */
- LocalUnlock(hLeafPtr);
- LocalFree(hLeafPtr); /* Destroy self */
- }
- }
-
- /* Like DestroyLeaf, but operates on a tree in Global (long pointer) memory */
- DestroyGLeaf(hLeafPtr)
- HANDLE hLeafPtr;
- {
- LPDW LeafPtr;
-
- if (hLeafPtr)
- {
- LeafPtr = (LPDW) GlobalLock(hLeafPtr);
- DestroyGLeaf(LeafPtr -> lt); /* Destroy all less than */
- DestroyGLeaf(LeafPtr -> gt); /* Destroy all greater than */
- GlobalUnlock(hLeafPtr);
- GlobalFree(hLeafPtr); /* Destroy self */
- }
- }
-
- /* Not 100% foolproof, but tries to take a guess as to the root word, given
- * a word which may have a suffix attached.
- * The guess is returned in the Dest parameter.
- * Returns handle to the word in dictionary if it was able to find the word
- * Warning: may barf on words shorter than 3 letters
- */
- HANDLE RemoveSuffix(FullWord, Dest)
- char FullWord[], Dest[];
- {
- int len;
- HANDLE hFound;
- PDW LeafPtr;
-
- strcpy(Dest, FullWord);
- len = strlen(Dest);
-
- /* First check the word by itself. Many will have no suffix at all */
- hFound = FindLeaf(Dest, hTreeTop);
- if (hFound)
- {
- /* return only the root word */
- LeafPtr = (PDW) LocalLock(hFound);
- strcpy(Dest, LeafPtr -> w);
- LocalUnlock(hFound);
- return(hFound);
- }
-
- /* -S */
- if (Dest[len-1] == 'S')
- {
- /* -SSES */
- if (len > 3 && Dest[len-2] == 'E' && Dest[len-3] == 'S' & Dest[len-4] == 'S')
- {
- Dest[len-2] = NULL;
- }
- /* -IES */
- else if (Dest[len-2] == 'E' && Dest[len-3] == 'I')
- {
- Dest[len-3] = 'Y';
- Dest[len-2] = NULL;
- }
- /* -HES, -XES */
- else if (Dest[len-2] == 'E' && (Dest[len-3] == 'H' || Dest[len-3] == 'X'))
- {
- Dest[len-2] = NULL;
- }
- /* anything else but -SS */
- else if (Dest[len-2] != 'S')
- {
- Dest[len-1] = NULL;
- }
- }
- /* -ED, -ER, -EN*/
- else if (len > 4 && (Dest[len-1] == 'D' || Dest[len-1] == 'R' || Dest[len-1] == 'N') && Dest[len-2] == 'E')
- {
- /* ignore words less than 5 letters - probably not suffixed */
- /* -IED, -IER, -IEN */
- if (Dest[len-3] == 'I')
- {
- Dest[len-3] = 'Y';
- Dest[len-2] = NULL;
- }
- /* -XXED, -XXER, -XXEN, X=doubled letter */
- else if (Dest[len-3] == Dest[len-4] && Dest[len-3] != 'S' && Dest[len-3] != 'L')
- {
- Dest[len-3] = NULL;
- }
- /* -CVCED, -CVCER, -CVCEN, C=consonant, V=vowel */
- /* or -EED, -EER, -EEN */
- /* or -xSED, -xSER, -xSEN , x != S */
- else if (Dest[len-3] == 'E' || (Dest[len-3] == 'S' && Dest[len-4] != 'S') || (!isvowel(Dest[len-3]) && isvowel(Dest[len-4]) && !isvowel(Dest[len-5])))
- {
- Dest[len-1] = NULL;
- }
- else
- {
- Dest[len-2] = NULL;
- }
- }
- /* -Y, -LY, but not -AY */
- else if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- /* -LY */
- if (Dest[len-2] == 'L')
- {
- Dest[len-2] = NULL;
- }
- /* -XXY, X=doubled letter */
- else if (Dest[len-2] == Dest[len-3])
- {
- Dest[len-2] = NULL;
- }
- /* -CVCY, C=consonant, V=vowel */
- else if (len > 3 && !isvowel(Dest[len-2]) && isvowel(Dest[len-3]) && !isvowel(Dest[len-4]))
- {
- Dest[len-1] = 'E';
- }
- else
- {
- Dest[len-1] = NULL;
- }
- }
- /* -EST */
- /* do not consider small words like best, west, crest ... */
- else if (len > 5 && Dest[len-1] == 'T' && Dest[len-2] == 'S' && Dest[len-3] == 'E')
- {
- /* -IEST */
- if (Dest[len-4] == 'I')
- {
- Dest[len-4] = 'Y';
- Dest[len-3] = NULL;
- }
- /* -XXEST, X=doubled letter */
- else if (Dest[len-4] == Dest[len-5] && Dest[len-4] != 'L' && Dest[len-4] != 'S')
- {
- Dest[len-4] = NULL;
- }
- /* -CVCEST, C=consonant, V=vowel */
- /* or -EEST i.e. FREEST */
- else if (Dest[len-4] == 'E' || (!isvowel(Dest[len-4]) && isvowel(Dest[len-5]) && !isvowel(Dest[len-6])))
- {
- Dest[len-2] = NULL;
- }
- else
- {
- Dest[len-3] = NULL;
- }
- }
- /* -ING, -ISH */
- /* check len first so as not to process short words like sing, fish, bring */
- else if (len > 5 && ((Dest[len-1] == 'G' && Dest[len-2] == 'N') || (Dest[len-1] == 'H' && Dest[len-2] == 'S')) && Dest[len-3] == 'I')
- {
- /* -XXING, -XXISH, X=doubled letter, except -SSING, -SSISH */
- if (Dest[len-4] == Dest[len-5] && Dest[len-4] != 'S' && Dest[len-4] != 'L')
- {
- Dest[len-4] = NULL;
- }
- /* -CVCING, -CVCISH, C=consonant, V=vowel */
- else if (!isvowel(Dest[len-4]) && isvowel(Dest[len-5]) && !isvowel(Dest[len-6]))
- {
- Dest[len-3] = 'E';
- Dest[len-2] = NULL;
- }
- else
- {
- Dest[len-3] = NULL;
- }
- }
- return(FindLeaf(Dest, hTreeTop));
- }
-
- /* increments the frequency of the word at hLeaf */
- IncFreq(hLeaf)
- HANDLE hLeaf;
- {
- PDW LeafPtr;
-
- LeafPtr = (PDW) LocalLock(hLeaf);
- if (LeafPtr -> Freq < 32767) (LeafPtr -> Freq)++;
- LocalUnlock(hLeaf);
- }
-
- /* Verify that a word is actually on the board, returning TRUE if it is */
- /* Searches the word BACKWARDS (no reason) */
- /* Something like SearchBoard, only much faster */
- /* This routine also doubles as a path-finder for displaying where a given */
- /* word is on the board. To use in this manner, first clear out the cube */
- /* stack by setting CubeStackPtr = 0. If Verify returns TRUE, then the */
- /* cubes forming the word are left on the stack, in order */
- BOOL Verify(TrialW, CubePtr, TrialLen)
- char *TrialW;
- BOARD *CubePtr;
- int TrialLen;
- {
- int Neighbor;
- CUBELOC cube;
-
- if (CubePtr == NULL || (CubePtr -> Cused))
- return(FALSE);
-
- if (TrialLen==1)
- {
- if (*TrialW == CubePtr -> val)
- {
- cube.row = CubePtr -> r; cube.col = CubePtr -> c;
- PushCube(cube);
- return(TRUE);
- }
- else
- return(FALSE);
- }
- else
- {
- if (TrialW[TrialLen-1] == CubePtr -> val)
- {
- cube.row = CubePtr -> r; cube.col = CubePtr -> c;
- PushCube(cube);
- CubePtr -> Cused = TRUE;
- for (Neighbor=0; Neighbor < 8; Neighbor++)
- {
- if (Verify(TrialW, CubePtr -> link[Neighbor], TrialLen-1))
- {
- CubePtr -> Cused = FALSE;
- return(TRUE);
- }
- }
- CubePtr -> Cused = FALSE;
- PopCube();
- }
- return(FALSE);
- }
- }
-
- /* Score the list of words whose handle is hList. */
- /* Running score and word count are updated */
- /* This routine also updates the window to display the scores */
- /* Return value is the score for the round */
- /* Running score and running word count are updated */
- int Score(hList, RScore, RWords)
- HWND hList;
- int *RScore, *RWords;
- {
- char CurLine[30];
- char OutBuf[30];
- int CurScore;
- int count; /* count of lines in the list */
- int wcount; /* count of good words */
- int Tscore; /* Total score for this round*/
- int LineNo;
- HDC hDC; /* to calclulate width of word */
- MSG msg; /* for PeekMessage yield */
-
- hDC = GetDC(hList);
-
- Tscore = 0;
- wcount = 0;
- count = SendMessage(hList, LB_GETCOUNT, 0, 0L);
- for (LineNo=0; LineNo < count; LineNo++)
- {
- SendMessage(hList, LB_GETTEXT, LineNo, (LONG) (LPSTR) CurLine);
- if (*CurLine >= 'A')
- {
- wcount++;
- switch (strlen(CurLine))
- {
- case 4:
- CurScore=1; break;
- case 5:
- CurScore=2; break;
- case 6:
- CurScore=3; break;
- case 7:
- CurScore=5; break;
- default:
- CurScore=11; break;
- }
-
- /* Format score for display */
- if (LOWORD(GetTextExtent(hDC, CurLine, strlen(CurLine))) < TScoreWidth)
- {
- /* the only possible word scores have 1 and 2 digits */
- if (CurScore < 10)
- sprintf(OutBuf, "%s\t\t\t%d", CurLine, CurScore); /* 1 digit */
- else
- sprintf(OutBuf, "%s\t\t%d", CurLine, CurScore); /* 2 digits */
- }
- else /* Word is too wide, do what we can */
- sprintf(OutBuf, "%s %d", CurLine, CurScore);
-
- SendMessage(hList, LB_DELETESTRING, LineNo, 0L);
- SendMessage(hList, LB_INSERTSTRING, LineNo, (LONG) (LPSTR) OutBuf);
- Tscore += CurScore;
- }
- }
- *RScore += Tscore;
- if (Tscore < 10)
- sprintf(OutBuf, "Total Score:\t\t\t%d", Tscore);
- else if (Tscore < 100)
- sprintf(OutBuf, "Total Score:\t\t%d", Tscore);
- else
- /* Assume that there are no score totals of 4 digits */
- sprintf(OutBuf, "Total Score:\t%d", Tscore);
-
- SendMessage(hList, LB_INSERTSTRING, -1, (LONG) (LPSTR) OutBuf);
-
- if (wcount != 1)
- sprintf(OutBuf, "(%d Words)", wcount);
- else
- strcpy(OutBuf, "(1 Word)");
- *RWords += wcount;
- SendMessage(hList, LB_INSERTSTRING, -1, (LONG) (LPSTR) OutBuf);
- /* set selection in order to scroll last line of window into view */
- count = SendMessage(hList, LB_GETCOUNT, 0, 0L);
- SendMessage(hList, LB_SETCURSEL, count-1, 0L); /* to get bottom in view */
- SendMessage(hList, LB_SETCURSEL, count-2, 0L); /* highlight score line */
- ReleaseDC(hList, hDC);
- return(Tscore);
- }
-
- /* Process the End-of-game signal */
- ProcessBagoEndGame(hWnd)
- HWND hWnd;
- {
- int Pwcount; /* how many words the user entered */
- int Pwi; /* the index of the word we're looking at */
- int Pwl; /* length of the word we're looking at */
- int Cwcount; /* same for computer's list */
- int Cwi;
- BOOL Bogus; /* true if any bogus words entered */
- int RewardLevel; /* How well the computer was beat */
- int PicNumber; /* Resource number of reward picture */
- int Uscore, Cscore; /* User, Computer score for round */
- char CurWord[30]; /* a word from User word list */
- char CurWord1[30]; /* a word from User word list */
- char RootWord[30]; /* the root of the above (could be equal) */
- char OutBuf[30]; /* buffer for string output */
- HANDLE hOldBuffer; /* The raw buffer from the User Word list */
- HANDLE hCurWord; /* Handle, if any to current word in dictionary */
- BOOL BadWord; /* Set to true if current word is disqualified */
- HCURSOR hOldCursor;
- MSG msg; /* for PeekMessage Yield */
-
- GameOver = TRUE; /* This global will abort computer word search */
-
- /* Sound the bell! Open and close the sound device every time */
- /* it doesn't take too much time, and also don't want to hog the */
- /* sound generator away from other windows */
- if (Sound)
- {
- OpenSound();
- SetVoiceAccent(1, 120, 50, S_STACCATO, 0);
- SetVoiceNote(1, 52, 32, 0);
- SetVoiceNote(1, 48, 32, 0);
- SetVoiceNote(1, 52, 32, 0);
- SetVoiceNote(1, 48, 32, 0);
- SetVoiceNote(1, 52, 32, 0);
- StartSound();
- }
-
- hOldCursor = SetCursor(hHourGlass); /* could be lengthy operation */
-
- EnableCubes(FALSE); /* Stop player input! */
- EnableWindow(hUEdit, FALSE);
-
- /* Game over, allow dictionary functions again */
- EnableMenuItem(GetMenu(hWnd), 2, MF_BYPOSITION | MF_ENABLED);
- DrawMenuBar(hWnd);
-
- /* get all the words from the user list and process */
- Pwcount = SendMessage(hUEdit, EM_GETLINECOUNT, 0, 0L);
-
- Bogus = FALSE;
- /* Capitalize, trim, and copy all words from Edit to List */
- for (Pwi=0; Pwi<Pwcount; Pwi++)
- {
- CurWord[0] = 30; CurWord[1] = 0; /* windows wants a max byte count */
- Pwl = SendMessage(hUEdit, EM_GETLINE, Pwi, (LONG) (LPSTR) CurWord);
- TrimWord(CurWord, Pwl); /* make into a valid word */
- /* For each reasonable word, display in user's buffer, and optionally */
- /* add it into the dictionary */
- if (strlen(CurWord) > 3)
- {
- /* Remove suffix twice, for things like JAILERS, PAIRINGS... */
- RemoveSuffix(CurWord, RootWord);
- hCurWord = RemoveSuffix(RootWord, RootWord);
- if (hCurWord)
- /* if word is known, update frequencies */
- IncFreq(hCurWord);
- else if (Learn && strlen(RootWord) <= 10)
- /* if in Learn mode, and word is short enough, try to add */
- {
- if (LocalCompact(USERWORDLEN) >= USERWORDLEN)
- /* Do not learn words if low on heap space */
- {
- sprintf(OutBuf, "Add %s to dictionary?", RootWord);
- if (IDYES == MessageBox(hWnd, OutBuf, "Learn Mode", MB_YESNO))
- /* 0x8000 suffix indicates word is new and should */
- /* have a human look it over for suffixes */
- {
- RemoveQu(RootWord);
- AddLeaf(RootWord, &hTreeTop, 1, 0x8000, NULL);
- DictChanged = TRUE;
- }
- }
- else
- {
- MessageBox(hWnd, "Oops, running out of heap space (memory).\n"
- "Turning word learning feature off.",
- "Warning", MB_OK | MB_ICONASTERISK);
- ProcessBagoLearn(hWnd, MN_DD_OPTIONS + MN_OPT_LEARN);
- }
- }
- }
- SendMessage(hUList, LB_INSERTSTRING, -1, (LONG) (LPSTR) CurWord);
- }
-
- /* Now all words are copied to player LIST */
- /* Exchange the windows */
- ShowWindow(hUList, SW_SHOW);
- ShowWindow(hUEdit, SW_HIDE);
-
- /* If the computer is playing, display it's list */
- if (CPlay)
- {
- /* eliminate flicker */
- SendMessage(hCList, WM_SETREDRAW, FALSE, 0L);
- DisplayClist(hCListTop);
- /* force update */
- SendMessage(hCList, LB_INSERTSTRING, 0, (LONG) (LPSTR) "");
- /* turn flicker back on so that scoring will be dramatic */
- SendMessage(hCList, WM_SETREDRAW, TRUE, 0L);
- SendMessage(hCList, LB_DELETESTRING, 0, 0L);
- Cwcount = SendMessage(hCList, LB_GETCOUNT, 0, 0L);
- }
-
- /* Now start cancelling and disqualifying words */
- for (Pwi=0; Pwi < Pwcount; Pwi++)
- {
- /* select word from player list and get it */
- SendMessage(hUList, LB_SETCURSEL, Pwi, 0L);
- SendMessage(hUList, LB_GETTEXT, Pwi, (LONG) (LPSTR) CurWord);
- if (strlen(CurWord)) /* ignore blank lines */
- {
- BadWord = FALSE;
- if (strlen(CurWord) < 4)
- /* word too short */
- {
- strcpy(OutBuf, "<");
- strcat(OutBuf, CurWord);
- SendMessage(hUList, LB_DELETESTRING, Pwi, 0L);
- SendMessage(hUList, LB_INSERTSTRING, Pwi, (LONG) (LPSTR) OutBuf);
- BadWord = TRUE;
- }
- if (!BadWord && CPlay)
- {
- /* see if the word is duplicated in the computer's list */
- for (Cwi=0; Cwi < Cwcount; Cwi++)
- {
- SendMessage(hCList, LB_GETTEXT, Cwi, (LONG) (LPSTR) CurWord1);
- if (!strcmp(CurWord, CurWord1))
- /* duplicate found between Player and Computer */
- {
- strcpy(OutBuf, " ");
- strcat(OutBuf, CurWord);
- SendMessage(hUList, LB_DELETESTRING, Pwi, 0L);
- SendMessage(hUList, LB_INSERTSTRING, Pwi, (LONG) (LPSTR) OutBuf);
- SendMessage(hCList, LB_DELETESTRING, Cwi, 0L);
- SendMessage(hCList, LB_INSERTSTRING, Cwi, (LONG) (LPSTR) OutBuf);
- BadWord = TRUE;
- break;
- }
- }
- }
- if (!BadWord)
- {
- /* See if player listed this word twice */
- /* Tricky, since could match a word already disqualified */
- for (Cwi=0; Cwi < Pwi; Cwi++)
- {
- SendMessage(hUList, LB_GETTEXT, Cwi, (LONG) (LPSTR) CurWord1);
- if ((*CurWord1 >= 'A' && !strcmp(CurWord, CurWord1))
- || (*CurWord1 < 'A' && !strcmp(CurWord, &CurWord1[1])))
- /* word was listed twice - disqualify the second one */
- {
- strcpy(OutBuf, "\"");
- strcat(OutBuf, CurWord);
- SendMessage(hUList, LB_DELETESTRING, Pwi, 0L);
- SendMessage(hUList, LB_INSERTSTRING, Pwi, (LONG) (LPSTR) OutBuf);
- BadWord = TRUE;
- break;
- }
- }
- }
- if (!BadWord)
- /* Make sure the word does appear on the board */
- {
- BOOL found;
- int row, col;
-
- RemoveQu(CurWord); /* convert Qu to Q for verifying purposes */
- found = FALSE;
- for (row=0; row<NROWS; row++)
- {
- for (col=0; col<NCOLS; col++)
- {
- if (verify(CurWord, &board[row][col], strlen(CurWord)))
- {
- found = TRUE;
- break;
- }
- }
- if (found) break;
- }
- AddQu(CurWord); /* put back Qu for display */
- if (!found)
- {
- strcpy(OutBuf, "?");
- strcat(OutBuf, CurWord);
- SendMessage(hUList, LB_DELETESTRING, Pwi, 0L);
- SendMessage(hUList, LB_INSERTSTRING, Pwi, (LONG) (LPSTR) OutBuf);
- BadWord = TRUE;
- }
- }
- if (!BadWord && (!isword(CurWord) || Pwi == Pwcount-1))
- /* 1. Possibly a partial line is typed as the last entry */
- /* 2. Somebody trying to enter bogus words */
- {
- /* do we know the word? */
- RemoveSuffix(CurWord, OutBuf); /* remove suffix twice in case */
- RemoveSuffix(OutBuf, OutBuf); /* MAKERS, MAKINGS, etc */
- RemoveQu(OutBuf);
- if (!FindLeaf(OutBuf, hTreeTop))
- {
- sprintf(OutBuf, "Is %s really a word?", CurWord);
- if (MessageBox(hWnd, OutBuf, "", MB_YESNO) == IDNO)
- {
- strcpy(OutBuf, "-");
- strcat(OutBuf, CurWord);
- SendMessage(hUList, LB_DELETESTRING, Pwi, 0L);
- SendMessage(hUList, LB_INSERTSTRING, Pwi, (LONG) (LPSTR) OutBuf);
- BadWord = TRUE;
- }
- /* Don't penalize for a badly typed last line */
- else if (Pwi != Pwcount-1) Bogus = TRUE;
- }
- }
- }
- }
-
- /* Show the score and update stats*/
- NGames++;
- Uscore = Score(hUList, &RUScore, &RUWords);
- if (CPlay) Cscore = Score(hCList, &RCScore, &RCWords);
-
- /* Set up for the next game */
- NextRackNumber = rand();
- SetNextRack(NextRackNumber);
-
- SetCursor(hOldCursor); /* end of lengthy operation */
-
- /* Disable stop and enter buttons */
- EnableWindow(hEnter, FALSE);
- EnableWindow(hStop, FALSE);
-
- /* do the rewards here */
- if (Uscore > Cscore)
- {
- RewardLevel = 0;
- if (Bogus)
- RewardLevel = -1; /* The cheater's reward */
- else
- {
- if (Smartness >= 50 && CountLeaf(hTreeTop) >=400)
- /* no big rewards if no challenge */
- {
- if (Uscore >= Cscore+5) RewardLevel++;
- if (Uscore >= Cscore+10) RewardLevel++;
- if (Uscore >= Cscore+15) RewardLevel++;
- if (Smartness == 100) RewardLevel++;
- }
- }
- /* Select appropriate reward for winner */
- switch (RewardLevel)
- {
- case -1:
- strcpy(OutBuf, "Good!"); /* no reward for cheaters */
- PicNumber = 0;
- break;
- case 0:
- case 1:
- strcpy(OutBuf, "Good!");
- PicNumber = REWARD1BMP;
- break;
- case 2:
- strcpy(OutBuf, "Excellent!");
- PicNumber = REWARD2BMP;
- break;
- case 3:
- strcpy(OutBuf, "Superb!");
- PicNumber = REWARD3BMP;
- break;
- case 4:
- strcpy(OutBuf, "Outstanding!");
- PicNumber = REWARD4BMP;
- break;
- }
- if (!Rewards) PicNumber = 0; /* supress the picture, usually */
- CreatePicBox(hWnd, PicNumber, OutBuf);
- }
- else
- {
- /* Set focus to appropriate word list so keyboard-only user can */
- /* see word paths */
- /* note: if reward is given, focus is set upon CreatePicBox completion */
- PostMessage(hWnd, WM_SETFOCUS, 0, 0L);
- }
-
- /* wait for music to complete */
- if (Sound)
- {
- WaitSoundState(S_QUEUEEMPTY);
- CloseSound();
- }
- }
-
- /* Cleanup when window closed before program termination */
- ProcessBagoClose(hWnd)
- HWND hWnd;
- {
- RECT Rect;
- char ProString[40];
- BOOL junk;
-
- /* Offer to save the dictionary if it changed size */
- if (DictChanged)
- if (MessageBox(hWnd, "Dictionary has changed. Save it?", "Bago", MB_YESNO)==IDYES)
- ProcessBagoSaveDict(hWnd);
-
- /* If a help window is open, kill it */
- WinHelp(hWnd, BAGOHLP, HELP_QUIT, 0L);
-
- /* Save window positions and option settings */
- if (!IsIconic(hWnd))
- {
- /* but don't save ridiculous iconic dimensions */
- GetWindowRect(hWnd, (LPRECT) &Rect);
- sprintf(ProString, "%d %d %d %d", Rect.left, Rect.top, Rect.right, Rect.bottom);
- WritePrivateProfileString("Bago", "Window", ProString, BAGOINI);
- }
- sprintf(ProString, "%d", Smartness);
- WritePrivateProfileString("Bago", "Computer Smartness", ProString, BAGOINI);
- sprintf(ProString, "%d", EndTime);
- WritePrivateProfileString("Bago", "Game Duration", ProString, BAGOINI);
- sprintf(ProString, "%d", Sound);
- WritePrivateProfileString("Bago", "Sound", ProString, BAGOINI);
- sprintf(ProString, "%d", UseTimer);
- WritePrivateProfileString("Bago", "Timed Game", ProString, BAGOINI);
- sprintf(ProString, "%d", Learn);
- WritePrivateProfileString("Bago", "Learn Words", ProString, BAGOINI);
- sprintf(ProString, "%d", CPlay);
- WritePrivateProfileString("Bago", "Computer Plays", ProString, BAGOINI);
- sprintf(ProString, "%d", RotCubes);
- WritePrivateProfileString("Bago", "Rotatable Cubes", ProString, BAGOINI);
- /* don't want to show string in BAGOINI unless it is enabled */
- if (Rewards)
- {
- WritePrivateProfileString("Bago", "Pictoral", "1", BAGOINI);
- DeleteObject(hEyes);
- }
- else
- WritePrivateProfileString("Bago", "Pictoral", NULL, BAGOINI);
-
- DestroyLeaf(hTreeTop); /* return all allocated memory */
-
- DeleteObject(hGrayBrush0); /* put away our pens */
- DeleteObject(hGrayBrush1);
- DeleteObject(hGrayBrush2);
- }
-
- /* Load the dictionary from disk, if any */
- /* return FALSE if dictionary not found */
- BOOL LoadDictionary(hWnd)
- {
- int hDictFile; /* handle of dictionary file */
- HANDLE hLeafPtr;
- char linebuf[80];
- DW TempWord; /* used to hold a single word at a time from dict */
- char *bufptr;
- OFSTRUCT OfStruct;
- HWND hPro;
- unsigned charcount;
- HCURSOR hOldCursor;
-
- /* possibly lengthy operation */
- hOldCursor = SetCursor(hHourGlass);
-
- /* Get rid of whatever dictionary was in core */
- DestroyLeaf(hTreeTop);
- hTreeTop = NULL;
-
- if ((hDictFile = OpenFile(BAGODIC, &OfStruct, OF_READ)) < 0)
- {
- /* cannot open file */
- return(FALSE);
- }
- else
- {
- hPro = CreateProBox(hWnd);
- /* wParam is range, lParam is message string */
- SendMessage(hPro, PRO_INIT, filelength(hDictFile), (LONG) (LPSTR) "Loading Dictionary");
- charcount = 0;
-
- while (!eof(hDictFile))
- {
- /* Stop reading if we run out of heap space. Leave enough for */
- /* the user's edit window */
- if (LocalCompact(USERWORDLEN) < USERWORDLEN)
- {
- MessageBox(hWnd, BAGODIC " is too big. Only part of it was read.",
- "Warning", MB_OK | MB_ICONASTERISK | MB_SYSTEMMODAL);
- break;
- }
-
- /* Read a line. There is no formatted read from a file handle */
- /* Therefore, must build the line ourselves */
- bufptr = linebuf;
- while (read(hDictFile, bufptr, 1) > 0)
- {
- charcount++;
- if (*bufptr == '\n') break; /* stop at end of line */
- bufptr++;
- }
- *(++bufptr) = NULL; /* terminate the string */
-
- if (strlen(linebuf))
- {
- TempWord.Freq = 0; /* default values in case only a */
- TempWord.Suffix1 = 0; /* word is included on the line */
- /* get word and add it to data structure */
- sscanf(linebuf, "%s %d %X\r\n",
- TempWord.w, &(TempWord.Freq), &(TempWord.Suffix1));
- TrimWord(TempWord.w, strlen(TempWord.w));
- AddLeaf(TempWord.w, &hTreeTop, TempWord.Freq,
- TempWord.Suffix1, NULL);
- }
- SendMessage(hPro, PRO_SETPOS, charcount, 0L);
- }
- DestroyWindow(hPro);
- close(hDictFile);
- }
-
- DictChanged = FALSE;
-
- SetCursor(hOldCursor);
- return(TRUE);
- }
-
- /* Takes input from dictionary on disk, and eliminates words with frequencies
- * less than the Fence. Results written to a different file.
- */
- BOOL CullDictionary(hWnd, Fence)
- HWND hWnd;
- int Fence;
- {
- OFSTRUCT OfStructD;
- OFSTRUCT OfStructO;
- int hDictFile; /* handle of dictionary file */
- int hOutFile;
- char linebuf[80];
- int Freq;
- char *bufptr;
- int OverCount, UnderCount; /* Count of words over and under fence */
- HWND hPro;
- unsigned charcount;
- HCURSOR hOldCursor;
-
- /* possibly lengthy operation */
- hOldCursor = SetCursor(hHourGlass);
-
- if ((hDictFile = OpenFile(BAGODIC, &OfStructD,
- OF_PROMPT | OF_CANCEL | OF_READ)) < 0)
- {
- /* cannot open file */
- return(FALSE);
- }
-
- if ((hOutFile = OpenFile(BAGONEW, &OfStructO,
- OF_PROMPT | OF_CANCEL | OF_CREATE | OF_WRITE)) < 0)
- {
- /* cannot open file */
- close(hDictFile);
- return(FALSE);
- }
-
- OverCount = 0;
- UnderCount = 0;
- hPro = CreateProBox(hWnd);
- SendMessage(hPro, PRO_INIT, filelength(hDictFile), (LONG) (LPSTR) "Culling Dictionary");
- charcount = 0;
-
- while (!eof(hDictFile))
- {
- /* Read a line. There is no formatted read from a file handle */
- /* Therefore, must build the line ourselves */
- bufptr = linebuf;
- while (read(hDictFile, bufptr, 1) > 0)
- {
- charcount++;
- if (*bufptr == '\n') break; /* stop at end of line */
- bufptr++;
- }
- *(++bufptr) = NULL; /* terminate the string */
-
- if (strlen(linebuf))
- {
- /* Copy the line only if it has frequency >= fence */
- Freq = 0; /* default frequency if none found */
- sscanf(linebuf, "%*s %d", &Freq);
- if (Freq >= Fence)
- {
- write(hOutFile, linebuf, strlen(linebuf));
- OverCount++;
- }
- else
- {
- UnderCount++;
- }
- }
- SendMessage(hPro, PRO_SETPOS, charcount, 0L);
- }
- DestroyWindow(hPro);
- close(hDictFile);
- close(hOutFile);
- SetCursor(hOldCursor);
- sprintf(linebuf, "Total Words: %3d\nKept: %3d\nDiscarded: %3d",
- OverCount+UnderCount, OverCount, UnderCount);
- MessageBox(hWnd, linebuf, "Results of Culling", MB_OK);
- return(TRUE);
- }
-
- /* This procedure will reset the usage frequencies of a leaf and */
- /* all its inferior leaves to zero */
- ResetFreqLeaf(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
-
- if (hLeafPtr)
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- ResetFreqLeaf(LeafPtr -> lt); /* do all less than */
- LeafPtr -> Freq = 0;
- ResetFreqLeaf(LeafPtr -> gt); /* do all greater than */
- LocalUnlock(hLeafPtr);
- }
- }
-
- ProcessBagoCreate(hWnd, wParam, lParam)
- HWND hWnd;
- WORD wParam;
- LONG lParam;
- {
- HMENU hMenu; /* handle to the System menu */
- int row, col; /* used to address board array */
- HDC hDC;
-
- hHourGlass = LoadCursor(NULL, IDC_WAIT);
-
- /* Rewards: a semi-hidden menu pick */
- hMenu = GetSystemMenu(hWnd, FALSE);
- AppendMenu(hMenu, MF_SEPARATOR, 0, 0L);
- AppendMenu(hMenu, MF_STRING, MN_REWARDS, " ");
-
- /* Load accelerators */
- hAccTable = LoadAccelerators(hInst, MAKEINTRESOURCE(BAGOACCEL));
-
- /* Initialize game variables */
-
- /* The contents of the dice, and the linkages between cubes */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- {
- board[row][col].val = '@'; /* This is the only time a cube has */
- board[row][col].orient = 0; /* this null face */
- board[row][col].link[0] = (row-1 >= 0 && col-1 >= 0) ? &(board[row-1][col-1]) : NULL;
- board[row][col].link[1] = (row-1 >= 0) ? &(board[row-1][col]) : NULL;
- board[row][col].link[2] = (row-1 >= 0 && col+1 < NCOLS) ? &(board[row-1][col+1]) : NULL;
- board[row][col].link[3] = (col-1 >= 0) ? &(board[row][col-1]) : NULL;
- board[row][col].link[4] = (col+1 < NCOLS) ? &(board[row][col+1]) : NULL;
- board[row][col].link[5] = (row+1 < NROWS && col-1 >= 0) ? &(board[row+1][col-1]) : NULL;
- board[row][col].link[6] = (row+1 < NROWS) ? &(board[row+1][col]) : NULL;
- board[row][col].link[7] = (row+1 < NROWS && col+1 < NCOLS) ? &(board[row+1][col+1]) : NULL;
- board[row][col].r = row;
- board[row][col].c = col;
- /* now make a corresponding control */
- board[row][col].hWindow = CreateWindow("CubeButton",
- "",
- WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS | WS_VISIBLE,
- col*32, row*32, 32, 32,
- hWnd, /* parent handle */
- ID_FIRSTCUBE + row*NCOLS + col, /* ID is function of position */
- hInst, /* instance */
- NULL); /* additional info */
- if (!board[row][col].hWindow)
- {
- MessageBox(hWnd, "Unable to create cube controls", "BAD ERROR",
- MB_ICONQUESTION | MB_OK);
- break;
- }
- }
-
- hTreeTop = NULL; /* There is no dictionary */
- hCListTop = NULL; /* The computer has not found any words */
-
- RackNumber = -1; /* No rack has been assigned, yet */
- /* Set up the first rack (it is not shown until first NewGame() */
- srand(GetCurrentTime());
- NextRackNumber = rand();
- SetNextRack(NextRackNumber);
-
- /* Make controls for ENTER and STOP */
- hEnter = CreateWindow("Button",
- NULL,
- WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS | WS_VISIBLE
- | BS_OWNERDRAW | BS_PUSHBUTTON,
- 176, 64, 64, 32,
- hWnd,
- ID_ENTER,
- hInst,
- NULL);
-
- hStop = CreateWindow("Button",
- NULL,
- WS_CHILD | WS_DISABLED | WS_CLIPSIBLINGS | WS_VISIBLE
- | BS_OWNERDRAW | BS_PUSHBUTTON,
- 208, 112, 32, 32,
- hWnd,
- ID_STOP,
- hInst,
- NULL);
-
- if (!hStop || !hEnter)
- MessageBox(hWnd, "Unable to create cube controls", "BAD ERROR",
- MB_ICONQUESTION | MB_OK);
-
- /* Make the windows for user's word input */
- /* Same location, but only one appears at a time */
- hUEdit = CreateWindow("Edit", /* predefined EDIT type */
- "", /* initial text for EDIT */
- WS_CHILD | ES_MULTILINE | ES_UPPERCASE | WS_BORDER | WS_CLIPSIBLINGS
- | WS_VSCROLL | ES_AUTOVSCROLL, /* window style */
- 0, 0, 0, 0, /* leave sizing to WM_SIZE */
- hWnd, /* parent handle */
- ID_USERWORDS, /* menu or child ID */
- hInst, /* instance */
- NULL); /* additional info */
-
- hUList = CreateWindow("Listbox", /* Predefined type LISTBOX */
- "", /* No title */
- WS_CHILD | WS_BORDER | WS_CLIPSIBLINGS | LBS_USETABSTOPS | LBS_NOTIFY
- | LBS_NOINTEGRALHEIGHT | WS_VSCROLL, /* window style */
- 0, 0, 0, 0, /* leave sizing to WM_SIZE */
- hWnd, /* parent handle */
- ID_PLIST, /* menu or child ID */
- hInst, /* instance */
- NULL); /* additional info */
-
- if (!hUList || !hUEdit)
- MessageBox(hWnd, "Unable to create window for player's words", "BAD ERROR",
- MB_ICONQUESTION | MB_OK);
-
- /* compute size and tab stops for list boxes */
- hDC = GetDC(hWnd);
- TabStops[0] = TScoreWidth * 4 / LOWORD(GetDialogBaseUnits());
- TabStops[1] = (TScoreWidth + LOWORD(GetTextExtent(hDC, "0", 1)))
- * 4 / LOWORD(GetDialogBaseUnits());
- TabStops[2] = (TScoreWidth + LOWORD(GetTextExtent(hDC, "00", 2)))
- * 4 / LOWORD(GetDialogBaseUnits());
- ReleaseDC(hWnd, hDC);
-
- /* Do the options */
- Smartness = GetPrivateProfileInt("Bago", "Computer Smartness", 15, BAGOINI);
- EndTime = GetPrivateProfileInt("Bago", "Game Duration", 180, BAGOINI);
- Sound = GetPrivateProfileInt("Bago", "Sound", TRUE, BAGOINI);
- UseTimer = GetPrivateProfileInt("Bago", "Timed Game", TRUE, BAGOINI);
- Learn = GetPrivateProfileInt("Bago", "Learn Words", FALSE, BAGOINI);
- CPlay = GetPrivateProfileInt("Bago", "Computer Plays", TRUE, BAGOINI);
- RotCubes = GetPrivateProfileInt("Bago", "Rotatable Cubes", FALSE, BAGOINI);
- Rewards = GetPrivateProfileInt("Bago", "Pictoral", FALSE, BAGOINI);
-
- if (UseTimer)
- {
- UseTimer = FALSE; /* set up for routine which toggles */
- ProcessBagoTimer(hWnd, MN_DD_OPTIONS + MN_OPT_TIMER);
- }
-
- if (CPlay)
- {
- CPlay = FALSE; /* set up for routine which toggles */
- ProcessBagoCPlay(hWnd, MN_DD_OPTIONS + MN_OPT_CPLAY);
- }
-
- if (Learn)
- {
- Learn = FALSE; /* set up for routine which toggles */
- ProcessBagoLearn(hWnd, MN_DD_OPTIONS + MN_OPT_LEARN);
- }
-
- if (RotCubes)
- {
- RotCubes = FALSE; /* set up for routine which toggles */
- ProcessBagoRotCubes(hWnd, MN_DD_OPTIONS + MN_OPT_ROTATE);
- }
-
- if (Sound)
- {
- Sound = FALSE; /* set up for routine which toggles */
- ProcessBagoSound(hWnd, MN_DD_OPTIONS + MN_OPT_SOUND);
- }
-
- if (Rewards)
- {
- Rewards = FALSE; /* set up for routine which toggles */
- ProcessBagoRewards(hWnd, MN_DD_OPTIONS + MN_OPT_REWARDS);
- }
-
- /* Tell the User and computer lists where to put tabs */
- PostMessage(hUList, LB_SETTABSTOPS, 3, (LONG)(LPSTR) TabStops);
-
- /* Post message to start the rest of the initialization */
- /* But first, we want to allow the window to be shown */
- PostMessage(hWnd, BAGOM_INIT, 0, 0L);
- }
-
- /* Load a rack from a file. The first 25 alphabetic characters */
- /* in the file are used. Note that this loads the NEXT rack, not the */
- /* actual game board that is being displayed */
- ProcessBagoGLoad(hWnd)
- HWND hWnd;
- {
- int hInFile;
- char InBuf[30];
- OFSTRUCT OfStruct;
- char *BufPtr;
- int row, col; /* used to step through board array */
- char InChar; /* We input characters one at a time */
- int nchar; /* How many valid characters we have read */
- char FileName[30];
- int dummy;
-
- strcpy(FileName, BAGOSAVE);
- if (InputBox(hWnd, "Load rack from:",
- FileName, &dummy, FALSE) == ID_CANCEL) return;
-
- if ((hInFile = OpenFile(FileName, &OfStruct,
- OF_PROMPT | OF_CANCEL | OF_READ)) >= 0)
- {
- nchar = 0;
- BufPtr = InBuf;
- while (nchar < NDICE && read(hInFile, &InChar, 1))
- {
- if (isupper(*BufPtr = toupper(InChar)))
- {
- BufPtr++;
- nchar++;
- }
- }
- close(hInFile);
-
- if (nchar == NDICE)
- {
- BufPtr = InBuf;
- for (row=0; row < NROWS; row++)
- {
- for (col=0; col < NCOLS; col++)
- {
- NextVal[row][col] = *BufPtr;
- BufPtr++;
- }
- }
- }
- else
- {
- MessageBox(hWnd, "Not enough letters in file.", "Error",
- MB_ICONQUESTION | MB_OK);
- }
-
- NextRackNumber = -1; /* we have no idea what rack number is, now */
- }
- }
-
- /* Save the current rack into a file */
- /* Also save's both the user's and computer's word lists, if any */
- ProcessBagoGSave(hWnd)
- HWND hWnd;
- {
- int hOutFile;
- char OutBuf[40];
- OFSTRUCT OfStruct;
- char *BufPtr;
- int row, col; /* used to step through board array */
- int nlines; /* for writing out list box */
- char FileName[30];
- int dummy;
-
- strcpy(FileName, BAGOSAVE);
- if (InputBox(hWnd, "Save this rack to:",
- FileName, &dummy, FALSE) == ID_CANCEL) return;
-
- if ((hOutFile = OpenFile(FileName, &OfStruct,
- OF_PROMPT | OF_CANCEL | OF_CREATE | OF_WRITE)) >= 0)
- {
- BufPtr = OutBuf;
- for (row=0; row < NROWS; row++)
- {
- for (col=0; col < NCOLS; col++)
- {
- *BufPtr = board[row][col].val;
- BufPtr++;
- }
- *BufPtr = '\r'; BufPtr++;
- *BufPtr = '\n'; BufPtr++;
- }
- *BufPtr = NULL; /* terminating null */
- write(hOutFile, OutBuf, strlen(OutBuf));
-
- /* Copy user word list, if any */
- if (hUList)
- {
- strcpy(OutBuf, "\r\nYour Words ----\r\n");
- write(hOutFile, OutBuf, strlen(OutBuf));
- nlines = SendMessage(hUList, LB_GETCOUNT, 0, 0L);
- for (row=0; row < nlines; row++)
- {
- SendMessage(hUList, LB_GETTEXT, row, (LONG)(LPSTR) OutBuf);
- strcat(OutBuf, "\r\n");
- write(hOutFile, OutBuf, strlen(OutBuf));
- }
- }
-
- /* Copy computer word list, if any */
- if (hCList)
- {
- strcpy(OutBuf, "\r\nBago's Words ----\r\n");
- write(hOutFile, OutBuf, strlen(OutBuf));
- nlines = SendMessage(hCList, LB_GETCOUNT, 0, 0L);
- for (row=0; row < nlines; row++)
- {
- SendMessage(hCList, LB_GETTEXT, row, (LONG) (LPSTR) OutBuf);
- strcat(OutBuf, "\r\n");
- write(hOutFile, OutBuf, strlen(OutBuf));
- }
- }
-
- close(hOutFile);
- }
- }
-
- /* Enable/disable feature of learning new words from user's play */
- ProcessBagoLearn(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- if (!Learn)
- /* Not in learn mode, enable */
- {
- CheckMenuItem(GetMenu(hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
- Learn = TRUE;
- }
- else
- /* In learn mode now, disable */
- {
- CheckMenuItem(GetMenu(hWnd), wParam, MF_BYCOMMAND | MF_UNCHECKED);
- Learn = FALSE;
- }
- }
-
- /* Enable or disable the egg timer option. Check on the menu item is updated */
- ProcessBagoTimer(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- if (!UseTimer)
- /* Egg timer does not exist, create it. */
- {
- CheckMenuItem(GetMenu(hWnd), wParam, MF_BYCOMMAND | MF_CHECKED);
- hEgg = CreateEggTimer(hWnd);
- UseTimer = TRUE;
- }
- else
- {
- CheckMenuItem(GetMenu(hWnd), wParam, MF_BYCOMMAND | MF_UNCHECKED);
- DestroyWindow(hEgg);
- hEgg = NULL;
- UseTimer = FALSE;
- }
- }
-
- /* The Computer play menu selection enables/disables computer from playing */
- ProcessBagoCPlay(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- HMENU hMenu;
-
- hMenu = GetMenu(hWnd);
-
- if (!CPlay)
- /* If not in computer play, make the window */
- {
- RECT Rect;
-
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_CHECKED);
-
- hCList = CreateWindow("Listbox", /* Predefined type LISTBOX */
- "", /* No title */
- WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS | LBS_NOTIFY
- | LBS_USETABSTOPS | LBS_NOINTEGRALHEIGHT | WS_VSCROLL,
- 0, 0, 0, 0, /* let WM_SIZE handle */
- hWnd, /* parent handle */
- ID_CPLAY, /* menu or child ID */
- hInst, /* instance */
- NULL); /* additional info */
-
- if (!hCList)
- {
- MessageBox(hWnd, "Unable to create Computer's window", "ERROR",
- MB_ICONQUESTION | MB_OK);
- }
- else
- {
- /* so initial size will be set */
- GetClientRect(hWnd, (LPRECT) &Rect);
- SendMessage(hWnd, WM_SIZE, SIZENORMAL,
- MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top));
- PostMessage(hCList, LB_SETTABSTOPS, 3, (LONG)(LPSTR) TabStops);
- CPlay = TRUE;
- }
- }
- else
- /* Turn off Computer Play */
- {
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_UNCHECKED);
-
- DestroyWindow(hCList); hCList = NULL;
-
- CPlay = FALSE;
- }
- }
-
- /* Generate statistics display */
- ProcessBagoStats(hWnd)
- HWND hWnd;
- {
- char outstring[200];
- char compstring[50];
- int RS; /* Recommended smartness level */
-
- strcpy(outstring, "\t\tYou\t\Computer\n\n");
- sprintf(compstring, "Total Score:\t%d\t%d\n", RUScore, RCScore);
- strcat(outstring, compstring);
- sprintf(compstring, "Total Words:\t%d\t%d\n", RUWords, RCWords);
- strcat(outstring, compstring);
- if (NGames > 0)
- {
- sprintf(compstring, "Words/Game:\t%d\t%d\n", RUWords/NGames, RCWords/NGames);
- strcat(outstring, compstring);
- }
- if (NGames != 1)
- sprintf(compstring, "\n%d Rounds Played.\n", NGames);
- else
- strcpy(compstring, "\n1 Round Played.\n");
- strcat(outstring, compstring);
- if (NGames > 0)
- {
- RS = (RCScore > 0) ? (1.0 * RUScore * Smartness) / RCScore : 100;
- if (RS > 100) RS = 100;
- sprintf(compstring, "Difficulty = %d; try %d for challenge.\n", Smartness, RS);
- strcat(outstring, compstring);
- }
- else
- {
- sprintf(compstring, "Difficulty = %d.\n", Smartness);
- strcat(outstring, compstring);
- }
- MessageBox(hWnd, outstring, "Statistics", MB_OK);
- }
-
- /* Enable/disable feature of realistically rotated cubes */
- ProcessBagoRotCubes(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- HMENU hMenu;
- int row, col;
-
- hMenu = GetMenu(hWnd);
- if (!RotCubes)
- /* Not in RotCube mode, enable */
- {
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_CHECKED);
- RotCubes = TRUE;
- }
- else
- /* In RotCube mode now, disable */
- {
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_UNCHECKED);
- RotCubes = FALSE;
- }
-
- /* Need to redisplay all the cubes */
- for (row=0; row<NROWS; row++)
- for (col=0; col<NCOLS; col++)
- InvalidateRect(board[row][col].hWindow, NULL, FALSE);
- }
-
- /* Enable/disable feature of pictoral rewards */
- ProcessBagoRewards(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- HMENU hMenu;
-
- hMenu = GetSystemMenu(hWnd, FALSE);
-
- if (!Rewards)
- /* Not in Reward mode, enable */
- {
- hEyes = LoadBitmap(hInst, MAKEINTRESOURCE(EYESBMP));
- ModifyMenu(hMenu, MN_REWARDS,
- MF_BYCOMMAND | MF_BITMAP, MN_REWARDS,
- (LPSTR) (LONG) hEyes);
- Rewards = TRUE;
- }
- else
- /* In Reward mode now, disable */
- {
- ModifyMenu(hMenu, MN_REWARDS,
- MF_BYCOMMAND | MF_STRING, MN_REWARDS,
- "");
- DeleteObject(hEyes);
- Rewards = FALSE;
- }
- }
-
- /* Enable/disable sound */
- ProcessBagoSound(hWnd, wParam)
- HWND hWnd;
- WORD wParam;
- {
- HMENU hMenu;
-
- hMenu = GetMenu(hWnd);
- if (!Sound)
- /* Sound off, enable */
- {
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_CHECKED);
- Sound = TRUE;
- }
- else
- /* Sound on, disable */
- {
- CheckMenuItem(hMenu, wParam, MF_BYCOMMAND | MF_UNCHECKED);
- Sound = FALSE;
- }
- }
-
- /* saves the entire dictionary to disk */
- ProcessBagoSaveDict(hWnd)
- HWND hWnd;
- {
- OFSTRUCT OfStruct;
- int hDictFile; /* handle of dictionary file */
- HCURSOR hOldCursor;
-
- if ((hDictFile = OpenFile(BAGODIC, &OfStruct,
- OF_PROMPT | OF_CANCEL | OF_CREATE | OF_WRITE)) < 0)
- {
- MessageBox(hWnd, "Cannot open dictionary file for writing.", "ERROR",
- MB_ICONQUESTION | MB_OK);
- }
- else
- {
- /* show hourglass for long file I/O */
- hOldCursor = SetCursor(hHourGlass);
- if (!PrintDict(hDictFile, hTreeTop))
- MessageBox(hWnd, "Error writing dictionary file.", "ERROR",
- MB_ICONQUESTION | MB_OK | MB_SYSTEMMODAL);
- close(hDictFile);
-
- DictChanged = FALSE;
-
- SetCursor(hOldCursor);
- }
- }
-
- /* Puts the entire dictionary into the user window */
- ProcessBagoShowDict(hWnd)
- HWND hWnd;
- {
- HANDLE hOldBuffer, hNewBuffer;
- char *pNewBuffer;
-
- SendMessage(hCList, WM_SETREDRAW, FALSE, 0L);
- PrintLeaf(hCList, hTreeTop);
- SendMessage(hCList, LB_INSERTSTRING, 0, (LONG) (LPSTR) "");
- SendMessage(hCList, WM_SETREDRAW, TRUE, 0L);
- SendMessage(hCList, LB_DELETESTRING, 0, 0L);
- }
-
- /* Optimize the dictionary */
- /* The progress box is brought up to inform the user of our progress */
- ProcessBagoOptDict(hWnd)
- HWND hWnd;
- {
- HANDLE hFTreeTop; /* handle to top of frequency-sorted tree */
- HANDLE hLinArray; /* handle to sorted linear array of HANDLES */
- LPHANDLE LinArray; /* sorted linear array of HANDLES */
- int nWords; /* count of number of words in tree */
- int i; /* used to index LinArray */
- LPDW pLinArray; /* used to retrieve data from LinArray */
- int first, last; /* array bounds of a set with equal frequency */
- int BaseFreq; /* the frequency of the set above */
- int CurFreq; /* frequency of word under inspection */
- HCURSOR hOldCursor;
- HWND hPro;
-
- OptimizeFail = FALSE;
- hFTreeTop = NULL;
- hOldCursor = SetCursor(hHourGlass);
- nWords = CountLeaf(hTreeTop);
- hPro = CreateProBox(hWnd);
- SendMessage(hPro, PRO_INIT, nWords, (LONG) (LPSTR) "Re-sorting Dictionary");
- i=0;
- ReSortLeaf(hTreeTop, (LPHANDLE) &hFTreeTop, &i, hPro);
-
- /* allocate enough space for linear array */
- if (!OptimizeFail)
- {
- hLinArray = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT,
- (LONG) nWords*sizeof(HANDLE));
- if (!hLinArray) OptimizeFail = TRUE;
- }
-
- if (!OptimizeFail)
- {
- LinArray = (LPHANDLE) GlobalLock(hLinArray);
-
- /* Get rid of old tree to free up space */
- DestroyLeaf(hTreeTop);
- hTreeTop = NULL;
-
- /* copy the F-tree into array */
- i = 0;
- CopyTreeToLin(hFTreeTop, LinArray, &i);
-
- /* Scan the linear array for sets of words with the same frequency */
- /* and output a balanced tree for each set */
- SendMessage(hPro, PRO_INIT, nWords, (LONG) (LPSTR) "Balancing Dictionary Tree");
- i=0;
- while (i < nWords)
- {
- first = i;
- pLinArray = (LPDW) GlobalLock(LinArray[i]);
- BaseFreq = pLinArray -> Freq;
- LocalUnlock(LinArray[i]);
- do {
- i++;
- if (i < nWords)
- {
- pLinArray = (LPDW) GlobalLock(LinArray[i]);
- CurFreq = pLinArray -> Freq;
- GlobalUnlock(LinArray[i]);
- }
- SendMessage(hPro, PRO_SETPOS, i, 0L);
- } while (i < nWords && CurFreq == BaseFreq);
- last = i - 1;
- Balance(&hTreeTop, LinArray, first, last);
- }
-
- DestroyWindow(hPro);
-
- if (MessageBox(hWnd, "Save optimized dictionary to disk?", "Optimize", MB_YESNO) == IDYES)
- ProcessBagoSaveDict(hWnd);
-
- /* Get rid of global memory used for sort */
- GlobalUnlock(hLinArray);
- GlobalFree(hLinArray);
- }
- else
- /* OptimizeFail: not enough global memory */
- {
- /* print warning message */
- MessageBox(hWnd, "Out of memory - can't optimize.", "ERROR",
- MB_ICONQUESTION | MB_OK);
-
- DestroyWindow(hPro);
- }
-
- /* This must be done whether or not GlobalAlloc failed */
- DestroyGLeaf(hFTreeTop);
-
- SetCursor(hOldCursor);
- }
-
- /****************************************************************************
-
- FUNCTION: About(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages for "About" dialog box
-
- MESSAGES:
-
- WM_INITDIALOG - initialize dialog box
- WM_COMMAND - Input received
-
- COMMENTS:
-
- No initialization is needed for this particular dialog box, but TRUE
- must be returned to Windows.
-
- Wait for user to click on "Ok" button, then close the dialog box.
-
- ****************************************************************************/
-
- BOOL FAR PASCAL About(hDlg, message, wParam, lParam)
- HWND hDlg;
- unsigned message;
- WORD wParam;
- LONG lParam;
- {
- switch (message) {
- case WM_INITDIALOG:
- return (TRUE); /* returning TRUE sets focus to OK button */
-
- case WM_COMMAND:
- if (wParam == IDOK) { /* "OK" box selected? */
- EndDialog(hDlg, NULL); /* Exits the dialog box */
- return (TRUE);
- }
- break;
- }
- return (FALSE); /* Didn't process a message */
- }
-
- /****************************************************************************
-
- FUNCTION: EditWord(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages for "EditWord" dialog box
-
- MESSAGES:
-
- WM_INITDIALOG - initialize dialog box
- WM_COMMAND - Input received
-
- COMMENTS:
-
- No initialization is needed for this particular dialog box, but TRUE
- must be returned to Windows.
-
- Wait for user to click on "Ok" button, then close the dialog box.
-
- ****************************************************************************/
-
- BOOL FAR PASCAL EditWord(hDlg, message, wParam, lParam)
- HWND hDlg;
- unsigned message;
- WORD wParam;
- LONG lParam;
- {
- HWND hControl; /* handle to a control */
-
- switch (message) {
- case WM_INITDIALOG: /* message: initialize dialog box */
- hWord = hTreeTop; /* good a starting point as any */
- UpdateControls(hDlg);
- return (FALSE); /* so windows won't arbitrarily set focus */
- break;
- case WM_COMMAND: /* message: received a command */
- ProcessEditWordCommand(hDlg, wParam, lParam);
- return (TRUE);
- break;
- default:
- return (FALSE); /* Didn't process a message */
- }
- }
-
- /* returns the Suffix mask, set according to the current buttons */
- /* This automatically returns the virgin bit (MSB) set to 0, since */
- /* ID_LASTSUF - ID_FIRSTSUF does not do all 16 bits */
- unsigned GetButtons(hDlg)
- HWND hDlg;
- {
- int nControl;
- unsigned BitMask;
-
- BitMask = 0;
-
- for (nControl=ID_LASTSUF; nControl >= ID_FIRSTSUF; nControl--)
- {
- BitMask <<= 1; /* move to the next bit */
- if (IsDlgButtonChecked(hDlg, nControl)) BitMask |= 1;
- }
-
- return(BitMask);
- }
-
- /* Posts the frequency and suffix information from the dialog box to the
- * dictionary. The word is assumed to be in global handle hWord.
- * Returns TRUE if hWord is NULL, or the posting succeneds.
- * Returns FALSE if the posting fails. Only possible reason for failure
- * at present is invalid frequency.
- */
- BOOL PostWord(hDlg)
- {
- PDW pWord; /* pointer to record corresponding to current word */
- BOOL TransOk; /* flag to see if integer translation succeeded */
- int TempFreq; /* frequency in the dialog box, if any */
- unsigned TempSuffix;
-
- if (hWord)
- {
- TempFreq = GetDlgItemInt(hDlg, ID_FREQ, (BOOL FAR *)&TransOk, FALSE);
- if (TransOk)
- {
- /* rewrite an existing leaf */
- pWord = (PDW) LocalLock(hWord);
- /* pWord -> w should already be right */
- pWord -> Freq = TempFreq;
- /* user may have changed buttons, so get latest settings */
- TempSuffix = GetButtons(hDlg);
- /* note that GetButtons() by nature kills the virgin bit */
- if (pWord -> Suffix1 != TempSuffix)
- {
- pWord -> Suffix1 = TempSuffix;
- DictChanged = TRUE;
- }
- LocalUnlock(hWord);
- return(TRUE);
- }
- else
- {
- MessageBox(hDlg, "Need non-negative number for word frequency", "Error",
- MB_OK);
- /* restore word in case it was altered */
- pWord = (PDW) LocalLock(hWord);
- SetDlgItemText(hDlg, ID_WORD, (LPSTR) pWord -> w);
- LocalUnlock(hWord);
- /* Give the focus to the frequency */
- SetFocus(GetDlgItem(hDlg, ID_FREQ));
- return(FALSE);
- }
- }
- else
- return(TRUE);
- }
-
- /* The processing of the dialog box for the dictionary editor is complex */
- /* Processing of ID_OK:
- * 1. Try to put all the current information back into the dictionary.
- * 2. If the word has been changed, try to look it up in the dictionary.
- * a. If the word exists, display the information.
- * b. If the word is NULL, disable most of the editing fields in box.
- * c. If the word is not in the dictionary, see if the user wants to add it.
- * Processing of ID_DELETE:
- * 1. Try to put all the current information back into the dictionary.
- * 2. If the word given is in the dictionary
- * a. Delete the word.
- * b. Relocate any words which may have been in the linked list under
- * the deleted word.
- */
-
- ProcessEditWordCommand(hDlg, wParam, lParam)
- HWND hDlg;
- WORD wParam;
- LONG lParam;
-
- {
- int NewWordLen;
- PDW pWord; /* pointer to record corresponding to current word */
- PDW pSuper; /* pointer to record superior to current word */
- BOOL TransOk; /* flag to see if integer translation succeeded */
- HANDLE hNextWord; /* next word handle temp storage */
- static DW TempWord; /* temp copy of word begin considered */
-
- switch (wParam)
- {
- case ID_OK:
- if (!PostWord(hDlg)) return;
-
- if (SendDlgItemMessage(hDlg, ID_WORD, EM_GETMODIFY, 0, 0L))
- /* word has been changed, take action */
- {
- /* Remember the present word, in case user declines */
- /* adding a new word */
- hNextWord = hWord;
- /* get the changed word (which may be null) */
- NewWordLen = GetDlgItemText(hDlg, ID_WORD, (LPSTR) TempWord.w, 10);
- TrimWord(TempWord.w, NewWordLen);
- if (strlen(TempWord.w))
- /* valid word - is it already in dictionary? */
- {
- RemoveQu(TempWord.w);
- /* Fetch the word from the tree if we can */
- if (hWord = FindExactLeaf(TempWord.w, hTreeTop))
- {
- pWord = (PDW) LocalLock(hWord);
- TempWord.Suffix1 = pWord -> Suffix1;
- TempWord.Freq = pWord -> Freq;
- LocalUnlock(hWord);
- }
- else
- /* add a word that is not already in the dictionary */
- {
- TempWord.Suffix1 = 0;
- TempWord.Freq = 0;
- if (MessageBox(hDlg, "Add the word?", "Not in Dictionary",
- MB_YESNO) == IDYES)
- {
- AddLeaf(TempWord.w, &hTreeTop, 0, 0x8000, NULL);
- /* retrieve handle for word we just added */
- hWord = FindExactLeaf(TempWord.w, hTreeTop);
- }
- else
- /* if adding new word declined, go back to old */
- hWord = hNextWord;
- }
- }
- else
- /* if No word entered, go back to previous word */
- hWord = hNextWord;
- UpdateControls(hDlg);
- }
- /* else word has not changed. Do nothing. */
- break;
- case ID_CANCEL:
- if (!PostWord(hDlg)) return;
- EndDialog(hDlg, NULL); /* Exits the dialog box */
- break;
- case ID_DELETE:
- if (!PostWord(hDlg)) return;
- NewWordLen = GetDlgItemText(hDlg, ID_WORD, (LPSTR) TempWord.w, 10);
- TrimWord(TempWord.w, NewWordLen);
- RemoveQu(TempWord.w);
- if (strlen(TempWord.w))
- /* valid word - look up in dictionary */
- {
- /* if can find leaf, get rid of it */
- if (hWord = FindExactLeaf(TempWord.w, hTreeTop))
- {
- /* first determine what next word diplayed will be */
- /* must do this BEFORE modifying the tree */
- hNextWord = FindPrev(hWord); /* could be null */
- if (!hNextWord) hNextWord = FindNext(hWord); /* could be null */
-
- pWord = (PDW) LocalLock(hWord);
- /* delete reference in parent leaf */
- if (pWord -> up)
- {
- pSuper = (PDW) LocalLock(pWord -> up);
- /* null out reference to the word */
- if (pSuper->lt == hWord) pSuper->lt = NULL;
- if (pSuper->gt == hWord) pSuper->gt = NULL;
- LocalUnlock(pWord -> up);
- }
- else
- /* rare case that this word has no superior, it IS TreeTop */
- {
- hTreeTop = NULL;
- }
- /* relocate inferior leaves, if any, from deleted word */
- if (pWord -> lt) RelocateLeaf(pWord -> lt, &hTreeTop, NULL);
- if (pWord -> gt) RelocateLeaf(pWord -> gt, &hTreeTop, NULL);
- LocalUnlock(hWord);
- LocalFree(hWord);
- hWord = hNextWord;
- DictChanged = TRUE;
- }
- UpdateControls(hDlg);
- }
- break;
- case ID_PREV:
- if (!PostWord(hDlg)) return;
- hNextWord = FindPrev(hWord);
- /* Avoid running off end of list */
- if (hNextWord) hWord = hNextWord;
- UpdateControls(hDlg);
- break;
- case ID_NEXT:
- if (!PostWord(hDlg)) return;
- hNextWord = FindNext(hWord);
- /* Avoid running off end of list */
- if (hNextWord) hWord = hNextWord;
- UpdateControls(hDlg);
- break;
- case ID_VIRGIN:
- if (!PostWord(hDlg)) return;
- hNextWord = FindVirgin(hTreeTop);
- if (hNextWord)
- hWord = hNextWord;
- else
- MessageBox(hDlg, "No virgin words in dictionary.",
- "", MB_OK | MB_ICONASTERISK);
- UpdateControls(hDlg);
- break;
- default:
- break;
- }
- }
-
- /* Enable and update the fields in the dialog box to match the word
- * corresponding to handle hWord. If hWord is null, disable the
- * appropriate fields.
- */
- UpdateControls(hDlg)
- HWND hDlg;
- {
- PDW LeafPtr;
- int nControl; /* used for hiding and unhiding windows */
- HWND hControl; /* used for hiding and unhiding windows */
-
- if (hWord)
- {
- LeafPtr = (PDW) LocalLock(hWord);
-
- /* display the word and its frequency */
- AddQu(LeafPtr -> w);
- SetDlgItemText(hDlg, ID_WORD, (LPSTR) LeafPtr -> w);
- SetDlgItemInt(hDlg, ID_FREQ, LeafPtr -> Freq, FALSE);
- /* display the suffixes with proper check marks */
- UpdateButtons(hDlg, LeafPtr -> w, LeafPtr -> Suffix1);
- /* show controls to allow editing */
- for (nControl=ID_FIRSTEDIT; nControl <= ID_LASTEDIT; nControl++)
- {
- hControl = GetDlgItem(hDlg, nControl);
- SetWindowLong(hControl, GWL_STYLE,
- ~WS_DISABLED & GetWindowLong(hControl, GWL_STYLE));
- InvalidateRect(hControl, NULL, FALSE);
- }
- RemoveQu(LeafPtr -> w);
- LocalUnlock(hWord);
- }
- else
- {
- /* blank out the word */
- SetDlgItemText(hDlg, ID_WORD, "");
- SetDlgItemText(hDlg, ID_FREQ, "");
- /* blank out the suffix check boxes */
- for (nControl=ID_FIRSTSUF; nControl <= ID_LASTSUF; nControl++)
- {
- SetDlgItemText(hDlg, nControl, "");
- CheckDlgButton(hDlg, nControl, 0);
- }
- /* disable controls which are only appropriate when word is selected */
- for (nControl=ID_FIRSTEDIT; nControl <= ID_LASTEDIT; nControl++)
- {
- hControl = GetDlgItem(hDlg, nControl);
- SetWindowLong(hControl, GWL_STYLE,
- WS_DISABLED | GetWindowLong(hControl, GWL_STYLE));
- InvalidateRect(hControl, NULL, FALSE);
- }
- /* Give the focus to the word to enter */
- SetFocus(GetDlgItem(hDlg, ID_WORD));
- }
- }
-
- /* update all the buttons with their proper checks */
- UpdateButtons(hDlg, RootWord, Suffixes)
- HWND hDlg;
- char RootWord[];
- unsigned Suffixes;
- {
- int nControl;
- char FullWord[13];
- unsigned BitMask;
-
- BitMask = 1;
-
- for (nControl=ID_FIRSTSUF; nControl <= ID_LASTSUF; nControl++)
- {
- AddSuffix(RootWord, nControl, FullWord);
- SetDlgItemText(hDlg, nControl, FullWord);
- if (BitMask & Suffixes)
- /* if the bit is set, check the box */
- CheckDlgButton(hDlg, nControl, 1);
- else
- CheckDlgButton(hDlg, nControl, 0);
- BitMask <<= 1; /* move to the next bit */
- }
- }
-
- /* Add the suffix specified by suf_id to the RootWord. Store result in dest */
- /* Warning: this routine may barf if given words shorter than 3 letters */
- AddSuffix(RootWord, suf_id, Dest)
- char RootWord[], Dest[];
- int suf_id;
- {
- int len;
- strcpy(Dest, RootWord);
- len = strlen(Dest);
- switch (suf_id)
- {
- case ID_SUFS:
- if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- Dest[len-1] = NULL;
- strcat(Dest, "IES");
- }
- else if (Dest[len-1] == 'S' || Dest[len-1] == 'H' || Dest[len-1] == 'X')
- strcat(Dest, "ES");
- else if (Dest[len-1] == 'F')
- {
- Dest[len-1] = NULL;
- strcat(Dest, "VES");
- }
- else
- strcat(Dest, "S");
- break;
- case ID_SUFED:
- if (Dest[len-1] == 'E')
- strcat(Dest, "D");
- else if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- Dest[len-1] = 'I';
- strcat(Dest, "ED");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "ED");
- }
- else
- strcat(Dest, "ED");
-
- break;
- case ID_SUFER:
- if (Dest[len-1] == 'E')
- strcat(Dest, "R");
- else if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- Dest[len-1] = 'I';
- strcat(Dest, "ER");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "ER");
- }
- else
- strcat(Dest, "ER");
- break;
- case ID_SUFEN:
- if (Dest[len-1] == 'E')
- strcat(Dest, "N");
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "EN");
- }
- else
- strcat(Dest, "EN");
- break;
- case ID_SUFY:
- if (Dest[len-1] == 'E')
- Dest[len-1] = 'Y';
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = 'Y';
- Dest[len+2] = NULL;
- }
- else
- strcat(Dest, "Y");
- break;
- case ID_SUFLY:
- strcat(Dest, "LY");
- break;
- case ID_SUFEST:
- if (Dest[len-1] == 'E')
- strcat(Dest, "ST");
- else if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- Dest[len-1] = 'I';
- strcat(Dest, "EST");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "EST");
- }
- else
- strcat(Dest, "EST");
- break;
- case ID_SUFISH:
- if (Dest[len-1] == 'E') Dest[len-1] = NULL;
- strcat(Dest, "ISH");
- break;
- case ID_SUFING:
- /* drop the e before ing */
- if (Dest[len-1] == 'E')
- {
- Dest[len-1] = NULL;
- strcat(Dest, "ING");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "ING");
- }
- else
- strcat(Dest, "ING");
- break;
- case ID_SUFERS:
- if (Dest[len-1] == 'E')
- strcat(Dest, "RS");
- else if (Dest[len-1] == 'Y' && Dest[len-2] != 'A')
- {
- Dest[len-1] = 'I';
- strcat(Dest, "ERS");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "ERS");
- }
- else
- strcat(Dest, "ERS");
- break;
- case ID_SUFINGS:
- /* drop the e before ing */
- if (Dest[len-1] == 'E')
- {
- Dest[len-1] = NULL;
- strcat(Dest, "INGS");
- }
- else if (isdoub(Dest[len-1]) && isvowel(Dest[len-2]) && !isvowel(Dest[len-3]))
- /* if word ends in consonant-vowel-consonant, double last letter */
- {
- Dest[len] = Dest[len-1];
- Dest[len+1] = NULL;
- strcat(Dest, "INGS");
- }
- else
- strcat(Dest, "INGS");
- break;
- }
- }
-
- /* number of bad combinations to search */
- #define NBADCHARS 274
-
- static char badchars[NBADCHARS][3] = {
- "AA","BC","BD","BF","BG","BH",
- "BK","BN","BP","BQ","BV","BW","BX","BZ",
- "CB","CD","CF","CG","CJ","CP","CQ",
- "CV","CW","CX","CZ","DC","DF","DH","DK",
- "DP","DQ","DX","DZ","FB","FC","FD",
- "FG","FH","FJ","FK","FM","FN","FP","FQ","FV",
- "FW","FX","FZ","GB","GC","GD","GF","GJ","GK","GP",
- "GQ","GT","GV","GW","GX","GZ","HB","HC","HD",
- "HF","HG","HH","HJ","HK","HL","HP","HQ",
- "HS","HV","HW","HX","HZ","IH","II","IW","IY",
- "JB","JC","JD","JF","JG","JH","JJ","JK","JL","JM",
- "JN","JP","JQ","JR","JS","JT","JV","JW","JX","JY",
- "JZ","KB","KC","KD","KF","KG","KH","KJ","KK","KM",
- "KP","KQ","KR","KT","KV","KW","KX","KZ","LH",
- "LJ","LQ","LR","LX","LZ","MC","MD",
- "MG","MH","MJ","MK","ML","MQ","MR","MV",
- "MW","MX","MZ","NQ",
- "OJ","OQ","PC","PF","PG","PJ",
- "PK","PM","PN","PQ","PV","PX","PZ","QA","QB",
- "QC","QD","QE","QF","QG","QH","QI","QJ","QK","QL",
- "QM","QN","QO","QP","QQ","QR","QS","QT","QV","QW",
- "QX","QY","QZ","RJ","RX","RZ","SB",
- "SF","SG","SJ","SR","SV","SX","SZ","TB","TD","TG",
- "TJ","TK","TP","TQ","TV","TX","UH",
- "UJ","UQ","UV","UW","VB","VC","VD",
- "VF","VG","VH","VJ","VK","VL","VM","VN","VP","VQ",
- "VR","VS","VT","VU","VV","VW","VX","VZ","WC",
- "WG","WJ","WP","WQ","WV",
- "WW","WX","WZ","XB","XD","XF","XG","XJ",
- "XK","XM","XN","XQ","XR","XS","XV",
- "XW","XX","XZ","YF","YH","YJ","YK",
- "YQ","YU","YV","YY","YZ","ZB","ZC","ZD",
- "ZF","ZG","ZH","ZJ","ZK","ZM","ZN","ZP","ZQ","ZR",
- "ZS","ZT","ZV","ZW","ZX"
- };
-
- /* A cheap, inexact algorithm to cull out strings of letters */
- /* that are probably not English words */
- /* Based on finding unlikely two-character sequences in the string */
- /* Warning: expects input to be capital-letters ONLY. Lowercase letters */
- /* make the routine asssume the word is valid */
-
- BOOL isword(TheWord)
- char TheWord[];
- {
- int pos;
- int EndCount;
- char tstr[3];
- int VowelCount;
-
- /* check vowel count - don't want all vowels, or no vowels */
- EndCount = strlen(TheWord);
- VowelCount = 0;
- for (pos=0; pos<EndCount; pos++)
- if (isvowel(TheWord[pos])) VowelCount++;
- if (VowelCount==0 || VowelCount==EndCount) return(FALSE);
-
- EndCount -= 2;
- if (EndCount < 0) return(FALSE);
-
- for (pos=0; pos <= EndCount; pos++)
- {
- tstr[0] = TheWord[pos];
- tstr[1] = TheWord[pos+1];
- tstr[2] = 0;
- if (bsearch(tstr, badchars, NBADCHARS, 3, strcmp)) return(FALSE);
- }
- return(TRUE);
- }
-
- /* These variables are applicable to the timer window only. */
- /* If this were an object-oriented language, they would be in */
- /* the domain of the set of timer subroutines */
-
- WORD idGameTimer; /* ID of the timer which ticks every second */
- int GameTime; /* used by Egg Timer window */
- /* Pens stay around until window closed */
- HPEN SandPen, FallingPen, EraserPen, GlassPen;
- HBRUSH SandBrush, EraserBrush;
- double K1; /* constant used to compute drawing of sand */
-
- /****************************************************************************
-
- FUNCTION: EggWndProc(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages
-
- MESSAGES:
-
- WM_CREATE - create window
- WM_PAINT - repaint window
- WM_TIMER - timer tick
- EGGM_SET - sets timeout value
- EGGM_START - start timer
- EGGM_STOP - stop timer (force to end state)
- WM_TIMER - 1 second game timer tick
- WM_DESTROY - destroy window
-
- COMMENTS:
-
- This is the windows procedure for the Egg Timer window.
- Once started, the egg timer automatically updates itself
- every second until the timeout value is reached. A message
- is then sent to the parent window to indicate that the timer
- has run out.
-
- ****************************************************************************/
-
- long FAR PASCAL EggWndProc(hEgg, message, wParam, lParam)
- HWND hEgg; /* window handle */
- unsigned message; /* type of message */
- WORD wParam; /* additional information */
- LONG lParam; /* additional information */
- {
- PAINTSTRUCT ps; /* used by paint procedure */
- HDC hDC; /* used by paint procedure */
-
- switch (message) {
- case WM_CREATE: /* message: window being created */
- ProcessEggCreate(hEgg);
- break;
-
- case WM_PAINT:
- hDC = BeginPaint(hEgg, (LPPAINTSTRUCT) &ps);
- ProcessEggPaint(hEgg, hDC);
- EndPaint(hEgg, (LPPAINTSTRUCT) &ps);
- break;
-
- case EGGM_SET:
- /* wParam is timeout value in seconds. Refuse nonpositive values */
- EndTime = max(wParam, 1);
- K1 = 60. * pow(10. / EndTime, 0.3333);
- break;
-
- case WM_LBUTTONDOWN:
- PostMessage(GetParent(hEgg), WM_COMMAND, MN_DD_GAME + MN_GAM_PLAY, 0L);
- break;
-
- case EGGM_START:
- ProcessEggStart(hEgg);
- break;
-
- case EGGM_STOP:
- if (!GameOver)
- {
- if (idGameTimer) KillTimer(hEgg, ID_GT); idGameTimer = 0;
- /* Reset the picture, too */
- GameTime = EndTime;
- /* Want timer to be redrawn immediately, especially before scoring */
- InvalidateRect(hEgg, NULL, TRUE);
- UpdateWindow(hEgg);
- /* Send message to parent, saying timer popped */
- PostMessage(GetParent(hEgg), BAGOM_ENDGAME, 0, 0L);
- }
- break;
-
- case WM_TIMER:
- ProcessEggTimer(hEgg);
- break;
-
- case WM_DESTROY: /* message: window being destroyed */
- if (idGameTimer) KillTimer(hEgg, ID_GT); idGameTimer = 0;
- /* put away our pens and brushes */
- DeleteObject(SandPen);
- DeleteObject(FallingPen);
- DeleteObject(SandBrush);
- PostMessage(GetParent(hEgg), WM_SETFOCUS, hEgg, 0L);
- break;
-
- default: /* Passes it on if unproccessed */
- return (DefWindowProc(hEgg, message, wParam, lParam));
- }
- return (NULL);
- }
-
- /* Egg Timer processing routines */
- ProcessEggCreate(hEgg)
- HWND hEgg;
- {
- GlassPen = GetStockObject(BLACK_PEN);
- SandPen = CreatePen(0, 1, RED);
- SandBrush = CreateSolidBrush(RED);
- FallingPen = CreatePen(2, 1, RED);
- EraserPen = CreatePen(0, 1, Mono ? WHITE : GRAY1);
- EraserBrush = hGrayBrush1;
- GameTime = EndTime;
- /* This is also recomputed every time the game length is set */
- K1 = 60. * pow(10. / EndTime, 0.3333);
- SetFocus(hEgg);
- }
-
- /* This routine is called every time the 1-second timer goes off */
- ProcessEggTimer(hEgg)
- HWND hEgg;
- {
- if (GameTime >= EndTime)
- /* This round is over */
- {
- if (idGameTimer) KillTimer(hEgg, ID_GT); idGameTimer = 0; /* stop the timer */
- /* Send message to parent, saying timer popped */
- PostMessage(GetParent(hEgg), BAGOM_ENDGAME, 0, 0L);
- }
- else
- GameTime++;
-
- InvalidateRect(hEgg, NULL, FALSE);
- UpdateWindow(hEgg);
- }
-
- /* Set up device context for Egg Timer window. */
- /* Regardless of physical dimensions of window, want to map a grid */
- /* of +-70 wide and +-290 high */
- SetupEggDC (hEgg, hDC)
- HWND hEgg;
- HDC hDC;
- {
- RECT rClient;
-
- GetClientRect(hEgg, &rClient);
-
- SetMapMode (hDC, MM_ANISOTROPIC);
- SetWindowOrg (hDC, -70, -290);
- SetWindowExt( hDC, 140, 580);
- SetViewportOrg (hDC, rClient.left, rClient.bottom);
- SetViewportExt (hDC, rClient.right-rClient.left, rClient.top-rClient.bottom);
- SetPolyFillMode(hDC, ALTERNATE);
- SetBkMode(hDC, TRANSPARENT);
- return(TRUE);
- }
-
- /* This draws the picture of the Egg timer and sand.
- * The routine is written with low flicker as the first priority.
- * Speed is important, too, but it is second priority.
- * In trying to simulate the real way sand looks in an hourglass,
- * the height of the sand varies linearly with time as long as the
- * top of the sand is in the cylindrical part of the glass. When the
- * top of the sand is in the funnel part of the glass, the height varies
- * as the cube root of time. In other words, the sand level drops faster
- * and faster once it reaches the funnel.
- */
- /* The outline of the Egg Timer glass */
- static int Glass[11][2] = {
- {-10, 0},
- {-50, 60},
- {-50, 270},
- { 50, 270},
- { 50, 60},
- { 10, 0},
- { 50, -60},
- { 50, -270},
- {-50, -270},
- {-50, -60},
- {-10, 0} };
-
- /* The sand on the top. Some y-values get overwritten in execution */
- static int TopSand[5][2] = {
- {-40, 240},
- { 40, 240},
- { 40, 60},
- { 0, 0},
- {-40, 60} } ;
-
- /* The air in the top section */
- static int TopAir[6][2] = {
- {-40, 240},
- { 40, 240},
- { 40, 60},
- { 0, 0},
- { 0, 0},
- {-40, 60} } ;
-
- /* The sand in the funnel section only */
- static int FunnelSand[3][2] = {
- {-40, 60},
- { 40, 60},
- { 0, 0} } ;
-
- ProcessEggPaint(hEgg, hDC)
- HWND hEgg;
- HDC hDC;
- {
- HPEN hOldPen;
- HBRUSH hBrush, hOldBrush;
- int yTemp; /* temporary storage to avoid floating point recomputation */
-
- SetupEggDC(hEgg, hDC);
-
- hOldPen = SelectObject(hDC, GlassPen);
- hOldBrush = SelectObject(hDC, EraserBrush);
- Polyline(hDC, (LPPOINT) Glass, 11);
-
- /* On top, Draw Sand first, then Air (avoid flicker )*/
- SelectObject(hDC, EraserPen);
- SelectObject(hDC, SandBrush);
-
- if (10*GameTime < 9*EndTime)
- /* Both in the tube and funnel section on top */
- {
- yTemp = 240 - 200L * GameTime / EndTime;
- /* Only the top of the sand changes */
- TopSand[0][1] = TopSand[1][1] = yTemp;
- Polygon(hDC, (LPPOINT) TopSand, 5);
- SelectObject(hDC, EraserBrush);
- Rectangle(hDC, -40, 240,
- 40, yTemp);
- }
- else if (GameTime < EndTime)
- /* Exclusively in the funnel section */
- {
- yTemp = K1 * pow(EndTime - GameTime, 0.3333);
- FunnelSand[0][1] = FunnelSand[1][1] = yTemp;
- FunnelSand[0][0] = 0.6667 * yTemp;
- FunnelSand[1][0] = -0.6667 * yTemp;
- Polygon(hDC, (LPPOINT) FunnelSand, 3);
- SelectObject(hDC, EraserBrush);
- TopAir[3][1] = TopAir[4][1] = yTemp;
- TopAir[3][0] = 0.6667 * yTemp;
- TopAir[4][0] = -0.6667 * yTemp;
- Polygon(hDC, (LPPOINT) TopAir, 6);
- }
- else
- /* GameTime >= EndTime (Game over) */
- {
- SelectObject(hDC, EraserBrush);
- TopSand[0][1] = TopSand[1][1] = 240;
- Polygon(hDC, (LPPOINT) TopSand, 5);
- }
-
- /* show the falling sand except at start and end */
- if (0 < GameTime && GameTime < EndTime)
- SelectObject(hDC, FallingPen);
- else
- SelectObject(hDC, EraserPen);
- yTemp = -260 + 200L * GameTime / EndTime;
- MoveTo(hDC, 0, 0);
- LineTo(hDC, 0, yTemp);
-
- /* Now draw the sand on the bottom. */
- SelectObject(hDC, SandPen);
- SelectObject(hDC, SandBrush);
- Rectangle(hDC, -40, yTemp,
- 40, -260);
- SelectObject(hDC, hOldBrush);
- SelectObject(hDC, hOldPen);
- }
-
- /* Start the Egg Timer */
- ProcessEggStart(hEgg)
- HWND hEgg;
- {
- GameTime = 0;
- idGameTimer = SetTimer(hEgg, ID_GT, 1000, NULL);
- if (idGameTimer)
- InvalidateRect(hEgg, NULL, TRUE);
- else
- /* timer not created */
- {
- MessageBox(hEgg, "Can't get windows timer.", "ERROR",
- MB_ICONQUESTION | MB_OK);
- DestroyWindow(hEgg);
- }
- }
-
- /********* Computer Play Routines *********/
- /* global used to build trial word */
- char TrialWord[25] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
- int TrialLen;
-
- /* Parital string search. Search the dictionary and return TRUE if the
- * string TrialWord could possibly be part of a known word. Also saves
- * TrialWord in a list if it is exactly a word. Written for search
- * efficiency, terminating branches which would clearly be fruitless.
- * psearch tries to return FALSE whenever possible, as a TRUE return
- * will cause as many as 8 more psearch calls, not including recursion.
- * If most of a dictionary word matches TrialWord, this routine tries
- * appending suffixes to the dictionary word on the fly.
- * Global TrialLen is actual length of TrialWord. Should be set
- * before calling psearch. Not always equal to strlen(TrialWord),
- * because Qu counts as 2 letters. Careful: in some cases, you
- * actually want strlen(TrialWord)
- */
- BOOL psearch(hLeaf)
- HANDLE hLeaf;
- {
- PDW LeafPtr;
- int result; /* result of string compare */
- BOOL retval; /* return value */
- int nSuffix; /* used for suffixing words */
- char FullWord[13];
- unsigned BitMask;
-
- /* DBCount++; */
- if (!hLeaf) return(FALSE);
- /* assumption that some word will begin with any given single letter */
- if (strlen(TrialWord) < 2) return(TRUE);
- LeafPtr = (PDW) LocalLock(hLeaf);
-
- result = strncmp(TrialWord, LeafPtr -> w, 2);
- /* check 1st 2 characters to start. */
- /* if trial=RATS, and current leaf is RATE, we would never go */
- /* to RAT to try suffixes otherwise. This greatly degrades the */
- /* searching efficiency, but provides enables the above case to */
- /* be found */
- if (result < 0)
- /* trial word definitely less than dictionary word. */
- {
- retval = psearch(LeafPtr -> lt);
- }
- else if (result > 0)
- {
- retval = psearch(LeafPtr -> gt);
- }
- else
- /* result == 0; first 2 characters match between trial and dict */
- {
- result = strcmp(TrialWord, LeafPtr -> w);
- if (!result)
- /* Perfect match. Record word and exit */
- /* We know that we can return TRUE, because we already match the */
- /* root word, and Trial is probably a subset of some suffixed version */
- {
- if (TrialLen > 3)
- /* only record words of legal size */
- {
- if ((rand() % 100) < Smartness)
- /* According to skill level, computer may miss some words */
- {
- AddLeaf(TrialWord, &hCListTop, 0, 0, NULL);
- /* computer find counts as a usage */
- if ((LeafPtr -> Freq) < 32767) (LeafPtr -> Freq)++;
- }
- }
- retval = TRUE;
- }
- else
- /* Non-perfect match. Must still consider lower leaves on */
- /* both gt and lt leaves */
- {
- /* if trial is a subset of dict word, return TRUE */
- retval = !strncmp(TrialWord, LeafPtr->w, strlen(TrialWord));
-
- /* only search further if there's a chance we can find a */
- /* legal word, or we are not sure whether this TrialWord */
- /* will match part of some dictionary word */
- if (TrialLen > 3 || !retval)
- if (psearch(LeafPtr -> lt)) retval = TRUE;
- if (TrialLen > 3 || !retval)
- if (psearch(LeafPtr -> gt)) retval = TRUE;
- if ((TrialLen > 3 || !retval) &&
- !strncmp(TrialWord, LeafPtr->w, strlen(LeafPtr->w)-1))
- /* As last resort, try suffixes. Costly operation. */
- {
- BitMask = 1;
-
- for (nSuffix=ID_FIRSTSUF; nSuffix <= ID_LASTSUF; nSuffix++)
- {
- if (BitMask & (LeafPtr->Suffix1))
- /* if the suffix is legal, try it */
- {
- AddSuffix(LeafPtr->w, nSuffix, FullWord);
- if (!strcmp(TrialWord, FullWord))
- /* matches suffixed word exactly */
- {
- if ((rand() % 100) < Smartness)
- /* Force computer to miss some according to level */
- {
- AddLeaf(TrialWord, &hCListTop, 0, 0, NULL);
- /* computer find counts as a usage */
- if ((LeafPtr -> Freq) < 32767) (LeafPtr -> Freq)++;
- }
- }
- else
- /* possibility of trial="MAKI", return true for "MAKING" */
- {
- if (!retval && !strncmp(TrialWord, FullWord, strlen(TrialWord)))
- retval = TRUE;
- }
- }
- BitMask <<= 1; /* move to the next bit */
- }
- }
- }
- }
- LocalUnlock(hLeaf);
- return(retval);
- }
-
- /* This routine searches all possible words on paths starting from the
- * die pointed to by CubePtr
- * It is assumed that a subroutine will be called from this routine to
- * determine whether any search path leads to a dead end. Otherwise,
- * this routine will search all 25! + 24! + 23! ... + 1! combinations!
- * The trial path is built in a global, TrialWord, for speed reasons.
- */
- SearchBoard(CubePtr)
- struct tagBOARD *CubePtr;
- {
- int l; /* length of trial string so far */
- int neighbor;
- MSG msg; /* for PeekMessage yield */
- char RealWord[11]; /* TrialWord with Qu expanded */
-
- if (GameOver) return; /* abort search if game over */
-
- /* We want to yield, so as not to hog CPU resources with the word search */
- /* Allow the message queue to clear */
- /* Otherwise, window will appear to hang while the computer is searching */
- while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- if (CubePtr == NULL || (CubePtr -> Cused)) return; /* not a viable path */
- CubePtr -> Cused = TRUE;
- l = strlen(TrialWord);
- TrialWord[l] = CubePtr -> val; /* append letter to search string */
- strcpy(RealWord, TrialWord); /* find length of real word with Qu */
- AddQu(RealWord);
- TrialLen = strlen(RealWord);
- if (psearch(hTreeTop))
- {
- for (neighbor=0; neighbor < 8; neighbor++)
- SearchBoard(CubePtr -> link[neighbor]);
- }
- TrialWord[l] = 0; /* remove the character we appended */
- CubePtr -> Cused = FALSE;
- }
-
- /* This routine recursively adds a leaf and all leaves below it in a
- * tree to the computer word list. Used to display the words that the
- * computer found when the game is over.
- */
- DisplayCList(hLeafPtr)
- HANDLE hLeafPtr;
- {
- PDW LeafPtr;
-
- if (hLeafPtr)
- {
- LeafPtr = (PDW) LocalLock(hLeafPtr);
- DisplayCList(LeafPtr -> lt); /* print all less than */
- AddQu(LeafPtr -> w); /* Change Q to Qu for display purposes */
- SendMessage(hCList, LB_INSERTSTRING, -1, (LONG) (LPSTR) LeafPtr->w);
- DisplayCList(LeafPtr -> gt); /* print all greater than */
- LocalUnlock(hLeafPtr);
- }
- }
-
- /* Sets up the next rack, which will be copied to the board on the next */
- /* call to NewGame. First, all the dice in the master list (dice[]) are */
- /* set to the unused state. Then, a die is randomly selected and placed */
- /* on the board, with a random face up. This routine insures by design */
- /* that no master die is used more than once */
- SetNextRack(Rack)
- unsigned Rack;
- {
- int row, col; /* used to step through board array */
- int cubeno; /* used to index master list of cubes */
-
- srand(Rack);
-
- for (cubeno=0; cubeno < NDICE; cubeno++)
- dice[cubeno][0] = FALSE;
-
- /* fill every space on the board */
- for (row=0; row < NROWS; row++)
- for (col=0; col < NCOLS; col++)
- {
- /* keep trying until a free cube is found */
- do { cubeno = rand() % NDICE; } while (dice[cubeno][0]);
- /* pick a face from the die, and an orientation */
- NextVal[row][col] = dice[cubeno][(rand() % NFACES)+1];
- NextOrient[row][col] = rand() % NORIENT;
- dice[cubeno][0] = TRUE; /* mark the cube as used */
- }
- }
-
- /* This function creates the progress box window. Do NOT call this */
- /* function again before destroying the corresponding window */
- /* Parameter passed in is handle of parent window */
- /* The handle to the progress box window is returned */
- HWND CreateProBox(hWnd)
- HWND hWnd;
- {
- HWND hPro;
-
- hPro = CreateWindow("Pro", /* window class */
- "", /* window name */
- WS_POPUP | WS_VISIBLE | WS_DLGFRAME,
- 0, 0, 0, 0, /* Leave sizing to window proc */
- hWnd, /* parent handle */
- NULL, /* menu or child ID */
- hInst, /* instance */
- NULL); /* additional info */
-
- BringWindowToTop(hPro);
- return(hPro);
- }
-
- /****************************************************************************
-
- FUNCTION: ProWndProc(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages
-
- COMMENTS:
-
- This is the windows procedure for the Progress Box.
- Similar to the progress bar. Used to placate user while
- a lengthy operation is going on. WARNING: only accomodates
- range to the limit of unsigned int (probably 64k).
-
- ****************************************************************************/
-
- long FAR PASCAL ProWndProc(hPro, message, wParam, lParam)
- HWND hPro; /* window handle */
- unsigned message; /* type of message */
- WORD wParam; /* additional information */
- LONG lParam; /* additional information */
- {
- static LPSTR ProMsg; /* the message to be displayed by progress box */
- static unsigned ProRange; /* range of bar will be 0 - ProRange */
- static unsigned ProPos; /* current position */
-
- PAINTSTRUCT ps; /* used by paint procedure */
- HDC hDC; /* used by paint procedure */
-
- static TEXTMETRIC tmFont; /* All this for initial size, place */
- int x, y; /* placement of ProBox */
- static int height, width; /* calculated size of ProBox */
- HWND hWnd; /* handle of parent */
- RECT Rect;
- POINT Point;
- static HBRUSH hMagBrush;
-
- char OutBuf[5]; /* for the percentage */
-
- switch (message) {
-
- /* PRO_INIT should come in via SendMessage just after creation */
- /* The wParam sets the range of the Progress bar. */
- /* lParam sets the message text */
- /* This code will make a progress box big enough for the text, */
- /* and center it in the client area of the caller */
- case PRO_INIT:
- ProMsg = (LPSTR) lParam;
- ProRange = wParam;
- ProPos = 0;
- hWnd = GetParent(hPro);
- GetClientRect(hWnd, (LPRECT) &Rect);
- hDC = GetDC(hPro);
- GetTextMetrics(hDC, &tmFont); /* size the window */
- height = tmFont.tmHeight * 6;
- width = 2*tmFont.tmAveCharWidth + LOWORD(GetTextExtent(hDC, ProMsg, lstrlen(ProMsg)));
- x = (Rect.right + Rect.left - width) >> 1; /* center the window */
- y = (Rect.bottom + Rect.top - height) >> 1;
- ReleaseDC(hPro, hDC);
- Point.x = x; /* convert to screen coordinates for popup */
- Point.y = y;
- ClientToScreen(hWnd, &Point);
- Point.x = max(Point.x, 0); /* in case parent too small */
- Point.y = max(Point.y, 0);
- MoveWindow(hPro, Point.x, Point.y, width, height, TRUE);
- /* the invalidate is needed in case of init more than once */
- InvalidateRect(hPro, NULL, TRUE);
- /* adjust size slightly: client rect <> window size */
- GetClientRect(hPro, (LPRECT) &Rect);
- height = Rect.bottom - Rect.top;
- width = Rect.right - Rect.left;
- hMagBrush = CreateSolidBrush(MAGENTA);
- break;
-
- case PRO_SETPOS:
- ProPos = wParam;
- InvalidateRect(hPro, NULL, FALSE);
- break;
-
- case WM_PAINT:
- /* This falls through to the paint code following */
- break;
-
- case WM_DESTROY:
- DeleteObject(hMagBrush);
- return(NULL);
- break;
-
- default: /* Passes it on if unproccessed */
- return (DefWindowProc(hPro, message, wParam, lParam));
- }
- /* We do a paint on any message, as we cannot wait for posted WM_PAINT */
- hDC = BeginPaint(hPro, (LPPAINTSTRUCT) &ps);
- SetBkColor(hDC, Mono ? WHITE : GRAY1);
- SetTextAlign(hDC, TA_CENTER | TA_TOP);
- TextOut(hDC, (ps.rcPaint.right - ps.rcPaint.left) >>1,
- tmFont.tmHeight, ProMsg, lstrlen(ProMsg));
- sprintf(OutBuf, "%d%%", 100L*ProPos/ProRange);
- TextOut(hDC, (ps.rcPaint.right - ps.rcPaint.left) >>1,
- (tmFont.tmHeight *5) >>1, OutBuf, strlen(OutBuf));
- /* the filled part of the bar */
- SelectObject(hDC, hMagBrush); /* filled part of bar */
- x = (long) (width - 2*tmFont.tmAveCharWidth) *ProPos/ProRange + tmFont.tmAveCharWidth;
- Rectangle(hDC, tmFont.tmAveCharWidth, tmFont.tmHeight <<2,
- x, tmFont.tmHeight * 5);
- SelectObject(hDC, hGrayBrush0); /* empty part of bar */
- Rectangle(hDC, x, tmFont.tmHeight <<2,
- width-tmFont.tmAveCharWidth, tmFont.tmHeight * 5);
- EndPaint(hPro, (LPPAINTSTRUCT) &ps);
- return (NULL);
- }
-
- /****************************************************************************
-
- FUNCTION: CubeWndProc(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages
-
- COMMENTS:
-
- This is the windows procedure for the the playing cube buttons.
- The buttons change their appearance when pressed down.
- Information on whether the button is pressed or not is contained
- in the global data structure board[x][y].
-
- ****************************************************************************/
-
- long FAR PASCAL CubeWndProc(hCube, message, wParam, lParam)
- HWND hCube; /* window handle */
- unsigned message; /* type of message */
- WORD wParam; /* additional information */
- LONG lParam; /* additional information */
- {
- PAINTSTRUCT ps; /* used by paint procedure */
- HDC hDC; /* used by paint procedure */
- int row, col, CubeNumber;
-
- switch (message) {
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- ProcessCubeButton(hCube);
- /* no break - fall through to paint */
-
- case WM_PAINT:
- hDC = BeginPaint(hCube, (LPPAINTSTRUCT) &ps);
- ProcessCubePaint(hCube, hDC);
- EndPaint(hCube, (LPPAINTSTRUCT) &ps);
- break;
- case WM_MOUSEACTIVATE:
- /* Don't pass this to DefWindowProc, else parent gets it */
- break;
- default: /* Passes it on if unproccessed */
- return (DefWindowProc(hCube, message, wParam, lParam));
- }
- return (NULL);
- }
-
- /* This is called when the player clicks on an enabled cube */
- /* Toggles the flag saying whether button is down or not */
- ProcessCubeButton(hWnd)
- HWND hWnd;
- {
- int CubeNumber; /* this is used to decode which control is responding */
- int row, col;
- WORD cubeloc;
-
- CubeNumber = GetWindowWord(hWnd, GWW_ID) - ID_FIRSTCUBE; /* which control? */
- row = CubeNumber / NCOLS;
- col = CubeNumber % NCOLS;
- if (board[row][col].Uused)
- {
- board[row][col].Uused = FALSE;
- /* if popping up cube, erase last entry in player list */
- PostMessage(hUEdit, WM_CHAR, '\b', 1L);
- PostMessage(GetParent(hWnd), BAGOM_CUBEUP, 0, 0L);
- /* To delete a Q, must also delete the U */
- if (board[row][col].val == 'Q')
- PostMessage(hUEdit, WM_CHAR, '\b', 1L);
- }
- else
- {
- board[row][col].Uused = TRUE;
- PostMessage(hUEdit, WM_CHAR, board[row][col].val, 1L);
- cubeloc = col << 8 | row;
- PostMessage(GetParent(hWnd), BAGOM_CUBEDN, cubeloc, 0L);
- /* Q has automatic U following */
- if (board[row][col].val == 'Q')
- PostMessage(hUEdit, WM_CHAR, 'U', 1L);
- }
- InvalidateRect(hWnd, NULL, FALSE);
- }
-
- /* Paint procedure for cube button controls */
- ProcessCubePaint(hWnd, hDC)
- HWND hWnd;
- HDC hDC;
- {
- HDC hMemoryDC, hMemoryDC1;
- HBITMAP hOldBitmap, hOldBitmap1, hLetterBitmap, hBackBitmap;
- int CubeNumber; /* this is used to decode which control is responding */
- int row, col;
- char letter; /* the letter shown on this cube */
- int rot; /* the rotation of the letter */
- HBITMAP hShade; /* used only for mono */
- HBRUSH hShadeBrush, hOldBrush;
-
- CubeNumber = GetWindowWord(hWnd, GWW_ID) - ID_FIRSTCUBE; /* which control? */
- row = CubeNumber / NCOLS; /* what is on face? */
- col = CubeNumber % NCOLS;
- letter = board[row][col].val;
- rot = (RotCubes ? board[row][col].orient : 0);
-
- hMemoryDC = CreateCompatibleDC(hDC);
- hMemoryDC1 = CreateCompatibleDC(hDC);
- hLetterBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(STARBMP+letter-'@'+rot*26));
- hOldBitmap = SelectObject(hMemoryDC, hLetterBitmap);
- if (hOldBitmap)
- {
- if (board[row][col].Uused) hBackBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(DOWNBMP));
- else hBackBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(UPBMP));
- hOldBitmap1 = SelectObject(hMemoryDC1, hBackBitmap);
-
- if (Mono && board[row][col].Uused)
- {
- hShade = LoadBitmap(hInst, MAKEINTRESOURCE(SHADEBMP));
- hShadeBrush = CreatePatternBrush(hShade);
- hOldBrush = SelectObject(hMemoryDC1, hShadeBrush);
- BitBlt(hMemoryDC1, 0, 0, 32, 32, hMemoryDC, 0, 0, 0x008003E9); /* DPSaa */
- SelectObject(hMemoryDC1, hOldBrush);
- DeleteObject(hShadeBrush);
- DeleteObject(hShade);
- }
- else
- BitBlt(hMemoryDC1, 0, 0, 32, 32, hMemoryDC, 0, 0, SRCAND);
-
- /* copy to display only once */
- BitBlt(hDC, 0, 0, 32, 32, hMemoryDC1, 0, 0, SRCCOPY);
- SelectObject(hMemoryDC1, hOldBitmap1);
- DeleteObject(hBackBitmap);
- SelectObject(hMemoryDC, hOldBitmap);
- }
- DeleteObject(hLetterBitmap);
- DeleteDC(hMemoryDC);
- DeleteDC(hMemoryDC1);
- }
-
- /* Creates a pictoral display box. */
- /* Displays the bitmap nicely, with the text centered underneath */
- /* If no bitmap to display, specify PicNumber = 0 */
- /* The box becomes system modal */
- CreatePicBox(hWnd, PicNumber, PicMsg)
- HWND hWnd;
- int PicNumber;
- LPSTR PicMsg;
- {
- HWND hPic;
- PICSTRUCT PicStruct; /* init structure */
-
- PicStruct.PicMsg = PicMsg;
- PicStruct.PicNumber = PicNumber;
-
- hPic = CreateWindow("Pic", /* window class */
- "", /* window name */
- WS_POPUP | WS_BORDER | WS_VISIBLE,
- 0, 0, 0, 0, /* window will size itself */
- hWnd, /* parent handle */
- NULL, /* no ID for popup window */
- hInst, /* instance */
- (LPSTR) &PicStruct); /* additional info */
-
- SetSysModalWindow(hPic);
- }
-
- /****************************************************************************
-
- FUNCTION: PicWndProc(HWND, unsigned, WORD, LONG)
-
- PURPOSE: Processes messages
-
- COMMENTS:
-
- This is the window procedure for a very simple window which
- displays a bitmap and some text. The bitmap and text are
- passed in a structure upon initialization.
-
- ****************************************************************************/
-
- long FAR PASCAL PicWndProc(hPic, message, wParam, lParam)
- HWND hPic; /* window handle */
- unsigned message; /* type of message */
- WORD wParam; /* additional information */
- LONG lParam; /* additional information */
- {
- static HBITMAP hBitmap; /* the picture to be displayed */
- static LPPICSTRUCT lpPic; /* the parameter passed upon create */
- static BITMAP Bitmap; /* to retrieve bitmap dimensions */
- static char PicMsg[80];
-
- PAINTSTRUCT ps; /* used by paint procedure */
- HDC hDC; /* used by paint procedure */
-
- int x, y; /* placement of PicBox */
- /* TrueBmWidth compensates for aspect ratio of monitor */
- static int height, width, TrueBmWidth;
- static TEXTMETRIC tmFont;
- int textwidth;
- HWND hWnd; /* handle of parent */
- RECT Rect;
- POINT Point;
- HBITMAP hOldBitmap; /* for drawing picture */
- HDC hMemoryDC;
-
- switch (message) {
-
- case WM_CREATE:
- lpPic = (LPPICSTRUCT) ((LPCREATESTRUCT) lParam) -> lpCreateParams;
- if (lpPic -> PicNumber)
- {
- hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(lpPic -> PicNumber));
- GetObject(hBitmap, sizeof(BITMAP), (LPSTR) &Bitmap);
- }
- else /* no bitmap specified */
- {
- Bitmap.bmHeight = 0;
- Bitmap.bmWidth = 0;
- hBitmap = 0;
- }
- lstrcpy(PicMsg, lpPic -> PicMsg);
- hWnd = GetParent(hPic);
- GetClientRect(hWnd, (LPRECT) &Rect);
- hDC = GetDC(hPic);
- GetTextMetrics(hDC, &tmFont); /* size the window */
- height = Bitmap.bmHeight + tmFont.tmHeight * 2 + 2; /* +2 for thin border */
- TrueBmWidth = MulDiv(Bitmap.bmWidth, GetDeviceCaps(hDC, ASPECTY), GetDeviceCaps(hDC, ASPECTX));
- width = TrueBmWidth + 2;
- textwidth = LOWORD(GetTextExtent(hDC, PicMsg, lstrlen(PicMsg))) + 2*tmFont.tmAveCharWidth;
- /* width is larger of picture width or text width */
- if (width < textwidth) width = textwidth;
- x = (Rect.right + Rect.left - width) >> 1; /* center the window */
- y = (Rect.bottom + Rect.top - height) >> 1;
- ReleaseDC(hPic, hDC);
- Point.x = x; /* convert to screen coordinates for popup */
- Point.y = y;
- ClientToScreen(hWnd, &Point);
- Point.x = max(Point.x, 0); /* in case parent too small */
- Point.y = max(Point.y, 0);
- MoveWindow(hPic, Point.x, Point.y, width, height, TRUE);
- break;
-
- case WM_PAINT:
- hDC = BeginPaint(hPic, (LPPAINTSTRUCT) &ps);
- SetBkMode(hDC, TRANSPARENT);
- SetTextAlign(hDC, TA_CENTER | TA_TOP);
- SetTextColor(hDC, WHITE);
- x = (width - 2) >> 1;
- y = height - 2 - 3*tmFont.tmHeight/2; /* -2 because thin border */
- TextOut(hDC, x, y, PicMsg, lstrlen(PicMsg));
- /* now draw the picture, if there is one */
- if (hBitmap)
- {
- x=(width-TrueBmWidth) >>1; /* center the picture */
- y=0;
- hMemoryDC = CreateCompatibleDC(hDC);
- hOldBitmap = SelectObject(hMemoryDC, hBitmap);
- SetStretchBltMode(hDC, COLORONCOLOR);
- StretchBlt(hDC, x, y, TrueBmWidth, Bitmap.bmHeight,
- hMemoryDC, 0, 0, Bitmap.bmWidth, Bitmap.bmHeight, SRCCOPY);
- SelectObject(hDC, hOldBitmap);
- DeleteDC(hMemoryDC);
- }
- EndPaint(hPic, (LPPAINTSTRUCT) &ps);
- break;
-
- /* close the window with almost any excuse */
- case WM_CHAR:
- case WM_LBUTTONDOWN:
- case WM_MBUTTONDOWN:
- case WM_RBUTTONDOWN:
- case WM_CLOSE:
- if (hBitmap) DeleteObject(hBitmap);
- DestroyWindow(hPic);
- break;
-
- default: /* Passes it on if unproccessed */
- return (DefWindowProc(hPic, message, wParam, lParam));
- }
- return (NULL);
- }
-