Forums: » Register « |  Free Tools |  User CP |  Games |  Calendar |  Members |  FAQs |  Sitemap |  Support |

New Free Tools on Dev Shed!

#1
November 8th, 2011, 06:14 AM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Error message when running this procedure

As a part of the Yahtzee game, a score for 'three of a kind' is awarded if there are three dice the same. The score is the total of all the dice in the hand. I have written the following code to score this, but get the error:

---------------------------
---------------------------

I know there must be something wrong in my code, but I am a beginner, and can't see what. Thanks for any help at all.

Code:
```procedure SortArray; {Sorting}
Var
Temp, I, J : Integer;
begin
For I := 1 to 4 do
For J := I+1 to 5 do
If DiceArray[J].Tag < DiceArray[I].Tag
then begin
Temp := DiceArray[I].Tag;
DiceArray[I].Tag := DiceArray[J].Tag;
DiceArray[J].Tag := Temp;
end;
end;

procedure TYahtzeeFrm.ThreeKindEdtClick(Sender: TObject);
Var
DiceTotal, Num : Integer;
begin
DiceTotal := 0;

SortArray;

if ThreeKindEdt.Text = '' then
begin
For Num := 1 to 5 do begin
if (DiceArray[Num].Tag = DiceArray[Num+1].Tag) and
(DiceArray[Num+1].Tag = DiceArray[Num+2].Tag) then
DiceTotal := DiceArray[Num].Tag + DiceTotal
end;
end;```

Last edited by peglegmeg152 : November 8th, 2011 at 06:20 AM. Reason: Left out section

#2
November 8th, 2011, 07:34 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
I don't know the language in use but, a quick look makes me think that
Code:
`(DiceArray[Num+1].Tag = DiceArray[Num+2].Tag)`

is causing in issue as the loop (for Num) is from 1 to 5, thus your subscripts will take on values up to 7, presumably outside the array - hence the access violation.
__________________
The moon on the one hand, the dawn on the other:
The moon is my sister, the dawn is my brother.
The moon on my left and the dawn on my right.
My brother, good morning: my sister, good night.
-- Hilaire Belloc

#3
November 8th, 2011, 07:06 PM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Thanks, I have changed it and it now works, but does not add up each of the dice correctly. Can you see what the problem is?

Code:
```procedure SortArray; {Sorting}
Var
Temp, I, J : Integer;
begin
For I := 1 to 4 do
For J := I+1 to 5 do
If DiceArray[J].Tag < DiceArray[I].Tag
then begin
Temp := DiceArray[I].Tag;
DiceArray[I].Tag := DiceArray[J].Tag;
DiceArray[J].Tag := Temp;
end;
end;

procedure TYahtzeeFrm.ThreeKindEdtClick(Sender: TObject);
Var
DiceTotal, Num : Integer;
Score : Boolean;
begin
DiceTotal := 0;

SortArray;

if ThreeKindEdt.Text = '' then
begin
For Num := 1 to 3 do begin
if (DiceArray[Num].Tag = DiceArray[Num+1].Tag) and
(DiceArray[Num+1].Tag = DiceArray[Num+2].Tag) then
Score := True else
Score := False;
end;
end;

if Score = True then
For Num := 1 to 5 do
DiceTotal := DiceArray[Num].Tag + DiceTotal;

if Score = False then
DiceTotal := 0;```

#4
November 9th, 2011, 11:52 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
Just a personal style thing, I'd set Score to be false outside the loop and only set it to true inside the loop if your condition to check for three numbers being the same is true.
Next, you need to exit the loop when you find three numbers the same - posit the situation when you have three 1s. Your loop will start at 1, and check for array[1]=array[2] and array[2]=array[3] which will be true, so yo set SCore to be true. All very good. Next time round the loop you'll check array[2]=array[3] (which will be true) and array[3]=array[4] (which will likely not be true) so you'll ste Score to false, ditto the next iteration. Thus, unless the three same numbers are the highest numbers rolled (appearing in array[3], array[4] and array[5]) you will end up with Score being false.

You already preset the total to be 0 so there's no real need to have the check for Score being fale to set it to 0 again.

#5
November 10th, 2011, 04:53 AM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Sorry to annoy you more, but I have another procedure that has to calculate if there is a low straight (a consecutive run of 4), and if so, give a score of 30. My code below gives 30 every time (i.e. never 0 if there is no straight). Can you see the issue?

Code:
```procedure TYahtzeeFrm.LowStrtEdtClick(Sender: TObject);
Var DiceTotal, Num : Integer;
Score : Boolean;
begin
Score := False;

SortArray;

For Num := 1 to 4 do
begin
if DiceArray[Num].Tag = DiceArray[Num+1].Tag then
DiceArray[Num].Tag := 10;
end;

SortArray;

DiceTotal := 0;

For Num := 1 to 2 do
begin
if (DiceArray[Num].Tag < DiceArray[Num+1].Tag) and
(DiceArray[Num+1].Tag < DiceArray[Num+2].Tag) and
(DiceArray[Num+2].Tag < DiceArray[Num+3].Tag) then
Score := True;
end;

if Score then
DiceTotal := 30 else
DiceTotal := 0;
end;```

#6
November 10th, 2011, 04:55 AM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Also, going back to the original topic, here are some examples of the dice displayed and the score (sum) calculated:

4,3,3,1,3 = 9
1,2,1,4,1 = 4
2,4,6,6,6 = 19

I have changed the code a little:

Code:
```procedure TYahtzeeFrm.ThreeKindEdtClick(Sender: TObject);
Var
DiceTotal, Num : Integer;
Score : Boolean;
begin
DiceTotal := 0;

SortArray;

if ThreeKindEdt.Text = '' then
begin
Score := False;
For Num := 1 to 3 do
begin
if (DiceArray[Num].Tag = DiceArray[Num+1].Tag) and
(DiceArray[Num+1].Tag = DiceArray[Num+2].Tag) then
begin
Score := True;  //set to true if it is found
Break;          //leave for..loop, no sense continuing searvh
end
end;
end;

if Score then
begin
For Num := 1 to 5 do
DiceTotal := DiceArray[Num].Tag + DiceTotal;
end
else
DiceTotal := 0;
end;```

If you could give me ideas on this issue as well as the one i just posted, i would be very appreciative!!

#7
November 10th, 2011, 07:22 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
Quote:
 Originally Posted by peglegmeg152 Sorry to annoy you more, but I have another procedure that has to calculate if there is a low straight (a consecutive run of 4), and if so, give a score of 30. My code below gives 30 every time (i.e. never 0 if there is no straight). Can you see the issue? [/code]

Not an annoyance - don't worry!
It may not be your whole issue, but that first for loop (and one of the sorts) can be tossed out! I think I know why you are doing it, but consider ... you have 5 dice, looking for 4 of them to be in a straight. What are the odds that the 5th die holds a value the same as one of the other 4? For example, 1, 1, 2, 3. 4 is still a low straight

#8
November 10th, 2011, 07:33 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
Quote:
 Originally Posted by peglegmeg152 Also, going back to the original topic, here are some examples of the dice displayed and the score (sum) calculated: 4,3,3,1,3 = 9 1,2,1,4,1 = 4 2,4,6,6,6 = 19 . . . If you could give me ideas on this issue as well as the one i just posted, i would be very appreciative!!

That looks better, one further small point, place the initial assignment of false to outside, just before, the if (just after the setting of DiceTotal to 0 would be good (I tend to like to have all that sort of thing in one, easy to find, place.

Plus points for providing example numbers and totals! The third example, I think, exhibits the best display of the result of the issue - you have 5 EVEN numbers adding up to provide an ODD total ... cannot happen! Something is happening ,,, somewhere! Best way of debugging is to put a display of the numbers as they get processed in the loop that adds them up (output both the number to be added, and the result of the addition, with each loop round).

#9
November 10th, 2011, 07:47 AM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Quote:
 Originally Posted by SimonJM Not an annoyance - don't worry! It may not be your whole issue, but that first for loop (and one of the sorts) can be tossed out! I think I know why you are doing it, but consider ... you have 5 dice, looking for 4 of them to be in a straight. What are the odds that the 5th die holds a value the same as one of the other 4? For example, 1, 1, 2, 3. 4 is still a low straight

I put that in there because if the numbers are 1,2,2,3,4 for example, then i can't say if this number is less than this number, and this number is less than this number, and so on, because the two 2s would be equal! does that make sense? That's why i made it 10, so it would be out of the way, at the end. Do I not need to do this?

Quote:
 Originally Posted by SimonJM The third example, I think, exhibits the best display of the result of the issue - you have 5 EVEN numbers adding up to provide an ODD total ... cannot happen! Something is happening ,,, somewhere! Best way of debugging is to put a display of the numbers as they get processed in the loop that adds them up (output both the number to be added, and the result of the addition, with each loop round).

With this, sorry, but I don't know how to display the numbers? I am very new at this! can you just explain more what to do? thanks so much for all your help!

#10
November 10th, 2011, 10:15 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
Ok - now sitting at leisure (as opposed to trying not to spill lunch over my keyboard ...) that (the setting duplicate numbers to 10 and re-sorting) is a nice bit of lateral thinking in determining a straight - so, ignore me and keep doing that!

As for the displaying the values:

Code:
```  if Score then
begin
For Num := 1 to 5 do
DiceTotal := DiceArray[Num].Tag + DiceTotal;
end```

is what you have. After the addition you'd need to add an extra line, or two, (purely for debug purposes, so remove before releasing the code!) that will display the values. As I do not know the language you are using I don't know what the correct verb and syntax woudl be, but it'd be something like:

Code:
```Print "Die value: " DiceArray[Num].Tag;
Print "New running total: " DiceTotal;```

#11
November 10th, 2011, 07:27 PM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Thanks. So for the low straight, I still get 30 every time, even when there is none.

Also, I am using Delphi - so I tried to use ShowMessage, but got a violation error:

---------------------------
---------------------------

This is the code I put in:

Code:
``` if Score then
begin
For Num := 1 to 5 do
DiceTotal := DiceArray[Num].Tag + DiceTotal;
ShowMessage('Die Value: ' + IntToStr(DiceArray[Num].Tag));
ShowMessage('New running total: ' + IntToStr(DiceTotal));
end
else
DiceTotal := 0;```

#12
November 11th, 2011, 04:44 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
I had a suspicion it might be Delphi, but had not seen any for years!
Anyway ... not knowing the development environment is a bit of a hindrance so: do you have the option of setting breakpoints in the code and, once the breakpoint has been reached to interrogate the values of the variables?
Failing that, a technique for debugging that I have used in the past with Visual Basic has been to have a List control and adding the debug output to that.
As for the access violation ... not sure, but are you sure that those .Tag controls are actually a proper integer?

#13
November 11th, 2011, 05:05 AM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
Thank you for your help, but I think I have figured out the issue. It was to do with the image lists and their indexes. I can't really explain it, but it was adding the value one less than what it was displaying. Like 4,2,4,4,4 = 13, which was actually adding 3,1,3,3,3 which DOES equal 13! Hahaha. Thanks for all your help and perseverance anyway! I will let you know if I have further issues if that's okay? Thanks again.

#14
November 11th, 2011, 08:09 AM
 SimonJM
Contributing User

Join Date: Mar 2006
Posts: 2,247
Time spent in forums: 1 Month 1 Week 2 Days 22 h 19 m 20 sec
Reputation Power: 1585
Wholly explicable!
Indexes, in computing tend to be zero-based, thus the first entry in aarry is the 0-th and an array with 10 rows is from array[0] to array[9].
That is something I always ahd tp be careful of in VB, when looping over the elements in a List for example it had to be
Code:
`for index = 0 to List.IndexCount -1`

But, the main thing is, you found and fixed the issue, and it works - so good job!

#15
November 11th, 2011, 08:01 PM
 peglegmeg152
Registered User

Join Date: Oct 2011
Posts: 26
Time spent in forums: 3 h 30 m 35 sec
Reputation Power: 0
I'm back already! Haha - this should be easy enough. I am trying to create new 'ResetUpper' and 'ResetLower' procedures and put all the general output stuff and resetting stuff in there and call them in the necessary procedures. I currently have all this repetitive code at the end of every procedure - it works fine there, but when I move it to a new procedure, everything becomes an 'undeclared identifier'. I am stumped! Any ideas?

 Viewing: Dev Shed Forums > Other > Beginner Programming > Error message when running this procedure