![]() |
Problem Set 8 Due on Tuesday 5 December at the start of class |
The purpose of this problem set is to give you hands-on experience with:
for
loops)
All parts of the assignment involve a pared-down version of BuggleWorld called TuggleWorld, which is described below. Working on this assignment will give you insight into the implementation of micro-worlds like BuggleWorld, TurtleWorld, and PictureWorld.
The problem set has three tasks, all of which are parts of one large problem. To pace yourself, you should try to finish Tasks 1 and 2 (or at least make a lot of progress on them) by Friday, Dec. 1, and then complete Task 3 by Tuesday, Dec. 5.
On this problem set, you are encouraged (but not required) to work with a partner as part of a two-person team. If you work on a team, your team will submit a single softcopy and hardcopy of the problem set and the same grade will be given to both team members.
All work by a team must be a true collaboration in which members actively work together on all parts of the assignment. It is not acceptable for team members to split up the problems and work on them independently. All programming should be done with both team members working at the same computer console. It is strongly recommended that both team members share the responsibility of "driving" (typing at the keyboard), swapping every so often. The only work that you may do alone is debugging code that you have written together and talking with the instructors and drop-in tutors.
There are many advantages to programming in pairs. People who program in pairs often claim to take less time than those who program alone. By continuously reviewing the code they find bugs sooner. Catching more bugs also leads to higher-quality code. When it comes to problem solving, two heads are better than one, and less time is spent exploring blind alleys. It can be a better learning experience, since team members both learn from and teach each other. And pair programmers often report that the experience is more enjoyable than programming alone. Many empirical studies have confirmed these and other benefits of pair programming. For example, see The Costs and Benefits of Pair Programming and other publications by Laurie Williams.
It's only fair to note that there are drawbacks to programming in
pairs as well. Some pairs take longer to complete a program than
they would individually. A mismatch in the skill level or working style
of pair members can lead to friction between the individuals and
disrupt the work. At Wellesley, the most common problem in pair
programming is finding enough time in common to work together.
You should not choose a partner to program with on this assignment
unless you can schedule at least 10 hours to work together.
To find a partner with a schedule similar to yours, feel free
to post a message on CS111-F06 Q&A
.
Although you clearly can share Java code with your team partner on this assignment, other aspects of the course collaboration policy still hold. In particular, while you can talk with other individuals and teams about high-level problem-solving strategies, you cannot share any Java code with them.
Tuggle.java
file.
TuggleWorld.java
file.
TuggleWorld
main
method works correctly in the following cases:
java TuggleWorld example
java TuggleWorld exampleCommands
java TuggleWorld execFile example.tgl
java TuggleWorld execFile example.tgl true
java TuggleWorld execFile filename true
for any additional TuggleScript files filename
that you write for testing purposes.
Staple these together, and submit them at the start of class on the due date.
A two-member team need only submit one hardcopy. Make sure that the names of both team members are on the hardcopy.
ps08_programs
folder. This should include
the final version of your Tuggle.java
and TuggleWorld.java
files
and any TuggleScript (.tgl
) files you
have written.
A two-member team need only submit one softcopy. Please indicate whose drop directory the softcopy is in.
Once considered clunky and old-fashioned, textual (in contrast with graphical) representations are becoming popular again in the context of text-based environments like text messaging and chat rooms. One branch of the Buggle line has seized the opportunity to propagate to text-based applications by evolving to live in a textual environment. These Textual Buggles, who call themselves Tuggles, share much of the behavior of the Buggles from which they evolved. They live in a rectangular grid of cells called TuggleWorld in which they can move forward and backward, turn left and right, leave colored trails, drop and pick up bagels, and so on.
The details of the Tuggle's behavior and their world, which are described in the Tuggle contract and TuggleWorld contract (both of which you should study closely), should look very familiar. There are some differences from the Buggle and BuggleWorld contracts that are worth noting:
isOverBagel()
and
isFacingWall()
.
Tuggle()
constructor takes an explicit
TuggleWorld
argument. Each Tuggle needs to know the
world in which it lives in order to perform actions like
determining whether it's safe to move forward/backward,
determining the color of its cell,
painting its cell,
and dropping and picking up bagels.
(In BuggleWorld, each Buggle also needs to know the
world in which it lives, but we have hidden this detail from
you in order to simplify things. In BuggleWorld applications, there is
a "current" BuggleWorld, and each new Buggle implicitly uses
this world.)
BuggleWorld
, which is an Applet
and is not constructed explicitly by the programmer,
TuggleWorld
has a constructor method that
should be explicitly invoked by the programmer (see the example below).
TuggleWorld
, all tuggles in the world
are created when an instance of TuggleWorld
is constructed.
These can be accessed later using the getTuggle()
method
(see the example below). This stands in contrast to
BuggleWorld
, in which new buggles are created in
the run()
method.
TuggleWorld
have a textual representation
(created by the toString()
method) rather than a
graphical representation (see the example below).
TuggleWorld
:
TuggleWorld tw = new TuggleWorld(3, 4, 4); System.out.println(tw); Tuggle t1 = tw.getTuggle(1); Tuggle t2 = tw.getTuggle(2); Tuggle t3 = tw.getTuggle(3); Tuggle t4 = tw.getTuggle(4); t1.forward(3); System.out.println(tw); t1.dropBagel(); t1.left(); t1.forward(2); t1.dropBagel(); System.out.println(tw); t2.setPosition(1, 2); t2.setColor(Color.blue); t2.dropBagel(); t2.forward(); System.out.println(tw); t2.brushUp(); t2.dropBagel(); t2.forward(); System.out.println(tw); t2.dropBagel(); t2.forward(); System.out.println(tw); t2.dropBagel(); t3.setPosition(1, 3); t3.setColor(Color.green); t3.forward(); System.out.println(tw); t3.dropBagel(); t3.right(); t3.forward(2); t4.setHeading(Direction.WEST); System.out.println(tw);
Below, we show each chunk of code ending in System.out.println()
and the result displayed by this System.out.println()
:
TuggleWorld tw = new TuggleWorld(3, 4, 4); System.out.println(tw);
+-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>| | | | +-+-+-+-+
Notes: The 3x4 grid is empty except for 4 tuggles at (1,1). The cell (1,1) shows the heading ">" of the highest-numbered tuggle (#4) at (1,1).
Tuggle t1 = tw.getTuggle(1); Tuggle t2 = tw.getTuggle(2); Tuggle t3 = tw.getTuggle(3); Tuggle t4 = tw.getTuggle(4); t1.forward(3); System.out.println(tw);
+-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>|r|r|>| +-+-+-+-+
Notes: Although cells (1,1), (2,1), and (3,1) are all red, only (2,1) and (3,1) show an "r" for "red". Cell (1,1) still shows the heading ">" of the highest-numbered tuggle (#4) at (1,1). Cell (4,1) shows the heading ">" of tuggle #1.
t1.dropBagel(); t1.left(); t1.forward(2); t1.dropBagel(); System.out.println(tw);
+-+-+-+-+ | | | |^| +-+-+-+-+ | | | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+
Notes: Cell (4,1) is painted red and has a bagel, so it shows an uppercase letter "R". Cell (4,2) is painted red but has no bagel, so it shows a lowercase letter "r". Cell (4,3) shows the heading "^" of tuggle #1.
t2.setPosition(1,2); t2.setColor(Color.blue); t2.dropBagel(); t2.forward(); System.out.println(tw);
+-+-+-+-+ | | | |^| +-+-+-+-+ |B|>| |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+
Notes: Cell (1,2) is painted blue and has a bagel, so it shows "B". Cell (2,2) shows the heading ">" of tuggle #2. Cell (2,2) is not blue, because, just as buggles do, tuggles paint a cell when they leave it (if their brush is down).
t2.brushUp(); t2.dropBagel(); t2.forward(); t2.dropBagel(); t2.forward(); t2.dropBagel(); System.out.println(tw);
+-+-+-+-+ | | | |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+
Notes: Cells (2,2) and (3,2) are unpainted with a bagel, so they show "O". Cell (4,2) is painted red with a bagel, but it only shows the heading of ">" of tuggle #2.
t3.setPosition(1, 3); t3.setColor(Color.green); t3.forward(); System.out.println(tw);
+-+-+-+-+ |g|>| |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+
Notes: Cell (1,3) is painted green with no bagel so it shows "g". Cell (2,3) shows the heading of ">" of tuggle #2. Cell (1,1) still shows the heading of ">" of tuggle #4.
t3.dropBagel(); t3.right(); t3.forward(2); t4.setHeading(Direction.WEST); System.out.println(tw);
+-+-+-+-+ |g|G| |^| +-+-+-+-+ |B|G|O|>| +-+-+-+-+ |<|V|r|R| +-+-+-+-+
Notes: Cells (2,3) and (2,2) are painted green and have bagels so they show "G". Cell (2,1) is painted red with no bagel but only shows the heading of "V" of tuggle #3. Cell (1,1) shows the heading of "<" of tuggle #4.
Tuggle
and TuggleWorld
classes. In this assignment, we require you to use the following concrete
representations:
Tuggle
instance should be represented by
five instance variables:
pos
: A Point
indicating the position of the tuggle.
dir
: A Direction
indicating the heading of the tuggle.
col
: A Color
indicating the color of the tuggle.
brush
: A boolean
indicating the
brush state of the tuggle.
world
: The TuggleWorld
instance in which
the tuggle lives.
TuggleWorld
instance should be represented by
three instance variables:
colors
: A two-dimensional Color
array,
where the length of the outer dimension is the
number of columns in the world's grid and
the length of each inner dimension is the
number of rows in the world's grid.
Each slot in the array that has not been painted a particular
color should contain null
.
bagels
: A one dimensional array of booleans
whose length is c*r, where
c is the number of columns in the world's grid and
r is the number of rows in the world's grid.
The presence of a bagel in grid location (x,y)
is represented by the boolean in
bagels[(y-1)*c + (x-1)]
.
(Of course, we could have made bagels
a two-dimensional
array like colors
, but this one-dimensional array representation
underscores the power of data abstraction.)
tuggles
: A one dimensional array of Tuggle
instances whose length is the number of tuggles in the world.
Your classes should contain no other instance variables other than the ones specified above.
Note that the concrete instance variables specified for
TuggleWorld
differ from the abstract state variables
specified in the TuggleWorld contract.
This highlights the power of data abstraction.
TuggleWorld
instance and all four Tuggle
instances after executing the
code from the above Example section.
You should use the concrete representations
defined in the Concrete Representations section for displaying
TuggleWorld
and Tuggle
instances.
You may use our standard abbreviated notations for references to
Direction
and Color
instances,
but should explicitly show all Point
instances.
(You need only show the Points that are still "alive" at
the end of the code; you do not have to show
intermediate Points that were created during the execution
of the code but can no longer be referenced.)
Download the ps08_programs
folder from the CS111
download directory. This contains an implementation of the
Direction
class you have used in BuggleWorld.
In the ps08_programs
folder, create new files
Tuggle.java
and TuggleWorld.java
that implement all the methods defined by the
Tuggle contract and
TuggleWorld contract.
You must use the concrete representations specified
in the above Concrete Representations section.
Your TuggleWorld.java
class should also contain
a main()
method that, when called on the argument
example1
(via the DrJava command line java TuggleWorld example
)
executes the example shown in the above Example section.
Notes:
.java
files should begin with
the import declaration
so that they can refer directly to theimport java.awt.*;
Point
and Color
classes (otherwise, you would have to
write java.awt.Point
and java.awt.Color
).
Direction
. Color
,
String
, and Character
.
These contracts can be found on the
CS111 contracts page.
Tuggle
and TuggleWorld
contracts,
you are welcome to define any other methods you find helpful —
but they must be private
.
void
method has an empty body.
A stub for a fruitful method returning an element of type
T
has a body whose sole line
is
return elt;
where elt
is an arbitrary element of type T
.
toString()
method of TuggleWorld
class.
Since this method is important for debugging all the other methods,
it is recommended that you implement at least a simple version
early on using the following stages:
RuntimeException
class with a helpful error message.
The Java Runtime System will automatically catch these errors and
show a stack trace indicating where the error occurred.
NullPointerException
and IndexOutOfBoundsException
exceptions.
In order to debug these problems,
you should use System.out.println()
statements in relevant parts of
your code. (Comment these debugging statements out of your final code,
but do not remove them so we can see your debugging strategy.)
main()
method of TuggleWorld.java
.
However, this is cumbersome, since it requires editing the
main()
method and recompiling TuggleWorld.java
.
In this Task, you will implement an interpreter
for a mini-language we'll call TuggleScript
that makes it possible to test TuggleWorld programs without
editing the main()
method or
recompiling TuggleWorld.java
.
Instead, you can write TuggleScript programs in
a file and ask the TuggleScript interpreter to execute these files.
TuggleScript programs have the following format:
These specify, respectively, the number of rows, columns, and tuggles in the instance of TuggleWorld created by the program.rows cols numTuggles
where index indicates the index of a tuggle in the world, commandName indicates the method that the tuggle should perform, and arguments... is zero or more arguments expected by the method. Note: TuggleScript commands do not use the parentheses, commas, and semicolons used in Java, but simply separate elements with spaces.index commandName arguments...
The following table summarizes TuggleScript commands. It uses these naming conventions:
i
, j
, n
,
x
, and y
stand for integers;
b
stands for a boolean
(true
or false
).
R
, G
, and
B
stand for integers in the range [0..255]
and are used to specify color components.
c
stands for a color name, which can be one of
the following:
black
,
blue
,
cyan
,
green
,
magenta
,
red
,
white
, or
yellow
.
Case does not matter in the name, so blue
can also be written as Blue
,
BLUE
, or bLuE
.
d
stands for a direction name, which can be one of
the following:
east
,
north
,
west
, or
south
.
Case does not matter in the name, so east
can also be written as East
,
EAST
, or eASt
.
Command | Description |
---|---|
i forward |
Move tuggle i forward 1 space. |
i forward n |
Move tuggle i forward n spaces. |
i backward |
Move tuggle i backward 1 space. |
i backward n |
Move tuggle i backward n spaces. |
i left |
Turns tuggle i left 90 degrees. |
i right |
Turns tuggle i right 90 degrees. |
i brushDown |
Lowers tuggle i 's brush. |
i brushUp |
Raises tuggle i 's brush. |
i pickUpBagel |
Instructs tuggle i to pick up a bagel. |
i dropBagel |
Instructs tuggle i to drop a bagel. |
i paintCell c |
Paints the cell under tuggle i the color c. |
i paintCell j |
Paints the cell under tuggle i the color of tuggle j. |
i paintCell R G B |
Paints the cell under tuggle i the color whose red component is R, green component is G, and blue component is B | .
i setColor c |
Changes tuggle i's color to c. |
i setColor j |
Changes tuggle i's color to the color of tuggle j. |
i setColor R G B |
Changes tuggle i's color to a color whose red component is R, green component is G, and blue component is B | .
i setPosition j |
Move tuggle i to the position
of tuggle j . |
i setPosition x y |
Move tuggle i to position
(x , y ). |
i setHeading d |
Changes tuggle i's heading to Direction d. |
i setHeading j |
Changes tuggle i's heading to the heading of tuggle j. |
i setBrush b |
Changes tuggle i's brush state to the boolean b .
|
i setBrush j |
Changes tuggle i's brush state to the brush state of of tuggle j. |
For example, below is the contents of the file example.tgl
(our convention is to use the .tgl
extension
for TuggleScript programs). This corresponds to the TuggleWorld program
from the Example section above (except that it does not
include the System.out.println()
statements):
When a TuggleScript program finishes executing, it displays a textual representation of the TuggleWorld state at the end of the program. So the execution of3 4 4 1 forward 3 1 dropBagel 1 left 1 forward 2 1 dropBagel 2 setPosition 1 2 2 setColor blue 2 dropBagel 2 forward 2 brushUp 2 dropBagel 2 forward 2 dropBagel 2 forward 2 dropBagel 3 setPosition 1 3 3 setColor green 3 forward 3 dropBagel 3 right 3 forward 2 4 setHeading west
example.tgl
ends by displaying:
+-+-+-+-+ |g|G| |^| +-+-+-+-+ |B|G|O|>| +-+-+-+-+ |<|V|r|R| +-+-+-+-+
TuggleWorld
class:
public void execCommand (String cmd)
Executes the TuggleScript commandcmd
in this world.
public static void execFile (String filename, boolean traceOn)
Executes the TuggleScript program in the file namedfilename
by creating an instance ofTuggleWorld
as described by the first line of the file and executing all the commands in the remaining lines of the file relative to this world. Displays the state of the world after executing all the commands in the file. IftraceOn
istrue
, then for every command in the file it additionally displays (1) the state of the world before executing the command and (2) the command itself. IftraceOn
isfalse
, only the final state of the world is displayed.
An an illustration of execCommand
,
the effect of the TuggleScript program example.tgl
can be achieved by executing the following:
TuggleWorld tw = new TuggleWorld(3,4,4); tw.execCommand("1 forward 3"); tw.execCommand("1 dropBagel"); tw.execCommand("1 left"); tw.execCommand("1 forward 2"); tw.execCommand("1 dropBagel"); tw.execCommand("2 setPosition 1 2"); tw.execCommand("2 setColor blue"); tw.execCommand("2 dropBagel"); tw.execCommand("2 forward"); tw.execCommand("2 brushUp"); tw.execCommand("2 dropBagel"); tw.execCommand("2 forward"); tw.execCommand("2 dropBagel"); tw.execCommand("2 forward"); tw.execCommand("2 dropBagel"); tw.execCommand("3 setPosition 1 3"); tw.execCommand("3 setColor green"); tw.execCommand("3 forward"); tw.execCommand("3 dropBagel"); tw.execCommand("3 right"); tw.execCommand("3 forward 2"); tw.execCommand("4 setHeading west"); System.out.println(tw);
An an illustration of execFile
,
TuggleWorld.execFile("example.tgl", false)
displays
+-+-+-+-+ |g|G| |^| +-+-+-+-+ |B|G|O|>| +-+-+-+-+ |<|V|r|R| +-+-+-+-+
but TuggleWorld.execFile("example.tgl", true)
displays
+-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>| | | | +-+-+-+-+ 1 forward 3 +-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>|r|r|>| +-+-+-+-+ 1 dropBagel +-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>|r|r|>| +-+-+-+-+ 1 left +-+-+-+-+ | | | | | +-+-+-+-+ | | | | | +-+-+-+-+ |>|r|r|^| +-+-+-+-+ 1 forward 2 +-+-+-+-+ | | | |^| +-+-+-+-+ | | | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 1 dropBagel +-+-+-+-+ | | | |^| +-+-+-+-+ | | | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 setPosition 1 2 +-+-+-+-+ | | | |^| +-+-+-+-+ |>| | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 setColor blue +-+-+-+-+ | | | |^| +-+-+-+-+ |>| | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 dropBagel +-+-+-+-+ | | | |^| +-+-+-+-+ |>| | |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 forward +-+-+-+-+ | | | |^| +-+-+-+-+ |B|>| |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 brushUp +-+-+-+-+ | | | |^| +-+-+-+-+ |B|>| |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 dropBagel +-+-+-+-+ | | | |^| +-+-+-+-+ |B|>| |r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 forward +-+-+-+-+ | | | |^| +-+-+-+-+ |B|O|>|r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 dropBagel +-+-+-+-+ | | | |^| +-+-+-+-+ |B|O|>|r| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 forward +-+-+-+-+ | | | |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 2 dropBagel +-+-+-+-+ | | | |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 setPosition 1 3 +-+-+-+-+ |>| | |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 setColor green +-+-+-+-+ |>| | |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 forward +-+-+-+-+ |g|>| |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 dropBagel +-+-+-+-+ |g|>| |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 right +-+-+-+-+ |g|V| |^| +-+-+-+-+ |B|O|O|>| +-+-+-+-+ |>|r|r|R| +-+-+-+-+ 3 forward 2 +-+-+-+-+ |g|G| |^| +-+-+-+-+ |B|G|O|>| +-+-+-+-+ |>|V|r|R| +-+-+-+-+ 4 setHeading west +-+-+-+-+ |g|G| |^| +-+-+-+-+ |B|G|O|>| +-+-+-+-+ |<|V|r|R| +-+-+-+-+
Notes:
FileReader
and BufferedReader
classes to read lines from a file.
Add the import declaration
toimport java.io.*
TuggleWorld.java
so that you can use these
classes without the java.io
prefix.
split
instance method of the
String
class to parse a command string
into its component parts.
Integer.parseInt
class method to
convert strings of digit characters to Java integers.
boolean
value.
Direction
object.
Color
object.
main
method of the
TuggleWorld
class so that:
java TuggleWorld exampleCommands
executes the execCommand
example shown above;
java TuggleWorld execFile filename
executes TuggleWorld.execFile("filename", false)
;
java TuggleWorld execFile filename bool
executes TuggleWorld.execFile("filename", bool)
;
example.tgl
does not test all TuggleScript commands.
You should write additional TuggleScript programs that provide evidence
that your Tuggle methods, TuggleWorld methods, and TuggleScript commands
all work as expected (including exceptional cases).
execCommand()
and execFile()
methods implement an interpreter for the very simple TuggleScript
language, in which a program is a sequence of simple commands.
It would be more challenging to implement an interpreter
for a language like Java having nested expresssion and statements,
type information, and other features. The course
CS251 (Programming Languages) explores how to write
interpreters for languages with these sorts of features.