-- Boggle Game for Win32 -- by Brett Pantalone (pantalone@sprintmail.com) -- **REQUIRES** Win32Lib with thanks to David Cuny -- Bitmap functions stolen with pride from Colin Taylor -- Version 0.50 "Alpha" include win32lib.ew include wildcard.e include bitmap.e include msgbox.e include file.e constant Ver = "Version 0.50" without warning ------------------------------------------------------------------------------- -- Graphical Objects ------------------------------------------------------------------------------- constant MainWin = create(Window, "Boggle", 0, Default, Default, 468, 330, 0), AcceptBtn = create(PushButton, "Accept", MainWin, 36, 236, 80, 30, WS_DISABLED), UndoBtn = create(PushButton, "Undo", MainWin, 132, 236, 80, 30, WS_DISABLED), TextBox = create(LText, "", MainWin, 252, 5, 180, 20, 0), WordList = create(SortedList, "", MainWin, 252, 36, 180, 180, WS_VSCROLL), ScoreBox = create(LText, "Score 0", MainWin, 252, 241, 80, 30, 0), TimeBox = create(RText, "Time 03:00", MainWin, 348, 241, 80, 30, 0) constant FileMenu = create(Menu, "&Game", MainWin, 0, 0, 0, 0, 0), MenuNew = create(MenuItem, "&New Game", FileMenu, 0, 0, 0, 0, 0), MenuSep1 = create(MenuItem, "-", FileMenu, 0, 0, 0, 0, 0), MenuExit = create(MenuItem, "&Exit", FileMenu, 0, 0, 0, 0, 0), HelpMenu = create(Menu, "&Help", MainWin, 0, 0, 0, 0, 0), MenuAbout= create(MenuItem, "&About...", HelpMenu, 0, 0, 0, 0, 0) constant Background = getSysColor(COLOR_BTNFACE), GameTimer = 9999 ------------------------------------------------------------------------------- -- Manifest constants (fields) ------------------------------------------------------------------------------- constant LETTER = 1, ROTATION = 2, SELECTED = 3, PALETTE = 1, PIXELS = 2 ------------------------------------------------------------------------------- -- Global variables (file scope) ------------------------------------------------------------------------------- atom wordFile object bmpAlpha, ok integer firstLetter, XPrev, YPrev, minutes, seconds integer totalWords, score sequence board, textWord textWord = {} ------------------------------------------------------------------------------- -- Subroutines ------------------------------------------------------------------------------- procedure Randomize() -- Randomly (?) populate the board with letter cubes integer cube, face, skew sequence dice, row -- These are the actual faces of the 25 letter cubes dice = {"ETILCI","MGAEUE","EAEAEE","DNANEN","TMTETO", "AAAFRS","TCSNWC","SSNSUE","EMEAEE","EGNANM", "TETIII","DHORHL","SPTEIC","DORDNL","HOTHND", "YIRPRH","FRYSIA","TOOOUT","NOWOTU","PCEITL", "ASARIF","RFSYPI","OHDRLN","KQXZJB","WGORRV"} board = {} for i = 1 to 5 do row = {} for j = 1 to 5 do cube = rand(length(dice)) face = dice[cube][rand(6)] - '@' skew = rand(4) row = append( row, {face, skew, 0} ) -- Remove the "used" cube from the kitty dice = dice[1..(cube-1)] & dice[(cube+1)..length(dice)] end for -- Add this row to the game board board = append( board, row ) end for end procedure ------------------------------------------------------------------------------- procedure Initialize() sequence name, s, error s = command_line() if length(s) > 2 then name = s[3] else name = "words.txt" end if -- Open the dictionary file wordFile = open( name, "r" ) if wordFile = -1 then ok = message_box( "Could not find dictionary\n" & name, "Application Error", MB_ICONHAND+MB_TASKMODAL ) abort(-1) end if -- Read the bitmap file bmpAlpha = read_bitmap("alpha.bmp") if atom(bmpAlpha) then ok = message_box( "Error reading bitmap file\n", "Application Error", MB_ICONHAND+MB_TASKMODAL ) abort(-1) end if setFont(WordList, "Arial", 12, 0) setFont(TextBox, "Arial", 16, 0) end procedure ------------------------------------------------------------------------------- procedure DrawCube( integer x, integer y ) -- Draw a letter cube at board position (x,y) sequence subImage integer x1, x2, y1, y2 integer letter, rotation, selected atom hndBitmap, hndPixmap letter = board[y][x][LETTER] -- letter on the cube (A..Z) rotation = board[y][x][ROTATION] -- rotation of cube (0, 90, 180, 270) selected = board[y][x][SELECTED] -- cube is selected (highlight) or not -- Define the rectangle for extraction of the letter image x1 = 32 * (letter - 1) + 1 x2 = 32 * letter if not selected then y1 = 1 y2 = 32 else y1 = 33 y2 = 64 end if -- Extract the desired image from the larger bitmap subImage = bm_trim(bmpAlpha[PIXELS], {x1, y1}, {x2, y2}) -- Rotate the image 90 degrees as many times as needed while rotation > 1 do subImage = bm_rotate( subImage ) rotation = rotation - 1 end while -- Create a Windows bitmap from pixel and palette info hndBitmap = createDIB(subImage, bmpAlpha[PALETTE]) -- Convert bitmap into pixmap so we can use transBlt below -- (Is there a better way to do this?) hndPixmap = create(Pixmap, "", 0, 0, 0, 32, 32, 0) setPixmap(hndPixmap, hndBitmap) transBlt(MainWin, x * 36, y * 36, hndPixmap, {255,0,0}) deleteObject(hndPixmap) deleteObject(hndBitmap) end procedure ------------------------------------------------------------------------------- procedure DrawBoard( integer x1, integer y1, integer x2, integer y2 ) -- Redraw the whole game board -- This could be modified to only draw the part bounded by (x1,y1)(x2,y2) for y = 1 to 5 do for x = 1 to 5 do DrawCube( x, y ) end for end for end procedure onPaint[ MainWin ] = routine_id("DrawBoard") ------------------------------------------------------------------------------- procedure UpdateScore(sequence word) sequence st integer l l = length(word) if l < 3 then score += 0 elsif l < 5 then score += 1 elsif l < 6 then score += 2 elsif l < 7 then score += 3 elsif l < 8 then score += 5 else score += 11 end if st = sprintf("Score %d", score) setText(ScoreBox, st) end procedure ------------------------------------------------------------------------------- procedure onClickUndoBtn() -- reset the game board (remove selections) firstLetter = 1 for y = 1 to 5 do for x = 1 to 5 do if board[y][x][SELECTED] != 0 then board[y][x][SELECTED] = 0 DrawCube( x, y ) end if end for end for -- reset the text box textWord = {} setText(TextBox, textWord) -- remove any list box selection ok = sendMessage(WordList, LB_SETCURSEL, -1, 0 ) end procedure onClick[ UndoBtn ] = routine_id("onClickUndoBtn") ------------------------------------------------------------------------------- function isDuplicate(sequence word) -- Determine if the word is already in the list word = lower(word) & 0 -- null char terminates list items for i = 1 to getCount(WordList) do if compare(word, getItem(WordList, i)) = 0 then setIndex(WordList, i) return 1 end if end for return 0 end function ------------------------------------------------------------------------------- procedure onClickAcceptBtn() object word -- Ignore words already used or less than 3 letters if length(textWord) < 3 or isDuplicate(textWord) then return end if -- Rewind to the front of the dictionary if seek(wordFile, 0) then abort(-1) end if -- Search the dictionary word = gets(wordFile) while not atom(word) do if compare(word[1..length(word)-1], textWord) = 0 then -- Word found in dictionary! addItem( WordList, lower(textWord) ) totalWords += 1 UpdateScore(textWord) onClickUndoBtn() return end if word = gets(wordFile) end while end procedure onClick[ AcceptBtn ] = routine_id("onClickAcceptBtn") ------------------------------------------------------------------------------- function isLegalPlay(integer x, integer y) -- Check that the selected square is -- (1) on the board -- (2) not already used -- (3) adjacent to the previous selection integer dX, dY if x > 0 and x < 6 and y > 0 and y < 6 then -- (1) if firstLetter then return 1 end if if board[y][x][SELECTED] = 0 then -- (2) dX = XPrev - x dY = YPrev - y if dX < 2 and dX > -2 and dY < 2 and dY > -2 then -- (3) return 1 end if end if end if return 0 end function ------------------------------------------------------------------------------- procedure onMouseEvent( integer event, integer x, integer y ) -- Handle mouse clicks on the game board -- Ignore clicks when not wanted if not isEnabled(AcceptBtn) then return end if if event = LEFT_DOWN then x = floor(x / 36) y = floor(y / 36) if isLegalPlay(x, y) then board[y][x][SELECTED] = 1 DrawCube(x, y) firstLetter = 0 XPrev = x YPrev = y textWord = textWord & board[y][x][LETTER] + '@' -- Cube marked "Qu" is really two letters if board[y][x][LETTER] + '@' = 'Q' then textWord = textWord & 'U' end if setText( TextBox, textWord ) end if end if end procedure onMouse[ MainWin ] = routine_id("onMouseEvent") ------------------------------------------------------------------------------- procedure EndGame() sequence st setEnable(AcceptBtn, 0) setEnable(UndoBtn, 0) st = sprintf("Score:\t%d\n" & "Words:\t%d", {score, totalWords}) ok = message_box(st, "Time's Up!", MB_ICONEXCLAMATION+MB_TASKMODAL) end procedure ------------------------------------------------------------------------------- procedure onTimerMainWin(integer id) -- We'll assume it's the GameTimer, since it's the only one sequence t seconds = seconds - 1 if seconds < 0 then seconds = 59 minutes = minutes - 1 if minutes < 0 then killTimer(MainWin, GameTimer) minutes = 0 seconds = 0 EndGame() end if end if t = sprintf("Time %02d:%02d", {minutes, seconds}) setText(TimeBox, t) end procedure onTimer[ MainWin ] = routine_id("onTimerMainWin") ------------------------------------------------------------------------------- procedure onClickMenuNew() textWord = {} setText(TextBox, textWord) firstLetter = 1 XPrev = 0 YPrev = 0 minutes = 3 seconds = 0 totalWords = 0 score = 0 UpdateScore(textWord) eraseItems(WordList) Randomize() repaintWindow(MainWin) setEnable(AcceptBtn, 1) setEnable(UndoBtn, 1) setTimer(MainWin, GameTimer, 1000) end procedure onClick[ MenuNew ] = routine_id("onClickMenuNew") ------------------------------------------------------------------------------- procedure onClickMenuExit() closeWindow( MainWin ) end procedure onClick[ MenuExit ] = routine_id("onClickMenuExit") ------------------------------------------------------------------------------- procedure onClickMenuAbout() ok = message_box( "Boggle " & Ver & 13 & 10 & "by Brett Pantalone" & 13 & 10 & 10 & "Developed using David Cuny's Win32Lib" & 13 & 10 & "and bitmap tools by Colin Taylor.", "About This Game", MB_ICONINFORMATION+MB_TASKMODAL) end procedure onClick[ MenuAbout ] = routine_id("onClickMenuAbout") ------------------------------------------------------------------------------- Initialize() Randomize() setWindowBackColor(MainWin, Background) WinMain( MainWin )