On this page:
Problem 1: Knitted fabric
Problem 2: Rush Hour, Part 3
8.1 Klotski
8.2 Keeping score
8.3 Fixing mistakes:
8.4 Submission notes:

Assignment 8: Iterators and Sameness, and Finishing Games🔗

Goals: Further practice with ArrayLists; mutable worlds.


The submissions will be organized as follows:

Due Date: Thursday, March 21st at 9:00pm

Problem 1: Knitted fabric🔗

In this problem you are going to design two distinct but related data definitions: one to describe knitted fabric, and another to describe the instructions needed to actually make a fabric. Read the entire problem carefully before starting; you might otherwise jump to conclusions that are not warranted.

A knitted fabric is made up of two basic kinds of stitches: knits and purls. On the front side of the fabric, a knit stitch looks like a V, while on the back side it looks like a -. Purl stitches are the opposite: on the front side of the fabric they look like a -, while on the back side they look like a V. A knitted fabric is made up of rows of these stitches, typically starting from the bottom and working upward (e.g. from the waistband of a sweater up to the neck), and combining different stitches in different pattern on different rows naturally produces different textures of results.

Design a class KnittedFabric (and any helper classes) to represent a knitted fabric. (Hint: your design should not need any fields of type String.) Your KnittedFabric class must include a constructor with zero arguments, to create an empty fabric.

Design a method KnittedFabric addRow(Iterator<IStitch> rowIter) that takes in an iterator of stitches, from left to right on the front side of the fabric, and adds that row of stitches to the current fabric — and then returns the current fabric, so that you can add another row to it easily.

Design a method String renderFabric that draws your fabric as a string of text. You can see some examples of rendered fabrics below.

Design a method sameFabric that checks if two knitted fabrics look the same. Keep in mind, you might be looking at the front side of one fabric and the back side of the other, but they might be the same fabric if you turn them both to face forward — the following two fabrics are the same:

VVV----V    and     -VVVV---
---VVVV-            V----VVV

Knitting instructions are a bit trickier. They follow a few rules:
  • Instructions are written for right-handed knitters, so the first instruction in a row is on the right edge of the fabric, and the last instruction in a row is on the left edge of the fabric.

  • A simple instruction for a row of fabric might say something like “Knit 3, purl 3, knit 1, purl 3.” This will produce the fabric ---V---VVV.

  • A fancier set of instructions might include grouping: “Knit 4, (purl 2, knit 2) 3 times, purl 4” would produce the fabric ----VV--VV--VV--VVVV. We can actually think of this grouping as extending to individual stitches: the simple instruction “Knit 3, purl 3” could be written as “(knit) 3 times, (purl) 3 times” instead. So there are really three kinds of instructions: knit, purl and repeat.

  • Knitting is typically worked from the bottom up, so the first row of instructions is the bottom of the fabric.

  • At the end of every row, knitters turn the fabric around, so that they’re now looking at the other side of the fabric. This swaps the left and right edges of the fabric, so that the first instruction of the next row produces a stitch that sits above the last stitch of the previous row. So for example, the instructions “row 1: knit 1, purl 5; row 2: knit 2, purl 4” will produce the fabric (looking at the front of the fabric):


    The first row is on the bottom, and is worked from right to left; the second row is above it, is worked from left to right, and the stitches are all backwards in appearance.

Design the class KnitFabricInstructions (and any helper classes needed) to represent knitting instructions for a full fabric. You should at minimum have classes that represent the three kinds of instructions, single rows of instructions, and an entire fabric’s worth of instructions. Your KnitFabricInstructions class must have a zero-argument constructor that creates an empty set of instructions.

Design a method KnitFabricInstructions addRow(Iterator<IInstruction> instructions) that adds a row of instructions to the growing fabric. Note that the instructions should be interpreted based on whichever side of the fabric is next: either right-to-left instructions for a front-side row, or left-to-right instructions for a back-side row. Like the other addRow method, this one will return the current set of instructions, so that you can continue add more rows of instructions.

Design the method KnittedFabric makeFabric() that follows the instructions and generates the knitted fabric result. (Hint: you will likely want an accumulator parameter in a helper method somewhere; that accumulator likely will be a boolean; you may need other accumulators or other helpers as well.)

Design the method boolean sameInstructions(KnitFabricInstructions other) that decides whether this set of instructions and that set of instructions will produce the same final fabric. As a tiny example, “knit 3, purl 3, knit 3, purl 3” will produce the same fabric as “((knit) 3 times, (purl) 3 times) 2 times.”

Problem 2: Rush Hour, Part 3🔗

In the previous part of Rush Hour, you implemented player movement rules, added obstacles and irregularly-shaped levels. In this week’s exciting conclusion, you’ll create a variation on the game, and add a way to fix mistakes.

8.1 Klotski🔗

The general mechanic of “moving rectangular tiles in straight lines and trying to get a goal piece out the exit” has come up in lots of varieties over time. This week, you will extend your implementation to support Klotski, whose rules are similar to Rush Hour but with a few variations:

Here are two Klotski boards to get you started:

image image

In both of these levels, the goal is to get the red square out the exit.

To enter these worlds as strings, extend your string-parsing such that

NOTE: you will still need to support standard Rush Hour rules! You must be able to start a Rush Hour level and play by Rush Hour rules (where pieces can only move in one dimension) as well as be able to start a Klotski level and play by Klotski rules (as described above).


Extend your implementation of Rush Hour to now support Klotski as well. Hint: You will likely need at least two World subclasses, to represent your distinct rulesets. Be sure to avoid as much code duplication as possible: your code will still be graded on its design and clarity.

8.2 Keeping score🔗


Add a move-counter to keep track of the number of moves a player has made. A move should count how many pieces are selected and moved — merely selecting and deselecting a piece should not count as a move, and multiple consecutive moves of the same piece should count as only one move.

Show the score somewhere on screen. Lower scores are better!

8.3 Fixing mistakes:🔗


It’s far too easy to make mistakes in this game, and it’s reasonable for a player to try out some ideas and then want to “go back” to a previous board state. Add an undo feature, that lets the player type "U" in order to rewind the game by one step. (Note that each undo should increase the player’s score! Undoing a bad move should not also rewind their score to something better.) Make sure that the game does not crash if the player tries to undo when there are not currently any moves to undo.

Have fun!

You can find a few more levels at https://josephpetitti.com/klotski. You might also try designing a few levels of your own – see if you can combine both Rush Hour mechanics (like trucks and obstacles and irregular board shapes) and Klotski rules, or Klotski shapes (1x1 and 2x2 pieces) with Rush Hour rules.

8.4 Submission notes:🔗

As with prior parts, you should submit an updated UserGuide.txt and Design.txt that describe how a user should play your game, and how a developer should read and understand your code. Make sure you submit all the necessary source and image files that your graders need in order for them to run your games.

There will likely be a self-eval questionnaire the day after this assignment is due. Much like the peer evaluations asked you to review each other’s code, this self-evaluation will ask you to justify your design choices against your Design.txt explanations, and to guide your graders to understand where to find particular test cases, examples, or other implementation choices.