Yahtzee question

BlitzMax Forums/BlitzMax Beginners Area/Yahtzee question

Zacho(Posted 2009) [#1]
I've been trying to make a yahtzee port and am having trouble with rolling the die. I can roll the first one just fine, but when I try to change the numberofrolls variable in the roll() function, I can't keep the first roll and then roll my second time. Any suggestions?

Strict
AppTitle="Yahtzee Port by ZaChO"
Graphics 600,600
SeedRnd MilliSecs()
AutoMidHandle False

Const NUMBEROFDICE = 6
Const MAXROLLS = 3
Global ROLLSLEFT = 3

Type Dice1
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type

Type Dice2
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type

Type Dice3
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice4
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice5
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice6
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type	

Global diceuno:Dice1 = New Dice1
Global dicedos:Dice2 = New Dice2
Global dicetres:Dice3 = New Dice3
Global dicequatro:Dice4 = New Dice4
Global dicecinco:Dice5 = New Dice5
Global diceseis:Dice6 = New Dice6

While Not KeyDown(KEY_ESCAPE)
	Cls 
	DrawText"---------------------------YAHTZEE PORT BY ZACHO-----------------------------",0,0
	If KeyHit(KEY_SPACE) And ROLLSLEFT <> 2 And ROLLSLEFT <> 1
		roll()
		ROLLSLEFT = 2
	EndIf	
	If KeyHit(KEY_SPACE) And ROLLSLEFT = 2
		roll2()
		ROLLSLEFT = 1
	EndIf
	If KeyHit(KEY_SPACE) And ROLLSLEFT = 1
		roll3()
		ROLLSLEFT = 0
	EndIf	
	
	'
	'YAHTZEE CHECK
	'
	If diceuno.number = 1 And dicedos.number = 1 And dicetres.number = 1 And dicequatro.number = 1 And dicecinco.number = 1 And diceseis.number = 1
		DrawText "YAHTZEE!!!!",400,400
	EndIf
	If diceuno.number = 2 And dicedos.number = 2 And dicetres.number = 2 And dicequatro.number = 2 And dicecinco.number = 2 And diceseis.number = 2
		DrawText "YAHTZEE!!!!",400,400
	EndIf	
	If diceuno.number = 3 And dicedos.number = 3 And dicetres.number = 3 And dicequatro.number = 3 And dicecinco.number = 3 And diceseis.number = 3 
		DrawText "YAHTZEE!!!!",400,400
	EndIf
	If diceuno.number = 4 And dicedos.number = 4 And dicetres.number = 4 And dicequatro.number = 4 And dicecinco.number = 4 And diceseis.number = 4
		DrawText "YAHTZEE!!!!",400,400
	EndIf
	If diceuno.number = 5 And dicedos.number = 5 And dicetres.number = 5 And dicequatro.number = 5 And dicecinco.number = 5 And diceseis.number = 5
		DrawText "YAHTZEE!!!!",400,400
	EndIf
	If diceuno.number = 6 And dicedos.number = 6 And dicetres.number = 6 And dicequatro.number = 6 And dicecinco.number = 6 And diceseis.number = 6
		DrawText "YAHTZEE!!!!",400,400
	EndIf
	
	drawHUD()
	drawROLLS()
	
	Flip
Wend




Function drawHUD()
	SetColor Rand(0,255),Rand(0,255),Rand(0,255)
	DrawText"Click <SpaceBar> to roll",300,300
	SetColor 255,255,255
End Function

Function drawROLLS()
	SetColor 255,0,0
	DrawText"*****Roll #1*****",0,90
	DrawText diceuno.number,0,110		
	DrawText dicedos.number,10,110
	DrawText dicetres.number,20,110
	DrawText dicequatro.number,30,110
	DrawText dicecinco.number,40,110 
	DrawText diceseis.number,50,110
	'
	SetColor 0,255,0
	DrawText"*****Roll #2*****",0,130
	'
	DrawText diceuno.number2,0,150		
	DrawText dicedos.number2,10,150
	DrawText dicetres.number2,20,150
	DrawText dicequatro.number2,30,150
	DrawText dicecinco.number2,40,150 
	DrawText diceseis.number2,50,150
	'
	SetColor 0,0,255
	DrawText"*****Roll #3*****",0,170
	DrawText diceuno.number3,0,190		
	DrawText dicedos.number3,10,190
	DrawText dicetres.number3,20,190
	DrawText dicequatro.number3,30,190
	DrawText dicecinco.number3,40,190 
	DrawText diceseis.number3,50,190
	SetColor 255,255,255
	
	
End Function

Function roll()
	diceuno.number = Rand(1,6)
	dicedos.number = Rand(1,6)
	dicetres.number = Rand(1,6)
	dicequatro.number = Rand(1,6)
	dicecinco.number = Rand(1,6)
	diceseis.number = Rand(1,6)
	ROLLSLEFT=2
End Function

Function roll2()
	diceuno.number2 = Rand(1,6)
	dicedos.number2 = Rand(1,6)
	dicetres.number2 = Rand(1,6)
	dicequatro.number2 = Rand(1,6)
	dicecinco.number2 = Rand(1,6)
	diceseis.number2 = Rand(1,6)
	ROLLSLEFT=1
End Function

Function roll3()
	diceuno.number3 = Rand(1,6)
	dicedos.number3 = Rand(1,6)
	dicetres.number3 = Rand(1,6)
	dicequatro.number3 = Rand(1,6)
	dicecinco.number3 = Rand(1,6)
	diceseis.number3 = Rand(1,6)
	ROLLSLEFT=0
End Function



Gabriel(Posted 2009) [#2]
I took just the quickest of glances and noticed that you have six different types, all of them identical. I really wish you'd stick to one program and fixing everything that's wrong with it instead of just going from one broken program to the next without stopping to fix all the errors with the last one.


plash(Posted 2009) [#3]
I agree with Gabriel, you should stick to one project until you master it.

You only need one Dice type.

EDIT: The reason none of your other rolls are going through is because calling KeyHit nulls the state for the given key when it polls it.


Zacho(Posted 2009) [#4]
@Gabriel-I'm trying to get some accomplishment by trying to make simpler (text-based) programs. If I managed to fix my errors (by the way making 200+ help posts), I would be in my late-fifties. It takes me that long...seriously...


Zacho(Posted 2009) [#5]
@Plash-Do I create an array?
Dice[number:Int,number2:Int,number3:Int]


EDIT: The reason none of your other rolls are going through is because calling KeyHit nulls the state for the given key when it polls it.

My program isn't affected by the state of the spacebar. Im only trying to get at is I want a variable to change when the func is called so I can go to roll #2, instead of repeating roll #1.


Gabriel(Posted 2009) [#6]
@Gabriel-I'm trying to get some accomplishment by trying to make simpler (text-based) programs.

So we can safely assume that this is the program you're going to be working on until it's fixed, can we? And there won't be a completely new one in two days time while this one carries on unanswered?

My program isn't affected by the state of the spacebar.

How do you figure? There are three if..endif sections all of which are only executed if the spacebar has been hit. They all contain the call to the roll functions. Unless you happen to press the space button on the minute fraction of a second between the first and third if statements, the second and third ones will never be true. Which is exactly what Plash told you.


Jesse(Posted 2009) [#7]
why do you keep on doing this?
Type Dice1
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type

Type Dice2
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type

Type Dice3
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice4
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice5
	Field number:Int	
	Field number2:Int
	Field number3:Int
End Type

Type Dice6
	Field number:Int
	Field number2:Int
	Field number3:Int
End Type

[edited]
another thing the keyhit should be like this:
	If KeyHit(KEY_SPACE)
		If ROLLSLEFT = 3 
			roll()  
		ElseIf ROLLSLEFT = 2 
			roll2()
		ElseIf ROLLSLEFT = 1 
			roll3()
		EndIf
	EndIf	



Brucey(Posted 2009) [#8]
why do you keep on doing this?

Heh :-)


Aren't there only 5 dice in Yahtzee?

But anyway... you may want to sit down and think a bit more before you start banging away at the keyboard.

So, you get (up to) three rolls of (let's say) 5 dice.
How might you represent this?

If we break that down further to a single roll of 5 dice, you can see that you could, in theory, have one thing to store 5 numbers.

Our one thing could be a Type..
Type TDice

End Type


Our 5 numbers may well be an array of Ints of size 5. We could store this our Type...
Type TDice

    Field numbers:Int[5]

End Type


One nice thing about Types, is that you can add Methods to them. So perhaps we want a Roll() method, to indicate we want to roll some dice..
Type TDice

    Field numbers:Int[5]

    Method Roll()

    End Method

End Type


But what are we rolling? 5 Dice?

Well... sometimes... On the first roll, yes. On the second, according to the rules, you might only want to roll the 2nd and 4th dice. How might you solve that problem?

One way might be to define which dice are actually rolled during Roll().

To keep things simple, why don't we add some parameters to indicate which dice is being rolled this time...

Type TDice

    Field numbers:Int[5]

    Method Roll(d1:int, d2:int, d3:Int, d4:int, d5:int)

    End Method

End Type


We could use 1 to indicate a roll is required, and 0 to indicate that no roll is required...
So, for our first roll, we could call our Roll() method like this :
dice.Roll(1, 1, 1, 1, 1)

(this assumes that "dice" is an object)

Now, how might we actually roll the dice?
Keeping things simple, we'll just check each parameter and roll if required:
Type TDice

    Field numbers:Int[5]

    Method Roll(d1:Int, d2:Int, d3:Int, d4:Int, d5:Int)

        If d1 Then
            numbers[0] = Rand(1, 6)
        End If

        If d2 Then
            numbers[1] = Rand(1, 6)
        End If

        If d3 Then
            numbers[2] = Rand(1, 6)
        End If

        If d4 Then
            numbers[3] = Rand(1, 6)
        End If

        If d5 Then
            numbers[4] = Rand(1, 6)
        End If

    End Method

End Type


There are of course more efficient ways to do this, but this should keep things clear.

What about the second roll? Well, if the player decided to roll the 2nd and 4th dice again, you could call Roll() with the following parameters :
    dice.Roll(0, 1, 0, 1, 0)


Much of writing code is deciding what needs to be done.
Then you need to think about how you might implement it.
Write some code, see if it does what you want... if not, tweak it a little - or even go back to the drawing board and start over with your ideas.

But thinking about the problem is quite important :-)


Jesse(Posted 2009) [#9]

Heh :-)


he knows what I am talking about:

http://www.blitzmax.com/Community/posts.php?topic=84372#953894
@Brucey
Good luck getting through. ;)
he is too inpatient. doesn't take the time to learn one thing when he is already jumping to 10 others and that is what is slowing him down.

@Zacho, Dont take it personal it's just what I think based on my experiences.


Zacho(Posted 2009) [#10]
@Jesse-@Brucey- Its true, very true. I am sorta impatient. Lol

@Gabriel-
So we can safely assume that this is the program you're going to be working on until it's fixed, can we? And there won't be a completely new one in two days time while this one carries on unanswered?

You can never be sure of that :)

How do you figure? There are three if..endif sections all of which are only executed if the spacebar has been hit. They all contain the call to the roll functions. Unless you happen to press the space button on the minute fraction of a second between the first and third if statements, the second and third ones will never be true. Which is exactly what Plash told you.

I was just a little unsure of his wording.

@Brucey-
Aren't there only 5 dice in Yahtzee?

Typo

Your explanation of my code is awesome! And I'd listen to Jesse. Giving me the code isn't ganna solve my questions, its only going to give me answers. But I really truly appreciate your time on my Yahtzee port. Really do, honestly. I'm actually still happy that everyone hasn't left me yet....Lol


Btw: Im still reading the noob guide.


Zacho(Posted 2009) [#11]
Here is the work-in-progress. Please don't comment as I will try to figure this game out myself (for once, lol) :)




Thareh(Posted 2009) [#12]
Looking good Zacho! :)
You're using very "static" code right now, you should try to think more dynamiclly :)
For example:

Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT=2
End Function

Function roll2()
	dice.Roll(1,1,1,1,1)

	ROLLSLEFT=1
End Function

Function roll3()
	dice.Roll(1,1,1,1,1)

	ROLLSLEFT=0
End Function


Could be replaced by 1 function, like this:

Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT = ROLLSLEFT - 1
	'ROLLSLEFT:-1 'Works aswell, but the other way is easier to see :)
End Function


Which just substracts 1 from ROLLSLEFT each time you call it, instead of declaring ROLLSLEFT to something static each time :)
(I hope you get what I mean :P)


Derron(Posted 2009) [#13]
Function drawROLLS()
...
...
End Function


could be replaced with

Function drawROLLS()
	local y:int = 0
	If ROLLSLEFT = 3
		SetColor 255,0,0
		y = 90
	else 	If ROLLSLEFT = 2
		SetColor 0,0,255
		y = 110
	else 	If ROLLSLEFT = 1
		SetColor 0,255,0
		y = 130
	endif
	DrawText "*****Roll #"+(4-ROLLSLEFT)+"*****",0,y
	DrawText dice.numbers[0],0,y+20
	DrawText dice.numbers[1],10,y+20
	DrawText dice.numbers[2],20,y+20
	DrawText dice.numbers[3],30,y+20
	DrawText dice.numbers[4],40,y+20
	SetColor 255,255,255
End Function


What should my code-replacement show off? You see that certain parts of your code are similar or nearly the same, cutting down repeated elements to one call will make it easier to make bugfixes or changes because eg. only one line has to be changed instead of 3.

Going further would change:
	DrawText dice.numbers[0],0,y+20
	DrawText dice.numbers[1],10,y+20
	DrawText dice.numbers[2],20,y+20
	DrawText dice.numbers[3],30,y+20
	DrawText dice.numbers[4],40,y+20


into
	For local i:int = 0 to 4
		DrawText dice.numbers[i],i*10,y+20
	Next


But like obvious this all is rather cosmetic than functional in its changes.


bye MB


EDIT: @thareh


Could be replaced by 1 function, like this:
Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT = ROLLSLEFT - 1
	'ROLLSLEFT:-1 'Works aswell, but the other way is easier to see :)
End Function




isn't exactly the same thing, consider using
Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT = Max(0, ROLLSLEFT - 1)
End Function


The Max-function takes care of variable ROLLSLEFT decreasing to negative values.


Jesse(Posted 2009) [#14]
I personally don't think that ROLLSLEFT should be global or inside the function. the "max" or "if" statement should be kept in the main loop.


Zacho(Posted 2009) [#15]
@Thareh-

Could be replaced by 1 function, like this:
Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT = ROLLSLEFT - 1
	'ROLLSLEFT:-1 'Works aswell, but the other way is easier to see :)
End Function



Ok, but what if the player wants to hold a certain die? Eh? That is why I have it like this for the moment:
Function roll()
	dice.Roll(1, 1, 1, 1, 1)
	
	ROLLSLEFT=2
End Function

Function roll2()
	dice.Roll(1,1,1,1,1)

	ROLLSLEFT=1
End Function

Function roll3()
	dice.Roll(1,1,1,1,1)

	ROLLSLEFT=0
End Function


Which just substracts 1 from ROLLSLEFT each time you call it, instead of declaring ROLLSLEFT to something static each time :)
(I hope you get what I mean :P)


Ya, your saying its easier to type ROLLSLEFT:-1

@MichaelB

Wow, you are a very clever person. I would have never thought of this:
Function drawROLLS()
	local y:int = 0
	If ROLLSLEFT = 3
		SetColor 255,0,0
		y = 90
	else 	If ROLLSLEFT = 2
		SetColor 0,0,255
		y = 110
	else 	If ROLLSLEFT = 1
		SetColor 0,255,0
		y = 130
	endif
	DrawText "*****Roll #"+(4-ROLLSLEFT)+"*****",0,y
	DrawText dice.numbers[0],0,y+20
	DrawText dice.numbers[1],10,y+20
	DrawText dice.numbers[2],20,y+20
	DrawText dice.numbers[3],30,y+20
	DrawText dice.numbers[4],40,y+20
	SetColor 255,255,255
End Function

Very well done. Thanks for the tip! :) As well as this snippet of code:
	For local i:int = 0 to 4
		DrawText dice.numbers[i],i*10,y+20
	Next


[b][u]Here is one question to ask before I procede; what method should I use to allow the user to keep the die he/she wants. I want to say with a mouseclick or something but I'm not sure what is best. What do you guys think?


Derron(Posted 2009) [#16]
As you want it textbased you could wait for userinput

Global DiesHold:int[5]

'inside mainloop
'the formula value = 1 - value is used to switch between 1 and 0 as result
if KeyHit(KEY_1) then DiesHold[0] = 1 - DiesHold[0]
..
if KeyHit(KEY_5) then DiesHold[4] = 1 - DiesHold[4]
'----

'draw part
Function drawROLLS()
	local y:int = 0
	If ROLLSLEFT = 3
		SetColor 255,0,0
		y = 90
	else 	If ROLLSLEFT = 2
		SetColor 0,0,255
		y = 110
	else 	If ROLLSLEFT = 1
		SetColor 0,255,0
		y = 130
	endif
	DrawText "*****Roll #"+(4-ROLLSLEFT)+"*****",0,y
	for local i:int = 0 to 4
		if DiesHold[i]
			SetColor 150,150,150
			DrawText (dice.numbers[i],0 + i*10,y+20)
		else 
			SetColor 255,255,255
			DrawText (dice.numbers[i],0 + i*10,y+20)
		endif
	Next
	SetColor 255,255,255
End Function




bye MB