Risk Simulation Help

BlitzMax Forums/BlitzMax Beginners Area/Risk Simulation Help

midget_overlord(Posted 2013) [#1]
Hello all! I've been working on a simulation for a game of risk in order to determine probabilities of victory as the armies stack up. I've encountered a problem however. For some reason, the numbers are not being as random as they should be. Below, a = attack victories, and d = defense victories. The problem is that every other result, the attacker gets a 100% chance of victory no matter the odds. So, at attackarmies = 3 and defensearmies = 6 I got attacker wins 100% of the time, but at attackarmies = 4 defensearmies = 3 the defense has a 21% chance of victory. I think it may have something to do with the random number generator I have set. Help please?
a = 0
d = 0
Repeat
attackarmies = 12
defencearmies = 6
Repeat
attack1 = (Rnd(1)*5 + 1)
attack2 = (Rnd(1)*5 + 1)
attack3 = (Rnd(1)*5 + 1)
defence1 = (Rnd(1)*5 + 1)
defence2 = (Rnd(1)*5 + 1)
If attack1 >= attack2
	If attack1 >= attack3
	attackhigh = attack1
		If attack2 >= attack3
		attackmed = attack2
		Else attackmed = attack3
		EndIf
	Else attackhigh = attack3
		If attack1 >= attack2
		attackmed = attack1
		Else attackmed = attack2
		EndIf
	EndIf
Else
	If attack2 >= attack3
	attackhigh = attack2
		If attack1 >= attack3
		attackmed = attack1
		Else attackmed = attack3
		EndIf
	Else attackhigh = attack3
		If attack1 >= attack2
		attackmed = attack1
		Else attackmed = attack2
		EndIf
	EndIf
EndIf
If defence1 >= defence2
defencehigh = defence1
defencelow = defence2
Else defencehigh = defence2
defencelow = defence1
EndIf
If defencehigh >= attackhigh
attackarmies = attackarmies-1
Else defencearmies = defencearmies-1
EndIf
If defencelow >= attackmed
attackarmies = attackarmies - 1
Else defencearmies = defencearmies-1
EndIf
Until defencearmies < 2 Or attackarmies < 3
Repeat
If defencearmies < 2
defence1 = (Rnd(1)*5 + 1)
defencelow = defence1
defencehigh = defence1
Else defence1 = (Rnd(1)*5 + 1)
defence2 = (Rnd(1)*5 + 1)
	If defence1 >= defence2
	defencehigh = defence1
	defencelow = defence2
	Else defencehigh = defence2
	defencelow = defence1
	EndIf
EndIf
If attackarmies = 2
attack1 = (Rnd(1)*5 + 1)
attack2 = (Rnd(1)*5 + 1)
	If attack1 >= attack2
	attackhigh = attack1
	attackmed = attack2
	Else attackhigh = attack2
	attackmed = attack1
	EndIf
EndIf
If attackarmies = 1
attack1 = (Rnd(1)*5 + 1)
attackhigh = attack1
attackmed = attack1
EndIf
If attackarmies >= 3
attack1 = (Rnd(1)*5 + 1)
attack2 = (Rnd(1)*5 + 1)
attack3 = (Rnd(1)*5 + 1)
If attack1 >= attack2
	If attack1 >= attack3
	attackhigh = attack1
		If attack2 >= attack3
		attackmed = attack2
		Else attackmed = attack3
		EndIf
	Else attackhigh = attack3
		If attack1 >= attack2
		attackmed = attack1
		Else attackmed = attack2
		EndIf
	EndIf
Else
	If attack2 >= attack3
	attackhigh = attack2
		If attack1 >= attack3
		attackmed = attack1
		Else attackmed = attack3
		EndIf
	Else attackhigh = attack3
		If attack1 >= attack2
		attackmed = attack1
		Else attackmed = attack2
		EndIf
	EndIf
EndIf
EndIf
If defencehigh >= attackhigh
attackarmies = attackarmies-1
Else defencearmies = defencearmies-1
EndIf
If defencelow >= attackmed
attackarmies = attackarmies - 1
Else defencearmies = defencearmies-1
EndIf
Until attackarmies Or defencearmies = 0
If attackarmies = 0
d = d+1
EndIf
If defencearmies = 0
a = a+1
EndIf
Until a + d =10000
Print "a = " + a
Print "d = " + d
Print "end"
WaitKey()



GaryV(Posted 2013) [#2]
As somebody with little people in the family, can I ask is there a particular reason you are using such a socially unacceptable and offensive user name? Or are you just a jerk? You can't claim you don't know it is offensive, as you are in the USA, so you know this is the same as using the N word or other vulgar and cruel words to describe those different than you.


midget_overlord(Posted 2013) [#3]
I know some people like that and none of them have ever been offended. You are right that I should have recognized that some people would be though. I simply made it that out of force of habit, as I've never encountered a site where it was taken. I really need to break that habit. Sorry.


GaryV(Posted 2013) [#4]
apology accepted.


matibee(Posted 2013) [#5]
First off, if you're trying to simulate a dice roll, your rand function never returns a six. Secondly you really should seed the random value or every run of the code will always give the same results. Here's a little tester that does both those things;

SuperStrict 
SeedRnd( MilliSecs() )

Local results:Int[6]
Local r:Int 

Print "your random:"
For Local i:Int = 0 To 100000
	r = (Rnd(1)*5 + 1)
	results[r-1] :+ 1
Next 

For Local i:Int = 0 To 5
	Print (i + 1) + "'s = " + results[i]
	results[i] = 0
Next 

Print "~nalt random:"
For Local i:Int = 0 To 100000
	r = (Rnd(1)*6 + 1)
	results[r-1] :+ 1
Next 

For Local i:Int = 0 To 5
	Print (i + 1) + "'s = " + results[i]
Next 


Finally I know nothing about Risk, but the problems are probably in your convoluted logic somewhere. Here's a much simpler way of sorting values into Low/Med/High using arrays, Constant values and Sort()

SuperStrict 
SeedRnd( MilliSecs() ) 

Const LOW:Int = 0
Const MED:Int = 1
Const HIGH:Int = 2

Local attack:Int[3]
For Local i:Int = 0 To 2
	attack[i] = RollDice()
Next 
attack.Sort()

Print attack[ LOW ]
Print attack[ MED ]
Print attack[ HIGH ]



Function RollDice:Int()
	Local result:Int = (Rnd(1)*6 + 1)
	Assert( 0 < result And result < 7 )
	Return result 
End Function 


Hope that helps!


midget_overlord(Posted 2013) [#6]
Thanks, but could you tell me what the second code is actually saying? This is really the first code I've ever written and am unfamiliar with many of the codes.


matibee(Posted 2013) [#7]
I'm sorry I can't go over everything in too fine a detail. Try reading the excellent tutorial here: http://www.truplo.com/blitzmaxbeginnersguide/

Remember you can select keywords in the IDE and press F1 twice to see their documentation.

I'll add some comments, maybe that will help a little..

SuperStrict   'Really strict code formatting enforcement catches lots of silly errors
SeedRnd( MilliSecs() ) ' Seed the rand function so it spits out different results each time the program runs

' CONST-ant values never change during the execution of you program and are safer than trying to remember things like "is LOW zero? or is it one??"
Const LOW:Int = 0  
Const MED:Int = 1
Const HIGH:Int = 2

Local attack:Int[3] ' using an array to hold three attack values
For Local i:Int = 0 To 2
	attack[i] = RollDice() ' set the three attach values
Next 
attack.Sort() ' sort the values in numerical order

' output the attack values (which will be sorted, and between 1 and 6 inclusive)
Print attack[ LOW ]
Print attack[ MED ]
Print attack[ HIGH ]


' I turned the Rand(...) call into a function in its own right
Function RollDice:Int()
	Local result:Int = (Rnd(1)*6 + 1)
' in a debug build an Assert tests the code condition
' and stops app execution if the test condition fails
' Here we are just proving that the rollDice function always outputs
' a value we are expecting.
' A bit silly and pointless, but you never know, and asserts can
' be very, very useful in other, situations like this
	Assert( 0 < result And result < 7 )
	Return result 
End Function