Help with my Minesweeper game I developed over Christmas.

Started by ScottieB, December 30, 2013, 06:10:38 PM

Previous topic - Next topic

ScottieB

Dear Kevin,
 This is Scott.  I designed a game over Christmas at least the guts of it.  The only part I see lagging is when I pick a box.  I was wondering if you see the issue?
It's the guts to minesweeper!  I was hopeing that you might be able to shorten the code or make routines look better.  I am by no means real good at data structures or functions.
This is where I would like to seek your help to make it more readable and clean. Please,  Give it a try it's not all that long and it is a working model.

Thanks,
ScottieB.

kevin

#1


  There's lots of text rendering and all the same old same redundancies. So I'd recommend converting the text stuff to 'blocks' and drawing the grid like that.  I suspect you don't really even need to draw the screen between frames most of the time, so a applying delta might be viable also.  

  e.g.

PlayBASIC Code: [Select]
   X_Screen_Res = GetScreenWidth()
Y_Screen_Res = GetScreenHeight()

LoadFont "Arial",2,20,0

; Character size
X_Character_Size = 20
Y_Character_Size = 20

; Size of playing field
Number_Of_Rows = X_Screen_Res / X_Character_Size - 2
Number_Of_Columns = Y_Screen_Res / Y_Character_Size - 2


// Make some bitmap blocks
Dim BlockSet(100)
BlockIndex=0
For lp =0 to 9
ThisImage=NewIMage(X_Character_Size,Y_Character_Size,2)
rendertoimage ThisIMage
cls 0
ink $ffff00ff
text 1,1,Str$(lp)
BlockSet(BlockIndex) =ThisImage
BlockIndex++
next

Total_Block_Count=BlockIndex

// Init map styed 2D array
DIm Map(Number_Of_Rows ,Number_Of_Columns)

For ylp =0 to Number_Of_Columns
For xlp =0 to Number_Of_Rows
Map(xlp,ylp)=floor(rnd#(Total_Block_Count-1))
next
next


rendertoscreen

Do
cls 255

lockbuffer
For ylp =0 to Number_Of_Columns
Ypos=(Ylp*Y_Character_Size)+(Y_Character_Size/2)
Xpos=X_Character_Size/2
For xlp =0 to Number_Of_Rows
TileIndex=Map(xlp,ylp)
DrawImage BlockSet(TileIndex),Xpos,Ypos,false
Xpos+=X_Character_Size
next
next
unlockbuffer

Sync
loop






 In terms of redundancies, examine the following closely..  (deva ju ?)


PlayBASIC Code: [Select]
For Y_Map = 1 To Number_Of_Columns    
For X_Map = 1 To Number_Of_Rows

; If we are on the parent and the cell is available and the searchmap has not been written to yet.
; No diagonals.

If Matrix_Table_5(X_Map + X_Offset,Y_Map + Y_Offset) = Parent And Matrix_Table_3(X_Map + X_Offset,(Y_Map - 1) + Y_Offset) = 0 And Matrix_Table_5(X_Map + X_Offset,(Y_Map - 1) + Y_Offset) = 0 Then Matrix_Table_5(X_Map + X_Offset,(Y_Map - 1) + Y_Offset) = Child ; Up Child
If Matrix_Table_5(X_Map + X_Offset,Y_Map + Y_Offset) = Parent And Matrix_Table_3(X_Map + X_Offset,(Y_Map + 1) + Y_Offset) = 0 And Matrix_Table_5(X_Map + X_Offset,(Y_Map + 1) + Y_Offset) = 0 Then Matrix_Table_5(X_Map + X_Offset,(Y_Map + 1) + Y_Offset) = Child ; Down Child
If Matrix_Table_5(X_Map + X_Offset,Y_Map + Y_Offset) = Parent And Matrix_Table_3((X_Map - 1) + X_Offset,Y_Map + Y_Offset) = 0 And Matrix_Table_5((X_Map - 1) + X_Offset,Y_Map + Y_Offset) = 0 Then Matrix_Table_5((X_Map - 1) + X_Offset,Y_Map + Y_Offset) = Child ; Left Child
If Matrix_Table_5(X_Map + X_Offset,Y_Map + Y_Offset) = Parent And Matrix_Table_3((X_Map + 1) + X_Offset,Y_Map + Y_Offset) = 0 And Matrix_Table_5((X_Map + 1) + X_Offset,Y_Map + Y_Offset) = 0 Then Matrix_Table_5((X_Map + 1) + X_Offset,Y_Map + Y_Offset) = Child ; Right Child

If Matrix_Table_5(X_Map + X_Offset,Y_Map + Y_Offset) <> 0 And Matrix_Table_1(X_Map,Y_Map) <> 1 Then Matrix_Table_4(X_Map + X_Offset,Y_Map + Y_Offset) = 9

Jump_1:

Next X_Map
Next Y_Map






    The above is the original code, for each iteration there's a load of calculations that are being made over and over (more than i can be bothered to count), that just don't need to be.  
       
PlayBASIC Code: [Select]
For Y_Map = 1 To Number_Of_Columns    

// Compute Y offsets in outer loop, since they never change inside X_MAP loop..
Y_Map_PLUS_Y_OFFSET =Y_Map + Y_Offset
Y_Map_Minus_1_PLus_YOffset =(Y_Map - 1) + Y_Offset
Y_Map_PLus_1_PLus_YOffset =(Y_Map + 1) + Y_Offset
For X_Map = 1 To Number_Of_Rows

; If we are on the parent and the cell is available and the searchmap has not been written to yet.
; No diagonals.

X_Map_PLUS_X_OFFSET =X_Map + X_Offset

ThisTile =Matrix_Table_5(X_Map_PLUS_X_Offset,Y_Map_PLUS_Y_Offset)
If ThisTile = Parent

If Matrix_Table_3(X_Map_PLUS_X_Offset,Y_Map_Minus_1_PLus_YOffset) = 0 And Matrix_Table_5(X_Map_PLUS_X_Offset,Y_Map_Minus_1_PLus_YOffset) = 0 Then Matrix_Table_5(X_Map_PLUS_X_Offset,(Y_Map - 1) + Y_Offset) = Child ; Up Child
If Matrix_Table_3(X_Map_PLUS_X_Offset,Y_Map_Plus_1_PLus_YOffset) = 0 And Matrix_Table_5(X_Map_PLUS_X_Offset,Y_Map_PLus_1_PLus_YOffset) = 0 Then Matrix_Table_5(X_Map_PLUS_X_Offset,(Y_Map + 1) + Y_Offset) = Child ; Down Child

; here you could compuite the X offsets once, rather than each time.. which is SLOW!
If Matrix_Table_3((X_Map - 1) + X_Offset,Y_Map_PLus_Y_Offset) = 0 And Matrix_Table_5((X_Map - 1) + X_Offset,Y_Map_PLus_Y_Offset) = 0 Then Matrix_Table_5((X_Map - 1) + X_Offset,Y_Map_PLUS_Y_Offset) = Child ; Left Child
If Matrix_Table_3((X_Map + 1) + X_Offset,Y_Map_PLus_Y_Offset) = 0 And Matrix_Table_5((X_Map + 1) + X_Offset,Y_Map_PLus_Y_Offset) = 0 Then Matrix_Table_5((X_Map + 1) + X_Offset,Y_Map_PLUS_Y_Offset) = Child ; Right Child
endif

If ThisTile <> 0 And Matrix_Table_1(X_Map,Y_Map) <> 1 Then Matrix_Table_4(X_Map_PLUS_X_Offset,Y_Map_PLUS_Y_Offset) = 9

Jump_1:

Next X_Map
Next Y_Map




   This trims about 30% of operational redundancy from this loop.

   
    * Maze Rendering



ScottieB

I will try it out.  Kevin,  I noticed that in my program where I'm doing the flood-fill parents and child I'm doing a high number but...
Is there a way to make it do only what it needs to and then come out? also for the border fill.

ScottieB

I just messed with the bitmaps.  I plan to use this because I did want to add images anyways.
Your saying all that adding of offset really causes extra computations?  I take it.

ScottieB

Although your speed-ups still matter.  I think the main problem here that is slowing down the program is the flood-fill recursion always set to a high number.
This might matter when we fist come on the board but as we unveil tiles it's deep search is way to high for little areas.

Any ideas how we can stop it when it does the region it is within???

ScottieB

I think I got it.  Maybe

How about when I scan for 3BV's I keep track of the highest number and rescan that number back into another marked regions map so that all
marked regions have the the number of there highest parent and then during game when I'm unveiling tiles I only do it until that regions highest number is achieved.

Hmmmmmmmmmmm.

kevin


QuoteI think the main problem here that is slowing down the program is the flood-fill recursion always set to a high number


     it's not recursion , it's a nested loop.. So basically it's calling the filler 100 times, why I have no idea as don't really know you're trying to do but it doesn't seem like a very optimal solution. 

     Never played mine sweeper in my life, so what are the rules ?

ScottieB

I know your going to say that this has too much redundancy and your right.
I was just figuring out something else and I got it.

During 3BV count which is maximum number of clicks in a game used for scoring.
I decided to count the maximum number in the mark map which is the highest number of flood-fill
and this now will give me the maximum I have to do the loop for any region.

I still have more to learn about this game but the general rules are you try to uncover everything but the hidden mines
the numbers accept 9 which is empty space 1-8 tell you how that each cell with a number in it has that many neighboring cells with a mine in it.
You use this info to deduct which in the next you will press.  The is other rules as well but this is the start.

Again if you have a look at the source code the next thing I'm thinking about is do just what you said to optimize it.
Any other ideas as to speed this up.  I think I now got the main one. that darn loop.
You can now see the speed up process.

ScottieB

Hey guys!  I'm back.
I have continued on with minesweeper and it's coming along nicely but...

I was wondering if any one could help me with some artwork?
I'm not that good at making graphics and I would love to see this game have a nice face.
There is some GFX online but I wanna give this game a new look.
Maybe, Someone could think how we might be able to put a twist on the game like newer versions.
Any help would be greatly appreciated.  I don't just wanna copy someones stuff.
I would rather work with someone or some people making our playbasic version tuff.

I have received help from post like this before with some 3D stuff in the past but it's been awhile
since I've colaberated with anyone.  So I'm open for suggestions. I don't wanna hire anyone but
It would be nice if I could get alittle help.

Making games is hard and it is a long process and user help make it alittle bit easier.

Thanks!
ScottieB

ScottieB

Here is the game so far.

I don't really know where to go from here.
I was hoping someone could help me but there has not been any replies for days.

Things are adjustable within the code.
I've intergraded 15 Tiles on the board, 5 Smiley faces, and 10 Leds.



kevin


 
QuoteI was hoping someone could help me

   help you do what ?   we're not all mind readers.

   Looking at the newer version and it looks like a minesweeper game to me,  to be honest I don't know if it works or not having never played the original.  I'm not going to much help with that.

   Code wise there's all the same issues as before, these might seem like the trivial ramblings of the guy who wrote PlayBASIC, but they'll make your programs much easier maintain and perform better. 

   Some tips:

       * JPG is a lossy format and generally inappropriate for sprite sheets.   

       * GetImage can grab from the image, not just the4 screen, making the following not unnecessary.


PlayBASIC Code: [Select]
LoadImage "Sprites\Sprite_Sheet_01.jpg",1
DrawImage 1,0,0,0

For Sprites = 0 To 14

GetImage 100 + Sprites,Sprites * X_Sprite_Size,0,(Sprites + 1) * X_Sprite_Size,Y_Sprite_Size

Next Sprites

; 0 - 8
; Untouched
; Bomb
; Exploded Bomb
; Not a bomb.
; Question mark.
; Flag

Cls




    Ideally you'd load the media and render to that surface RenderToImage
       
PlayBASIC Code: [Select]
LoadImage "Sprites\Sprite_Sheet_01.jpg",1
rendertoimage 1

For Sprites = 0 To 14

GetImage 100 + Sprites,Sprites * X_Sprite_Size,0,(Sprites + 1) * X_Sprite_Size,Y_Sprite_Size

Next Sprites

; 0 - 8
; Untouched
; Bomb
; Exploded Bomb
; Not a bomb.
; Question mark.
; Flag





      Since the loading appears to be same for the various images, you could roll a Psub or Function to encapsulate this process.

       Something like this.     
PlayBASIC Code: [Select]
Function LoadAndCutImage(File$, StartingSprite, Frames, X_Digit_Size,Y_Digit_Size )

oldsurface=getsurface()

LoadImage "Sprites\"+file$,1
rendertoimage 1

For Tiles = 0 To Frames
GetImage StartingSprite + Tiles,Tiles * X_Digit_Size,0,(Tiles + 1) * X_Digit_Size,Y_Digit_Size
Next Tiles
rendertoimage oldsurface

EndFunction




      You could get rid of the passing the width and height fields if the sprite sheet is always trimmed.  So grab the height from the image height and calc the width from the image width divided by the number of frames across the page..



       * The following type of code is just really frustrating,  given PB has bitmap fonts support built in. 


PlayBASIC Code: [Select]
For L = 1 To 3 

Read$ = Mid$(Str$(Int(Per_Second#)),L,1)

If Read$ = "" Then DrawImage 50,(L - 3) * X_Digit_Size + 768,0,0

If Read$ = "0" Then DrawImage 50,L * X_Digit_Size + 768,0,0
If Read$ = "1" Then DrawImage 51,L * X_Digit_Size + 768,0,0
If Read$ = "2" Then DrawImage 52,L * X_Digit_Size + 768,0,0
If Read$ = "3" Then DrawImage 53,L * X_Digit_Size + 768,0,0
If Read$ = "4" Then DrawImage 54,L * X_Digit_Size + 768,0,0
If Read$ = "5" Then DrawImage 55,L * X_Digit_Size + 768,0,0
If Read$ = "6" Then DrawImage 56,L * X_Digit_Size + 768,0,0
If Read$ = "7" Then DrawImage 57,L * X_Digit_Size + 768,0,0
If Read$ = "8" Then DrawImage 58,L * X_Digit_Size + 768,0,0
If Read$ = "9" Then DrawImage 59,L * X_Digit_Size + 768,0,0

Next L



     While machines might well be 1000's of times faster than the good old days,  falling through redundant string comparisons is still a programming no no..  There's really no need to trap every combination with it's own IF/THEN statement,  when we can compute which image index directly from the ASCII value. Like so,
   
PlayBASIC Code: [Select]
ThisValue$=Str$(Int(Per_Second#))
For L = 1 To 3
ThisCHR = Mid(ThisValue$,L)-asc("0")
if ThisChr=>0 and ThisChr=<9
DrawImage 50+ThisChr,L * X_Digit_Size + 768,0,0
else
DrawImage 50,(L - 3) * X_Digit_Size + 768,0,0
endif
Next





      etc etc ...  All my previous points still stand


ScottieB

Thanks for the tips kevin.
I going to have to go back and clean a lot of things up.
If this only makes it faster I think I will.
I don't claim to be a professional programmer and most of the time I'm pretty lucky I can
get something to work anyways but...
I guess this kinda mop up would be better practice to a better program.
So thanks and if there is more you can see let me know.

I am stumped with the scoreing.  It takes 3BV Count which is amount of clicks to unveal everything but mines.
Then 3BV/s which is 3BV Count divided by seconds.

so it's takes difficulty and time into consideration but...
The score are all over the place.  I can't tell weighter it was a god one or not
and it gets low fast.

Any ideas how I can use this process but make it better somehow???

Thanks
ScottieB