Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Division beyond my grasp!!! 2

Status
Not open for further replies.

lespaul

Programmer
Feb 4, 2002
7,083
US
Ok, for some reason I just can't get this!!

I am programming a dice game that we play with our neighbors. And I'm having some real problems with a scoring function because I can't get the numbers to work with each other and divide the way I need them too!

So I have created a function that checks to see if there is more than 3 of a kind.
Code:
function CheckKind(ARoll : array of integer; Dcounter : integer): integer;
var
pipsArray : array [1..6] of integer;
i, multiplier, base : integer;
begin
//reset all values to zero
  for i := 1 to 6 do
    pipsArray[i] := 0;
//ARoll is an array that contains 6 random values 1 - 6
//Dcounter is the number of dice rolled
  for i := 0 to Dcounter - 1 do
  begin
//I check the value of each slot in the ARoll array
//if the die value in ARoll[1] is 1 then pipsArray[1] 
//increments; if the value in ARoll[2] is also 1 then 
//pipsArray[1] increments to 2

    Case ARoll[i] of
     1 : inc(pipsArray[1]);
     2 : inc(pipsArray[2]);
     3 : inc(pipsArray[3]);
     4 : inc(pipsArray[4]);
     5 : inc(pipsArray[5]);
     6 : inc(pipsArray[6]);
    end;
  end;
  for i := 1 to 6 do
  begin
//so now pipsArray has counts of the dice thrown
(1, 4, 4, 4, 6, 3)
//I only need to score if there are more than 3 of a kind
    if pipsArray[i] >= 3 then
    begin
      base := 0;
//1's get a special score
      if i = 1 then
        multiplier := 1000
      else
        multiplier := 100;
//so in my array I have three 4's so I would get 400 points
//if I had four 4's i would get 600 (Take the DICE value 
//(4) divide by 2 add to Dice Value (2 + 4) * 100.
//If I had three 3's I would get 300 points, four 3's would 
//be 450 points (((3/2) + 3) * 100) = (1.5 + 3) * 100 = 450
      if pipsArray[i] = 3 then
        frmRollingBase.PendingScore := frmRollingBase.PendingScore + (i * multiplier)
      else begin
//here is where the major trouble is!!  This always rounds
//down to zero, so none of the over 3 scores are calculated 
//correctly
        base := (((pipsArray[i] - 3) div 2) + i);
        frmRollingBase.PendingScore := frmRollingBase.PendingScore + (base * multiplier);
      end;
    end;
  end;
  Result := frmRollingBase.PendingScore;
end;
Can somebody please help me figure out this division??

Thanks!
Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
Can you explain this line for me?
Code:
        base := (((pipsArray[i] - 3) div 2) + i);
Why the "- 3" ?

Have you tried using the debugger to find what values are in pipsArray [ i ] when base is being calculated?


Andrew
 
This is the line that calculates the score when there are more than 3 of a kind. Unfortunately it got mangled during some cutting and pasting. It should be:
Code:
base := ((((pipArray[i] - 3) * i) div 2) + i)
So if I rolled the following: (1, 4, 4, 4, 6, 3)

pipsArray would look like this
Code:
pipsArray[1] = 1  (one die is a 1)
pipsArray[2] = 0
pipsArray[3] = 1  (one die is a 3)
pipsArray[4] = 3  (three dies are a 4)
pipsArray[5] = 0
pipsArray[6] = 1  (one die is a 6)

If you roll 3 of a kind you get the value of the dice times 100. So in this case I would get a score of 400 points.

If you roll more than 3 of a kind, each subsequent matching die is worth 1/2 of the 3 die total. So the first 3 dies that are 4 give me 400 points, if I have a 4th four it is worth another 200 points for a total of 600;if I have a 5th four it is also worth 200 points, for a total of 800 points; if I roll all a 4 on all six dice it would be 400 points for the first 3 and 200 points for EACH of the other 3 for a total of 1000 points.

Now lets re-roll the dice and I get the following:
(2, 5, 5, 4, 5, 5)
Code:
pipsArray[1] = 0  
pipsArray[2] = 1  (one die is a 2)
pipsArray[3] = 0  
pipsArray[4] = 1  (one die is a 4)
pipsArray[5] = 4  (four dies are a 5)
pipsArray[6] = 0  (one die is a 6)

[ignore]So now I loop through pipsArray, when it gets to i = 5, since it is more than three, I need to find out how many additional 5's were rolled (pipsArray[5] - 3) = 1.
Then I need to know what 1/2 of the dice is (for 5 that would be 2.5). Now if I add that to it equals 7.5 and when multipled by 100 equals the 750 points that I need for rolling 4 fives.

base := ((((4 - 3) * 5)/2) + 5 = ((1*5)/2) + 5 = 2.5 + 5 = 7.5 * 100 = 750[/ignore]
Code:
base := ((((pipArray[i] - 3) * i) div 2) + i)




Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
I'm assuming here that "base" is a double or some other floating point type. If not, you will get rounded values. Also, the "div" operator rounds down, you should use "/". I didn't try to compile this. Good luck.

For i := 1 to 6 do
begin
if pipsArray >= 3 then
begin
base := 0;
if i = 1 then
multiplier := 1000
else
multiplier := 100;

base := i;
if pipsArray > 3 then
base := base + (((pipsArray - 3)*i)/2);
frmRollingBase.PendingScore :=
frmRollingBase.PendingScore + (base * multiplier);
end;
Result := frmRollingBase.PendingScore;
end;

"The difference between practice and theory is that in theory, there is no difference between practice and theory" - Somebody's tag line I stole
 
No actually in the code above base is declared as an integer. That's my major problem. I can't get the division to work properly and not round it. I have tried declaring every type of numeric type I could find and no matter what, I either got an error on mismatched types (Integer and Extended) or base was always rounded down and the calculation was wrong.

So, what do I need to declare base as so the calcuation will be right?

thanks Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
I think that you should use integers throughout. However you must avoid a calculation which would in effect give a non integer answer as this will get rounded down to the nearest integer.

The way I would code this is to work out the total for 3 die and then add in the bonus points.

if pipsArray [ i ] >= 3 then begin
TotalFor3Die := pipsArray [ i ] * Multiplier;
bonus := ( basic div 2 ) * ( pipsArray [ i ] - 3 );
frmRollingBase.PendingScore := frmRollingBase.PendingScore + TotalFor3Die + Bonus;
end;


Andrew
 
Sorry, the bit with

( basic div 2 )

should be

( TotalFor3Die div 2 )


Andrew
 
ARGH!!!:

Case ARoll of
1 : inc(pipsArray[1]);
2 : inc(pipsArray[2]);
3 : inc(pipsArray[3]);
4 : inc(pipsArray[4]);
5 : inc(pipsArray[5]);
6 : inc(pipsArray[6]);

Why not:
Inc(PipsArray[ARoll]);

As for your round-down problem--multiply first, then divide:

For i := 1 to 6 do
If PipsArray > 2 then
Begin
Base := i * 100;
Score := Score + Base;
If PipsArray > 3 then Score := Score + (Base * (PipsArray - 3)) Div 2;
End;
 
Thanks Loren! That looks great! But, where you have:
Code:
Base := i * 100

I need:
Code:
Base := i * multiplier

I'll see if I can get it to work (or not I'll come up with a way around it!)


Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
Missed that part of the formula.

If i = 1 then
Base := 1000
Else
Base := i * 100;

Alternately, ditch the math entirely if there's a maximum number of dice (I'm assuming 6 max here):

Const
Table : Array [1..6, 1..6] of Integer = (
(0, 0, 3000, 4500, 6000, 7500),
(0, 0, 200, 300, 400, 500),
(0, 0, 300, 450, 600, 750),
(0, 0, 400, 600, 800, 1000),
(0, 0, 500, 750, 1000, 1250),
(0, 0, 600, 900, 1200, 1500));

Leaving the following:

Score := 0;
fillchar(pipsArray, sizeof(pipsarray), 0);
for i := 0 to dcounter - 1 do
inc(pipsarray[aroll]);
for i := 1 to 6 do
score := score + table[i, pipsarray];
 
Yeah! I have all the scoring completed! (stars to Loren multipling then dividing did the trick) But now I'm having another problem!

Say a person rolls the following: (and yes Loren there are only six dice).
#1: 2
#2: 3
#3: 2
#4: 2
#5: 3
#6: 2

since there are four twos the score for matching dice is 300 points; but another scoring combination is triple pairs (pair of 2's, pair of 3's, pair of 2's) for which the score is 750 points.
So on my playing surface I have a StringGrid that shows all the different ways to score and the possible scores for the current roll:
Straight (blank)
Six of a Kind (blank)
Five of a Kind (blank)
Four of a Kind 300
Three of a Kind (blank)
Triple Pairs 750
Continue (blank)
Score with Roll (blank)

There is also Posted Score (points that have been accepted) and Pending Score (points from the current turn that have not yet been accepted).

What I would like to do is:
When the person clicks a row in the StringGrid, take the value and add it to Pending Score and show it in 'Score with Roll'. When the person double clicks a row in the StringGrid, take the value and add it to PendingScore and reset all the values to blank.

My problem is that I can't figure out which cell/row is being clicked on and what the value of the cell is!!

Any suggestions???



Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
Leslie, Did you not read my posting which had the multiplication before the division and the correct setting of the multiplier?

Anyway, it is easy to find the cell that has been clicked. The StringGrid's MouseToCell function will give you that.

The usual place to handle a mouse click is in the MouseUp event which gives you the X, Y position of the mouse and also indicates which mouse button has been pressed.

Your code would look like:
Code:
procedure TForm1.StringGrid1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
  Column, Row: Longint;
begin
  StringGrid1.MouseToCell(X, Y, Column, Row);
  ShowMessage ( 'You clicked column ' + IntToStr ( column ) + ' and row ' + IntToStr ( Row ) );
end;
which I've adapted from the Delphi 5 Help file.

Andrew

 
A bit of advise--if you're monitoring mouseup messages, also monitor the mousedown and discard the event if the mouse moved too far while down.

Incidently, why do you need the string grid at all? Would not the player always simply take the highest score?
 
Towerbase - I apologize for skimming over your posting. You're right you also suggested the mulitple first! (stars to you too!).

Thanks for the information about the mouse events, that will help alot!!

Loren, i need the string grid because the player doesn't always take the higher score. If on my first roll I get:
1, 2, 2, 2, 3, 6
Personally i would take the 1 (and have 100 points pending) and roll the five remaining dice because the second roll is the only time you can get a small straight (1,2,3,4,5) which is worth 750 points. If I take the 200 points from the three 2's, I don't have a chance at the 750.

Once I'm finished, I would love for everyone who helped or is just interested in playing to try it out. It's a really neat game.

Right now I'm just working out the programming logic of the dice rolls and scores and players. Once I'm finished with the hard work, I'll probably need more assistance with graphics (I've never done anything with graphics before!!).

thanks again for all your help!! You guys ROCK!
Leslie
landrews@metrocourt.state.nm.us

SELECT * FROM USERS WHERE CLUE > 0
No Rows Returned
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top