http://www.perlmonks.org?node_id=605013

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

I'm just starting to play around with Curses and I want to draw a (n,n) box of X's to the screen. Then I want to move that box and draw it again. I'm trying to figure out how modify the coordinate variables stored in the matrix.

Currently, I'm storing my coordinates in a matrix. I create my matrix like this...

```my (\$x, \$y) = qw(5 10);
my @A = (
[ ([\$x, \$y  ]), ([\$x+1, \$y  ]), ([\$x+2, \$y  ]), ([\$x+3, \$y  ]) ],
[ ([\$x, \$y+1]), ([\$x+1, \$y+1]), ([\$x+2, \$y+1]), ([\$x+3, \$y+1]) ],
[ ([\$x, \$y+2]), ([\$x+1, \$y+2]), ([\$x+2, \$y+2]), ([\$x+3, \$y+2]) ],
[ ([\$x, \$y+3]), ([\$x+1, \$y+3]), ([\$x+2, \$y+3]), ([\$x+3, \$y+3]) ],
);

After drawing my matrix, I try to move and redraw the matrix, but when I change \$x and \$y, it doesn't change the elements in the already created matrix. I've looked at a couple of the Matrix modules, but they all seem to want my matrix elements to be a single value, not an array.

Is there a way to get (\$x,\$y) to update without cycling through the entire matrix again?

Replies are listed 'Best First'.
Re: Storing variable coordinates in a matrix
by davidrw (Prior) on Mar 15, 2007 at 16:46 UTC
the my @A assignment uses the values of \$x and \$y at that time, and then you get an AoA of static numbers .. changing \$x and \$y after the fact will have no effect. I believe what you're looking for is a function, so you can pass in \$x and \$y and get back the array calculated for those two values.
```sub makeBoxArray {
my (\$x, \$y) =  @_;
return (
[ ([\$x, \$y  ]), ([\$x+1, \$y  ]), ([\$x+2, \$y  ]), ([\$x+3, \$y  ]) ],
[ ([\$x, \$y+1]), ([\$x+1, \$y+1]), ([\$x+2, \$y+1]), ([\$x+3, \$y+1]) ],
[ ([\$x, \$y+2]), ([\$x+1, \$y+2]), ([\$x+2, \$y+2]), ([\$x+3, \$y+2]) ],
[ ([\$x, \$y+3]), ([\$x+1, \$y+3]), ([\$x+2, \$y+3]), ([\$x+3, \$y+3]) ],
);
}

my @A = makeBoxArray( 5, 10 );
# use @A for something
@A = makeBoxArray( 7, 2 );
# use @A for something
To take it a step further, the array can be generated using map to eliminate the repetitive text, and also add optional params for the box size:
```sub makeBoxArray {
my \$left = shift;
my \$top = shift;
my \$width = shift || 4;
my \$height = shift || 4;
return map {
my \$y = \$_;
[ map { [\$left+\$_, \$top+\$y] } 0 .. \$width-1 ]
} 0 .. \$height-1 ;
}
Re: Storing variable coordinates in a matrix
by Fletch (Bishop) on Mar 15, 2007 at 16:37 UTC

Aside from a few extra parens, your problem is that you're storing the value in \$x and \$y as it is at the time @A is initialized. In order to get close to doing what you want you'd need to store references to \$x and \$y, but that won't let you store (say) \$y+1 and you'd have an additional layer of dereferencing to get the values out.

The best compromise would be to make a sub which returns a new set of coords given a new \$x and \$y.

Re: Storing variable coordinates in a matrix
by andye (Curate) on Mar 15, 2007 at 16:42 UTC
Shandor, I'm sorry to not really answer your question, but: I'm not clear why you want to do it like that? Does Curses force it on you somehow? Wouldn't it be easier to just run through \$x..\$x+3 and \$y..\$y+3 each time?

Perhaps I'm missing something. I think that PDL can do what you want, but it's probably overkill...

Best wishes, andye

update: actually, come to think of it: one way that you could do what you want would be to store the definition of @A as a string, then eval() it when you need it. That should work all right.

Re: Storing variable coordinates in a matrix
by Moron (Curate) on Mar 15, 2007 at 17:18 UTC
Hint: you need two nested loops -- nested because of two dimensions x and y -- one loop to clear the 'screen' matrix and one loop to repopulate it and ..."One loop to bring them all and in the darkness run them" ;) (just kidding at the end there)...

Also I'd be expecting to pass five variables to a more generic subroutine -- reference to screen matrix, x, y, width and height rather than hard-code the 3x3.

Totals: 0 modules and about 6 - 12 lines of code should do this.

More hint: the syntax for assigning to an element of a matrix passed by reference would be

```    \$ref -> [\$x][\$y] = 'X';

-M

One loop to bring them all and in the darkness run them

You mean TK's mainloop? :)

How can you feel when you're made of steel? I am made of steel. I am the Robot Tourist.
Robot Tourist, by Ten Benson

Re: Storing variable coordinates in a matrix
by jettero (Monsignor) on Mar 16, 2007 at 19:29 UTC

What you really want is for each element of your matrix to be dynamically calculated — like a spreadsheet. You need to overload the way perl indexes the matrix. For that, you want Tie::Array, actually Tie::StdArray in particular. Then just alter the way the package works to suit your needs.

In this case, you want to store expressions at each index and evaluate them on the fly. I admit to thinking that wasn't possible in perl for a couple days, but tye straightened me out (ironically/punny) in the CB. I felt rather foolish about it actually.

-Paul