PDA

View Full Version : Infinite Loop of Doom


rollercoaster375
2006-08-03, 22:34
As you probably guessed from the title, I'm having some problems with an Infinite Loop.

We're re-painting our bathroom, and we decided on stripes in various colors and widths, aranged randomly. Since I was bored, and because it's probably easier than doing it ourselves, I decided to write a script to do so for us. It selects a width for the stripe, chooses a color, and then displays it. Pretty simple.

It has a few requirements, however, that break it, for some reason (At least, when I implemented it). Firstly, we can't have two colors in a row. Duh. Secondly, we don't want to have a 5" brown stripe, because the brown is being used as an accent, not as a primary color in the room. Lastly, I attempted to allow probability picking of The size and color, so that where brown was picked 10% of the time, white would be picked 40% of the time.

The sizes we've decided on are 1.5", 2.5", 3.5" and 5". The colors are Blue, Teal, Brown, and White, if that's helpful, for some reason (It's not too hard to grasp from the code...).

Now, the code I wrote worked, until I tried to add additional restrictions on the color choice. By now, you're probably sick of reading an explaination, and want to see the code. I wrote it in both Ruby and PHP, just to make sure I wasn't running into a language bug. So, here's the code. (It's also very likely that my Ruby code is horrible, as I'm not strong in the language)

PHP:
<?php

$sizes = array ( array ( 1.5, 20 ), array ( 2.5, 25 ), array ( 3.5, 30 ), array ( 5.0, 25 ) );
$colors = array ( array ( "Teal", 25 ), array ( "Blue", 25 ), array ( "White", 40 ), array ( "Brown", 10 ) );

$prev = 0;

echo "ID\tSize\tSum\tColor\n";
for ( $i = 1; $i < 4; $i++ ) {
do {
$size = $sizes [ mt_rand ( 0, 3) ];
} while ( $size['1'] <= mt_rand (1, 100) );
do {
$color = $colors[ mt_rand ( 0, 3) ];
} while (
( $color ['1'] <= mt_rand (1, 100) ) || !( ( $size['0'] == 5.0 ) XOR ( $color['0'] == "Brown") ) || ( $color['0'] == $lastcolor['0'] ) );
echo $i . ":\t". $size ['0'] . "\"\t(" . $prev . '")' . "\t " . $color['0']. "\n";
$prev += $size['0'];
$lastcolor = $color;
}

?>

Ruby:

#!/usr/bin/env ruby

sizes = [ [1.5, 20], [2.5, 25], [3.5, 30], [5.0, 25] ]
colors = [ ["Teal", 25], ["Blue", 25], ["White", 40], ["Brown", 10] ]

prev = 0
i = 1
lastcolor = "";

puts "ID\tSize\tSum\tColor\n"
while ( i < 4 )
size = sizes[rand(4)]
while (size[1] >= rand(100))
size = sizes[rand(4)]
end
color = colors[rand(4)]
while ( color [1] >= rand(100) ) || ( ( size[0] == 5.0 ) ^ ( color[0] == "Brown") ) || (color[0] != lastcolor[0])
color = colors[rand(4)]
end
puts i.to_s + ":\t" + size[0].to_s + "\"\t(" + prev.to_s + '")' + "\t " + color[0] + "\n"
prev += size[0]
lastcolor = color
i += 1
end


Expected output would be a Tab-columned list of the ID of the stripe, the length of the stripe, the total of all the stripes so far, and the color of the stripe.

billybobsky
2006-08-03, 22:43
Just a guess since I barely understand what your code is doing -- but have you tried reversing the color size xor statement?

Robo
2006-08-03, 22:47
We're re-painting our bathroom, and we decided on stripes in various colors and widths, aranged randomly. Since I was bored, and because it's probably easier than doing it ourselves, I decided to write a script to do so for us. It selects a width for the stripe, chooses a color, and then displays it. Pretty simple.

Hahaha...leave it to a geek to walk around the earth to move a mile.

Boredom inspires great things.

I don't know anything about code, but I wish you luck on your geeky endeavors.

I love this board.

(I'm painting my room, too...three 7"-wide horizontal stripes of lime green, yellow, and orange, going all the way around the room, with an inch of padding inbetween.)

rollercoaster375
2006-08-03, 22:48
It is reversed. It originally wasn't, so I'm quite sure that isn't the problem.

Also worth mentioning, it can generate 2-3 results, just not the 100+ we're going to need.

billybobsky
2006-08-03, 22:58
ok... while i<4... could that be the issue?

Edit: Can you walk me through your code... perhaps it will help you as well...

rollercoaster375
2006-08-03, 23:04
Heh. Whoops. In my conversion from the for loop to the while loop, I forgot to add the i += 1.

However, even with that fixed, it still runs without a stop.

As for the array... I don't use that exact statement, and I'm not aware if it causes that behaviour. From my testing in irb, rand(4) generates an int between 0 and 3 (Including the numbers themselves)

billybobsky
2006-08-03, 23:07
Is it outputting the same size over and over?

rollercoaster375
2006-08-03, 23:11
It's outputting nothing, except the little key that would go at the top of the page.

billybobsky
2006-08-03, 23:16
You say it worked before you modified the code to isolate brown...

What was it outputting then?

rollercoaster375
2006-08-03, 23:21
A randomized list of stripes...

An example of this:
5: 2.5" (12.5") Brown
6: 5" (15") Brown

However, that breaks two of the rules. Colors in a row and 5" brown.

thuh Freak
2006-08-03, 23:21
ok... while i<4... could that be the issue?
first thing i thot of too. on the ruby side, i is only set once, and never modified again.

i would go about the randoms a little different. i'd say: r=random(1,100). if r < 20, then size[0], else r-=20; if r < 25, then size[1], else r -= 25; ... but i aint perfectly sure if thats where the issue is, i'm just saying i'd do it different.

billybobsky
2006-08-03, 23:23
If you don't mind me asking...

what does the expression $size['1'] mean?

also...

this $size = $sizes [ mt_rand ( 0, 3) ] seems to be defining the size to be one of the first four elements in the sizes array right?

billybobsky
2006-08-03, 23:24
first thing i thot of too. on the ruby side, i is only set once, and never modified again.

i would go about the randoms a little different. i'd say: r=random(1,100). if r < 20, then size[0], else r-=20; if r < 25, then size[1], else r -= 25; ... but i aint perfectly sure if thats where the issue is, i'm just saying i'd do it different.


I had the same thought... This way you are avoiding doing comparisons of strings and using numbers instead...

Majost
2006-08-03, 23:50
You know, some times you just gotta start over. Shoe-horning is great and all, but it gets tough to read and update after a while. :)

This is how I envisioned it. It's not the most efficient thing nor the best way to do it, but it was a snap to write and is easy to read and it works (http://beta.mbauman.net/test.php).
<?php
$NUMSTRIPES=100;

$color[0]='';

function pickcolor() {
$colorseed= rand(0,99);

if($colorseed<10) {
$colorpicked="brown";
} elseif ($colorseed<50) {
$colorpicked="white";
} elseif ($colorseed<75) {
$colorpicked="teal";
} elseif ($colorseed<100) {
$colorpicked="blue";
}

return $colorpicked;
}

function pickstripe() {
$stripeseed= rand(0,99);

if($stripeseed<20) {
$stripepicked="1.5";
} elseif ($stripeseed<45) {
$stripepicked="2.5";
} elseif ($stripeseed<75) {
$stripepicked="3.5";
} elseif ($stripeseed<100) {
$stripepicked="5.0";
}

return $stripepicked;
}

for ( $i = 1; $i < $NUMSTRIPES; $i++ ) {
$color[$i]=pickcolor();
while ($color[$i]==$color[$i-1]) {
$color[$i]=pickcolor();
}

$stripe[$i]=pickstripe();
while ($color[$i]=="brown" && $stripe[$i]=="5.0") {
$stripe[$i]=pickstripe();
}

echo $i . " " . $color[$i] . " " . $stripe[$i] . "<br>";
}
?>

billybobsky
2006-08-03, 23:55
Now that is code I understand...

spotcatbug
2006-08-04, 07:07
Shouldn't this:
while ( color [1] >= rand(100) ) || ( ( size[0] == 5.0 ) ^ ( color[0] == "Brown") ) || (color[0] != lastcolor[0])

Be like this:
while ( color [1] >= rand(100) ) || ( ( size[0] == 5.0 ) && ( color[0] == "Brown") ) || (color[0] == lastcolor[0])

That xor was saying, keep picking a new color as long as size is 5 or color is brown, but not both. Plus also the other conditions. That might make a seemingly infinite loop.

Anyway, the and seems more correct - keep picking colors if the size is 5 and the color is brown.

thuh Freak
2006-08-04, 07:20
If you don't mind me asking...

what does the expression $size['1'] mean?

also...

this $size = $sizes [ mt_rand ( 0, 3) ] seems to be defining the size to be one of the first four elements in the sizes array right?


$size looks to be a zero-based array. the '1'th element is the second item. mt_rand( x, y ) seems to return a rand int in the range x-y, inclusive. sizes was all the options, size was the specific option to choose (at random)

Gargoyle
2006-08-04, 07:26
change the last line to read as follows for a preview:-


echo "<div style=\"width: ".$stripe[$i]."em; height: 500px; float:left; background: ".$color[$i]."\"></div>

rollercoaster375
2006-08-04, 10:56
Shouldn't this:
while ( color [1] >= rand(100) ) || ( ( size[0] == 5.0 ) ^ ( color[0] == "Brown") ) || (color[0] != lastcolor[0])

Be like this:
while ( color [1] >= rand(100) ) || ( ( size[0] == 5.0 ) && ( color[0] == "Brown") ) || (color[0] == lastcolor[0])

That xor was saying, keep picking a new color as long as size is 5 or color is brown, but not both. Plus also the other conditions. That might make a seemingly infinite loop.

Anyway, the and seems more correct - keep picking colors if the size is 5 and the color is brown.
Correct ;)

Thanks for your help, everybody. That was the error. I'd shown this code to multiple people, and non were able to figure out what was wrong :P

It works now, so thanks for the help