Question Details

(Solved) Overview By the early-1990's, Tetris (Links to an external site.) had become arguably the most popular single-player computer game ever at that time....


Overview

By the early-1990's, Tetris (Links to an external site.) had become arguably the most popular single-player computer game ever at that time.  It's incredibly simple and fun to play, and even to this day it's widely considered to be among the best games of all time.

In case you've never seen it, the game consists of a 10-unit wide by 24-unit tall well, into which randomly-selected geometric 4-unit pieces begin to fall one at a time.  The player can manipulate each piece as it falls by moving it horizontally within the well, and rotating it in 90° increments.  Once the piece can fall no further, it becomes locked in place, taking up space in the well.  However, if the player forms one or more full horizontal (10-unit by 1-unit) rows, those rows are removed, with all rows above shifting downward.  The goal is to continue playing as long as possible, so the player must attempt to pack the pieces strategically.  Eventually, though, the well fills upward to a limit line, and if any portion of a piece is locked in place above this line, the game is over.

Requirements

Building a full-functional Tetris application requires a little more Java than what we've covered yet this term, so you'll be provided a working application that you can download and play.  So what is this assignment all about?  The goal of this assignment is to develop a basic Artificial Intelligence ("AI") system capable of controlling this game as if it were a player!

Implementing an Interface

In previous assignments, you were given a class file with method declarations, Javadoc comments, and placeholder implementations.  In this assignment, you'll be given an interface instead.  An interface contains the method declarations and the Javadoc comments, but no code at all (not even placeholders).  Your task is to will implement this interface, which means you'll develop a class that provides code for all the methods declared in the interface.  In this case, the interface only has one method, but you will likely need to develop several private helper methods in order to fully implement it. It's important to note that there can be multiple implementations of a single interface, each with different behaviors.  For example, LinkedList and ArrayList both implement the List interface of the collections framework.  We've already touched on this idea a few times, and we'll study it in depth later in the term.

System Description

The interface you will implement is called edu.vt.cs5044.tetris.Brain, and your implementation class must be called edu.vt.cs5044.CleverBrain.  You will need to develop the code needed to implement the one method defined by the interface.  This method will be passed some parameters, defining the current state of the game board and the shape to be placed, and will need to return the move that your AI player has determined is best.  Your JUnit test file must be called edu.vt.cs5044.CleverBrainTest.

Downloads

tetris5044.jar library file containing all the compiled game engine classes
tetris5044-api.jar library file containing the Javadocs for the game engine

Setting up Eclipse

Download the provided files to your computer, and place them in a convenient folder.  Open Eclipse and create a new Java Project for this assignment.  Right-click the project and select Build Path | Configure Build Path, then select the Libraries tab.  Click Add External JARs and navigate to where you placed the downloaded JAR files, select tetris5044.jar, and click OK.  You should now see that file listed within just above the JRE System Library.  Now click the little triangle to expand the file, select Javadoc location: (None), and click Edit.   Here you select Javadoc in archive, then click Browse. Navigate again, this time selecting tetris5044-api.jar, and click Validate.  It should tell you the location is likely valid, so click OK, then OK, then OK to get back to your project.  Your should see a new Referenced Libraries section, which you can expand to see the tetris5044.jar file.

Shall We Play a Game?

At this point, you can right-click your project and select Run As | Java Application to play Tetris!

A window should appear with an empty game board and a prompt to type P to play.  Once you type P, you will see a new random piece near the top, slowly falling toward the bottom of the well. There are alternative keyboard controls you can use, but for now just type J and L to move the piece left and right, and type I to rotate the piece. Once the piece is situated as you wish, you can use K to drop the piece immediately, or just enjoy watching it fall gently into place.  You can type ? in the game at any time to produce a listing in the Eclipse console of all of the available options and keyboard controls.

Game Notation

It's useful to have a common vocabulary, so let's take a quick look at a few components of our game.  There are seven distinct geometric shapes, represented by the Shape enum in our system, each named for the letter it vaguely resembles:

Shape.T Shape.O Shape.I
Shape.J and Shape.L Shape.Z and Shape.S

Each shape is composed of four 1-unit blocks. The L and the J happen to be mirror images of each other, as are the S and the Z, but they are still distinct shapes.

Any shape can be rotated counter-clockwise, in 90° increments.  This is represented by the Piece class in our game, which holds a single shape along with an associated rotation value.  The rotation indicates how many (if any) rotations of the shape have been applied.  Enough rotations will get you back to the original unrotated shape.  The O shape has only one distinct rotation; the I, S, and Z shapes have two distinct rotations each; and  the T, L, and J shapes have four distinct rotations each.

For example, here are four different Piece objects, each holding Shape.J, with rotation values ranging from zero to three:

Anatomy of a Brain

If you typed ? for the keyboard help, you probably noticed some interesting options.  Specifically, you can enable the AI Player by typing Ctrl-P.  When you enable this mode, just before a new shape appears in the game, the current Brain is asked how it would like to rotate and place the shape.  The AI must also provide a relative cost measure, which is lower for better moves and higher for worse moves.

Mind the Lameness

When you launch the game, it defaults to a built-in sample implementation of the Brain interface called LameBrain. This brain is a very ineffective AI, which always selects the left-most column, with no rotations, and the same cost for all placements.  It completely ignores everything and just mindlessly places every piece the same way.  If you haven't tried it yet, type Ctrl-P and watch the AI control the placement of the pieces.  It's not very interesting, and the games don't last very long, so type Ctrl-P again to disable it once you get bored.  Your goal in this assignment is to develop an AI that performs substantially better than this, by examining the current board and the piece about to be displayed.

Trying to Take Over the World

Ok, close the game for a moment while we get some of the basics in place.  First, create a new package called edu.vt.cs5044 then right-click within that package select New Class.  Before you enter the class name, click the Add button to the right of the Interfaces section. In the search box at the top, type Brain and you should soon see the Brain interface (in the edu.vt.cs5044.tetris package) selected.  Click Ok to add that interface, and now you can enter the class name CleverBrain and click Finish.

Notice that the CleverBrain file declaration says public class CleverBrain implements Brain.  This is what tells Java that we intend to be compatible with any system that can work with the Brain interface.  You'll also notice Eclipse automatically provided a placeholder method for you!  Your implementation is already compatible with the game system, even though all it does is return null.  That's even worse than LameBrain, but we're just getting started.  Let's see if it's recognized by the game as a valid AI.  Run the application again, and type Ctrl-B to attempt to toggle from LameBrain to CleverBrain.  The console should show Brain selected: CleverBrain at this point.

Do we dare activate it?  Sure, type Ctrl-P to activate the Player AI, then type P to start the game.  Well, that wasn't very exciting.  The console just keeps saying that the AI selected an invalid move for each shape.  That's fair enough, though, since all we have is a placeholder that returns null, and Eclipse wrote that for us anyway.  Close the game again.

Maybe we can take the very simple logic from LameBrain and use that as a starting point for our own CleverBrain implementation.  At least that brain provides valid moves.  So let's replace this:
        return null;

with this:

        return new Move(0, 0, 0);

It doesn't seem like much of an improvement, but we'll see.  Launch the game, and use Ctrl-B, Ctrl-P, and P to check it out.  Ok that's actually better.  It's placing all the pieces in column 0, which is exactly what LameBrain does, so things can only get better from here.

Need More Input

Obviously we need to examine the shape and the state of the board in order to make some reasonable decisions.  Let's take a look at all those Javadocs that make up the API.  In your source file click within the word Brain of "implements Brain" and type Shift-F2.  This should open the Javadocs for the Brain interface using an internal browser within Eclipse.  You can set it to use an external browser, if you prefer, but this is fine for now.

Reading the Javadocs for our getBestMove() method, we see that it actually gives us the outline of a strategy.  We need to create a Piece from the Shape, then for each possible rotation, we need to iterate over ever possible column placement.  We can also ask the provided Board object to tell us what the result of each move would be.  Click the method Board.getResultBoard() to see what that does.  The Javadocs say that the original board instance is not modified, and we'll get a new board instance that we can examine.  That's perfect for our needs, but how do we examine one of these hypothetical results?  There are only two other methods available.  One provides a human-readable rendering of the board, which might prove very useful to visualize what's happening, and another promising method that seems to let us query any location within the board to see which locations are occupied by fixed blocks.

There are also three static constants that tell us the overall size of any board, plus two constructors.  One of the constructors allows us to generate arbitrary board configurations, which is exactly what we'll need in order to create repeatable test cases.

Navigate throughout the Javadocs to see what each class can do.  At the top of each page you can select All Classes or click Overview to navigate by package.  A fundamental part of this assignment is to learn how to make use of Javadocs to explore unknown libraries, as well as to see how a somewhat larger scale system is divided into multiple classes, each with its own purpose.

Perfect is the Enemy of Good

There's no such thing as a perfect strategy, so don't even try.  We are necessarily taking a heuristic (Links to an external site.) approach to this problem.  However, you may be wondering exactly how well your implementation is expected to perform.  Please don't worry too much about that.  You aren't being graded on how long your implementation can survive with randomly selected pieces. You just need to implement some reasonable strategy that includes some non-trivial cost calculations.  The minimum expectations are detailed in the subsections below.

More than Full Coverage

Unlike in the previous assignment, creating JUnit tests to cover all of your code will be very straightforward, since there aren't many branches involved in the solution.  You can likely achieve full coverage with just one or two test cases, so complete coverage is not nearly enough to ensure a reasonable strategy.  You must devise at least 6 test cases that highlight some of the strengths of your overall strategy, by demonstrating your brain making good (or even not so good) placement decisions.  You don't necessarily need to use Javadocs, but be sure to comment these test cases thoroughly to include your thoughts on the performance of your algorithm in these cases.

Minimum Standards

Despite the above discussion, there are a few common behaviors that we will specifically test:

  • A smaller overall block count is better than a larger count
  • A shorter highest column is better than a taller highest column
  • A fewer number of holes is better than a larger number (a hole is a gap with a block above it)

However, the above cases will only be tested in reasonable situations, where these behaviors aren't mutually incompatible.

For example, suppose there is only a single row of 9 blocks (a full row minus 1 block somewhere) at the bottom of the well, and you're given Shape.I to place.  Placing the shape in a vertical orientation at the gap to clear the row will result in a smaller overall block count than any other placement.  However, this placement also results in a taller highest column than if it had been placed in a horizontal orientation.  Even human experts may not always agree upon which is better, and it would depend upon whether the gap is at an edge or not, so that's not a case we would test.

Too Much Information

Regarding the cost computation, there are a vast number of possibilities.  Here are just a few ideas for some factors that you might want to consider for inclusion in your algorithm:

  • Total number of blocks
  • Height of highest column
  • Average height of columns
  • Variance of column heights
  • Range of column heights
  • Max difference between adjacent column heights
  • Total number of holes
  • Minimum hole depth
  • Average hole depth
  • Average hole size
  • Concentration of blocks toward the edges

You are certainly not limited to these, and you definitely don't need to use all of them.  We will inspect your code to ensure you've included at least 5 reasonable factors (whether listed above or otherwise).  You need to include at least 2 tests for each factor included, to ensure the factor is calculated properly.  These particular tests (and only these tests!) should bypass the Brain interface, and invoke your factor calculation methods directly.

Making Adjustments

You'll need to combine the various factors into a single cost value, which is typically done by taking a weighted average.  For this assignment, you can simply hand-tune the relative weightings by trial-and-error, to whatever seems to work reasonably well overall in actual game play.  You'll likely want to further refine these weightings as you add more factors, and you may even end up setting some factors to have very small or even negative weights.  Please comment your weightings to provide some of your thoughts about how the weightings evolved in your system.

Functional Decomposition

Judicious use of helper methods can significantly reduce the overall amount of code you need to develop.  For example, you might want to create a helper method that returns the height of one specified column.  You can then call that method from within a loop of all columns, and use the return value to help compute several of the factors above.  Your code will be inspected for redundancies, so use helper methods wherever appropriate.  The helper methods that calculate individual factors can be declared as public, so you can test them separately as noted above.

My Own Worst Enemy (optional)

Finally, there's an interesting diversion you can explore, if you have time later in the development process. If you play the game enough, it may seem that sometimes the game is working against you, giving you all bad pieces, but normally it's not.  It's just selecting each next piece for the player completely at random. However, this can all be changed!

Once your AI is providing reasonable suggestions, just for fun, turn off the Player Brain and turn on the Enemy Brain.  When you activate the Enemy Brain, instead of the game selecting a shape at random, it asks the selected brain to evaluate the best possible move for each of the seven shapes.  The game actually selects the shape with the highest (worst!) overall cost.  This means the game will actively try to work against you, by offering what your brain thinks is the worst possible shape at each time.

Just for fun, try playing against your own AI. Can you tell the difference in difficulty, or at least that the pieces are decidedly less random now? For the ultimate ironic experience, you can even let your brain compete against itself as both the player and the enemy, by activating both modes at the same time.

This unusual feature works because of the abstraction and separation between the classes. The brain is normally used to select a good placement for a random piece, but it works just as well in this somewhat bizarre context of selecting the worst possible next shape for the player.  This is exactly how modular code should work.

 


Solution details:
STATUS
Answered
QUALITY
Approved
ANSWER RATING

This question was answered on: Sep 05, 2019

PRICE: $18

Solution~000200107536.zip (25.37 KB)

Buy this answer for only: $18

This attachment is locked

We have a ready expert answer for this paper which you can use for in-depth understanding, research editing or paraphrasing. You can buy it or order for a fresh, original and plagiarism-free solution (Deadline assured. Flexible pricing. TurnItIn Report provided)

Pay using PayPal (No PayPal account Required) or your credit card . All your purchases are securely protected by .
SiteLock

About this Question

STATUS

Answered

QUALITY

Approved

DATE ANSWERED

Sep 05, 2019

EXPERT

Tutor

ANSWER RATING

GET INSTANT HELP/h4>

We have top-notch tutors who can do your essay/homework for you at a reasonable cost and then you can simply use that essay as a template to build your own arguments.

You can also use these solutions:

  • As a reference for in-depth understanding of the subject.
  • As a source of ideas / reasoning for your own research (if properly referenced)
  • For editing and paraphrasing (check your institution's definition of plagiarism and recommended paraphrase).
This we believe is a better way of understanding a problem and makes use of the efficiency of time of the student.

NEW ASSIGNMENT HELP?

Order New Solution. Quick Turnaround

Click on the button below in order to Order for a New, Original and High-Quality Essay Solutions. New orders are original solutions and precise to your writing instruction requirements. Place a New Order using the button below.

WE GUARANTEE, THAT YOUR PAPER WILL BE WRITTEN FROM SCRATCH AND WITHIN YOUR SET DEADLINE.

Order Now