Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

comment on

( #3333=superdoc: print w/replies, xml ) Need Help??

There is more to address here than algorithm efficiency. You need to learn more of perls' features. One glaring example is the lack of return values from subroutines. In perl subroutines can also be functons. Another example is the global variables defined at the beginning of the program. Globals are variables that are used anywhere in the program. They are usually frowned on. Let's take a look at one global: @fire_items. It is used exclusively in the subroutine: handle_fire().

handle_fire() is called each pass through the while block. The reason for making @fire_items global is because we don't want to lose the items between passes. The problem is if we want to use @fire_items in the future we need to take into account that at least one subroutine is changing it in an inobvious way. The use of many global variables makes it difficult to optimize and debug a program. There are too many dependencies.

When designing a subroutine, pretend a manager or teacher has assigned you the task. She has given the inputs, the outputs, and a few details. The rest of the program is not written yet or is not shown to you. Changing a variable in the program is not an option. Everything you need must be passed in and everthing you change must be passed back out. You can break the rules as you become a better programmer or as the situation dictates. While your learning, try to find a way to stick to them.

Here is the handle_fire() subroutine:

sub handle_fire { my ($new, $x, $y) = @_; my $skip = 0; if($new){ push(@fire_items, $x.' '.$y); } my $i = 0; while($i < @fire_items) { my ($xc, $yc) = split(' ',$fire_items[$i]); splice(@fire_items,$i,1) and $skip = 1 unless $xc < $app->widt +h + $images{'beam1'}->width; if($skip){ $skip = 0; next; } &erase_image($images{'beam1'}->width, $images{'beam1'}->height +,$xc-10,$yc); &put_image($images{'beam1'}, $xc, $yc); $fire_items[$i]=join(' ',$xc + 10, $yc); $i++; } }

Three items initially caught my eye:

  1. The use of an index to step through an array.
  2. The use of the & prefix to subroutines. Re-read perlsub. & doesn't always mean what you think.
  3. The use of @fire_items, %images, and $app which have not been passed to the subroutine.

This is how handle_fire() is called:

#draw gunshots, possibly add new one handle_fire( $fire, $x, $y );

Let's change handle_fire( $fire, $x, $y ) to accept and return a reference to @fire_items.

#draw gunshots, possibly add new one $fire_items = handle_fire( $fire, $x, $y, $fire_items );

Let's keep $fire_items defined outside the while block to maintain it's value between passes. Remember $fire_items is a reference to @fire_items.

my $fire_items; . . . while (1) { . . . #draw gunshots, possibly add new one $fire_items = handle_fire( $fire, $x, $y, $fire_items ); . . . }

Here's our sub again (with some whitespace added).

sub handle_fire { my ( $new, $x, $y ) = @_; my $skip = 0; if ( $new ){ push(@fire_items, $x.' '.$y); } my $i = 0; while( $i < @fire_items ) { my ( $xc, $yc ) = split(' ', $fire_items[$i] ); splice( @fire_items, $i, 1 ) and $skip = 1 unless $xc < $app-> +width + $images{beam1}->width; if( $skip ){ $skip = 0; next; } erase_image( $images{beam1}->width, $images{beam1}->height, $x +c-10, $yc ); put_image( $images{beam1}, $xc, $yc ); $fire_items[$i] = join(' ', $xc + 10, $yc ); $i++; } }

In order to use $fire_items reference we'll need to de-reference it. We'll also need to add a return and change the line that receives the passed variables.

sub handle_fire { my ( $new, $x, $y, $fire_items ) = @_; my $skip = 0; if ( $new ){ push(@$fire_items, $x.' '.$y); } my $i = 0; while( $i < @$fire_items ) { my ( $xc, $yc ) = split(' ', $$fire_items[$i] ); splice( @$fire_items, $i, 1 ) and $skip = 1 unless $xc < $app- +>width + $images{beam1}->width; if( $skip ){ $skip = 0; next; } erase_image( $images{beam1}->width, $images{beam1}->height, $x +c-10, $yc ); put_image( $images{beam1}, $xc, $yc ); $$fire_items[$i] = join(' ', $xc + 10, $yc ); $i++; } return $fire_items; }

Now let's look at the data structure. By using an Array of Arrays, we can eliminate the joining and splitting of spaces from $x and $y.

if ( $new ){ push(@$fire_items, $x.' '.$y); }
Becomes:
if ( $new ){ push @$fire_items, [$x, $y]; }
Or just:
push @$fire_items, [$x, $y] if $new;

and:

my ( $xc, $yc ) = split(' ', $$fire_items[$i] );
Becomes:
my ( $xc, $yc ) = @{ $fire_items[$i] };

and:

$$fire_items[$i] = join(' ', $xc + 10, $yc );
Becomes:
$$fire_items[$i] = [$xc + 10, $yc];

The splice is removing something from the array and going to the next item. Since $fire_items is a reference, changing it changes an external variable. Something we normally want to avoid if possible. Also $skip is only used to get to the next index. First, we'll get rid of $skip. As far as I can tell splice always returns a value:

unless ( $xc < $app->width + $images{beam1}->width ) { splice( @$fire_items, $i, 1 ); next; }

Now we'll add a temporary array to hold the values we're keeping and to avoid changing the $fire_items array. This is what I ended up with:

sub handle_fire { my ( $new, $x, $y, $fire_items ) = @_; my $i = 0; my @temp; while ( $i < @$fire_items ) { my ( $xc, $yc ) = @{ $fire_items[$i] }; next unless $xc < $app->width + $images{beam1}->width; erase_image( $images{beam1}->width, $images{beam1}->height, $x +c-10, $yc ); put_image( $images{beam1}, $xc, $yc ); push @temp, [$xc + 10, $yc]; $i++; } push @temp, [$x, $y] if $new; return \@temp; }

Since we are no longer using splice, we no longer need to track the index:

sub handle_fire { my ( $new, $x, $y, $fire_items ) = @_; my @temp; foreach my $item ( @$fire_items ) { my ( $xc, $yc ) = @$item; next unless $xc < $app->width + $images{beam1}->width; erase_image( $images{beam1}->width, $images{beam1}->height, $x +c-10, $yc ); put_image( $images{beam1}, $xc, $yc ); push @temp, [$xc + 10, $yc]; } push @temp, [$x, $y] if $new; return \@temp; }

For speed you could forgo not changing $fire_items, but pushing is probably faster than splicing.

HTH,
Charles K. Clarkson
Clarkson Energy Homes, Inc.

In reply to Re: Sprite animation with SDL_perl by CharlesClarkson
in thread Sprite animation with SDL_perl by Mirage

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post; it's "PerlMonks-approved HTML":



  • Are you posting in the right place? Check out Where do I post X? to know for sure.
  • Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
    <code> <a> <b> <big> <blockquote> <br /> <dd> <dl> <dt> <em> <font> <h1> <h2> <h3> <h4> <h5> <h6> <hr /> <i> <li> <nbsp> <ol> <p> <small> <strike> <strong> <sub> <sup> <table> <td> <th> <tr> <tt> <u> <ul>
  • Snippets of code should be wrapped in <code> tags not <pre> tags. In fact, <pre> tags should generally be avoided. If they must be used, extreme care should be taken to ensure that their contents do not have long lines (<70 chars), in order to prevent horizontal scrolling (and possible janitor intervention).
  • Want more info? How to link or or How to display code and escape characters are good places to start.
Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others perusing the Monastery: (4)
As of 2022-05-23 12:25 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    Do you prefer to work remotely?



    Results (82 votes). Check out past polls.

    Notices?