|Perl: the Markov chain saw|
From terminal output to avi - "let's go to the movies" explainedby teamster_jr (Curate)
|on Apr 12, 2006 at 10:02 UTC||Need Help??|
Hi all, I'm not sure if this is the right place for this, or if people are interested, but below is a cleaned up, commented version of my latest obfu.
I tend to rely on tersness to make my code obfuscated, so, as noted in a reply the obfuscation is quite weak - it's mainly done to shape the code, I could have run it through huffman or something, but, er, didn't.alex
Looking back through it, there's definitely scope for some golfing, however you have to stop and post at some point!
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).
The easiest way to get the code is to remove the second e and then add a print $a. I prepared the following by doing this and running the result through perltidy.
In all my obfuscations i use single character variable names - these i tend to assign sequentially starting at $a as i write it. All i've done is reformat and name the variables meaningfully, the code below should still work - so the download link will give you code that works exactly the same as the obfuscated version, but there's a good chance i've messed something up in the tidying! (it worked when i tested it briefly though)
InitialisationSet up the width and height of the maze (in boxes - 1 box = 10px by 10px);
Set up the width and height of each frame: size of boxes + 10px white border.
Maze GenerationThis code is canibalised from a previous sig here
Set up an array with an initial values for each box in the maze:
This next part is a single until statement. it walks the maze, using a depth first search:
The values in the array determine the properties of that square. This is done by checking which bits are set with that value:
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.
Set the visited bit - this means the search can't now go back here
This is the start of a conditional
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:
this can be left in to draw the output as it solves it (although this is just ripped out without the proper values in, or the whole thing could be moved around to draw a point moving round to the solution (but the num_frames etc isn't known in time to draw the header, requiring a large buffer holding all the frames).
This stops the loop when the maze is drawn and the cursor is back in the bottom right:
Image PreparationBmp's (which are the format used in the data stream for the video), require that each line of pixels is padded until the length of the data for each row is divisible by 4 bytes, this does that:
This is the size of each frame's data:
$image is the image data and is initialised to be the correct length of all null bytes
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.
This function draws a line, it takes $x, <length of line>, y1, y2, colour:
Set up to draw a vertical line - get the lowest to do range from y1 to y2. There is significan scope for golfing here.
Then from the top (ie the end of the file), set each bit to the correct colour (or 2 = black by default)
This function converts a number in the @m maze to a pixel x/y
Draw the borders:
Now draw the maze onto $image
Get x/y pixel for this point in the maze:
If it's not the last point in a row (which is used to define the edge and is initialised to stop access)
Check if we can go down - draw horizontal line if we can't
And the same for the top
Repeat this for all the boxes in the maze
So now we have a string ($image) with each byte set correctly to draw out an empty maze.
Output the AVII'm tidying this up and turning it into a CPAN module, as it could be useful, maybe.
Draw the headerThe following takes a list of headers and values and packs them in the correct format:
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).
The following is the data stream format header, it's format is that of a BMP data header, which is explained here3.
And now draw the colour table4- 0th entry white, 1st entry blue , the last 254 black
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, maybe
Now we get to draw the data.
First the data header:
This is the length of the data in the file (image size + image header size ) for each frame + "movi"
Draw the Image dataThe following block travels along the path of @p (which is the shortest route from the top left to the bottom right), drawing a line (ie updating $image) as it goes. Each pass draws 1 frame of the clip.
Print to STDOUT the frame number (we gotta have some kind of feedback!)
Find the position of the previous position
Set left edge of block to be drawn
And the top
Find the x/y of current position
Get the actual right and left (i should have just square and sqrt'd the length part)
Draw a line for the depth of the block to be drawn
Actually print out the data (and header) - $image_size is the length of $image (or should be!)
And now the index, simply a header,
And an entry for each frame telling the offset within the data chunk of the image for each frame
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
update: fixed typo - second line call is for right side of box rather than left again (obv)