Assignment 9

COMP102/112 2022 Tri 1: Assignment 9

days Due 26 May 10am

Goals

The WaveformAnalyser program will give you experience in manipulating values in ArrayLists. The BattleGame program uses arrays and ArrayLists of objects.

Preparation

Download the zip file for assignment 9 and extract it to the COMP-102-112-2022T1-Assig9 folder in your home folder. It should contain templates for the Java programs you are to complete. Read through the whole assignment to see what you need to do.

Look again at your answer and/or the model answer to the TemperatureAnalyser program from assignment 4 and go over the code examples in slides from the lectures on ArrayLists and arrays.

Later when the model answer to assignment 8 becomes available, make sure you understand all the components of the programs.

ALERT! Make sure that you do TileExercise before starting the battle game program.

Summary

  • WaveformAnalyser:
    right reads a waveform from a file, displays it, analyses it, and edits it.
  • Battle Game.
    right Write a version of the Battle card game.

To Submit:

  • Your version of WaveformAnalyser.java
  • Your version of BattleGame.java

You are reminded of the School's policy on plagiarism - see the course Web site for details.

Program 1: Waveform Analyser

Many music players will allow you to display the sound being played. One of the displays is typically the waveform. For this program you will write a very simple waveform display.

There are several things about a waveform that one may be interested in:
  • The highest and lowest (most negative) points on the waveform are significant.
  • The distortion level: if the signal is too large (positive or negative), the sound might get distorted. Reporting on the points gone over the distortion level becomes then useful.
  • The peaks of the waveform which are all the points that are greater than both their neighbouring points.
  • The envelope, which is the line linking all the upper peaks and the line linking the lower peaks of the signal.
  • Editing the waveform, eg by changing the frequency, scaling parts of it up or down, removing segments of the waveform, and duplicating segments of the waveform.

WaveformAnalyser reads its data from a file (eg waveform1.txt, waveform2.txt, or waveform3.txt) into an ArrayList of numbers stored in the waveform field, displays it, and lets the user edit it and display it in different ways. Note, the program will initialise waveform to contain a simple triangular waveform.

The code that sets up and responds to the buttons and the mouse is provided for you - the parts of the program you have to complete are the ones involving the ArrayList. The mouse allows the user to select a region of the waveform.

  • If you are using a computer in a lab, you can run the WaveformAnalyser= demo to see what your program should do (look in the assig9-demos folder).
  • Or, you can watch the demo video.

Core

For the core, you should complete the following methods:

  • display(): Displays the waveform as a line graph with an x-axis. If the data goes beyond the edge of the window, that is OK. The selected region is shown by a red bar along the axis. The horizontal positions of the points on the waveform should be 1 pixel apart.

  • read(): asks the user for a waveform file and reads data from the file into the waveform. (Should start a new waveform - it should not add the values to the end of the current waveform.)

  • showSpread(): Displays two horizontal lines on the waveform, one green line for the maximum value and one red line for the minimum (most negative) value, as in the demo.

waveform-display.png waveform-spread.png

  • increaseRegion and decreaseRegion: increases/decreases all the values in the selected region of the waveform by 10%. The user selects a region using the mouse and the fields regionStart and regionEnd contain the indexes of the start and end of the region.

  • doubleFrequency(): Doubles the frequency of the waveform by removing every second value in the list.

Completion

For the completion, you should complete the following methods:

  • highlightPeaks(): draws small green circles on all the peaks. A peak is defined as a point that is greater or equal to both neighbouring points.

  • displayDistortion(): Shows in red the distorted part of the signal. A distorted value is defined as one that is either greater than the positive value of the threshold or less than the negative value of the threshold. This method should draw in red every line that has either end point beyond the distortion threshold. Note that the threshold value is stored in the constant THRESHOLD.

waveform-peaks.pngwaveform-distortion.png

  • deleteRegion(): Deletes all the values in the selected region (from regionStart up to, but not including regionEnd) from the waveform. Needs to reset the selected region.

Challenge:

For the challenge, you should complete the following methods:

  • duplicateRegion(): inserts a copy of the selected region into the waveform, immediately following the selected region. Needs to reset the selected region.

  • displayEnvelope(): displays the envelope with green lines connecting all the upper peaks and all the lower peaks, as in the demo.

waveform-envelope.png

  • save(): asks the user for a filename and saves the current waveform to that file.

It would also be nice to be able to edit real sound files. The WaveformLoader class (in the zip file) has a method that will load a wav file into an arraylist of numbers that could be used in your program. The problem is that 1 second of sound from a 1 channel wav file typically has 44,100 numbers, so that it won't fit in the window nicely without more complicated scaling than the WaveformAnalyser program does. Extend WaveformAnalyser so that it loads wav files, scales the data to fit the window, and allows the user to zoom in and out. There is also a save method to write it back as a wav file so you can listen to the result of your edits. There are lots of WAV files on the web; http://bbcsfx.acropolis.org.uk/ has a bunch of sound effect WAV files you could use.

Program 2: Battle Game

Battle is a simple two-player card game played with a standard 52-card deck of playing cards.

The objective of the game is to win "battles" against the other player. For each battle, the two players place one card face up on the table, and the player that has the highest rank card wins the battle. If the cards have the same rank, the battle is a draw.

For the Core and Completion, you are to complete a program that implements a modified version of the game in which the player is playing against the computer.

  • If you are using a computer in a lab, you can run the BattleGame= demo to see what your program should do (look in the assig9-demos folder).
  • Or, you can watch the demo video.

This version of the game starts by shuffling the deck of cards, and giving a hand of five cards to the player.

The player then repeatedly "battles" the computer by placing a card on the table. The computer places a card at the same time. The program compares the ranks of the card to see who won, and keeps score of how many battles the player has won and how many battles the computer has won. The first player to win 7 battles is the winner.

If the player's hand is not full, they can pick up the next card from the deck at any time.

Up to three times in a game, the player can replace a card in their hand by the next card in the deck.

The player can re-order the cards in their hand, but must always play by placing the card at the left end of their hand on the table. The computer doesn't have a hand, and always plays by taking and placing the next card from the deck.

Template Program

The template for the BattleGame program includes some code that is already completed for you. This code declares constants and fields, sets up the GUI, handles some of the display and allows the user to select a card (for moving or replacing).

You are to complete the methods that perform the "core mechanics" of the game that display the cards and respond to the buttons:
  • Battle, which performs a "battle": putting the card at the left end of the player's hand onto the table, putting the computer's card on the table, and updating the score. If the left end of the hand is empty, then it does nothing.
  • Pickup, which picks up the next card in the deck to fill an empty space in the hand.
  • Replace, which replaces the selected card in the hand with the card from the top of the deck. (There is a limit of three replace actions in any game.)
  • Left to move the selected card one step to the left (swapping it with card (or the space) in the adjacent position.
  • Restart, which clears the table, gets a new deck, and restocks the hand,

The template has four fields to keep track of the cards:
  • deck: an ArrayList containing a shuffled deck of cards.
  • hand: an array that can hold up to 5 Cards. It will contain null in any position that does not have a Card.
  • tableComputer: an ArrayList of the Cards that have been placed on the table by the computer.
  • tablePlayer: an ArrayList of the Cards that have been placed on the table by the player.

It has four fields to keep track of the scores, the index of the selected card, and how many cards have been replaced.

Your program should display
  • the cards (and gaps) in the player's hand
    (displayed in a rectangle at the bottom of the window)
  • the cards that the computer and the player have placed on the table.
    (displayed in two rows in the middle of the window. The cards should be overlapped so that only the most recent "battle" is visible)
  • The current scores, at the top of the window.

Here is a screenshot of the layout of the "hand" and the "table", showing a hand with four cards, and a "table" with five battles (ten cards). The player won the first three battles, the computer won the fourth and the fifth is a draw.

battle-game-table.png

There is a completed Card class which represents playing cards. It contains
  • a draw(left, top) method for drawing a Card at a specified position,
  • constants specifying the size of the cards,
  • getSuit() and getRank() methods to get the suit ("clubs", "diamonds", "hearts", or "spades"), and rank (1..13) of the card, and
  • a static getShuffledDeck() method that returns an ArrayList of Card containing a shuffled deck of d52 cards. You can call this method on the Card class: Card.getShuffledDeck();

Core

Write the following methods:

  • The restart() method so that it
    • gets a new shuffled deck
    • sets the compScore and playScore fields to their initial values
    • sets the tableComputer and tablePlayer fields to be empty lists
    • sets the hand field to have 5 cards in it (taken from the front of the deck)
    • redraws the hand, the table, and the score (use the redraw() method!)

  • The pickupCard() method so that it
    • looks for an empty position in the hand array, and if there is one, and fills it with the card at the front of the deck.
    • redraws the hand, the table, and the score.

  • The drawHandCards() method so that it draws each card in the hand array.

  • The drawTableCards() method so that it draws the cards on the "table" for both the computer (on the top) and the player (below).

  • The playBattle() method so that it
    • checks if there is a card in the leftmost place in the player's hand.
    • places the card on the table
    • takes the top card from the deck for the computer player and places it on the table.
    • compares the ranks of the two cards and awards a point to the player with the highest card. Neither player gets a point if the two cards have the same rank.
    • redraws the hand, the table, and the score
    • if the player or the computer have reached the target, end the game

  • Test your program carefully, to make sure that it works correctly in all cases:
    • when the hand is empty
    • when the hand is full
    • when the hand is only part full

Completion

  • Complete the replaceCard() method so that a player can throw away the selected card in their hand (if there is one) and replace it with a new card from the deck. A player can only replace a card three times during a game. (Use the remainingReplaces field.)

  • Complete the moveLeft() method so that it swaps the contents of the currently selected position on the hand with the contents of one position to the left. (Note that it should not attempt to move something beyond the ends of the hand.)

  • Extend the drawTableCards() method so that it highlights the card with the highest rank on the last battle.

Challenge

Implement the true version of Battle Game (see the Wikipedia page about Battle).

Note: if you do the Challenge, you must submit BattleGame.java with the core/completion version, and a different file (eg FullBattleGame.java) with your challenge version. It is not possible to combine the simplified version and the full version in the same file. You will lose lots of marks if you only submit the full version.

To go further

It is important to understand how Java works, as well as writing programs in Java.

1. When working with ArrayLists, many errors occur at the boundaries of the list. Discuss some of the errors you had to deal with in your code. Did the errors involve the ends of the list?

2. This method is supposed to remove every negative value in an ArrayList of numbers. Why will it crash with an error if there are any negative numbers in the list?
     public void removeNegatives1(ArrayList<Double> numbers){
         for(double num : numbers){
             if (num < 0) {
                 numbers.remove(num);
             }
         }
     }

3. This method is also supposed to remove every negative value in an ArrayList of numbers? It does not crash, but it may not do the right thing. Give an example of a list of numbers that it would not work on, and explain why.
     public void removeNegatives2(ArrayList<Double> numbers){
         for(int i=0; i<numbers.size(); i++){
             if (numbers.get(i) < 0) {
                 numbers.remove(i);
             }
         }
     }

4. Both BattleGame and WaveformAnalyser used another class that was written for you. This saved you writing some code, but also constrained you to write the program in a particular way. What were the advantages and disadvantages you found when having a predefined class that you had to use as part of your program.