It is prepared and executed with this:
(append the previous match - which is non whitespace chars - to $a, inside $a replace Z with a space. the second e flag then evaluates the return value of the first pass - so it evaluates the $a which is the code (in a single line).# s#((?{$a.=$+})\s?(\S*)\s?)*#$a=~s/Z/ /g;$a#see
Set up the width and height of each frame: size of boxes + 10px white border.( $width, $height ) = split /x/, shift || "19x20";
$x_max = 10 + 10 * $width; $y_max = 20 + 10 * $height;
Set up an array with an initial values for each box in the maze:
@m = ( ( 31, (15) x ( $width - 1 ) ) x $height, (31) x $width );
So if bit 8 is set then you can't 1 go that way (the inital value of 15 means the following function has to unset the bit.# 8 # 1 2 # 4 # v u d r l # 1 1 1 1 1
Set the visited bit - this means the search can't now go back here
$c holds the box number we are currently in (initially 0)
This is the start of a conditional$m[$c] |= 16,
Find unvisited directions, tests the value of the box above, below etc. against 16 (the visited bit), and in generation mode 16+<the bit check value - second in the input array>.!(
If there isn't a valid direction (ie @a is empty) go back to where we last were:@a = grep !( $m[ $c + $$_[0] ] & 16 + $| * $$_[1] ), #left [ -1, 8 ], #right [ 1, 1 ], # up [ $width, 4 ], # down [ -$width, 2 ] )
Otherwise:? $c = pop @p :
${ ( $i, $j ) = @{ $a[ rand @a ] };
$m[$c] &= ~ (8 / $j);
push @p, $c;
$m[ $c += $i ] &= ~$j;
++$counter - $height * $width + $height || map $_ &= 15, @m, splice(@p), $c = $| = 1 }
This stops the loop when the maze is drawn and the cursor is back in the bottom right:#print"\ec", # map$_%9?($_-$c?$m[$_]&2?_:$":o).($m[$_]&8?"|":_):$/,1..72
until $| & $c + 2 > $width * $height;
This is the size of each frame's data:$space = $x_max - 4 * int $x_max / 4;
$image is the image data and is initialised to be the correct length of all null bytes$image_size = ( $x_max + $space ) * $y_max;
In eight bit per pixel bmp's 1 byte represents 1 pixel, set to a value which points to the position in the colour table.$image = pack "x" x ( ( $x_max + $space ) * $y_max );
Set up to draw a vertical line - get the lowest to do range from y1 to y2. There is significan scope for golfing here.sub line { my ( $x1, $x_len, $y1, $y2, $e ) = @_;
Then from the top (ie the end of the file), set each bit to the correct colour (or 2 = black by default)@a = sort { "000$a" <=> "000$b" } $y1, $y2 || $y1; for ( $a[0] .. $a[1] ) {
This function converts a number in the @m maze to a pixel x/y$s = ( $y_max - $_ ) * ( $x_max + $space ) + $x1; vec( $image, $_, 8 ) = $e || 2 for $s .. $s + $x_len - 1; } }
Draw the borders:sub t { $a = shift; $x = 10 * ( $a % $width ); $y = 10 * ( 2 + int $a / $width ) }
Now draw the maze onto $image# top line 9, $x_max - 20, 10; # bottom line 9, $x_max - 20, $y_max - 10; # left line 9, 1, 10, $y_max - 10; # right line $x_max- 11, 1, 10, $y_max - 10;
Get x/y pixel for this point in the maze:map {
If it's not the last point in a row (which is used to define the edge and is initialised to stop access)t $_;
Check if we can go down - draw horizontal line if we can'tif ( $_ % $width ) {
And the same for the top$m[$_] & 2 ? line $x - 1, 11, $y : "";
Repeat this for all the boxes in the maze$m[$_] & 8 ? line $x + 9, 1, $y - 10, $y : ""; }
} 0 .. -1 + $width * $height;
So now we have a string ($image) with each byte set correctly to draw out an empty maze.
open( FH, ">al.avi" ); binmode FH; select FH; # a space saver $LIST = "LIST";
The header format can be found here, it's reasonably complicated2, but most of the values here are defaults (so header lengths, scaling etc), and this header will work with most data (in $image, with heights and widths etc set).print pack "V*", /\d/ ? $_ : unpack "V*", $_ for
The following is the data stream format header, it's format is that of a BMP data header, which is explained here3."RIFF", # length of file (header length + data length + index length) ( 1256 + ( $image_size + 24 ) * ( $num_frames = 3 + scalar @p ) +), "AVI $LIST", 1216, "hdrl", "avih", 56, 500000, 32, 0, # avi flags (hasindex etc) 2064, $num_frames, 0, 1, $image_size, # movie width $x_max, # movie height $y_max, (0) x 4, $LIST, 1140, "strl", "strh", 56, "vids", (0) x 4, 1, 10, 0, $num_frames, $image_size, -1, (0) x 3, "strf", # length of avi header: # (40) + length of color table (1024) 1064,
And now draw the colour table4- 0th entry white, 1st entry blue , the last 254 black40, $x_max, $y_max, # 8 is the bits per pixel pack( "vv", 1, 8 ), 0, $image_size, (0) x 4,
There is an "optional" JUNK header that goes here, used (i think) to bring the header and image stream data boundary at a point i left it out, but i think that might why it doesn't work in winamp (or some WMP or macs etc etc!), perhaps, maybepack( ( "H" x 1024 ), "f", "f", "f", 0, "a" ),
Now we get to draw the data.# "JUNK", # <length of junk to boundary>, # <null bytes to boundry>
This is the length of the data in the file (image size + image header size ) for each frame + "movi"$LIST,
( 4 + ( $image_size + 8 ) * $num_frames ), "movi";
Print to STDOUT the frame number (we gotta have some kind of feedback!)map {
Find the position of the previous positionprint STDOUT ++$G, $/;
Set left edge of block to be drawnt $previous|| 1;
And the top$left = $x;
Find the x/y of current position$top = $y;
Get the actual right and left (i should have just square and sqrt'd the length part)t $_; $right = $x;
Draw a line for the depth of the block to be drawnif ( $left > $x ) { $right = $left; $left = $x }
In blueline $left+ 2, 5 + $right - $left, ( $top < $y ? $top : $y ) - 7, ( $top < $y ? $y : $top ) - 3,
Actually print out the data (and header) - $image_size is the length of $image (or should be!)1; $previous = $_;
And now the index, simply a header,print "00db" . pack( "V", $image_size ) . $image } @p, ( -1 + $width * $height ) x 3;
And an entry for each frame telling the offset within the data chunk of the image for each frameprint "idx1" . pack "V", 16 * $num_frames; $o = 4;
for ( 1 .. $num_frames ) { print "00db" . pack "VVV", 16, $o, $image_s +ize; $o += $image_size + 8 }
And we're done.
Considered by teamster_jr: I've put this in meditations, but could be reparented under Let's go to the movies, up to you guys. al
Unconsidered by planetscape: keep votes prevailed (keep:16 edit:11 reap:0)
update: fixed typo - second line call is for right side of box rather than left again (obv)
(and fix endianness - use V and v rather than L and S)
|
---|
Replies are listed 'Best First'. | |
---|---|
Re: From terminal output to avi - "let's go to the movies" explained
by liverpole (Monsignor) on Apr 12, 2006 at 15:16 UTC | |
Re: From terminal output to avi - "let's go to the movies" explained
by jesuashok (Curate) on Apr 13, 2006 at 04:19 UTC |