home *** CD-ROM | disk | FTP | other *** search
/ Dan Appleman's Visual Bas…s Guide to the Win32 API / Dan.Applmans.Visual.Basic.5.0.Programmers.Guide.To.The.Win32.API.1997.Ziff-Davis.Press.CD / VB5PG32.mdf / vbpg32 / samples4 / ch09 / puzzle.frm (.txt) < prev    next >
Encoding:
Visual Basic Form  |  1997-02-16  |  14.0 KB  |  387 lines

  1. VERSION 4.00
  2. Begin VB.Form Puzzle 
  3.    Appearance      =   0  'Flat
  4.    BackColor       =   &H80000005&
  5.    Caption         =   "Puzzle"
  6.    ClientHeight    =   3645
  7.    ClientLeft      =   1095
  8.    ClientTop       =   1770
  9.    ClientWidth     =   3735
  10.    BeginProperty Font {0BE35203-8F91-11CE-9DE3-00AA004BB851} 
  11.       Name            =   "MS Sans Serif"
  12.       Size            =   8.25
  13.       Charset         =   0
  14.       Weight          =   700
  15.       Underline       =   0   'False
  16.       Italic          =   0   'False
  17.       Strikethrough   =   0   'False
  18.    EndProperty
  19.    ForeColor       =   &H80000008&
  20.    Height          =   4335
  21.    Left            =   1035
  22.    LinkMode        =   1  'Source
  23.    LinkTopic       =   "Form1"
  24.    ScaleHeight     =   3645
  25.    ScaleWidth      =   3735
  26.    Top             =   1140
  27.    Width           =   3855
  28.    Begin VB.PictureBox Picture2 
  29.       Appearance      =   0  'Flat
  30.       BackColor       =   &H80000005&
  31.       ForeColor       =   &H80000008&
  32.       Height          =   2535
  33.       Left            =   1680
  34.       Picture         =   "PUZZLE.frx":0000
  35.       ScaleHeight     =   2505
  36.       ScaleWidth      =   1905
  37.       TabIndex        =   1
  38.       Top             =   360
  39.       Visible         =   0   'False
  40.       Width           =   1935
  41.    End
  42.    Begin VB.PictureBox Picture1 
  43.       Appearance      =   0  'Flat
  44.       BackColor       =   &H80000005&
  45.       ForeColor       =   &H80000008&
  46.       Height          =   1215
  47.       Left            =   240
  48.       ScaleHeight     =   79
  49.       ScaleMode       =   3  'Pixel
  50.       ScaleWidth      =   79
  51.       TabIndex        =   0
  52.       Top             =   360
  53.       Width           =   1215
  54.    End
  55.    Begin VB.Menu MenuScramble 
  56.       Caption         =   "Scramble"
  57.    End
  58.    Begin VB.Menu MenuLoad 
  59.       Caption         =   "Load"
  60.    End
  61.    Begin VB.Menu MenuEmptyCaption 
  62.       Caption         =   "Empty"
  63.       Begin VB.Menu MenuEmpty 
  64.          Caption         =   "Black"
  65.          Checked         =   -1  'True
  66.          Index           =   0
  67.       End
  68.       Begin VB.Menu MenuEmpty 
  69.          Caption         =   "White"
  70.          Index           =   1
  71.       End
  72.       Begin VB.Menu MenuEmpty 
  73.          Caption         =   "Random"
  74.          Index           =   2
  75.       End
  76.    End
  77. Attribute VB_Name = "Puzzle"
  78. Attribute VB_Creatable = False
  79. Attribute VB_Exposed = False
  80. Option Explicit
  81. ' Copyright 
  82.  1997 by Desaware Inc. All Rights Reserved
  83. '   Calculate all source and destination rectangles
  84. '   Call this whenever the form size changes or the
  85. '   image bitmap is changed.
  86. Private Sub CalcRects()
  87.     Dim x%, y%, pos%
  88.     Dim bmsegwidth%, bmsegheight%
  89.     Dim picsegwidth%, picsegheight%
  90.     Dim di&
  91.     ' Find the approx. height and width of each tile on
  92.     ' the puzzle screen.
  93.     picsegwidth% = (PuzzleRect.Right - PuzzleRect.Left) / 5
  94.     picsegheight% = (PuzzleRect.Bottom - PuzzleRect.Top) / 5
  95.     ' Get information on the bitmap in picture2
  96.     ' This loads the BITMAP structure bmInfo with information
  97.     ' on the bitmap.
  98.     di = GetObjectAPI(Picture2.Picture, Len(BMinfo), BMinfo)
  99.     bmsegwidth% = BMinfo.bmWidth / 5
  100.     bmsegheight% = BMinfo.bmHeight / 5
  101.     ' Fill in the rectangle description for each rectangle on
  102.     ' the destination DC
  103.     For y% = 0 To 4
  104.         For x% = 0 To 4
  105.             pos% = y% * 5 + x%
  106.             DestRects(pos%).Top = y% * picsegheight%
  107.             DestRects(pos%).Bottom = (y% + 1) * picsegheight%
  108.             DestRects(pos%).Left = x% * picsegwidth%
  109.             DestRects(pos%).Right = (x% + 1) * picsegwidth%
  110.         Next x%
  111.     Next y%
  112.     ' Fill in the rectangle description for each rectangle on
  113.     ' the source bitmap
  114.     For y% = 0 To 4
  115.         For x% = 0 To 4
  116.             pos% = y% * 5 + x%
  117.             SourceRects(pos%).Top = y% * bmsegheight%
  118.             SourceRects(pos%).Bottom = (y% + 1) * bmsegheight%
  119.             SourceRects(pos%).Left = x% * bmsegwidth%
  120.             SourceRects(pos%).Right = (x% + 1) * bmsegwidth%
  121.             ' Make sure the rectangle does not exceed the
  122.             ' source area for the bitmap or StretchBlt will fail
  123.             If x% = 4 Then SourceRects(pos%).Right = BMinfo.bmWidth
  124.             If y% = 4 Then SourceRects(pos%).Bottom = BMinfo.bmHeight
  125.         Next x%
  126.     Next y%
  127. End Sub
  128. '   Creates a brush to use for the empty square
  129. '   This function demonstrates the creation of device
  130. '   independent bitmaps, converting DIBs to a device dependent
  131. '   bitmap and finally converting a DDB into a brush.
  132. Private Sub CreateEmptyBrush()
  133. Dim compbitmap&
  134. Dim bih As BITMAPINFOHEADER
  135. Dim bi As BITMAPINFO
  136. ReDim colarray&(16)
  137. Dim x%
  138. Dim di&
  139. ' This used to be a string
  140. Dim da(32) As Byte  ' Each byte contains 2 x 4bit pixels
  141. Dim buf$
  142. Dim bufstart&, sourceaddr&
  143. Dim oldbm&
  144.     ' Prepare the bitmap information header
  145.     bih.biSize = 40     ' 40 bytes in this structure
  146.     bih.biWidth = 8     ' 8x8 -we'll be creating a brush
  147.     bih.biHeight = 8    ' from this bimap
  148.     bih.biPlanes = 1    ' DIB's always 1 plane
  149.     bih.biBitCount = 4  ' 16 colors, 4 bits/color
  150.     bih.biCompression = BI_RGB  ' no compression
  151.     bih.biSizeImage = 0         ' Not needed on BI_RGB
  152.     bih.biXPelsPerMeter = 0     ' Not used
  153.     bih.biYPelsPerMeter = 0     ' Not used
  154.     bih.biClrUsed = 16          ' All colors used
  155.     bih.biClrImportant = 0      ' All colors important
  156.     ' Now fill the color array
  157.     For x% = 0 To 15
  158.         colarray&(x%) = QBColor(x%)
  159.     Next x%
  160.     ' Now we need to set the data array - for now, we're
  161.     ' just going to put in random pixel data
  162.     For x% = 1 To 32
  163.         ' Note how we pack two nibbles
  164.         ' The old way
  165.         ' Mid$(da, x%, 1) = Chr$(Int(Rnd * 16) + Int(Rnd * 16) * 16)
  166.         ' The new way
  167.         da(x%) = Int(Rnd * 16) + Int(Rnd * 16) * 16
  168.     Next x%
  169.     ' Now we load the BITMAPINFO structure bi
  170.     LSet bi.bmiHeader = bih
  171.     ' Now copy the color array into the BITMAPINFO
  172.     ' bi.bmiColors string which begins 40 characters after
  173.     ' the start of the structure.
  174.     ' Refer to Chapter 15 for information on the subtleties
  175.     ' of extracting addresses for strings in a structure.
  176.     bufstart& = agGetAddressForObject(bi.bmiHeader.biSize) + 40
  177.     ' Get the address of the start of the colarray color array
  178.     sourceaddr& = agGetAddressForLong(colarray&(0))
  179.     ' And copy the 64 bytes
  180.     agCopyDataBynum sourceaddr&, bufstart&, 64
  181.     ' Now create the bitmap
  182.     compbitmap& = CreateDIBitmap(Puzzle.hdc, bih, CBM_INIT, da(0), bi, DIB_RGB_COLORS)
  183.     ' Now create a brush from this bitmap
  184.     EmptySquareBrush& = CreatePatternBrush(compbitmap)
  185.     ' And delete the source bitmap
  186.     di = DeleteObject&(compbitmap&)
  187. End Sub
  188. Private Sub DoUpdate()
  189. '   Update the picture with rectangles based on the
  190. '   puzzle array
  191.     Dim x%
  192.     For x% = 0 To 24
  193.         UpdateOne x%
  194.     Next x%
  195. End Sub
  196. ' Initialization routine
  197. Private Sub Form_Load()
  198.     Randomize
  199.     SetPuzzleSize   ' Set the size of the puzzle window
  200.     CalcRects       ' Calculate the window tiles
  201.     Scramble        ' Scramble them
  202.     CreateEmptyBrush    ' Create a random brush for the
  203.                         ' empty square.
  204. End Sub
  205. '   When the form is resized, call SetPuzzleSize to
  206. '   adjust the size of the picture window and rescale
  207. '   the image.
  208. Private Sub Form_Resize()
  209.     SetPuzzleSize   ' Set the size of the puzzle window
  210.     CalcRects       ' And recalculate the tiles
  211.     Picture1.Refresh    ' Update the picture control
  212. End Sub
  213. '   Clean up by deleting GDI objects that are no longer
  214. '   needed.
  215. Private Sub Form_Unload(Cancel As Integer)
  216.     Dim di&
  217.     If ShadowDC& Then di = DeleteDC(ShadowDC)
  218.     If EmptySquareBrush& Then di = DeleteObject(EmptySquareBrush)
  219. End Sub
  220. '   Choose the color for the empty square
  221. Private Sub MenuEmpty_Click(Index As Integer)
  222.     Dim x%
  223.     MenuEmpty(EmptySquareMode%).Checked = 0
  224.     MenuEmpty(Index).Checked = -1
  225.     EmptySquareMode% = Index
  226.     DoUpdate
  227. End Sub
  228. '   Bring up the file load dialog box to load a new
  229. '   bitmap into the puzzle.
  230. Private Sub MenuLoad_Click()
  231.     DoTheUpdate = 0 ' Preset the update flag to false
  232.     Puzzle2.Show 1  ' Show the file load form modal
  233.     If DoTheUpdate Then ' A valid bitmap was loaded
  234.         CalcRects   ' Recalculate the tiles
  235.         Scramble    ' And refresh the image
  236.     End If
  237.         
  238. End Sub
  239. '   Rescramble the bitmap image
  240. Private Sub MenuScramble_Click()
  241.     Scramble
  242.     DoUpdate  ' Redraw the puzzle window
  243. End Sub
  244. '   Clicking on a tile next to the empty tile causes that
  245. '   tile to slide into the empty space.
  246. Private Sub Picture1_MouseDown(Button As Integer, Shift As Integer, x As Single, y As Single)
  247.     Dim pt As POINTAPI
  248.     Dim u%
  249.     Dim xpos%, ypos%
  250.     Dim bxpos%, bypos%
  251.     Dim dx%, dy%, tval%, hidden%
  252.     pt.x = x    ' Picture1 scalemode is pixels
  253.     pt.y = y
  254.     ' Find the location of the black square
  255.     ' Tile 24 in the bitmap is the missing piece.
  256.     For hidden% = 0 To 24
  257.         If Position%(hidden%) = 24 Then Exit For
  258.     Next hidden%
  259.     For u% = 0 To 24
  260.         ' Find out which rectangle in the DestRects array
  261.         ' contains the point specified by the mouse click.
  262.         If PtInRect(DestRects(u%), pt.x, pt.y) Then
  263.             Exit For
  264.         End If
  265.     Next u%
  266.     ' Now find the X and Y coordinates for the mouse click
  267.     ' and for the hidden tile.
  268.     xpos% = u% Mod 5
  269.     ypos% = Int(u% / 5)
  270.     bxpos% = hidden% Mod 5
  271.     bypos% = Int(hidden% / 5)
  272.     ' The tile can slide into the empty square if it is
  273.     ' one away from the empty square on the horizontal
  274.     ' or vertical axis (but not both).
  275.     dx% = Abs(xpos% - bxpos%)
  276.     dy% = Abs(ypos% - bypos%)
  277.     If (dx% = 1 And dy% = 0) Or (dx% = 0 And dy% = 1) Then
  278.         tval% = Position%(u%)
  279.         ' So simply swap this tile with the hidden one
  280.         Position%(u%) = Position%(hidden%)
  281.         Position%(hidden%) = tval%
  282.         ' And update both these tiles
  283.         UpdateOne u%
  284.         UpdateOne hidden%
  285.     End If
  286. End Sub
  287. '   Paint picture1 by calling the full puzzle Update routine
  288. Private Sub Picture1_Paint()
  289.     DoUpdate
  290. End Sub
  291. '   Scramble the puzzle array
  292. Private Sub Scramble()
  293. Dim x%, newpos%, hold%
  294.     ' Initialize the positions
  295.     For x% = 0 To 24
  296.         Position%(x%) = x%
  297.     Next x%
  298.     ' Now scramble them
  299.     For x% = 0 To 24
  300.         ' For each source position, choose a random
  301.         ' location and swap the two values.
  302.         ' This is a simple and effective technique to
  303.         ' randomize an array of numbers.
  304.         newpos% = Int(Rnd * 25)
  305.         hold% = Position(x%)
  306.         Position(x%) = Position(newpos%)
  307.         Position(newpos%) = hold%
  308.     Next x%
  309. End Sub
  310. '   Sets the picture1 control to the visible form area
  311. '   Also creates a compatible bitmap to work with
  312. '   Call this any time the size of the form changes
  313. Private Sub SetPuzzleSize()
  314. Dim rc As RECT
  315.     Dim di&
  316.     Picture1.BorderStyle = 0
  317.     Picture1.Left = 0
  318.     Picture1.Top = 0
  319.     di = GetClientRect(Puzzle.hwnd, rc)
  320.     ' Actually, we need not subtract off rc.left and rc.top
  321.     ' below as these fields are always 0 after a call to
  322.     ' GetClientRect
  323.     ' Note the conversion to twips in order to set the
  324.     ' picture size using the VB properties
  325.     ' We could have used the MoveWindow API call as well- or just set it based on the ScaleWidth and ScaleHeight
  326.     ' of the form itself
  327.     Picture1.Width = Screen.TwipsPerPixelX * (rc.Right - rc.Left)
  328.     Picture1.Height = Screen.TwipsPerPixelY * (rc.Bottom - rc.Top)
  329.     ' This line is actually not necessary - we could
  330.     ' have just used a copy of rc because we just set
  331.     ' the client area to that specified by rc!
  332.     GetClientRect Picture1.hwnd, PuzzleRect
  333.     ' Create a compatible memory DC for Picture1
  334.     If ShadowDC Then di = DeleteDC(ShadowDC)
  335.     ShadowDC = CreateCompatibleDC(Picture1.hdc)
  336. End Sub
  337. '   Copies a single tile from the picture2 bitmap to the
  338. '   appropriate space in the picture1 destination.
  339. '   x% is the position on the puzzle to update
  340. Private Sub UpdateOne(x%)
  341.     Dim oldbm&, pos&, oldbrush&
  342.     ' Temporary variables for copying
  343.     Dim sx&, sy&, sw&, sh&, dx&, dy&, dw&, dh&
  344.     Dim di&
  345.     ' Select the bitmap into the ShadowDC
  346.     oldbm& = SelectObject(ShadowDC&, Picture2.Picture)
  347.     ' Select the random brush we created into the picture DC
  348.     If EmptySquareBrush& <> 0 Then oldbrush& = SelectObject(Picture1.hdc, EmptySquareBrush&)
  349.     ' Get the position in the bitmap.
  350.     ' Position 24 is the empty square
  351.     pos& = Position(x)
  352.     ' Calculate the rectangle on the puzzle display being
  353.     ' updataed
  354.     dx& = DestRects(x).Left
  355.     dy& = DestRects(x).Top
  356.     dw& = DestRects(x).Right - dx&
  357.     dh& = DestRects(x).Bottom - dy&
  358.         
  359.     ' The bitmap locations are based on x% - the source
  360.     ' location in the bitmap
  361.     sx& = SourceRects(pos&).Left
  362.     sy& = SourceRects(pos&).Top
  363.     sw& = SourceRects(pos&).Right - sx&
  364.     sh& = SourceRects(pos&).Bottom - sy&
  365.         
  366.     ' Now do the transfer
  367.     ' Transfer all tiles from the source except for tile
  368.     ' number 24 which is the black one.
  369.     If pos <> 24 Then
  370.         di& = StretchBlt(Picture1.hdc, dx, dy, dw, dh, ShadowDC, sx, sy, sw, sh, SRCCOPY)
  371.     Else  ' Tile #24 is empty - use EmptySquareMode% to
  372.           ' determine what type of square to set.
  373.         Select Case EmptySquareMode%
  374.             Case 0
  375.                 di = PatBlt(Picture1.hdc, dx, dy, dw, dh, BLACKNESS)
  376.             Case 1
  377.                 di = PatBlt(Picture1.hdc, dx, dy, dw, dh, WHITENESS)
  378.             Case 2
  379.                 di = PatBlt(Picture1.hdc, dx, dy, dw, dh, PATCOPY)
  380.          End Select
  381.     End If
  382.     ' Select the bitmap out of the shadow DC
  383.     di = SelectObject(ShadowDC, oldbm)
  384.     ' And select the brush back to the original one
  385.     If EmptySquareBrush <> 0 Then di = SelectObject(Picture1.hdc, oldbrush)
  386. End Sub
  387.