abrash-black-book/18-02.md
2013-12-30 20:26:41 +11:00

78 lines
4.1 KiB
Markdown

### Table-Driven Magic {#Heading4}
David Stafford won my first Optimization Challenge by means of a huge
look-up table and an incredible state machine driven by that table. The
table didn't cause David's entry to exceed the line limit because
David's submission included code to generate the table on the fly as
part of the build process. David has done himself one better this time
with his QLIFE program; not only does his build process generate a 64K
table, but it also generates virtually all his code, consisting of
17,000-plus lines of assembly language spanning another 64K. What David
has done is write the equivalent of a bitblt compiler for the Game of
Life; one might in fact call it a Life compiler. What David's code
generates is still a general-purpose program; it takes arbitrary seed
values, and can run for an arbitrary number of generations, so it's not
as if David simply hardwired the instructions to draw each successive
screen. However, it's a general-purpose program that is exquisitely
tailored to the task it needs to perform.
All the pieces of QLIFE are shown in Listings 18.1 through 18.5, as
follows: Listing 18.1 is BUILD.BAT, the batch file used to build QLIFE;
Listing 18.2 is LCOMP.C, the program used to generate the assembler code
and data file QLIFE.ASM; Listing 18.3 is MAIN.C, the main program for
QLIFE; Listing 18.4 is VIDEO.C, the video-related functions, and Listing
18.5 is LIFE.H, the header file. The following sidebar contains David's
build instructions, exactly as he wrote them. I certainly won't have
room to discuss all the marvelous intricacies of David's code; I suggest
you look over these listings until you understand them thoroughly (it
took me a day to pick them apart) because there's a lot of neat stuff in
there, and it's an approach to performance programming that operates at
a more efficient, tightly integrated level than you may ever see again.
One hint: It helps a *lot* to build and run LCOMP.C, redirect its output
to QLIFE.ASM, and look at the assembly code in that file. This code is
the entirety of David's generation engine, and it's almost impossible to
visualize its operation without actually seeing it.
> * * * * *
>
> How To Build Qlife
>
> QLIFE is written for Borland C++, but it shouldn't be too difficult to
> convert it to work with Microsoft C++. To build QLIFE, run the
> BUILD.BAT batch file with the size of the life grid on the command
> line (see below). The command-line options are:
>
> -- ----------- -------------------------------------------------------------
> WIDTH 32 Sets the width of the life grid to 96 cells (divided by 3).
> HEIGHT 96 Sets the height of the life grid to 96 cells.
> NOCOUNTER Turns off the generation counter (optional).
> NODRAW Turns off drawing of the cell map (optional).
> GEN 1000 Calculates 1,000 generations (optional).
> -- ----------- -------------------------------------------------------------
>
> These *must* be in uppercase. For example, the minimum you really need
> is "WIDTH 40 HEIGHT 120." I used "WIDTH 46 HEIGHT 138 NOCOUNTER NODRAW
> GEN 7000" during testing.
>
> If you have selected the GEN option, you will have to press a key to
> exit QLIFE when it is finished. This is so I could visually compare
> the result of N generations under QLIFE with N generations under
> Abrash's original life program. You should be aware that the program
> from the listing contains a small bug, which may make it appear that
> they do not generate identical results. The original program does not
> display a cell until it changes, so if a cell is alive on the first
> generation and never dies, then it will never be displayed. This bug
> is not present in QLIFE.
>
> You should have no trouble running QLIFE with cell grids up to
> 210x200.
>
> You *must* have a VGA and at least a 386 to run QLIFE. The 386
> features that it uses are not integral to the algorithm (they're a
> convenience for the code), so feel free to modify QLIFE to run on
> earlier CPUs if you wish. QLIFE works best if you have a large CPU
> cache (256K is recommended).
>
> —*David Stafford*
>
> * * * * *