How did she miss that?

Project 2: Connect 4

Due by: Friday, February 28, 2020 at 11:59 p.m.

As the second stop on our retro-gaming tour, you have to implement the game of Connect 4. While the level of strategy and information available to an Uno player is limited, Connect 4 is a classic abstract strategy game of perfect information. In other words, you know everything that your opponent knows.

Writing an artificial intelligence to play Connect 4 would be an interesting project, but our goals are simpler: We want to create a graphical user interface (GUI) using the Java Swing library that will allow two humans to play the game. (Although it's instructive to write an AI player, Connect 4 is a solved game. It's been proven that the first player will always win if both players play perfectly, and there's an algorithm for playing perfectly.)

Specification

Game play

If you are unfamiliar with the game of Connect 4, it is played on a vertical grid with 6 rows and 7 columns and two colors of colored discs, red and black for our implementation. When a player drops a disc into one of the columns, it will fall down to the lowest row that doesn't already have a disc in it. The goal of the game is to get four pieces of your own color in a line while blocking your opponent from doing the same before you. Discs can make four in a line in a horizontal row, a vertical column, or a diagonal.

To simplify our game, the first player, Player 1, will always play black, and the second player, Player 2, will always play red.

GUI

Before you begin programming the mechanics of the game, you first need to create a GUI to display it. Create a project called Project2, add a package to it called connect4, and add a class called Game to the package. Follow examples in the book to create a JFrame that looks like the following when it is initially created.

Note that its title should be "Connect 4". Just below the title is a JLabel stating which player's turn it is. By default, a JFrame uses BorderLayout, easily allowing you to put this JLabel at the top while reserving the central area for the board itself.

The board is an ideal place to use GridLayout, since it is formed of a number of rows and columns all identically sized. Although Connect 4 has 6 rows and 7 columns of playable space, your layout should have 7 rows and 7 columns where the first row is filled with JButton objects. These objects are how a player will decide which column to play. The remaining 6 rows and 7 columns should be filled with JLabel objects. Both the JButton and JLabel objects in the grid will be decorated with ImageIcon objects.

You may use the following images to represent, respectively, an empty slot, a black piece, a black piece that could be played, a black piece that is part of a winning group, a red piece, a red piece that could be played, and a red piece that is part of a winning group. Right-click on each image and save it into your Project2 directory but not into the src or bin directories.

Note that, in order to look right, my JButton objects needed to have their margins set (using their setMargin() method) with insets that were -5 on every side.

Game state

Although it's tempting to somehow use the images on the JLabel objects to represent the game state, it's much cleaner to use a separate data structure. I recommend that you make a 2D array of Piece objects representing the current state of the game. You can use the following Piece definition inside your Game class.

public enum Piece {
	RED,
	BLACK,
	EMPTY
}

You should initialize your 2D array to contain all Piece.EMPTY values. Then, whenever a player makes a move, you should update both the array of Piece objects and the appropriate JLabel.

Actions

Each JButton should have an ActionListener added to it that drops a piece into the appropriate column. Since the code needed to place the piece is complex, I recommend writing a method called by each ActionListener that drops a piece into the given column. Then, the ActionListener should play the click sound that accompanies a dropped piece.

The method that plays a piece needs to do the following:

  • Find the lowest row where the piece fits (either the last row that's empty or the very last row if no pieces are in that column)
  • Update the location in the 2D array that represents game state
  • Update the icon of the corresponding JLabel
  • If the game is won (ideally checked by calling another method):
    • Remove the icons from all the JButton objects and disable them
    • Update a label to say who the winner is
  • Otherwise, if the game is tied (easily done by counting the number of moves: 42 moves with no win is a tie):
    • Remove the icons from all the JButton objects and disable them
    • Update a label to say that the game is tied
  • Otherwise, if the game was neither won nor tied:
    • Update the icons to be the other player's pieces for all the JButton objects on columns where a move is still possible
    • Remove the icons from all the JButton objects on columns where moves are impossible and disable them
    • Update a label to say whose turn it is now

The method that checks for a win needs to do the following:

  • Loop through the column where the new piece was played to see if there are four or more in a line
  • If there are, go back and mark them all as the appropriate winning icon
  • Loop through the row where the new piece was played to see if there are four or more in a line (moving both left and right because there might be connected pieces on both sides)
  • If there are, go back and mark them all as the appropriate winning icon
  • Loop through the diagonal from lower left to upper right where the new piece was played to see if there are four or more in a line (moving both left and right because there might be connected pieces on both sides)
  • If there are, go back and mark them all as the appropriate winning icon
  • Loop through the diagonal from upper left to lower right where the new piece was played to see if there are four or more in a line (moving both left and right because there might be connected pieces on both sides)
  • If there are, go back and mark them all as the appropriate winning icon
  • If any of these directions had four or more in a line, return true, otherwise false

Playing a sound

Whenever a piece is played, your program must play a click noise. A file with the click noise is provided below. As with the images, right-click on the sound file and save it into your Project2 directory but not into the src or bin directories.

Use the code example in the textbook to load the sound into a Clip. Whenever a piece is played, stop the clip, use the setMicroSecondPosition() method to bring it back to the beginning, and then start the clip playing.

Game states

The image above shows the game just after it has been started. Here's a picture of the game after Player 1 has played. Note that the JButton objects have changed to show the red piece and that the label says that it's Player 2's turn.

After several more moves, the top of the board has been reached on one column. Note that the JButton there no longer has an icon and has been disabled, preventing anyone from playing in that location.

It's possible that this game could continue with no one winning, eventually reaching the tied state shown below.

Or, starting afresh, Player 1 might have reached an easy win.

Yet another game might have been a win for Player 2, highlighting all the ways that four or more in a line were reached.

Make sure your code handles all of these cases, looking as much like the samples as possible.

Testing

You must test your code to be sure that it does what it says that it does. Write down your testing plan describing your different approaches to playing the game to reveal any bugs. Include this file as a file called testing.txt, testing.docx, or testing.pdf.

Turn In

Your Eclipse project should be called Project2, but the class you create inside should be called Game and should be in the package connect4. Zip up Game.java from the Project2\src\connect4 folder inside your workspace folder with your testing file and upload the zip file to Blackboard. You should not need to make more than one class to solve this problem, but if you do, you can include those other .java files in your zip file. Only the team leader should turn in this file.

All work must be submitted before Friday, February 28, 2020 at 11:59 p.m. unless you are going to use a grace day.

All work must be done within assigned teams. You may discuss general concepts with your classmates, but it is never acceptable for you to look at another team's code. Please refer to the course policies if you have any questions about academic integrity. If you have trouble with the assignment, I am always available for assistance.

Grading

Your grade will be determined by the following categories:

Category Weight
Dropping pieces into the correct location 20%
Updating turn information and buttons 20%
Checking for wins and ties 20%
Highlighting the winning pieces 10%
Announcing the winner or a tie 5%
Playing a click when a piece is played 5%
Visual polish 5%
Testing plan 5%
Style and comments, including Javadoc comments 10%

Code that does not compile will automatically score zero points.

Under no circumstances should any member of one group look at the code written by another group. Tools will be used to detect code similarity automatically.