Splitting Probabilities - language-agnostic

I've the following code in PHP which works fine (returns more or less 10 results each time it runs):
function GetAboutTenRandomNumbers()
{
$result = array();
for ($i = 0; $i < 240; $i++)
{
if (Chance(10, 240) === true)
{
$result[] = $i;
}
}
echo '<pre>';
print_r($result);
echo '</pre>';
return $result;
}
And the Chance() function goes as follows:
function Chance($chance, $universe = 100)
{
$chance = abs(intval($chance));
$universe = abs(intval($universe));
if (mt_rand(1, $universe) <= $chance)
{
return true;
}
return false;
}
Now, I want to randomly split those 10 (on average) results in the 4 following segments:
the first one having a probability of 10% * 10 = 1
the second one having a probability of 20% * 10 = 2
the third one having a probability of 30% * 10 = 3
the fourth one having a probability of 40% * 10 = 4
As you can see the sum of all segments (1 + 2 + 3 + 4) equals 10, so I've coded the following function to do this.
function GetAboutTenWeightedRandomNumbers()
{
$result = array();
// Chance * 10%
for ($i = 0; $i < 60; $i++)
{
if (Chance(10 * 0.1, 240) === true)
{
$result[] = $i;
}
}
// Chance * 20%
for ($i = 60; $i < 120; $i++)
{
if (Chance(10 * 0.2, 240) === true)
{
$result[] = $i;
}
}
// Chance * 30%
for ($i = 120; $i < 180; $i++)
{
if (Chance(10 * 0.3, 240) === true)
{
$result[] = $i;
}
}
// Chance * 40%
for ($i = 180; $i < 240; $i++)
{
if (Chance(10 * 0.4, 240) === true)
{
$result[] = $i;
}
}
echo '<pre>';
print_r($result);
echo '</pre>';
return $result;
}
The problem is I've run the GetAboutTenWeightedRandomNumbers function dozens of times and the result is much more lower than the result returned by the GetAboutTenRandomNumbers function. I'm sure that I'm making a fundamental math mistake, I suspect where but I don't know how to solve it.

Indeed you are!
In your second pass, you're giving it 60 values each pass, instead of 240, so you'll get about a quarter of the expected values in that pass. Run each to 240 and use a modulo 60 to get the range of values you're looking for in each loop.

If you're expecting DoIt_02() to return about the same number of results as DoIt_01(), then yeah, you're making a fundamental math mistake. Your sections' probability weights summing to 10 means nothing because the weighted chances aren't applied to the entire 0..240 set. It would return similar results if you ran each restricted probability on 0..240 instead of 0..59, 60..119, etc.
Incidentally, your Chance() function is slightly off in that, to get the probabilities you seem to be trying for, it should be either mt_rand(1, $universe) <= $chance or mt_rand(0, $universe - 1) < $chance.

Related

How do I increase enemy's speed every time level increases?

I have a very long code set up, and I know there should be an easier way, but I can't seem to find it. I want the enemies to increase speed every level by .5. How can I do this?
function makeEnemies():void
{
var chance:Number = Math.floor(Math.random() * 150);
if (chance <= + level)
{
tempEnemy = new Enemy();
tempEnemy.speed = 2
//Math.random(); gets a random number from 0.0-1.0
tempEnemy.x = Math.round(Math.random() * 1000);
addChild(tempEnemy);
enemies.push(tempEnemy);
if (level == 2)
{
tempEnemy.speed = 3
}
if (level == 3)
tempEnemy.speed = 4
}
}
}
You can try something like:
var enemyBaseSpeed:int = 2;
var speedLevelInc:Number = 0.5;
then later:
tempEnemy.speed = enemyBaseSpeed + ((level - 1) * speedLevelInc);
(Though you sample code shows the speed increasing by 1 per level)

Flash AS3 - Timer goes crazy after a few loops

I've been making a "slideshow" where 4 images are animated in random order.
To prevent multiple animations to one image for example 3 times successively, I've write a little logic.
My problem : after a few times all the 4 images are animated (after the query 'array' is cleared the second time I think), the timer goes crazy and trace() random numbers in a high sequence rate without to animate the images, with would look creepy I think.
My code :
var myTimer:Timer = new Timer(2500);
myTimer.addEventListener(TimerEvent.TIMER, animate);
myTimer.start();
var array:Array = new Array();
var lastNum:int;
function animate(e:TimerEvent):void {
var num:int = getRandomNumber( 1, 4 );
trace( num );
if( array.indexOf( num ) < 0 && num != lastNum ) {
myTimer.delay = 2500;
if( num == 1 ) {
sideImg_start_1.play(); // comment this*
} else if( num == 2 ) {
sideImg_start_2.play(); // comment this*
} else if( num == 3 ) {
sideImg_start_3.play(); // comment this*
} else if( num == 4 ) {
sideImg_start_4.play(); // comment this*
}
array.push( num );
if( array.length == 4 ) {
array.splice(0, 4);
trace(" array cleared - " + array.length);
lastNum = num;
}
} else {
myTimer.delay = 100; // I've also tryed so make a higher delay
// like 500 but its the same problem...
}
}
function getRandomNumber( min:int, max:int ):int {
return Math.floor( Math.random() * ( 1 + max - min ) ) + min;
}
stop();
So guys, thanks for all your answers and your help :D
UPDATE:
First I've tried to simply call the 'animate()' function instead of defining a higher speed to the timer to call the next number fast, without to loose time, which would make the random animation look weird.
I've used animate(null); instead of myTimer.delay = 100; before, but then I was getting a STACKOVERFLOW error :P
For example if your lastNum is equal to 4, and you have 1,2 and 3 as new values, than you will end up with an infinite loop,
because you can't insert 4 (because it's equal to the lastNum) and you can't insert 1,2 or 3 because they are already in the array.
What you need to do is:
if (array.length == 4) {
array.splice(0, 4);
lastNum = num;
} else {
lastNum = 0; //<-- HERE
}

Percentage Distribution of numbers in AS3

I need to generate 238 numbers, with a range of 1-4, but I want to weight them, so there's say 35% chance of getting 3, 28% chance of getting 2, 18% chance of getting 4m, and 19% chance of getting 1.
I found this..
def select( values ):
variate = random.random() * sum( values.values() )
cumulative = 0.0
for item, weight in values.items():
cumulative += weight
if variate < cumulative: return item
return item # Shouldn't get here, but just in case of rounding... print select( { "a": 70, "b": 20, "c": 10 } )
But I don't see how to convert that to AS3?
I would do something like this:
var values:Array = [1,2,3,4];
var weights:Array = [35, 28, 18, 19];
var total:Number = 0;
for(var i in weights) {
total += weights[i];
}
var rndNum:Number = Math.floor(Math.random()*total);
var counter:Number = 0;
for(var j:Number = 0; j<weights.length; j++) {
counter += weights[j];
if( rndNum <= counter ) return values[j]; //This is the value
}
(untested code, but the idea should work)
Take a look at this article:
http://uihacker.blogspot.com/2009/09/actionscript-3-choose-random-item-from.html
You can also use Rnd.bit() to get a weighted 1 or 0 and adapt it to your situation.
Here for you:
/**
* random due to weighted values
*
* #param {{}} spec such as {'a':0.999, 'b':0.001}
* #return {*} return the key in object
*/
public static function weightedRand(spec:Object):* {
var i:String, j:int, table:Array = [];
for (i in spec) {
// from: https://stackoverflow.com/questions/8435183/generate-a-weighted-random-number
// The constant 10 below should be computed based on the
// weights in the spec for a correct and optimal table size.
// E.g. the spec {0:0.999, 1:0.001} will break this impl.
for (j=0; j<spec[i]*10; j++) {
table.push(i);
}
}
return table[Math.floor(Math.random() * table.length)];
}
Then you could test with this code:
public static function main():void {
// test calculate weighted rand
// random weighted
var result:Array = [];
for (var k:int = 0; k < 100; k++) {
var rand012:String = MyUtil.weightedRand({'y': 0.8, 'n1': 0.1, 'n2': 0.1});
result.push(rand012); // random in distribution...
}
logger.traceObject('result: ', result);
// counts
var counts:Object = {};
var totalCounts:int = 0;
for (var i:int = 0; i < result.length; i++) {
counts[result[i]] = 1 + (counts[result[i]] || 0);
totalCounts++;
}
logger.traceObject('counts: ', counts);
// ratios
var ratios:Object = {};
for (var c:String in counts) {
ratios[c] = counts[c] / totalCounts;
}
logger.traceObject('ratios: ', ratios);
}

Make an application that determines if a sequence of numbers is sorted

Yet another installment of the weekly code-bowling game as the previous incarnation is over a week old and fairly well explored by now. As a refresher:
Code-Bowling is a challenge for
writing the most obscure, unoptimized,
horrific and bastardized code
possible. Basically, the exact
opposite of Code-Golf.
The Challenge:
Create a program that takes a sequence of numbers, and determines if they are in an ascending order.
Example:
$ ./myprogram 1 2 7 10 14
true
$ ./myprogram 7 2 0 1
false
Rules:
There really are none. It can be a console application, it can be a webpage, it can be whatever. It just needs to be a stand-alone program that accepts numbers and returns numbers. The format and methods are 100% up to you.
So have fun, and let's see the bastardized solutions you can come up with!
This uses something I call "Parent Sort". For list greater than size 1, you have to ask Mom or Dad about each pair of numbers. It's interesting because there's a chance that Mom might have you go ask Dad, and there's a bigger chance that Dad will have you go ask Mom. Could run forever assuming infinite stack capabilities.
function askMom($num1, $num2) {
$chance = mt_rand(0,2);
if ($chance>1) {
return askDad($num1, $num2);
} else {
return $num1 <= $num2;
}
}
function askDad($num1, $num2) {
$chance = mt_rand(0,4);
if ($chance>1) {
return askMom($num1, $num2);
} else {
return $num1 <= $num2;
}
}
function parentSort(array $numbers) {
for ($i = 0; $i < count($numbers)-1; $i++) {
$chance = mt_rand(0,1);
if ($chance) {
if (askMom($numbers[$i], $numbers[$i+1])) {
} else {
return false;
}
} else {
if (askDad($numbers[$i], $numbers[$i+1])) {
} else {
return false;
}
}
}
return true;
}
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv){
int a, b;
if (argc > 2){
sscanf(argv[1], "%d", &a);
sscanf(argv[2], "%d", &b);
if (a<=b)
return main(argc-1, argv+1);
printf("false");
exit(0);
};
printf("true");
return 0;
};
This solution has worst-case performance O(n!) and works by generating all possible permutations of the list, and then calculating a number (see the function 'value') that has it's minimum for sequential lists (ascending or descending).
def value(list):
sum = 0
for i in range(len(list)-1):
sum = sum + (list[i]-list[i+1])**2.0
return sum
def drop(lst, i):
if i + 1 >= len(lst):
return lst[:i]
else:
return lst[:i] + lst[i+1:]
class list_permute:
def __init__(self, lst):
self.lst = lst
self.i = -1
self.subiter = None
def __iter__(self):
return self
def next(self):
if len(self.lst) == 1:
if self.i == -1:
self.i = self.i + 1
return self.lst
else:
raise StopIteration()
if self.subiter != None:
try:
return [self.lst[self.i]] + self.subiter.next()
except StopIteration:
self.subiter = None
if self.subiter == None:
self.i = self.i + 1
if self.i >= len(self.lst):
raise StopIteration()
else:
self.subiter = list_permute(drop(self.lst, self.i))
return self.next()
def test(list):
given = value(list)
for i in list_permute(list):
if value(i) < given:
return False
# Test for false positive
if list[0] > list[len(list)-1]:
return False
return True
list = []
print "Feed me your numbers (end with ^C)"
try:
while True:
try:
list.append(int(raw_input()))
except ValueError:
print "NaN"
except (KeyboardInterrupt, EOFError):
pass
print test(list)
Here's a quick one. Interestingly, it should still be pretty efficient, since it only iterates over the terms once. It can only work on numbers between 0 and 255...
array_shift($argv);
$str = str_repeat(chr(0), 256);
foreach ($argv as $key => $element) {
$str[(int) $element] = chr($key + 1);
}
$str = str_replace(chr(0), '', $str);
$hex = unpack('H*', $str);
for ($i = 1; $i < strlen($str); $i++) {
if (substr($hex[1], $i * 2 - 2, 2) != dechex($a)) {
echo "False\n";
die();
}
}
echo "True\n";
It works by inverting the string (1 2 5 4 becomes 1 2 0 4 3, in other words, the number in the sequence becomes the key in the result, and the position in the sequence becomes the value. Then all we need to check is that 1 is in position 1.
And along the same lines (same theory, just set-theory operations):
array_shift($argv);
$vals = array_flip($argv);
ksort($vals);
echo array_values($vals) == range(0, count($vals) - 1) ? "True\n" : "False\n";
This solution isn't unoptimised, but it is obscure, horrific, and bastardised...
/* Either #define macros FIRST, SECOND, THIRD, etc. here, or do so on the
* command line when "compiling" i.e.
* $ gcc -D FIRST=1 -D SECOND=5 -D THIRD=42
*/
#define min(X, Y) ((X) < (Y) ? (X) : (Y))
#define pairsorted(X, Y) (min((X), (Y)) == (X) ? 1 : 0)
#if defined (FIRST) && defined (SECOND) && pairsorted(FIRST, SECOND)
#if defined (THIRD) && pairsorted(SECOND, THIRD)
#if defined (FOURTH) && pairsorted (THIRD, FOURTH)
#if defined (FIFTH) && pairsorted (FOURTH, FIFTH)
#error "Sorted!"
#elif !defined (FIFTH)
#error "Sorted!"
#else /* FIFTH is defined and < FOURTH */
#error "Not sorted!"
#endif /* FIFTH */
#elif !defined (FOURTH)
#error "Sorted!"
#else /* FOURTH is defined and < THIRD */
#error "Not sorted!"
#endif /* FOURTH */
#elif !defined (THIRD)
#error "Sorted!"
#else /* THIRD is defined and < SECOND */
#error "Not sorted!"
#endif /* THIRD */
#elif !defined (SECOND)
#error "Sorted!"
#else /* SECOND is defined and < FIRST */
#error "Not sorted!"
#endif /* SECOND */
#ifndef SECOND
#error "I need at least two values to compare"
#endif
This (ab)uses the C compiler as it's runtime environment, or can be invoked with the following shell script for prettier output (relies on the above being in sortedcpp.c):
#!/bin/bash
ORDINALS=(ZEROTH FIRST SECOND THIRD FOURTH FIFTH)
VALUES=(0 $#)
for i in 1 2 3 4 5; do
if [ $i -le $# ]
then
flags="$flags -D ${ORDINALS[$i]}=${VALUES[$i]}"
fi
done
output=`gcc $flags sortedcpp.c 2>&1`
echo $output | sed -e 's/sortedcpp.c:[0-9]*: error: #error \"\(.*\)\"/\1/'
First time I used dynamic programing to make things worse
It has time and space complexity of O(n²)
#include <stdio.h>
int main (int argc, char **argv)
{
int is_ordered[1000][1000];
int list[1000];
int i,j;
for(i = 1; i < argc; i++)
sscanf(argv[i],"%d", &list[i-1]);
for (i = 0; i < argc -2; i++)
{
if (list[i] < list[i+1])
is_ordered[i][i+1] = 1;
else
is_ordered[i][i+1] = 0;
}
for (i = 2; i < argc -1; i++)
for (j = 0; j < (argc - 1 - i); j++)
{
if (is_ordered[j+1][i+j] && is_ordered[j][i+j-1])
is_ordered[j][j+i] = 1;
else
is_ordered[j][j+i] = 0;
}
if(is_ordered[0][argc-2])
printf("True\n");
else
printf("False\n");
return 0;
}
Yay, Python!
def IsSorted(lst):
return sorted(lst) == lst

action script string masking function

Following is a php function for masking a string. Can somebody give me the actionscript equalent for this function.
public static function simple_encrypt($input) {
$return = array();
for($i = 0; $i < strlen($input); $i++){
$ascii = ord(substr($input, $i, 1)) * 2;
$return[] = base_convert($ascii, 10, 32);
}
return sprintf('RL%s', implode('', $return) ); // "RL" ensures it starts with a letter
}
public static function simple_encrypt(input:String):String {
var ret = [];
var ascii:Number;
for(var i:Number = 0; i < input.length; i++) {
ascii = input.charCodeAt(i) * 2;
ret.push(ascii.toString(32));
}
//I don't speak php, so I am assuming that
//RL doesn't have any syntactical meaning with sprintf
return "RL" + ret.join(''); //joins everything to a single string.
}