The Blocks Problem
The Blocks Problem is problem 101 in the UVa Online Judge. Even though I include the problem description in this post, I encourage you to visit the UVa Online Judge because there you will be able to submit your solution to get it judged.
Problem
The problem is to parse a series of commands that instruct a robot arm
in how to manipulate blocks that lie on a flat table. Initially there
are n
blocks on the table (numbered from 0
to n - 1
) with block
b_i
adjacent to block b_i + 1
for all 0 <= i < n - 1
as shown
in the diagram below:
The valid commands for the robot arm that manipulates blocks are:
-
move a onto b
wherea
andb
are block numbers, puts blocka
onto blockb
after returning any blocks that are stacked on top of blocksa
andb
to their initial positions. -
move a over b
wherea
andb
are block numbers, puts blocka
onto the top of the stack containing blockb
, after returning any blocks that are stacked on top of blocka
to their initial positions. -
pile a onto b
wherea
andb
are block numbers, moves the pile of blocks consisting of blocka
, and any blocks that are stacked above blocka
, onto blockb
. All blocks on top of blockb
are moved to their initial positions prior to the pile taking place. The blocks stacked above blocka
retain their order when moved. -
pile a over b
wherea
andb
are block numbers, puts the pile of blocks consisting of blocka
, and any blocks that are stacked above blocka
, onto the top of the stack containing blockb
. The blocks stacked above blocka
retain their original order when moved. -
quit
terminates manipulations in the block world.
Any command in which a = b
or in which a
and b
are in the same
stack of blocks is an illegal command. All illegal commands should be
ignored and should have no effect on the configuration of blocks.
Input
The input begins with an integer n
on a line by itself representing the number of blocks in the block world. You may assume that 0 < n < 25
.
The number of blocks is followed by a sequence of block commands, one
command per line. Your program should process all commands until the
quit
command is encountered.
You may assume that all commands will be of the form specified above. There will be no syntactically incorrect commands.
Output
The output should consist of the final state of the blocks world. Each
original block position numbered i
(0 <= i < n)
where n
is the
number of blocks) should appear followed immediately by a colon. If
there is at least a block on it, the colon must be followed by one
space, followed by a list of blocks that appear stacked in that
position with each block number separated from other block numbers by
a space. Don’t put any trailing spaces on a line.
There should be one line of output for each block position (i.e., n
lines of output where n
is the integer on the first line of input).
Sample Input
Sample Output
Analysis
Commands are either actions or quit.
We analyze the syntax and semantics of actions to determine a set of primitive operations on blocks. Consider the following action.
Syntactically, each action consists of a verb, an object, a preposition, and a complement.
Semantically, each action consists of a sequence of three primitive operations. Consider the following state.
The verb indicates the first operation.
The first operation is either put back the blocks on top of the
object or keep them relative to the object.
For the state, move 8
indicates that blocks 7 and 6 be put back in
the following way.
The preposition indicates the second operation.
The second operation applies to the complement in an analogous way.
For the previous state, over 9
indicates that the blocks on top of 9
be kept where they are, thus the previous state remains unmodified.
The third operation is the same for all actions and consists in placing the object and everything above it on top of the stack that contains the complement. For the previous state, the third operation gives the following state.
Solution
We implement the primitive operations and then apply them for each action.
For verb move
and preposition onto
, we put back blocks on top of a
given block by means of function put_back
.
Array table
indicates the state of the table by pointing to the
bottom of each stack located on the table.
For a given instance of block
, pointer above
indicates the block
above if any and pointer below
a block below.
Integer table_loc
indicates the location on the table of the given
block.
For a given block, put_back
iterates the blocks on top.
For each block on top, put_back
removes the block
from the current stack (lines A and B), sets the current location of
the block to its initial position (line C), and puts the block back in
its initial position (line D).
For verb pile
and preposition over
, we keep blocks on top of a
given block by doing nothing.
We implement the primitive operation that is common to all actions
in function stack
.
We apply functions put_back
and stack
to actions in the following
main loop.
We stop as soon as the verb is quit
(line A).
Array blocks
holds a reference to each block in the world, so that
we can get a hold of any block in constant time (lines B and C).
A command is illegal when blocks a
and b
have the same location on
the table (line D).
For the first operation of the action, we apply put_back
for verb
move
and do nothing (line E).
Similarly for the second operation (line F).
We always stack a
on top of the stack that contains b
(line G).
Our solution is the following.
Summary
We took a compositional approach to solving the problem. We identified primitive operations and implemented each action as a sequence of primitive operations. We avoid searching for blocks by keeping a reference to each block. We avoid computing the location of blocks on the table by tagging each block with its location.