pb rules states that discussions are not allowed in source code forum,
so we better keep it that way. <img src="http://www.powerbasic.com/support/forums/smile.gif" alt="smile">
discussion at http://www.powerbasic.com/support/pb...ead.php?t=8519
------------------
http://www.tolkenxp.com/pb
download: inclean, pbcodec, custom controls and code, etc.
borje hagsten - [email protected]
X
-
YIKES <IMG SRC="http://www.powerbasic.com/support/forums/eek.gif" ALT="eek">
New at this
Use a colon and left bracket where the frown appears in both
of the above.
------------------
Leave a comment:
-
Replace the frown in the last message with <IMG SRC="http://www.powerbasic.com/support/forums/frown.gif" ALT="frown">
patrick
------------------
Leave a comment:
-
Neat game. Also nice programming.
I offer a a faster randomizer (see below) based on the fact
that placement of the bricks have two parities, that is, if
bricks are establisheded at random then there is only a 1/2
probability that a solution to the puzzle can be obtained.
Also, if you know that a given arrangement offers a solution
then it is easy to show that interchanging two bricks will
change the parity so that no solution can be obtained.
But, if you know that a given arrangement offers a solution
then it is also easy to show that interchanging any three
different bricks will not change the parity, thus allowing for
a solution. Knowing this, I changed the mixing routine in
"ReMix" as follows:
DELETE THe following FROM YOUR PROGRAM:
'-------------------------
ePos = n
RANDOMIZE ' Seed the random number generator
FOR aa = 1 TO n * 100 'experiment if you like - think this is enough to mix them properly..
DO
bb = RND(1, n) - 1 ' Generate number, then see if it can be moved
IF (bPos(bb).z + 1 = ePos AND (bPos(bb).z + 1) MOD brc <> 0) OR _ 'test right of pos 1-3
(bPos(bb).z - 1 = ePos AND (ePos + 1) MOD brc <> 0) OR _ 'test left of position 2-4
bPos(bb).z + brc = ePos OR bPos(bb).z - brc = ePos THEN 'test above/under
tmp = bPos(bb).z
bPos(bb).z = ePos
ePos = tmp
EXIT DO
END IF' LOOP
IF aa > n * 50 AND ePos = n THEN EXIT FOR 'enough many draws and empty pos in down/right corner - use it!
NEXT
EmptyPos = ePos
REPLACE WITH THIS <IMG SRC="http://www.powerbasic.com/support/forums/frown.gif" ALT="frown">Add cc as Local integer)
'---------------------------------------------
RANDOMIZE
FOR aa=0 TO n-1
bb=RND(0,n-1) : cc=RND(0,n-1)
WHILE aa=bb : bb=RND(0,n-1) : WEND
WHILE (cc=aa) OR (cc=bb): cc=RND(0,n-1) : WEND
tmp=bPos(aa).z
bPos(aa).z=bPos(bb).z
bPos(bb).z=bPos(cc).z
bPos(cc).z=tmp
NEXT aa
'---------------------------------------------
Actually, the "for loop" would also work just fine
with aa=0 to [n-1]/2 or thereabouts because at that
point most of the boxes have been replaced anyway.
Patrick <IMG SRC="http://www.powerbasic.com/support/forums/tongue.gif" ALT="stick tongue out">
------------------
Leave a comment:
-
Code updated with better shuffling - now always possible to solve,
olus added keyboard handling (can now also use arrow keys to play).
------------------
http://www.tolkenxp.com/pb
Download: incLean, PBcodec, custom controls and code, etc.
Borje Hagsten - [email protected]
Leave a comment:
-
Guest repliedBorje,
Thank you for this code. Again, a game provides so much
insight into programing. Keep up the excellent work [play?].
Thanks, P.
Leave a comment:
-
Hi Semen,
Yes, I guess one can get stuck there. For a computer game like this one, the
best solution would be to imitate a "real life" mix, by generating the random
numbers one step at the time and only consider each possible move - sort of
like like running the game randomly backwards.
Then again, one could also add a "cheat code" procedure, like if you press
the Alt-key and click on a brick, you can switch two brick places..
I whish I had more time to dive into game programming, because it's really
fascinating. Even the simpliest of games often turns out to be a real
challange when it comes to the mathematics behind it. Hm, wonder if this
sample could serves as the base for a nice little chess game..
Leave a comment:
-
Borje --
COOL !!!
But there is one problem in game. In "15 tiles" game not all combinations are valid.
On final step (when three rows are ready) could be
1) 13-14-15 2) 14-15-13 3) 15-13-14
4) 15-14-13 5) 14-13-15 6) 13-15-14
Var1. Game is over.
Var2-3. It's possible to convert to var.1
Var4-6. Have no solution.
I remember a book for children about mathematic, where described that in 19th century one popular american newspaper even offered one million dollars for person, who will be able to transform 15-14-13 to 13-14-15 and during some monthes many people tried to solve a task - clear, without success
I suggest the following algorithm to create valid combination.
You begin from
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 -
Then 1000-2000 times select "random" direction (left, right, up. down) to move empty place.
[This message has been edited by Semen Matusovski (edited January 26, 2000).]
Leave a comment:
-
I'm aware there is a slight redraw problem, but I couldn't find any good
solutions to it. Maybe a DIALOG DOEVENTS after a tile's been moved could
improve the performance enough to match even your wife's speed, Dave..
One could quite easily split a picture via StretchBlt into each brick
(label) and make a "real" puzzle game out of it. Add that to the list of
possible enhancements..
WOPS! There was a fault in the way it checked the tiles vs empty space, so
some tiles could be moved "around" the edge. I guess this could have caused
some tiles to suddenly disappear. The code above has been fixed, now using
the following to check if a tile can be moved:
Code:' Check to see if the Brick has an empty space next to it IF (bPos(bc).z + 1 = EmptyPos AND (bPos(bc).z + 1) MOD brc <> 0) OR _ (bPos(bc).z - 1 = EmptyPos AND (EmptyPos + 1) MOD brc <> 0) OR _ bPos(bc).z + brc = EmptyPos OR bPos(bc).z - brc = EmptyPos THEN
Made more changes to the code tonight and optimized it some by adding a
member to the TYPE to keep track of each brick's (tile's?) textcolor, so
a fast check for currently used color can determine if it needs another
color or not. Seems to have improved the speed a bit.
Also added the possibility for a user to cancel the closing procedure while
exiting the game/program. Thank you Lance, for the help with that one..
[This message has been edited by Borje Hagsten (edited January 24, 2000).]
Leave a comment:
-
Cool.
My wife plays something similar all the time where each time is a piece of a picture and you have to line them all up to see the picture.
I compiled this and gave it to her. She clicks so fast that several tiles disappear and the game starts beeping like crazy.
--Dave
-------------
PowerBASIC Support
mailto:[email protected][email protected]</A>
Leave a comment:
-
Guest repliedHey Neat game. I won the first time I played (in under 2 minutes) and thought "gee this game is easy." Then I played again after lunch and it took me over 10 minutes to win so I guess it is not that easy.
Kevin
-------------
mailto:[email protected][email protected]</A>
Leave a comment:
-
Brick Game for PB/DLL 6.0
Code:'~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' Game15 v2, a simple "15 tiles" brick game, written in PB/DLL 6.0 ' January 2000 by Borje Hagsten. Released as Public Domain. ' Updated June 2003 with better mix code - now shuffles bricks instead, ' plus added keyboard handling - can be played using the arrow keys. ' Free to enhance, learn from, or simply to enjoy and play. ' ' The "rules" are simple. Click on the tiles next to the open ' space in order to move them and try to line them up, 1 to 15. ' A beep and red caption on a brick indicates a correct position. ' It's not as easy as it may look like from the beginning and some ' people may even become addicted to playing it. A complete 32-bit ' game for Windows with a file size of just 20 KB - PB rules! ' ' - Some ideas, in case you want to do something more of it: ' Use a split bitmap instead of numbers on the labels ' Create and add resource file with version info and program icon ' Create routines to save and show results (maybe even store/recall a running game?) ' Add a "About" dialog, menu, sound support, help and some game info ' Set a price and sell a million copies (but please remember me, if you succeed.. <IMG SRC="http://www.powerbasic.com/support/forums/smile.gif" ALT="smile"> '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #COMPILE EXE #INCLUDE "WIN32API.INC" %ID_MIX = 11 %ID_LABEL1 = 20 %ID_LABEL2 = 21 %ID_LABEL3 = 22 %ID_TIMER = 40 TYPE bx x AS LONG ' x pos y AS LONG ' y pos z AS LONG ' reference number p AS LONG ' actual position c AS LONG ' color value END TYPE GLOBAL hDlg AS LONG GLOBAL gTime AS LONG GLOBAL brc AS LONG GLOBAL n AS LONG GLOBAL EmptyPos AS LONG GLOBAL hTimer AS LONG GLOBAL bPos() AS bx DECLARE CALLBACK FUNCTION DlgCallback() DECLARE FUNCTION CheckDone AS LONG DECLARE FUNCTION EndProcedure AS LONG DECLARE SUB NewGame DECLARE SUB ReMix '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' PBMAIN, where all controls and the dialog is created '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ FUNCTION PBMAIN LOCAL x AS LONG, y AS LONG, z AS LONG, w AS LONG, h AS LONG, b AS LONG LOCAL a AS LONG brc = 4 'number of columns/rows - use at least 3, classic is 4 (15-tile game) ' Note: The brc value is all you have to change. The dialog and all ' controls will resize themselves accordingly. Try with 5 or 6 to ' create a game with 25 or 36 bricks, but do have in mind that the ' time it takes to solve the puzzle relates to this number.. :-) w = 26 'width h = 24 'height a = 10 'distance from dialog edge n = brc^2 - 1 'number of bricks (tiles, whatever..) b = brc - 1 'zero based number of columns and rows EmptyPos = n 'initial empty space, down in the corner REDIM bPos (n) 'array for storing brick info DIALOG NEW 0, FORMAT$(n) & " tiles",,, brc * w + 22, brc * h + 90, _ %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hDlg CONTROL ADD LABEL, hDlg, %ID_LABEL2, "", 9, 9, _ brc * w + 2, brc * h + 2, %SS_SUNKEN OR %WS_TABSTOP CONTROL ADD LABEL, hDlg, %ID_LABEL1, "", a, brc * h + 18, _ brc * w + 2, 12, %SS_CENTER OR %SS_SUNKEN CONTROL ADD LABEL, hDlg, %ID_LABEL3, "", a, brc * h + 30, _ brc * w + 2, 12, %SS_CENTER OR %SS_SUNKEN CONTROL ADD BUTTON, hDlg, %ID_MIX, "&New game", a, brc * h + 50, brc * w + 2, 14 CONTROL ADD BUTTON, hDlg, %IDCANCEL, "E&xit", a, brc * h + 68, brc * w + 2, 14 'A zero based index would be better here, but some low values are already 'used by the DDT dialog (like IDCANCEL, etc), so we better use another 'approach and increase it to a "100 based" line of controls instead z = 100 FOR y = 0 TO b FOR x = 0 TO b bPos(z - 100).x = a + x * w bPos(z - 100).y = a + y * h CONTROL ADD LABEL, hDlg, z, FORMAT$(z - 99), a + x * w, a + y * h, w, h, _ %SS_NOTIFY OR %SS_CENTER, %WS_EX_DLGMODALFRAME INCR z IF z > 99 + n THEN EXIT FOR NEXT NEXT bPos(n).x = a + b * w 'x and y for the inital empty space bPos(n).y = a + b * h DIALOG SHOW MODELESS hDlg, CALL DlgCallback 'DDT dialog, so use own message loop to trap WM_KEYDOWN.. LOCAL msg AS TAGMSG WHILE GetMessage(Msg, %NULL, 0, 0) IF IsDialogMessage(hDlg, Msg) THEN SELECT CASE msg.message CASE %WM_CREATE CASE %WM_CHAR : MessageBeep &HFFFFFFFF CASE %WM_KEYDOWN IF GetDlgCtrlID(msg.hWnd) <> %ID_LABEL2 THEN EXIT SELECT SELECT CASE msg.wParam CASE %VK_LEFT IF (EmptyPos + 1) MOD brc <> 0 THEN FOR x = 0 TO n - 1 IF bPos(bPos(x).p).z = EmptyPos + 1 THEN x = 100 + bPos(x).p SendMessage hDlg, %WM_COMMAND, MAKLNG(x, %BN_CLICKED), GetDlgItem(hDlg, x) EXIT FOR END IF NEXT END IF CASE %VK_RIGHT IF EmptyPos MOD brc <> 0 THEN FOR x = 0 TO n - 1 IF bPos(bPos(x).p).z = EmptyPos - 1 THEN x = 100 + bPos(x).p SendMessage hDlg, %WM_COMMAND, MAKLNG(x, %BN_CLICKED), GetDlgItem(hDlg, x) EXIT FOR END IF NEXT END IF CASE %VK_UP IF EmptyPos + brc <= n THEN FOR x = 0 TO n - 1 IF bPos(bPos(x).p).z = EmptyPos + brc THEN x = 100 + bPos(x).p SendMessage hDlg, %WM_COMMAND, MAKLNG(x, %BN_CLICKED), GetDlgItem(hDlg, x) EXIT FOR END IF NEXT END IF CASE %VK_DOWN IF EmptyPos - brc >= 0 THEN FOR x = 0 TO n - 1 IF bPos(bPos(x).p).z = EmptyPos - brc THEN x = 100 + bPos(x).p SendMessage hDlg, %WM_COMMAND, MAKLNG(x, %BN_CLICKED), GetDlgItem(hDlg, x) EXIT FOR END IF NEXT END IF END SELECT END SELECT Else TranslateMessage Msg DispatchMessage Msg End If Wend END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' One dialog Callback function takes care of almost everything '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ CALLBACK FUNCTION DlgCallback() LOCAL rStr AS STRING STATIC hBrushDialog AS LONG SELECT CASE CBMSG CASE %WM_INITDIALOG hBrushDialog = CreateSolidBrush(RGB(255,223,161)) 'dialog color CALL ReMix 'mix and set up new game CheckDone CASE %WM_DESTROY 'at exit IF hTimer THEN KillTimer hDlg, hTimer 'Kill the timer DeleteObject hBrushDialog 'Delete the brush PostQuitMessage 0 CASE %WM_COMMAND SELECT CASE CBCTL CASE %ID_MIX 'Start a new game.. rStr = "Break current game and start a new?" IF hTimer = 0 OR MessageBox(hDlg, BYVAL STRPTR(rStr), _ FORMAT$(n) & " Tiles" & CHR$(0), _ %MB_YESNO OR %MB_ICONQUESTION) = %IDYES THEN CALL NewGame END IF CASE %IDCANCEL IF hTimer = 0 OR EndProcedure THEN DIALOG END CBHNDL 'exit program CASE 100 TO 100 + n 'The bricks - label controls LOCAL bc AS LONG, tmp AS LONG : bc = CBCTL - 100 'check to see if the brick has an empty space next to it IF (bPos(bc).z + 1 = EmptyPos AND (bPos(bc).z + 1) MOD brc <> 0) OR _ (bPos(bc).z - 1 = EmptyPos AND (EmptyPos + 1) MOD brc <> 0) OR _ bPos(bc).z + brc = EmptyPos OR bPos(bc).z - brc = EmptyPos THEN IF hTimer = 0 THEN hTimer = SetTimer(hDlg, %ID_TIMER, 1000, BYVAL %NULL) '1000 mSec = 1 sec END IF 'okay, so move the Brick into the empty space CONTROL SET LOC hDlg, CBCTL, bPos(EmptyPos).x, bPos(EmptyPos).y IF EmptyPos = bc THEN 'Was it a "good" position? bPos(bc).c = %RED : BEEP 'Could play something else here too.. ELSE bPos(bc).c = %BLACK END IF tmp = EmptyPos 'store new empty space EmptyPos = bPos(bc).z bPos(bc).z = tmp bPos(bc).p = bc 'following triggers %WM_CTLCOLORSTATIC (redraws brick) InvalidateRect CBLPARAM, BYVAL %NULL, 0 : UpdateWindow CBLPARAM bc = CheckDone IF bc >= n THEN 'All is done, build and show a message rStr = "Done in " rStr = rStr & FORMAT$(gTime \ 60, "0") & " min. " _ & FORMAT$(gTime MOD 60, "0") & " sec." rStr = rStr & CHR$(10, 10) rStr = rStr & "Play again?" & CHR$(0) IF MessageBox(hDlg, BYVAL STRPTR(rStr), FORMAT$(n) & " Tiles" & CHR$(0), _ %MB_YESNO OR %MB_ICONWARNING) = %IDYES THEN CALL NewGame ELSE DIALOG END CBHNDL 'exit game END IF END IF END IF END SELECT CASE %WM_CTLCOLORSTATIC 'color tiles and set their textcolor IF GetDlgCtrlID(CBLPARAM) > 99 THEN SetTextColor CBWPARAM, bPos(GetDlgCtrlID(CBLPARAM) - 100).c FUNCTION = GetSysColorBrush(%COLOR_INFOBK) END IF CASE %WM_CTLCOLORDLG : FUNCTION = hBrushDialog 'paint the dialog's background CASE %WM_SYSCOMMAND IF CBWPARAM = %SC_CLOSE THEN IF EndProcedure = 0 THEN FUNCTION = 1: EXIT FUNCTION END IF END IF CASE %WM_TIMER INCR gTime CONTROL SET TEXT hDlg, %ID_LABEL3, _ FORMAT$(gTime \ 60, "0") & " min. " & _ FORMAT$(gTime MOD 60, "0") & " sec." END SELECT END FUNCTION '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ' NewGame generates a new game. '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ SUB NewGame 'We get smother action with redraw turned off IF hTimer THEN KillTimer hDlg, hTimer 'Kill eventual timer hTimer = 0 CALL SendMessage(hDlg, %WM_SETREDRAW, %FALSE, 0) CALL ReMix 'Set new random order CALL SendMessage(hDlg, %WM_SETREDRAW, %TRUE, 0) InvalidateRect hDlg, BYVAL %NULL, 0 : UpdateWindow hDlg CALL CheckDone END SUB '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' ReMix generates random numbers and moves the bricks to their new positions. ' This is only (?) sure way to mix the bricks - mimics real life mix by moving ' bricks around randomly, using real empty space as target space. Cannot simply ' use a bunch of random numbers, since some combinations are impossible to solve.. '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ SUB ReMix LOCAL aa AS LONG, bb AS LONG, tmp AS LONG, ePos AS LONG FOR aa = 0 TO n - 1 ' Make sure all numbers are unique bPos(aa).z = aa bPos(aa).c = %BLACK NEXT ePos = n RANDOMIZE ' Seed the random number generator FOR aa = 1 TO n * 100 'experiment if you like - think this is enough to mix them properly.. DO bb = RND(1, n) - 1 ' Generate number, then see if it can be moved IF (bPos(bb).z + 1 = ePos AND (bPos(bb).z + 1) MOD brc <> 0) OR _ 'test right of pos 1-3 (bPos(bb).z - 1 = ePos AND (ePos + 1) MOD brc <> 0) OR _ 'test left of position 2-4 bPos(bb).z + brc = ePos OR bPos(bb).z - brc = ePos THEN 'test above/under tmp = bPos(bb).z bPos(bb).z = ePos ePos = tmp EXIT DO END IF LOOP IF aa > n * 50 AND ePos = n THEN EXIT FOR 'enough many draws and empty pos in down/right corner - use it! NEXT EmptyPos = ePos FOR aa = 0 TO n - 1 ' Re-position the bricks IF aa = bPos(aa).z THEN bPos(aa).c = %RED CONTROL SET LOC hDlg, 100 + aa, bPos(bPos(aa).z).x, bPos(bPos(aa).z).y bPos(aa).p = aa NEXT aa gTime = 0 ' Reset the timing of the game CONTROL SET TEXT hDlg, %ID_LABEL3, "0 min. 0 sec." SetFocus hDlg END SUB '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' CheckDone loops through all bricks to see which ones are ' placed correctly and then shows the result in %ID_LABEL1 '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION CheckDone AS LONG LOCAL aa AS LONG, isDone AS LONG FOR aa = 0 TO n - 1 IF aa = bPos(aa).z THEN bPos(aa).c = %RED 'in correct place, use red text color INCR isDone 'count correct ones ELSE bPos(aa).c = %BLACK 'not in correct place, use black text END IF NEXT aa IF isDone = 1 THEN CONTROL SET TEXT hDlg, %ID_LABEL1, FORMAT$(isDone) & " tile done" ELSE CONTROL SET TEXT hDlg, %ID_LABEL1, FORMAT$(isDone) & " tiles done" END IF FUNCTION = isDone 'return number of tiles in correct place END FUNCTION '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ ' message before end.. '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤ FUNCTION EndProcedure AS LONG IF MessageBox(hDlg, "Exit game?", FORMAT$(n) & " Tiles" & CHR$(0), _ %MB_YESNO OR %MB_ICONQUESTION) = %IDYES THEN FUNCTION = 1 : EXIT FUNCTION END IF END FUNCTION
[This message has been edited by Borje Hagsten (edited June 08, 2003).]Tags: None
Leave a comment: