none
Help to reduce the code of my program RRS feed

  • Question

  • Hello to all,

    I started making a sudoku game, each square represens a part of code. But the sudoku has 81 square. I make only 9 square. and the code is already big. I need help to reduce the amount of code to make each square.

    I sent to MediaFire because the Import option from Small Basic does not work with my game:

    http://www.mediafire.com/?knnimynm5ng

    Thanks.

    Friday, April 23, 2010 12:28 AM

Answers

  • To begin, we should simplify your ClickbgColor subroutine and change its name to something more appropriate.

    First of all, I recommend renaming your Sub from ClickbgColor to MouseClicks to represent its main purpose.

    Next, we will simplify the section of code that changes the background colour. Add the following three lines just after your 'Cor do fundo comment...

     

      if (xpos > 420 and xpos < 528) And (ypos > 60 And ypos < 160) then

        setBackground()

      endif


    Now move all of your code to do with setting the background (everything down to 'Iniciar o Timer) into a new subroutine called setBackground. (Make sure you put this new subroutine outside of the MouseClicks one.)

    It's best you do it yourself, but I have published a version with these changes as: FDB098 (http://smallbasic.com/program/?FDB098)

    Now you need to repeat this for the other sections in MouseClicks (Iniciar o Timer, Cor da grade, Select Box) which will give you a much clearer event subroutine and make it easier for us to work on each section later.

    Publish the code when you've done that and well move on to the next bit.

    Saturday, April 24, 2010 9:47 AM
  • Well done. Now that we have things split into their subs we can work on reducing them a bit. To do that we need to introduce Arrays and Loops. You may already understand arrays, but for others that don't I'll talk about them first...

    If you have used a Spreadsheet program of any sort, then you will be familiar with what is called a 2D (two dimensional) array. You can think of it like a grid split up with rows and columns. (See the image at the top of this page as an example: http://home.earthlink.net/~cassidyny/spreadsheet.htm)

    An array, like a spreadsheet, lets you store data in each of its cells. The difference between a spreadsheet and an array is that an array would reference the first cell as 1A (row first, then column), while the spreadhseet example references it as A1. When your data is stored in this grid (array) format, instead of individual variables, the computer can get at it much easier and you can shorten your code quite a bit.

    I'll start you off by giving an example how to use a 2D array in SmallBasic then we will use it later to shorten your new setBackground() sub.

    An array is made up of a name and some references to indicate the cell we want to store or read data from. We are going to call our first array 'bg' as it is our background array, and we will give it a column called 'c' as it will store our background colour. So, in SmallBasic this looks like...

    bg["c"]="WhiteSmoke"

    What we have created above is called a 1D (one dimensional) array, because it only has one reference (called 'c'). To allow us to store more than one colour, we must turn it into a 2D array, which would be...

    bg[1]["c"]="WhiteSmoke"

    Now we have a row (1) and a column (c) reference which contains our colour value (WhiteSmoke). You can see that the number of dimensions an array has is indicated by the number of square bracket pairs [] that are used. We can easily add another colour now by adding a second row...

    bg[1]["c"]="WhiteSmoke"

    bg[2]["c"]="RoyalBlue"

    Note that array references can be either numeric or textual. The benefit of using numerical references is that your program can use a loop to run through them, while text references make it easier for us humans to understand. Using a loop, we could for example display the two colour names stored in our array...

    For myLoop=1 to 2

        textwindow.writeline("Colour in row " + myLoop + " is: " + bg[myLoop]["c"] )

    EndFor

    Our loop example above uses the loop variable (myLoop) to access our array and pull out the value stored in column c (ie. bg[myLoop]["c"] )

    OK, that's enough on arrays and loops to move you forward in shortening your program which I'll cover in the next post.

     

    Sunday, April 25, 2010 1:25 PM
  • Capati,

    Yes, you will have to draw all the boxes exactly the same size. 

    As an 'example', change your allBox sub to...

     

    Sub allBox

      cellrow=Math.Floor( (ypos-21)/40 ) 

      cellcol=Math.Floor( (xpos-23)/40 ) 

      cellx = 23 + ( cellcol * 40 )

      celly = 21 + (cellrow * 40 )

      GraphicsWindow.Title="row="+cellrow+" col="+cellcol

     

     

      LineOne = cellrow * 9 + cellcol+1


     

      GraphicsWindow.PenWidth = 2

      GraphicsWindow.PenColor = "Blue"

      GraphicsWindow.DrawRectangle(cellx, celly, 40, 40)

    Endsub

     

    Note: I am assuming above that all cells are 40x40 pixels, which they aren't at the moment. The 21 and 23 is the x,y of the top left cell as it currently stands. I've put the LineOne setting in there so that your keypress sub keeps working for now - we won't need it once we sort the keypress sub out.

    You can also delete all your selectBox subs if you use the above allBox sub.

    Let me know the ID when you've tidied up your grid.

    If you want to have a go at removing the straggling blue boxes, you need to keep track of the previously selected cell, then redraw that cell before drawing the new blue box at the cell just clicked.

    Wednesday, April 28, 2010 8:25 PM
  • Now we can begin to get rid of the fBox#() subs by creating an array to hold the box values. The easiest way to do this is to create a sub that will populate our array. Later on, this will make it easy to create other games and levels.

    We need a 2D array to hold the 9 rows and 9 columns of our game grid. Here's the first row as an example, containing the initial values...

     

     

    Sub createBoxes

      box[1][1]=""

      box[1][2]=""

      box[1][3]="4"

      box[1][4]="9"

      box[1][5]="1"

      box[1][6]=""

      box[1][7]=""

      box[1][8]=""

      box[1][9]=""

      etc. up to...

      box[9][9]=""

    EndSub



    Because SmallBasic lets us create 2D arrays in a short format, we can instead do...


    Sub createBoxes
      box[1]="1=;2=;3=4;4=9;5=1;6=;7=;8=;9=;"
      box[2]=""
      box[3]=""
      box[4]=""
      box[5]=""
      box[6]=""
      box[7]=""
      box[8]=""
      box[9]=""
    EndSub


    Also, because SmallBasic doesn't need us to define our variables (or arrays) before we use them, we can shorten it even further and only fill in the bits that actually contain values...


    Sub createBoxes
      box[1]="3=4;4=9;5=1;"
    EndSub


    Put the above sub in your program somewhere. Now that we have an array containing the grid values, we need to display them. As we already have a Sub that displays the game grid (drawGrid), we may as well use that to display the grid values as well.

    Taking the contents of one of your fBox#() Subs, we need to take the following lines...

      GraphicsWindow.FontSize = 25
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawText(34,22, box1)

    And change them a bit so that the x and y values are calculated from the two loops (gLwpC and gLwpR), and take the value out of our box[] array...


            GraphicsWindow.FontSize = 25
            GraphicsWindow.BrushColor = "Black"
            GraphicsWindow.DrawText( gridLeft+gLwpC*boxSize+offsetX+(boxSize/3), gridTop+gLwpR*boxSize+offsetY+(boxSize/3), box[gLwpR+1][gLwpC+1] )


    Let's break that DrawText line down a bit.  We are taking the x and y position of the box being drawn ( gridLeft+gLwpC*boxSize+offsetX ) then adding another third of the box size to it... +(boxSize/3) which gives us a position somewhere in the box to display the text.

    This leaves us with a drawGrid() sub like this...

    Sub drawGrid
     gridTop=23
     gridLeft=20
     boxSize=57
     
     GraphicsWindow.PenColor="Black"
     
     ' draw the outer box
     GraphicsWindow.PenWidth=2
     GraphicsWindow.DrawRectangle(gridLeft-2,gridTop-2,8+boxSize*9,8+boxSize*9)
     
     ' draw the grid
     GraphicsWindow.PenWidth=2
     For gLwpR = 0 to 8 ' 9 cells high
     For gLwpC = 0 To 8 ' 9 cells wide
      ' calculate offsets to give us a small gap every 3 boxes to make the borders appear heavier
      offsetX = 2 * math.floor(gLwpC/3)
      offsetY = 2 * math.floor(gLwpR/3)
      
      GraphicsWindow.BrushColor="White"
      GraphicsWindow.FillRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
      GraphicsWindow.DrawRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
      
      ' display the cell contents
      GraphicsWindow.FontSize = 25
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawText(gridLeft+gLwpC*boxSize+offsetX+(boxSize/3), gridTop+gLwpR*boxSize+offsetY+(boxSize/3), box[gLwpR+1][gLwpC+1])
      
     EndFor
     EndFor
    EndSub

    The final thing to do to test this is to put a call to the new createBoxes() sub near the top of your program. I recommend putting it just before the call to initially draw the grid...

    'Load  Grid
    'grid = ImageList.LoadImage(Dir + "\images\grid.bmp")
    'GraphicsWindow.DrawImage(grid, 20, 20)
    createBoxes()
    drawGrid()


    That's it for now. Let me know when you've got it working. You can now delete all the fBox#() subs (also take them out of your KepPress sub) and get rid of box1, box2, box3, etc. variables.

    You should be able to re-write your KeyPress sub now to put the relevant keypresses into the box[] array. See how you get on.

     

    Tuesday, May 4, 2010 11:15 PM

All replies

  • Hi Capati,

    That's some good work you've done so far and I look forward to seeing the finished thing. I'm happy to help you with making it shorter but we will have to take it a step at a time.

    Your approach so far is typical of learning to program, and as we work through changing it from its current format to a more condensed one I think it will work as a very good example to other new programmers. At the moment you have taken a very logical but very linear approach to writing your game, which is a natural and good thing to do, but ends up being very long as you've discovered.

    The next stage in advancing your programming skills is to take what you have and look for similar parts of your code that are repeated more than once. Once we have a section that is repeated, we can start building sub-routines. This is what we will do to simplify and shorten your program.

    Saturday, April 24, 2010 9:28 AM
  • To begin, we should simplify your ClickbgColor subroutine and change its name to something more appropriate.

    First of all, I recommend renaming your Sub from ClickbgColor to MouseClicks to represent its main purpose.

    Next, we will simplify the section of code that changes the background colour. Add the following three lines just after your 'Cor do fundo comment...

     

      if (xpos > 420 and xpos < 528) And (ypos > 60 And ypos < 160) then

        setBackground()

      endif


    Now move all of your code to do with setting the background (everything down to 'Iniciar o Timer) into a new subroutine called setBackground. (Make sure you put this new subroutine outside of the MouseClicks one.)

    It's best you do it yourself, but I have published a version with these changes as: FDB098 (http://smallbasic.com/program/?FDB098)

    Now you need to repeat this for the other sections in MouseClicks (Iniciar o Timer, Cor da grade, Select Box) which will give you a much clearer event subroutine and make it easier for us to work on each section later.

    Publish the code when you've done that and well move on to the next bit.

    Saturday, April 24, 2010 9:47 AM
  • Thank you very much, I will publish as soon as I finished.
    Saturday, April 24, 2010 6:53 PM
  • Here the changes: (SWT064)

    http://smallbasic.com/program/?SWT064

    Sorry for my english, I translated all comments to english.

    Wainting for your help to continue the step. Thanks again.

    Saturday, April 24, 2010 8:26 PM
  • Well done. Now that we have things split into their subs we can work on reducing them a bit. To do that we need to introduce Arrays and Loops. You may already understand arrays, but for others that don't I'll talk about them first...

    If you have used a Spreadsheet program of any sort, then you will be familiar with what is called a 2D (two dimensional) array. You can think of it like a grid split up with rows and columns. (See the image at the top of this page as an example: http://home.earthlink.net/~cassidyny/spreadsheet.htm)

    An array, like a spreadsheet, lets you store data in each of its cells. The difference between a spreadsheet and an array is that an array would reference the first cell as 1A (row first, then column), while the spreadhseet example references it as A1. When your data is stored in this grid (array) format, instead of individual variables, the computer can get at it much easier and you can shorten your code quite a bit.

    I'll start you off by giving an example how to use a 2D array in SmallBasic then we will use it later to shorten your new setBackground() sub.

    An array is made up of a name and some references to indicate the cell we want to store or read data from. We are going to call our first array 'bg' as it is our background array, and we will give it a column called 'c' as it will store our background colour. So, in SmallBasic this looks like...

    bg["c"]="WhiteSmoke"

    What we have created above is called a 1D (one dimensional) array, because it only has one reference (called 'c'). To allow us to store more than one colour, we must turn it into a 2D array, which would be...

    bg[1]["c"]="WhiteSmoke"

    Now we have a row (1) and a column (c) reference which contains our colour value (WhiteSmoke). You can see that the number of dimensions an array has is indicated by the number of square bracket pairs [] that are used. We can easily add another colour now by adding a second row...

    bg[1]["c"]="WhiteSmoke"

    bg[2]["c"]="RoyalBlue"

    Note that array references can be either numeric or textual. The benefit of using numerical references is that your program can use a loop to run through them, while text references make it easier for us humans to understand. Using a loop, we could for example display the two colour names stored in our array...

    For myLoop=1 to 2

        textwindow.writeline("Colour in row " + myLoop + " is: " + bg[myLoop]["c"] )

    EndFor

    Our loop example above uses the loop variable (myLoop) to access our array and pull out the value stored in column c (ie. bg[myLoop]["c"] )

    OK, that's enough on arrays and loops to move you forward in shortening your program which I'll cover in the next post.

     

    Sunday, April 25, 2010 1:25 PM
  • In your setBackground sub, you can see that you have lots of repeated If...Then statements to check if the mouse is over a particular colour box. You can shorten this significantly by using an array to store the colour and position of your boxes, then use a loop to check which one the mouse has clicked on (if any).

    Our array this time needs three columns - one for the colour, one for the x, and one for the y of each colour box. Create this array just inside the setBackground sub...

     

    Sub setBackground

       bg[1]["c"]="WhiteSmoke"

       bg[1]["x"]="420"

       bg[1]["y"]="60"

     

    You can see from above that we are only using one row [1] in our array to store all the values related to that row (c, x and y). The x and y values relate to the x and y position for the top left corner of each colour box on screen (which I took from your If statements).  Let's show the code after we've added the second background colour...

     

     

    Sub setBackground

       bg[1]["c"]="WhiteSmoke"

       bg[1]["x"]="420"

       bg[1]["y"]="60"

     

       bg[2]["c"]="RoyalBlue"

       bg[2]["x"]="465"

       bg[2]["y"]="60"



    That's enough as an example. Now we can introduce the For loop, which will check if our mouse click happened to be on one of the background colours.  Put this loop code directly after the array code shown above...


      For bgLoop=1 to 2
        If (xpos > bg[bgLoop]["x"] And xpos < bg[bgLoop]["x"] + 20) Then
          If (ypos > bg[bgLoop]["y"] And ypos < bg[bgLoop]["y"]+20) Then
            GraphicsWindow.BackgroundColor = bg[bgLoop]["c"]
          EndIf
        EndIf
      EndFor



    Because we have only created two rows in our array, our loop only counts from 1 to 2. You can see that the If statements are identical to the ones you are already using, except that we are taking our numbers out of the array cells instead of typing them directly in the If statement.

    By doing this we have created one loop that can check any number of array entries without making our code longer. After typing the code into your setBackground sub, remember to delete (or comment out) your first two If...EndIf blocks.

    I'm sure you can see how to shorten your code further by creating more entries in your bg array?

    One other note about arrays. SmallBasic has a shortcut method to create each row, which you could use to shorten your program even further. The bg array above could be written as shown below if you prefer. As far as the computer is concerned, it will still create a 2D array identical to the one created by the code above. If this is too complicated, stick with the code above...

    bg[1]="c=WhiteSmoke;x=420;y=60"
    bg[2]="c=RoyalBlue;x=465;y=60"

    Let me know the ID when you've shortened your setBackground sub. (If you're feeling ambitious, you will notice that your gridColor and your allBox subs have very similar repetitions and you may want to have a go at shortening those subs using an array and a loop too!)

     

     

    • Edited by Davey-Wavey Monday, April 26, 2010 9:07 AM Removed spaces after semicolons in shortcut example.
    Sunday, April 25, 2010 2:05 PM
  • Thanks Davey-Wavey. nice explanation the use of arrays.

    I did that with the short array example. My code was like this:

     bg[1]="c=WhiteSmoke; x=420; y=60"
     bg[2]="c=RoyalBlue; x=465; y=60" 
     bg[3]="c=IndianRed; x=508; y=60"
     bg[4]="c=Tomato; x=420; y=100"
     bg[5]="c=SeaGreen; x=465; y=100"
     bg[6]="c=Orchid; x=508; y=100"
     bg[7]="c=Gold; x=420; y=140"
     bg[8]="c=Gray; x=465; y=140"
     bg[9]="c=Chocolate; x=508; y=140"
     
     For bgLoop = 1 to 9
     If (xpos > bg[bgLoop]["x"] And xpos < bg[bgLoop]["x"] + 20) Then
     If (ypos > bg[bgLoop]["y"] And ypos < bg[bgLoop]["y"] + 20) Then
     GraphicsWindow.BackgroundColor = bg[bgLoop]["c"]
     endif
     EndIf
     endfor

    But it did not work, the color not change. Only the big array worked:

     bg[1]["c"]="WhiteSmoke"
     bg[1]["x"]="420"
     bg[1]["y"]="60"
     bg[2]["c"]="RoyalBlue"
     bg[2]["x"]="465"
     bg[2]["y"]="60"
     bg[3]["c"]="IndianRed"
     bg[3]["x"]="508"
     bg[3]["y"]="60"
     bg[4]["c"]="Tomato"
     bg[4]["x"]="420"
     bg[4]["y"]="100"
     bg[5]["c"]="SeaGreen"
     bg[5]["x"]="465"
     bg[5]["y"]="100"
     bg[6]["c"]="Orchid"
     bg[6]["x"]="508"
     bg[6]["y"]="100"
     bg[7]["c"]="Gold"
     bg[7]["x"]="420"
     bg[7]["y"]="140"
     bg[8]["c"]="Gray"
     bg[8]["x"]="465"
     bg[8]["y"]="140"
     bg[9]["c"]="Chocolate"
     bg[9]["x"]="508"
     bg[9]["y"]="140"
     
     For bgLoop = 1 to 9
     If (xpos > bg[bgLoop]["x"] And xpos < bg[bgLoop]["x"] + 20) Then
     If (ypos > bg[bgLoop]["y"] And ypos < bg[bgLoop]["y"] + 20) Then
     GraphicsWindow.BackgroundColor = bg[bgLoop]["c"]
     endif
     EndIf
     endfor

     

    There a problem with the shortcut method?

     

    Monday, April 26, 2010 12:55 AM
  • Multi-dimensional arrays are a bit tricky to write as a string.

    Try TextWindow.Write(bg) to see how your multi-dimensional array is written as a string in Small Basic.

    Something like this output:
    "1=c\=WhiteSmoke\;x\=420\;y\=60\;;2=c\=RoyalBlue\;x\=465\;y\=60\;;3=c\=IndianRed\
    ;x\=508\;y\=60\;;4=c\=Tomato\;x\=420\;y\=100\;;5=c\=SeaGreen\;x\=465\;y\=100\;;6
    =c\=Orchid\;x\=508\;y\=100\;;7=c\=Gold\;x\=420\;y\=140\;;8=c\=Gray\;x\=465\;y\=1
    40\;;9=c\=Chocolate\;x\=508\;y\=140\;;"

    Single Dimension arrays can be written like this

    bgColor="1=WhiteSmoke;2=RoyalBlue;3=IndianRed;4=Tomato;5=SeaGreen;6=Orchid;7=Gold;8=Gray;9=Chocolate;"
    bgX="1=420;2=465;3=508;4=420;5=465;6=508;7=420;8=465;9=508;"
    bgY="1=60;2=60;3=60;4=100;5=100;6=100;7=140;8=140;9=140;"
    
    For bgLoop = 1 to 9
     GraphicsWindow.DrawRectangle(bgX[bgLoop],bgY[bgLoop],20,20)
    endfor
    GraphicsWindow.MouseDown = OnMouseDown
    
    Sub OnMouseDown
     xpos = GraphicsWindow.MouseX
     ypos = GraphicsWindow.MouseY
     
     For bgLoop = 1 to 9
      If (xpos > bgX[bgLoop] And xpos < bgX[bgLoop] + 20) Then
       If (ypos > bgY[bgLoop] And ypos < bgY[bgLoop] + 20) Then
        GraphicsWindow.BackgroundColor = bgColor[bgLoop]
       endif
      EndIf
     endfor
    EndSub
    

     

    Monday, April 26, 2010 2:35 AM
  • Thanks Davey-Wavey. nice explanation the use of arrays.

    I did that with the short array example. My code was like this:

     bg[1]="c=WhiteSmoke; x=420; y=60"
     bg[2]="c=RoyalBlue; x=465; y=60" 
     bg[3]="c=IndianRed; x=508; y=60"
     bg[4]="c=Tomato; x=420; y=100"
     bg[5]="c=SeaGreen; x=465; y=100"
     bg[6]="c=Orchid; x=508; y=100"
     bg[7]="c=Gold; x=420; y=140"
     bg[8]="c=Gray; x=465; y=140"
     bg[9]="c=Chocolate; x=508; y=140"
    

    There a problem with the shortcut method?

     

    Capati, sorry for the confusion, it's a problem with my typing rather than the shortcut method, although note that the shortcut method is undocumented in SmallBasic and it may stop working as the program develops in later versions.

    The problem was due to me trying to keep the example code clear by putting spaces after the semicolons. To make it work, just take out the spaces...

     

    bg[1]="c=WhiteSmoke;x=420;y=60"
    bg[2]="c=RoyalBlue;x=465;y=60" 
    bg[3]="c=IndianRed;x=508;y=60"
    bg[4]="c=Tomato;x=420;y=100"
    bg[5]="c=SeaGreen;x=465;y=100"
    bg[6]="c=Orchid;x=508;y=100"
    bg[7]="c=Gold;x=420;y=140"
    bg[8]="c=Gray;x=465;y=140"
    bg[9]="c=Chocolate;x=508;y=140"

     

    Monday, April 26, 2010 9:06 AM
  • Multi-dimensional arrays are a bit tricky to write as a string.

    Try TextWindow.Write(bg) to see how your multi-dimensional array is written as a string in Small Basic.

    Something like this output:
    "1=c\=WhiteSmoke\;x\=420\;y\=60\;;2=c\=RoyalBlue\;x\=465\;y\=60\;;3=c\=IndianRed\
    ;x\=508\;y\=60\;;4=c\=Tomato\;x\=420\;y\=100\;;5=c\=SeaGreen\;x\=465\;y\=100\;;6
    =c\=Orchid\;x\=508\;y\=100\;;7=c\=Gold\;x\=420\;y\=140\;;8=c\=Gray\;x\=465\;y\=1
    40\;;9=c\=Chocolate\;x\=508\;y\=140\;;"

    Single Dimension arrays can be written like this

    bgColor="1=WhiteSmoke;2=RoyalBlue;3=IndianRed;4=Tomato;5=SeaGreen;6=Orchid;7=Gold;8=Gray;9=Chocolate;"
    bgX="1=420;2=465;3=508;4=420;5=465;6=508;7=420;8=465;9=508;"
    bgY="1=60;2=60;3=60;4=100;5=100;6=100;7=140;8=140;9=140;"
    

    Rush, you're right, 2D arrays are a bit tricky because you have to escape (add a \ before) all the second dimension elements...

    bg="1=c\=WhiteSmoke\;x\=420\;y\=60\;;2=c\=RoyalBlue\;x\=465\;y\=60\;;3=c\=IndianRed\;x\=508\;y\=60\;"

     

    As you say, 1D arrays are simpler because the don't need the \...

    bg="c=WhiteSmoke;x=420;y=60;"

     

    To simplify it and keep the lines short for Capati, I was building a 1D array in the format of...

    bg[1]=""

    and putting another 1D array into it...

    bg[1]="c=WhiteSmoke;x=420;y=60;"

     

    SmallBasic then quite nicely does all the escaping ( \ ) and gives us a proper 2D array while keeping the code and explanation fairly simple.

     

    Thanks for the alternative example of the three 1D arrays and the For...Next loop though, it highlights the method of using multiple 1D arrays instead of the slightly more complex 2D arrays. The choice then is down to programmer preference.

    Monday, April 26, 2010 9:39 AM
  • Thanks for all help, cutting the spaces works now.

    I did the same with the GridColor. Here the code:

    http://smallbasic.com/program/?ZDX706

    Now, I need shorten the allBox (select, clear, show all boxes values and typing a number..

    I will do now, I publish when done. But, if they have any tips, I appreciate.

    Monday, April 26, 2010 9:52 PM
  • Capati,

    Start with your box1, box2...box10 variables and think about them as an array. Notice that the sudoku grid itself looks very much like an array structure, containing 9 rows and 9 columns, so depending on how far away from the top-left corner of the sudoku grid the mouse was clicked you can use a bit of maths to calculate which row and column matches the cell that was clicked.

    Using an array to store the entered values, you will be able to get rid of all your fbox1...fbox10 Sub's and condense them into a single fbox sub.

    See how you get on. Brain's too tired tonight to dig up an example. Will come back to it tomorrow.

    Monday, April 26, 2010 10:21 PM
  • Capati,

    For now, ignore my suggestions in the post above (did I mention I was tired ;). We'll get to that in a little while.

    Had a bit more of a look at the allBox sub now.  Without causing any real problems, you can remove all the GraphicsWindow lines and all the fbox() lines, the deletebox line and the If statement from all of the sections within allBox.

    This leaves each section looking like...

     

     

      If (xpos > 23 And xpos < (23 + 37)) then

        If (ypos > 21 And ypos < (21 + 35)) Then

          LineOne = 1

          SelectBox1()

        EndIf

      EndIf


    The only detrimental effect of doing this is that the blue selection boxes are not removed when a new box is clicked. This will be easy to solve once we condense all the SelectBox subs down into a single sub, so we won't worry about the extra selection boxes for now.

    Once you've done that, it's much easier to see what is actually happening. Now you can think about doing some maths to calculate which cell on the game grid has been clicked. Do the maths calculation just after the Sub allBox line before the first If (xpos) line. You need to calculate the x and y value for the top-left corner of the cell that was clicked.

     

    Tuesday, April 27, 2010 10:38 AM
  • Hey Davey-Wavey, do you have a exemple to calculate, just to I start. I need to calculate each box and create a FillRectangle to clear each box too? I think I have to adjust the grid, because all boxes don't have the same size. So, with a Loop For, I can create all rectangles to clear all boxes, less the last selected? Without have to create one by one to each box. Just use arrays too?
    Tuesday, April 27, 2010 10:08 PM
  • Capati,

    Yes, you will have to draw all the boxes exactly the same size. 

    As an 'example', change your allBox sub to...

     

    Sub allBox

      cellrow=Math.Floor( (ypos-21)/40 ) 

      cellcol=Math.Floor( (xpos-23)/40 ) 

      cellx = 23 + ( cellcol * 40 )

      celly = 21 + (cellrow * 40 )

      GraphicsWindow.Title="row="+cellrow+" col="+cellcol

     

     

      LineOne = cellrow * 9 + cellcol+1


     

      GraphicsWindow.PenWidth = 2

      GraphicsWindow.PenColor = "Blue"

      GraphicsWindow.DrawRectangle(cellx, celly, 40, 40)

    Endsub

     

    Note: I am assuming above that all cells are 40x40 pixels, which they aren't at the moment. The 21 and 23 is the x,y of the top left cell as it currently stands. I've put the LineOne setting in there so that your keypress sub keeps working for now - we won't need it once we sort the keypress sub out.

    You can also delete all your selectBox subs if you use the above allBox sub.

    Let me know the ID when you've tidied up your grid.

    If you want to have a go at removing the straggling blue boxes, you need to keep track of the previously selected cell, then redraw that cell before drawing the new blue box at the cell just clicked.

    Wednesday, April 28, 2010 8:25 PM
  • Sorry for the time, but I recreated the layout of the program and finished that part of the selection boxes ( maybe I need to make some adjustments ). I made the grid as an image, and now the boxes have the same size. I created a new panel as well, but without the color option of the grid, the white will be the default.

    Later I will add option to choose the difficulty and start a new grid.

    You can download the new version:

    http://www.mediafire.com/?mvjomy0mbyz

    What did you think of the changes?

    Thanks for continuing to help in my program, now comes the typing of numbers?

    Tuesday, May 4, 2010 12:55 AM
  • Looking good with the new graphics. Unfortunately the grid squares still aren't the same size, but I recommend drawing the grid in SmallBasic anyway to ensure it is consistent and takes up less memory.

    I suggest changing the part that loads the grid graphic to... (you can delete the old commented lines if you like)...

     

    'Load Grid
    'grid = ImageList.LoadImage(Dir + "\images\grid.bmp")
    'GraphicsWindow.DrawImage(grid, 20, 20)
    
    drawGrid()
    
    Sub drawGrid
     gridTop=23
     gridLeft=20
     boxSize=57
     
     GraphicsWindow.PenColor="Black"
     
     ' draw the outer box
     GraphicsWindow.PenWidth=2
     GraphicsWindow.DrawRectangle(gridLeft-2,gridTop-2,8+boxSize*9,8+boxSize*9)
     
     ' draw the grid
     GraphicsWindow.PenWidth=2
     For gLwpR = 0 to 8 ' 9 cells high
     For gLwpC = 0 To 8 ' 9 cells wide
      ' calculate offsets to give us a small gap every 3 boxes to make the borders appear heavier
      offsetX = 2 * math.floor(gLwpC/3)
      offsetY = 2 * math.floor(gLwpR/3)
      
      GraphicsWindow.BrushColor="White"
      GraphicsWindow.FillRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
      GraphicsWindow.DrawRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
     EndFor
     EndFor
    EndSub
    

     

    Then change your allBox() sub to...

     

    'Sub (Select the box)
    Sub allBox
     
     ' Note: gridTop, gridLeft and boxSize vars have already been defined in the drawGrid() sub
     cellrow=Math.Floor( (ypos-gridTop)/boxSize ) 
     cellcol=Math.Floor( (xpos-gridLeft)/boxSize ) 
     cellx = gridLeft + ( cellcol * boxSize )
     celly = gridTop + ( cellrow * boxSize )
     
     Cell = cellrow * 9 + cellcol+1
     
     ' remove previous selection rectangle
     drawGrid()
     
     ' calculate offsets to allow for the thicker lines every 3 squares
     offsetX = 2+ 2*math.floor(cellcol/3) ' add 2 to move selection box inside grid square
     offsetY = 2+ 2*math.floor(cellrow/3)
     
     GraphicsWindow.PenWidth = 3
     GraphicsWindow.PenColor = "Blue"
     GraphicsWindow.DrawRectangle(cellx+offsetX, celly+offsetY, boxSize-4, boxSize-4)
     
    Endsub
    

     

    I also recommend you change the name of your allBox() sub to something more relevant now, like selectBox()

     

    I like the new difficulty option. When we convert box1, box2, etc. into an array (see next post) it will be easy to set up the different difficulty grids.

     

    Tuesday, May 4, 2010 7:04 PM
  • Now we can begin to get rid of the fBox#() subs by creating an array to hold the box values. The easiest way to do this is to create a sub that will populate our array. Later on, this will make it easy to create other games and levels.

    We need a 2D array to hold the 9 rows and 9 columns of our game grid. Here's the first row as an example, containing the initial values...

     

     

    Sub createBoxes

      box[1][1]=""

      box[1][2]=""

      box[1][3]="4"

      box[1][4]="9"

      box[1][5]="1"

      box[1][6]=""

      box[1][7]=""

      box[1][8]=""

      box[1][9]=""

      etc. up to...

      box[9][9]=""

    EndSub



    Because SmallBasic lets us create 2D arrays in a short format, we can instead do...


    Sub createBoxes
      box[1]="1=;2=;3=4;4=9;5=1;6=;7=;8=;9=;"
      box[2]=""
      box[3]=""
      box[4]=""
      box[5]=""
      box[6]=""
      box[7]=""
      box[8]=""
      box[9]=""
    EndSub


    Also, because SmallBasic doesn't need us to define our variables (or arrays) before we use them, we can shorten it even further and only fill in the bits that actually contain values...


    Sub createBoxes
      box[1]="3=4;4=9;5=1;"
    EndSub


    Put the above sub in your program somewhere. Now that we have an array containing the grid values, we need to display them. As we already have a Sub that displays the game grid (drawGrid), we may as well use that to display the grid values as well.

    Taking the contents of one of your fBox#() Subs, we need to take the following lines...

      GraphicsWindow.FontSize = 25
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawText(34,22, box1)

    And change them a bit so that the x and y values are calculated from the two loops (gLwpC and gLwpR), and take the value out of our box[] array...


            GraphicsWindow.FontSize = 25
            GraphicsWindow.BrushColor = "Black"
            GraphicsWindow.DrawText( gridLeft+gLwpC*boxSize+offsetX+(boxSize/3), gridTop+gLwpR*boxSize+offsetY+(boxSize/3), box[gLwpR+1][gLwpC+1] )


    Let's break that DrawText line down a bit.  We are taking the x and y position of the box being drawn ( gridLeft+gLwpC*boxSize+offsetX ) then adding another third of the box size to it... +(boxSize/3) which gives us a position somewhere in the box to display the text.

    This leaves us with a drawGrid() sub like this...

    Sub drawGrid
     gridTop=23
     gridLeft=20
     boxSize=57
     
     GraphicsWindow.PenColor="Black"
     
     ' draw the outer box
     GraphicsWindow.PenWidth=2
     GraphicsWindow.DrawRectangle(gridLeft-2,gridTop-2,8+boxSize*9,8+boxSize*9)
     
     ' draw the grid
     GraphicsWindow.PenWidth=2
     For gLwpR = 0 to 8 ' 9 cells high
     For gLwpC = 0 To 8 ' 9 cells wide
      ' calculate offsets to give us a small gap every 3 boxes to make the borders appear heavier
      offsetX = 2 * math.floor(gLwpC/3)
      offsetY = 2 * math.floor(gLwpR/3)
      
      GraphicsWindow.BrushColor="White"
      GraphicsWindow.FillRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
      GraphicsWindow.DrawRectangle( gridLeft+gLwpC*boxSize+offsetX, gridTop+gLwpR*boxSize+offsetY, boxSize, boxSize )
      
      ' display the cell contents
      GraphicsWindow.FontSize = 25
      GraphicsWindow.BrushColor = "Black"
      GraphicsWindow.DrawText(gridLeft+gLwpC*boxSize+offsetX+(boxSize/3), gridTop+gLwpR*boxSize+offsetY+(boxSize/3), box[gLwpR+1][gLwpC+1])
      
     EndFor
     EndFor
    EndSub

    The final thing to do to test this is to put a call to the new createBoxes() sub near the top of your program. I recommend putting it just before the call to initially draw the grid...

    'Load  Grid
    'grid = ImageList.LoadImage(Dir + "\images\grid.bmp")
    'GraphicsWindow.DrawImage(grid, 20, 20)
    createBoxes()
    drawGrid()


    That's it for now. Let me know when you've got it working. You can now delete all the fBox#() subs (also take them out of your KepPress sub) and get rid of box1, box2, box3, etc. variables.

    You should be able to re-write your KeyPress sub now to put the relevant keypresses into the box[] array. See how you get on.

     

    Tuesday, May 4, 2010 11:15 PM