witandhumor has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Monks!

I have a problem that I need your help with.

The point of this is a little diddy that will create a random yet unique set of coordinates to place a specified character in a canvas. I cannot seem to get anything to get pushed into my array so I can compare the newly generated coordinate with values already used.

Any guidance will be greatly appreciated!

Thanks in advance!

use warnings; use strict; use Tk; #declarations my $char = "@"; my $num=0; my $width = 250; my $height =250; my (@xco,@yco,$xco,$yco); my $main=MainWindow->new(); $main->title("No Duplicates"); my $canvas=$main->Canvas(-width => $width, -height => $height) ->pack(-fill => "both", -expand => "true"); my $timer=Tk::After->new($main,'200','repeat',\&counter); MainLoop(); # Subroutines sub get_xcoord () { $xco = int (rand $height)+1; foreach my $value (@xco) { if ($value != $xco ) { push @xco,$xco; } } } sub get_ycoord () { $yco = int (rand $width)+1; foreach my $value (@yco) { if ($value != $yco) { push @yco,$yco; } } } sub counter { get_ycoord(); get_xcoord(); $num++; $canvas->createText($xco,$yco, -anchor => 'center', -text => $char, -fill => 'black'); print "@xco\n"; print "@yco\n"; print "$xco , $yco\n"; }

Replies are listed 'Best First'.
Re: Array remains empty
by graff (Chancellor) on Mar 29, 2004 at 03:47 UTC
    Well, the first thing wrong with your code is that you start with empty arrays, and the only place where anything is pushed into these arrays is inside a loop over the array elements:  for $value (@array) -- and since there are no array elements to start with, the push call is never reached.

    Apart from that, there seems to be a disconnect between your stated purpose and the design of your code, and there are some pending questions. How many characters do you plan to draw? Given a 250x250 (pixel) space, the characters will overlap more or less quickly (depending on the font size you're using), even though you don't re-use the same coordinates. If there is a limited number of characters to draw, you could "pre-select" a random set of coordinates by generating an x array and a y array of equal size (number of elements == number of characters to draw), making sure that each array is limited to unique values (something similar to suggestions provided in this thread: Select three random numbers between 1..10

    On the other hand, wouldn't it be okay if you use the same x or y coordinate more than once, so long as you don't repeat any given combination of x and y? If so, then you should be keeping a hash whose keys are strings like "123 78" -- that is, just the x and y integer values for a drawn letter, separated by a space. If you pick any two integers at random, it's very unlikely that it would match an existing point, but if it does, you'll find out quickly by testing  if ( exists( $drawn{"$xco $yco"} ))

    update: Oh yeah -- and that logic error that Mr. Muskrat alluded to... ooooh, it's quite the unpleasant sort. Look at your "for" loops, imagine that you start out with three values in @xco, and you have a fourth new random x coordinate (which happens not to match the other three). How many pushes do you want to do into @xco? And how many will actually be done by the code you've posted?

Re: Array remains empty
by Mr. Muskrat (Canon) on Mar 29, 2004 at 03:13 UTC

    You haven't put any values into @xco or @yco so how can you expect the loops to do anything?

    Added: Once you fix that, you'll find a logic error. ;-)

Re: Array remains empty
by witandhumor (Pilgrim) on Apr 04, 2004 at 05:14 UTC
    Thank you both for the responses! I have gotten closer to my original goal....

    use warnings; use strict; use Tk; #declarations my $char = "@"; my $width = 250; my $height =250; my ($xco,$yco); my @xco =(0..250); my @yco =(0..250); my $main=MainWindow->new(); $main->title("No Duplicates"); my $canvas=$main->Canvas(-width => $width, -height => $height) ->pack(-fill => "both", -expand => "true"); my $timer=Tk::After->new($main,'100','repeat',\&write); MainLoop(); # Subroutines sub write { if (@xco && @yco) { get_ycoord(); get_xcoord(); $canvas->createText($xco,$yco, -anchor => 'center', -text => $char, -fill => 'black'); } else { $canvas->createText('120','120',-anchor => 'center', -text => 'The end!', -fill => 'blue'); } } sub get_xcoord () { $xco = splice (@xco, int rand @xco, 1); } sub get_ycoord () { $yco = splice (@yco, int rand @yco, 1); }
    Thank you again!!!!!