RUBE II:  Das Klickenklacker, First Sketch at Implementation:

Supported Command-Line:

The RUBE II interpreter ("klik") supports the following syntax in the
command line:
	klik <sourcefile>
	klik <options> <sourcefile>
	klik <sourcefile> <options>
where options are a single "word," prefaced by a dash ('-') or a
slash ('/'), and are made up of any ordering of the following:
	option	example	description
	a	a	No ANSI signals to clear screen
	b<num>	b150	Begin animation at specified frame number
	e<num>	e400	End program after specified frame number
	h<num>	h12	Display no more than the first lines
	q	q	"Quiet Mode"--does not show animation
	t<num>	t78	Truncate display lines to a particular width
	x<num>	x25	Sets the width (x-dimension) of the warehouse
	y<num>	y10	Sets the depth (y-dimension) of the warehouse
Options can appear in any order.

So, as an example, we can have something like:
	klik -h24t80x500y750 hugeprog.rub
which will run the RUBE program in a warehouse 500 by 750 cells, but
only display the upper-left screenful.

Example Programs:

A language implementation is useless without good samples, so the
following (which, honestly, were created for testing, so don't
expect miracles) are included:
	echo.rub	A simple program that parrots keyboard input
	hi.rub		Hello, World! - inelegant
	hi2.rub		Hello, World! - slightly more RUBE-ish
	test.rub	Fairly extensive test
	bob.rub		Not quite 99 Bottles of Beer, but a few bottles
			of something, at least...

Random Meanderings:

The primary object in RUBE II will be the grid of objects, much
like in RUBE.  Each object in the grid will have to be one of
the three types:  Stationary, Motive, and Moveable.

This suggests a preliminary structure for the objects in general:
	struct	thing
		{
		 char	display;
		 int	type;
		 int	pushed;
		 int	motivation;
		 int	direction;
		}
Stationary Objects have pushed and motivation set to zero at all
times, resetting each round if necessary.
Motive Objects have motivation set to one.  Each cycle, an engine
tries to set pushed to one, which will succeed if nothing if
there is no conflict.
Moveable Objects have motivation and pushed set to zero, but a
Motive Object can set pushed to one until the end of the round.

The basic RUBE resolution algorithm, therefore, is something like
	save old gridstate
	for each square in grid
		conflict = no
		if square+(direction*pushed) is filled
			check old state of square
			resolve conflict = (yes/no)
		if conflict = no
			square+(direction*pushed) = square
			point square to square+(direction*pushed)
			square.pushed = square.motivation

Which works, but precedence rules might be better suited
	create newgrid
	for each square in grid, ordered by precedence
		point sq to newgrid.square+(direction*pushed)
		if sq is empty
			sq = grid.square
		else if newgrid.square is empty
			point sq to newgrid.square
			sq = grid.square
		else
			point sq to newgrid.square
			square.pushed = sq.motivation
			square.direction = sq.direction
			choose square on newgrid again
		sq.pushed = sq.motivation;

Precedence Rules are:
	 1.  Stationary Objects
	 2.  Motive Objects - Vertical
	 3.  Motive Objects - Horizontal
	 4.  Moveable Objects - Vertical
	 5.  Moveable Objects - Horizontal

Optimizations:

It seems to be much easier to treat gravity independently from the
rest of the action.  Not only does it speed up execution, since
spaces have no interesting semantics to speak of, but it also serves
as a template for other forces (wind, maybe?  slower falling?).

Specific comments on this implementation:

 1- The core code is fairly well-structured, in my opinion, but
    the "peripheral" code could be better managed as functions
    pointed to from within the Thing structure.  However, great
    thought needs to be given to the parameters, since changing
    every last call for every code change is not an appealing
    notion.
 2- The code, as it stands, is 100% ANSI, as far as I know,
    except for input.  It makes it through Borland C++ 5.01
    (bcc -wall) and gcc/CygWin (gcc -ansi -pedantic) without
    warnings.  To do so, however, requires that the input command
    be conditionally compiled, meaning that input is impossible
    on other platforms (until someone tells me how to poll the
    input stream on other systems).

Where to go from here:

One thing I would really like to do is to clean up the "Before" and
"On Collision" code, and make it a bit more object-oriented, as
mentioned in the code, itself.  If that gets done in a reasonable way,
it might even be possible to create a "RUBE framework" where the set
of objects and rules can be defined externally, rather than hardcoding
everything.

Color might be a useful visualization technique, changing the color
each cycle that an object stays in the same place.

It would be really nice if input worked for all the major systems
out there.

There are one or two other objects that might come in handy for RUBE
programmers, like comparison objects which can block or free
neighboring cells.  An addition to that might be to give each crate
a weight given its value, making this a scale.

Speaking of addition, an "overflow crate" might be nice.

Finally, There appears to be a minor bug or two regarding gravity.
The only known such bug is an admitted oversight--I need to add
vertical collision code for the ramps, so that objects that fall on a
ramp slide down.  It's probably just another line of code for each
case, but that shouldn't delay the interpreter any more than it
already has, right?
