I'm writing a simple game and have run into a coding issue.
I have 15 buttons on a form. As part of the game, you click the buttons to essentially move them around.
After each click, I run a subroutine to check if the user has "won" the game.
In order to check for a win condition, I check to make sure each of the 15 buttons are in the right location on the form.
This has caused me to have an "if statement" mess of code. The way I wrote it is like this:
Private Sub CheckWin() If ESX = 114 And ESY = 139 Then 'Initial check for empty square If B1.Top = 28 And B2.Top = 28 And B3.Top = 28 And B4.Top = 28 And B1.Left = 3 And B2.Left = 40 And B3.Left = 77 And B4.Left = 114 Then If B5.Top = 65 And B6.Top = 65 And B7.Top = 65 And B8.Top = 65 And B5.Left = 3 And B6.Left = 40 And B7.Left = 77 And B8.Left = 114 Then If B9.Top = 102 And B10.Top = 102 And B11.Top = 102 And B12.Top = 102 And B9.Left = 3 And B10.Left = 40 And B11.Left = 77 And B12.Left = 114 Then If B13.Top = 139 And B14.Top = 139 And B15.Top = 139 And B13.Left = 3 And B14.Left = 40 And B15.Left = 77 ThenMsgBox( "You Win!") End If End If End If End If End If End Sub |
As you can see, it looks like a mess. I didn't really have to make 5 IF statements, I could have just had one super long AND AND AND AND AND. But I figured if I do it this way, if the first IF fails, it will exit and not do every check, thus saving a smidgeon of processing time.
However, I know it's good programming practice to not have more then 2 or 3 embeded if statements.
So then, with less code, how can I make sure the left and top attributes of 15 buttons match my requirements for a win condition
Keep in mind, I'm ok using it this way, but eventually I may have a bigger layout and thus a lot more buttons, it could get messy.
Thanks all, this is my first post here!
(P.S. for a little more info. Note that each set of 4 buttons has the same TOP. So B1 - B4 are 28; B5-B8 are 65; etc... Also each 4 going down the grid, have the same LEFT. So B1,B5,B9,B13 are 3; B2,6,10,14 are 40; etc... So in other words, it is a perfect "table" of 4x4. The bottom right cell will be empty, thus the very first IF statement to check that.)
And with all this info, can you guess what game I'm making :)

Any way to trim all these IF statements?
khandar
Another take on this: rather than checking all of these locations at the end, you could simply track the changes as they happen as bits in a UShort. You presumably are handling some event which “moves” the buttons. You can detect then and there if a given square is in the right stop and, if so, set an appropriate value (or clear it, if it is not in the right place). SO for example, in your fourth button:
If B4.Top = 28 Then
Me.TrackingUShort = TrackingUShort Or 1 << 3 ‘ Shift this three spaces to be in the "4" spot
Else
Me.TrackingUShort = TrackingUShort And Not 1 << 3
End If
And do this for each handler, changing the bit being set appropriately. Then, at the end, you could just check for Me.TrackingUShort = &H7FFF (i.e., all 15 slots set to true) – if that’s a true statement, then everything is in place.
--Matt Gertz--*
VB Compiler Dev Lead
m.zirino
Dim
tic As Integer = 0 For i = 1 To 15 If Not ctrl(i).location = Pos(i) Then Exit Sub Else tic = tic + 1 Next i If tic = 15 ThenButtonBar.Items(0).Image = Images.Images(1)
ButtonBar.Items(0).Enabled =
False My.Computer.Audio.Play(My.Resources.win, AudioPlayMode.Background)MsgBox(
"you win'd") End IfThe next question of mine, has to do with program resources, of the CPU/RAM kind.
The last suggestion there, about using a 15 point counter, I've thought about that. Also not knowing how to implement it. So the question then becomes a matter of resources and CPU time.
Think of it this way. This is just for fun, because I highly doubt it has much impact on my little game.
But anyhoo, compare the two methods with each other.
Using this point method, I've got all kinds of variables, I've got the declaration of the collection, as well as 16 declarations for each point. Then I create the collection and add each point variable into the collection. This is a lot of variables and also extra code for creating the collection in the first place. On the other hand, having my points as variables let's me easily change them if I ever make different sizes etc..without hard coding the point values like I had before.
BUT, using the counter system as in the last suggestion, is there less overhead and code setting that up Is it less processing to check a single block on each click, and set a marker, versus checking ALL blocks on every click It would seem obvious, but I'm not so sure.
What do you guys think I should do Stick with the loop and collections Or try the marker system
(P.S. when this is over I'll let you all download my awesome new game. lol)
Dennis G.
I think the easiest and cleanest way to accomplish your goal would be to inherit the button class.
I would then add the following:
Private _LocID as Nullable(Of Integer)
Public Property LocID() as Nullable(Of Integer)
Get
Return _LocID
End Get
Set(ByVal value As Nullable(Of Integer)
_LocID = value
End Set
End Property
Public Function IsInPlace() as Booleen
If Not LocID().HasValue Then Return False
If LocID() = Me.Top
Return True
Else
Return False
End If
End Function
In the code for the form you could have your win condition checker run through like this:
Private _Winner as Booleen = True
Private Property Winner() as Booleen
Private Function IsWinner() as Booleen
If Not Button1.IsInPlace() Then Return False
If Not Button2.IsInPlace() Then Return False
If Not Button3.IsInPlace() Then Return False
If Not Button4.IsInPlace() Then Return False
Return True
End Function
The easiest way ever is to create a Component that you select an array of generic buttons with those properties and have the code behind check the status. (Just like a validation checker). I have some code laying around somewhere that does just something like that I just can't find it. If I do I'll be sure to shoot it up.
Drickus
Dim
MyLocation1 As New Point(3, 28)Dim MyLocation2 as New Point(40,28)
If Me.Button1.Location = MyLocation1 And Me.Button2.Location =MyLocation2 Then
messagebox.show("You Win")
End If
Newbe
This isn't really related to your question, but that quote made me wonder...
At least in C, if you have several AND or OR statements inside an IF, it only checks the necessary conditions to tell if that statement is true or false.
For instance, imagine you have
If (Condition1 and Condition2)
In C, if Condition1 returned false, it wouldn't even evaluate Condition2.
Likewise for OR - if Condition1 was true, even if Condition2 was false it would "enter" the if clause, and as such it wouldn't even evaluate Condition2.
Does anybody know if the same is true for VB.Net
Thanks!
Kunle
Dman1- I've never heard of that function, is that new to .NET If that works, it would certainly trim some of the code, but essentially would be doing the same thing. Which is fine, but less code is good for me. I will give that a try tonight and see what happens. Thanks.
I was also wondering, then, if this could be used in a loop, rather then as a long IF statement. Can your function, along with my collection, be iterated through
So instead of "If btn(0).location = xx AND btn(1).location = xx.....". Maybe could I loop through it if the counters match Like maybe:
For i = 0 to 14
if not btn(i).location = loc(i) then
exit sub
else
you win
end if
Just quazi code but you get the idea. That would make it so much cleaner. And I'm all for clean, tight code.
thanks again.
borgy tan
It looks to me as you are looking for each button to have a specific form location and that's how you are recognizing them.
Why not create a button class where you have Button(n)
You could give each location a number or actually you could number the locations such that when the buttons are in the right place
Btn 0 = Loc 0
Btn 1 = Loc 1
Btn 2 = Loc 3
.
.
.
Btn n = Loc N
If you did this...
For dim I as byte = 1 to 15
If button0 <> loc(i) then return
next
MsgBox "You win"
Colin F
I’ve worked on a number of similar problems during my career, and I’ve found that *most* of the time it’s better to cache the information in a bitfield simply because I never know how the product (in my case, Visual Basic) will be used at the enterprise level – I get it done at the point where it’s background noise, so I don’t have to sweat it later in one big (possibly noticeable) blob. The only exceptions are when another process is truly blocked on my getting “out” of whatever I’m doing, particularly if I’m in a loop, if (and only if) the bit setting is more expensive.
Hope this helps,
--Matt--*
JedG
Though my puzzle will probably not grow or even change, nor will I see a measurable performance difference. I would like to follow best practice programming. I didn't know VB had a built-in function like this, or I would have had to write another method to handle the changing of the bit field.
I'll try to implement this and see what happens.
Thanks.
Fraser Putnam
OrElse & AndAlso
ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_vbalr/html/ca474e13-567d-4b1d-a18b-301433705e57.htm
alkaline
Location is a method of the control object that is a "point" and yes you can iterate through the buttons and locations as you mentioned in code.
MikeFesta
I did figure out one thing though. I can create a new object collection and add all my buttons to it. Such as this:
Dim
ctrl As CollectionAnd then I fill it up will my buttons like this:
ctrl =
New Collectionctrl.Add(B1,
"1")ctrl.Add(B2,
"2")ctrl.Add(B3,
"3")ctrl.Add(B4,
"4")............
And then I can reference them like this:
ctrl(I).left
ctrl(I).top
However, for what you are saying, how would VB make the connection of "top" and "left" values to a single variable called "loc1" which has both values contained in it such as "if ctrl(I) = loc(I) Then...". I don't get it.
Like if I was coding, say, "move btn1 to loc1". This is still a function I have to write to handle changing left and top values. So I don't see the connection.
It is a primitive way to make a game, but it's very simple. Just taking the actual button object and move it around by left and top attributes. In order to win, B1 HAS to be at 3,28; and B2 HAS to be at 40,28; and so on. So I guess I'm not seeing the automation of your idea.
If you could maybe create an example, say with a 2x2 grid for simplicity sake. Or tell me how I can use my object collection to do it. That would be great. Cause like I said, this IF mess works, I just think there must be a cleaner way to do it.