# Session 33

## Source Code

```java
import java.util.*;

public class Session33 {
    public static void main(String[] args) {
        System.out.println("Session 33");

        // Menu
        System.out.println("Menu");
        System.out.println("E1 - Example 1");
        System.out.println("Q  - Quit");

        // setup Scanner
        Scanner in = new Scanner(System.in);
        System.out.print("Choice: ");
        String choice = in.nextLine();

        // switch choices
        switch (choice) {
            case "E1":
                System.out.println("Example 1");

                break;
            case "E2":
                System.out.println("Example 2");
 
                break;
            case "E3":
                System.out.println("Example 3");

                break;
            case "E4":
                System.out.println("Example 4");
  
                break;
            case "E5":
                System.out.println("Example 5");

                break;
            case "E6":
                System.out.println("Example 6");
  
                break;
            case "E7":
                System.out.println("Example 7");
  
                break;

            case "E8":
                System.out.println("Example 8");

                break;

            case "E9":
                System.out.println("Example 9");

                break;
            case "E10":
                System.out.println("Example 10");

                break;
            case "Q":
                System.out.println("Quitting..!");
                break;
        }
    }

    // example1 method
    

    // example2 method
    

    // example3 method
    
    
    // example4 method
    

    // example5 method
    

    // example6 method
    

    // example7 method
    

    // example8 method
    

    // example9 method
    

    // example10 method
    

}
```

## BookStoreFRQ.java

```java
import java.util.*;

public class BookStoreFRQ
{
    public static void main(String[] args)
    {
        ArrayList<Book> books = new ArrayList<Book>();
        books.add(new Book("Java Guide", 35.00, true));
        books.add(new Book("Data Structures", 50.00, true));
        books.add(new Book("Algorithms", 45.00, false));
        books.add(new Book("Intro to CS", 25.00, true));
        books.add(new Book("AI Basics", 60.00, true));

        BookStore store = new BookStore(books);

        System.out.println("Testing avgInStockPrice...");
        double result = store.avgInStockPrice(20.0, 55.0);

        System.out.printf("Result: %.2f%n", result);
        System.out.println("Expected: 36.67");
    }
}

class Book
{
    private String title;
    private double price;
    private boolean inStock;

    public Book(String title, double price, boolean inStock)
    {
        this.title = title;
        this.price = price;
        this.inStock = inStock;
    }

    public String getTitle()
    {
        return title;
    }

    public double getPrice()
    {
        return price;
    }

    public boolean isInStock()
    {
        return inStock;
    }
}

class BookStore
{
    private ArrayList<Book> catalog;

    public BookStore(ArrayList<Book> catalog)
    {
        this.catalog = catalog;
    }

    /**
     * Returns the average price of in-stock books whose price
     * is between minPrice and maxPrice, inclusive.
     * Precondition: minPrice <= maxPrice
     *   At least one in-stock book has a price between
     *   minPrice and maxPrice, inclusive.
     *   No elements of catalog are null.
     * Postcondition: catalog is unchanged.
     */
    public double avgInStockPrice(double minPrice, double maxPrice)
    {
        // TODO: Write your solution here

        return 0.0; // change this line
    }
}
```

## MusicPlaylistFRQ.java

```java
import java.util.ArrayList;

/**
 * The Song class stores information about songs.
 */
class Song {
    private String title;
    private String artist;
    private String genre;
    private int duration; // in seconds

    public Song(String title, String artist, String genre, int duration) {
        this.title = title;
        this.artist = artist;
        this.genre = genre;
        this.duration = duration;
    }

    public String getTitle() {
        return title;
    }

    public String getArtist() {
        return artist;
    }

    public String getGenre() {
        return genre;
    }

    public int getDuration() {
        return duration;
    }

    @Override
    public String toString() {
        return "\"" + title + "\" by " + artist + " (" + duration + "s)";
    }
}

/**
 * The MusicPlaylist class maintains an ArrayList of Song objects.
 */
public class MusicPlaylistFRQ {
    private ArrayList<Song> songs;

    public MusicPlaylistFRQ() {
        songs = new ArrayList<Song>();
    }

    public void addSong(Song song) {
        songs.add(song);
    }

    public ArrayList<Song> getSongs() {
        return songs;
    }

    /**
     * Returns a list of unique artist names whose songs in the
     * playlist have a duration greater than minLength (in seconds).
     * No duplicate artist names in the returned list.
     * Preconditions: songs is not null.
     * No elements of songs are null.
     * Postcondition: songs is unchanged.
     */
    public ArrayList<String> getLongSongArtists(int minLength) {
        // TODO: Implement this method

        return null;
    }

    /**
     * Main method for testing
     */
    public static void main(String[] args) {
        MusicPlaylistFRQ playlist = new MusicPlaylistFRQ();

        // Add test songs
        playlist.addSong(new Song("Song A", "Taylor Swift", "Pop", 180));
        playlist.addSong(new Song("Song B", "Drake", "Hip-Hop", 240));
        playlist.addSong(new Song("Song C", "Taylor Swift", "Pop", 300));
        playlist.addSong(new Song("Song D", "Beyoncé", "R&B", 200));
        playlist.addSong(new Song("Song E", "Drake", "Hip-Hop", 150));
        playlist.addSong(new Song("Song F", "Ed Sheeran", "Pop", 190));

        System.out.println("All songs in playlist:");
        for (Song s : playlist.getSongs()) {
            System.out.println("  " + s);
        }
        System.out.println();

        // Test 1: minLength = 190
        System.out.println("Test 1: Artists with songs longer than 190 seconds:");
        ArrayList<String> result1 = playlist.getLongSongArtists(190);
        System.out.println("  Result: " + result1);
        System.out.println("  Expected: [Drake, Taylor Swift, Beyoncé] (order may vary)");
        System.out.println();

        // Test 2: minLength = 250
        System.out.println("Test 2: Artists with songs longer than 250 seconds:");
        ArrayList<String> result2 = playlist.getLongSongArtists(250);
        System.out.println("  Result: " + result2);
        System.out.println("  Expected: [Taylor Swift]");
        System.out.println();

        // Test 3: minLength = 350 (no songs qualify)
        System.out.println("Test 3: Artists with songs longer than 350 seconds:");
        ArrayList<String> result3 = playlist.getLongSongArtists(350);
        System.out.println("  Result: " + result3);
        System.out.println("  Expected: []");
        System.out.println();

        // Test 4: minLength = 100 (all songs qualify)
        System.out.println("Test 4: Artists with songs longer than 100 seconds:");
        ArrayList<String> result4 = playlist.getLongSongArtists(100);
        System.out.println("  Result: " + result4);
        System.out.println("  Expected: [Taylor Swift, Drake, Beyoncé, Ed Sheeran] (order may vary)");
        System.out.println();

        // Verify original list is unchanged
        System.out.println("Verifying original playlist is unchanged:");
        System.out.println("  Number of songs: " + playlist.getSongs().size());
        System.out.println("  (Should still be 6)");
    }
}

```

## TemperatureLogFRQ.java

```java
import java.util.ArrayList;

/**
 * The TemperatureLogFRQ class maintains daily temperature readings.
 */
public class TemperatureLogFRQ {
    private ArrayList<Double> readings;

    /**
     * Constructs an empty TemperatureLogFRQ.
     */
    public TemperatureLogFRQ() {
        readings = new ArrayList<Double>();
    }

    /**
     * Constructs a TemperatureLogFRQ with the given readings.
     */
    public TemperatureLogFRQ(double[] temps) {
        readings = new ArrayList<Double>();
        for (double temp : temps) {
            readings.add(temp);
        }
    }

    /**
     * Adds a temperature reading.
     */
    public void addReading(double temp) {
        readings.add(temp);
    }

    /**
     * Returns the list of readings.
     */
    public ArrayList<Double> getReadings() {
        return readings;
    }

    /**
     * Returns a string representation of the readings.
     */
    public String toString() {
        return readings.toString();
    }

    /**
     * Removes all temperature readings from readings that are
     * less than min or greater than max.
     * The order of remaining elements is maintained.
     */
    public void removeOutliers(double min, double max) {
        // TODO: Implement part (a)

    }

    /**
     * Returns the length of the longest cold snap in readings.
     * A cold snap is a sequence of two or more consecutive days
     * with a temperature below the given threshold.
     * Precondition: There is at least one cold snap based on threshold.
     */
    public int longestColdSnap(double threshold) {
        // TODO: Implement part (b)

        return -1;

    }

    /**
     * Main method for testing
     */
    public static void main(String[] args) {
        System.out.println("===== PART (a) TESTS: removeOutliers =====\n");

        // Test 1: Mixed outliers
        double[] temps1 = { 72.5, 150.0, 68.3, -10.0, 75.2, 200.0, 70.1 };
        TemperatureLogFRQ log1 = new TemperatureLogFRQ(temps1);
        System.out.println("Test 1 - Before: " + log1);
        log1.removeOutliers(0.0, 100.0);
        System.out.println("  After removeOutliers(0.0, 100.0): " + log1);
        System.out.println("  Expected: [72.5, 68.3, 75.2, 70.1]");
        System.out.println();

        // Test 2: Some outliers on both ends
        double[] temps2 = { 32.0, 28.5, 35.2, 30.0, 33.0 };
        TemperatureLogFRQ log2 = new TemperatureLogFRQ(temps2);
        System.out.println("Test 2 - Before: " + log2);
        log2.removeOutliers(30.0, 34.0);
        System.out.println("  After removeOutliers(30.0, 34.0): " + log2);
        System.out.println("  Expected: [32.0, 30.0, 33.0]");
        System.out.println();

        // Test 3: No outliers
        double[] temps3 = { 50.0, 60.0, 70.0 };
        TemperatureLogFRQ log3 = new TemperatureLogFRQ(temps3);
        System.out.println("Test 3 - Before: " + log3);
        log3.removeOutliers(0.0, 100.0);
        System.out.println("  After removeOutliers(0.0, 100.0): " + log3);
        System.out.println("  Expected: [50.0, 60.0, 70.0]");
        System.out.println();

        // Test 4: All outliers
        double[] temps4 = { -5.0, 150.0, -20.0, 200.0 };
        TemperatureLogFRQ log4 = new TemperatureLogFRQ(temps4);
        System.out.println("Test 4 - Before: " + log4);
        log4.removeOutliers(0.0, 100.0);
        System.out.println("  After removeOutliers(0.0, 100.0): " + log4);
        System.out.println("  Expected: []");
        System.out.println();

        // Test 5: Consecutive outliers (tests index handling)
        double[] temps5 = { 50.0, -1.0, -2.0, -3.0, 60.0, 70.0 };
        TemperatureLogFRQ log5 = new TemperatureLogFRQ(temps5);
        System.out.println("Test 5 - Before: " + log5);
        log5.removeOutliers(0.0, 100.0);
        System.out.println("  After removeOutliers(0.0, 100.0): " + log5);
        System.out.println("  Expected: [50.0, 60.0, 70.0]");
        System.out.println();

        // Test 6: Boundary values (exactly at min and max)
        double[] temps6 = { 0.0, 50.0, 100.0, -0.1, 100.1 };
        TemperatureLogFRQ log6 = new TemperatureLogFRQ(temps6);
        System.out.println("Test 6 - Before: " + log6);
        log6.removeOutliers(0.0, 100.0);
        System.out.println("  After removeOutliers(0.0, 100.0): " + log6);
        System.out.println("  Expected: [0.0, 50.0, 100.0]");
        System.out.println();

        System.out.println("===== PART (b) TESTS: longestColdSnap =====\n");

        // Test 7: Two equal cold snaps
        double[] temps7 = { 45.0, 28.0, 25.0, 30.0, 50.0, 20.0, 22.0, 18.0, 40.0 };
        TemperatureLogFRQ log7 = new TemperatureLogFRQ(temps7);
        System.out.println("Test 7: " + log7);
        System.out.println("  longestColdSnap(32.0): " + log7.longestColdSnap(32.0));
        System.out.println("  Expected: 3");
        System.out.println();

        // Test 8: Second cold snap is longer
        double[] temps8 = { 55.0, 30.0, 28.0, 60.0, 25.0, 20.0, 22.0, 19.0, 50.0 };
        TemperatureLogFRQ log8 = new TemperatureLogFRQ(temps8);
        System.out.println("Test 8: " + log8);
        System.out.println("  longestColdSnap(32.0): " + log8.longestColdSnap(32.0));
        System.out.println("  Expected: 4");
        System.out.println();

        // Test 9: All readings are cold
        double[] temps9 = { 10.0, 15.0, 12.0, 8.0, 5.0 };
        TemperatureLogFRQ log9 = new TemperatureLogFRQ(temps9);
        System.out.println("Test 9: " + log9);
        System.out.println("  longestColdSnap(32.0): " + log9.longestColdSnap(32.0));
        System.out.println("  Expected: 5");
        System.out.println();

        // Test 10: Cold snap at the end
        double[] temps10 = { 50.0, 55.0, 60.0, 25.0, 20.0, 15.0 };
        TemperatureLogFRQ log10 = new TemperatureLogFRQ(temps10);
        System.out.println("Test 10: " + log10);
        System.out.println("  longestColdSnap(32.0): " + log10.longestColdSnap(32.0));
        System.out.println("  Expected: 3");
        System.out.println();

        // Test 11: Cold snap at the beginning
        double[] temps11 = { 20.0, 22.0, 18.0, 50.0, 55.0, 60.0 };
        TemperatureLogFRQ log11 = new TemperatureLogFRQ(temps11);
        System.out.println("Test 11: " + log11);
        System.out.println("  longestColdSnap(32.0): " + log11.longestColdSnap(32.0));
        System.out.println("  Expected: 3");
        System.out.println();

        // Test 12: Minimum cold snap (exactly 2)
        double[] temps12 = { 50.0, 25.0, 28.0, 55.0, 60.0 };
        TemperatureLogFRQ log12 = new TemperatureLogFRQ(temps12);
        System.out.println("Test 12: " + log12);
        System.out.println("  longestColdSnap(32.0): " + log12.longestColdSnap(32.0));
        System.out.println("  Expected: 2");
        System.out.println();

        // Test 13: Multiple cold snaps of varying lengths
        double[] temps13 = { 28.0, 25.0, 50.0, 20.0, 22.0, 18.0, 16.0, 60.0, 29.0, 27.0, 25.0 };
        TemperatureLogFRQ log13 = new TemperatureLogFRQ(temps13);
        System.out.println("Test 13: " + log13);
        System.out.println("  longestColdSnap(32.0): " + log13.longestColdSnap(32.0));
        System.out.println("  Expected: 4");
        System.out.println();

        System.out.println("===== ALL TESTS COMPLETE =====");
    }
}

```

## TextAnalyzerFRQ.java

```java
import java.util.ArrayList;

/**
 * The TextAnalyzer class contains a list of words for analysis.
 */
public class TextAnalyzerFRQ
{
    private ArrayList<String> words;

    /**
     * Constructs a TextAnalyzer with an empty word list.
     */
    public TextAnalyzerFRQ()
    {
        words = new ArrayList<String>();
    }

    /**
     * Constructs a TextAnalyzer with the given word list.
     */
    public TextAnalyzerFRQ(ArrayList<String> wordList)
    {
        words = new ArrayList<String>();
        for (String word : wordList)
        {
            words.add(word);
        }
    }

    /**
     * Adds a word to the list.
     */
    public void addWord(String word)
    {
        words.add(word);
    }

    /**
     * Returns the list of words.
     */
    public ArrayList<String> getWords()
    {
        return words;
    }

    /**
     * Returns true if each word in words (except the first)
     * is longer than the previous word, false otherwise.
     * Precondition: words contains at least two elements.
     * Postcondition: words is unchanged.
     */
    public boolean isStrictlyGrowing()
    {
        // TODO: Implement part (a)
        
        return false;
    }

    /**
     * Returns a new ArrayList containing each element of words
     * that ends with suffix, with the suffix removed.
     * Elements appear in the same order as in words.
     * Postcondition: words is unchanged.
     */
    public ArrayList<String> removeSuffix(String suffix)
    {
        // TODO: Implement part (
        
        return null;
    }

    /**
     * Main method for testing
     */
    public static void main(String[] args)
    {
        System.out.println("===== PART (a) TESTS: isStrictlyGrowing =====\n");

        // Test 1: Strictly growing - should return true
        ArrayList<String> list1 = new ArrayList<String>();
        list1.add("I");
        list1.add("am");
        list1.add("the");
        list1.add("best");
        TextAnalyzerFRQ ta1 = new TextAnalyzerFRQ(list1);
        System.out.println("Test 1: " + ta1.getWords());
        System.out.println("  isStrictlyGrowing(): " + ta1.isStrictlyGrowing());
        System.out.println("  Expected: true");
        System.out.println();

        // Test 2: Equal lengths - should return false
        ArrayList<String> list2 = new ArrayList<String>();
        list2.add("Hi");
        list2.add("my");
        list2.add("friend");
        TextAnalyzerFRQ ta2 = new TextAnalyzerFRQ(list2);
        System.out.println("Test 2: " + ta2.getWords());
        System.out.println("  isStrictlyGrowing(): " + ta2.isStrictlyGrowing());
        System.out.println("  Expected: false (\"my\" is not longer than \"Hi\")");
        System.out.println();

        // Test 3: Decreasing length - should return false
        ArrayList<String> list3 = new ArrayList<String>();
        list3.add("elephant");
        list3.add("dog");
        list3.add("cat");
        TextAnalyzerFRQ ta3 = new TextAnalyzerFRQ(list3);
        System.out.println("Test 3: " + ta3.getWords());
        System.out.println("  isStrictlyGrowing(): " + ta3.isStrictlyGrowing());
        System.out.println("  Expected: false");
        System.out.println();

        // Test 4: Growing then shrinking - should return false
        ArrayList<String> list4 = new ArrayList<String>();
        list4.add("go");
        list4.add("run");
        list4.add("jump");
        list4.add("fly");
        TextAnalyzerFRQ ta4 = new TextAnalyzerFRQ (list4);
        System.out.println("Test 4: " + ta4.getWords());
        System.out.println("  isStrictlyGrowing(): " + ta4.isStrictlyGrowing());
        System.out.println("  Expected: false (\"fly\" is not longer than \"jump\")");
        System.out.println();

        // Test 5: Two elements, growing - should return true
        ArrayList<String> list5 = new ArrayList<String>();
        list5.add("a");
        list5.add("ab");
        TextAnalyzerFRQ ta5 = new TextAnalyzerFRQ(list5);
        System.out.println("Test 5: " + ta5.getWords());
        System.out.println("  isStrictlyGrowing(): " + ta5.isStrictlyGrowing());
        System.out.println("  Expected: true");
        System.out.println();

        System.out.println("===== PART (b) TESTS: removeSuffix =====\n");

        // Test 6: "ing" suffix
        ArrayList<String> list6 = new ArrayList<String>();
        list6.add("running");
        list6.add("jumping");
        list6.add("swim");
        list6.add("flying");
        TextAnalyzerFRQ ta6 = new TextAnalyzerFRQ(list6);
        System.out.println("Test 6: " + ta6.getWords());
        System.out.println("  removeSuffix(\"ing\"): " + ta6.removeSuffix("ing"));
        System.out.println("  Expected: [runn, jump, fly]");
        System.out.println("  Original unchanged: " + ta6.getWords());
        System.out.println();

        // Test 7: "er" suffix
        ArrayList<String> list7 = new ArrayList<String>();
        list7.add("teacher");
        list7.add("player");
        list7.add("coach");
        list7.add("dancer");
        TextAnalyzerFRQ ta7 = new TextAnalyzerFRQ(list7);
        System.out.println("Test 7: " + ta7.getWords());
        System.out.println("  removeSuffix(\"er\"): " + ta7.removeSuffix("er"));
        System.out.println("  Expected: [teach, play, danc]");
        System.out.println();

        // Test 8: "y" suffix
        ArrayList<String> list8 = new ArrayList<String>();
        list8.add("happy");
        list8.add("sunny");
        list8.add("cloud");
        list8.add("rainy");
        TextAnalyzerFRQ ta8 = new TextAnalyzerFRQ(list8);
        System.out.println("Test 8: " + ta8.getWords());
        System.out.println("  removeSuffix(\"y\"): " + ta8.removeSuffix("y"));
        System.out.println("  Expected: [happ, sunn, rain]");
        System.out.println();

        // Test 9: No matches
        ArrayList<String> list9 = new ArrayList<String>();
        list9.add("cat");
        list9.add("dog");
        list9.add("bird");
        TextAnalyzerFRQ ta9 = new TextAnalyzerFRQ(list9);
        System.out.println("Test 9: " + ta9.getWords());
        System.out.println("  removeSuffix(\"ing\"): " + ta9.removeSuffix("ing"));
        System.out.println("  Expected: []");
        System.out.println();

        // Test 10: All match
        ArrayList<String> list10 = new ArrayList<String>();
        list10.add("singing");
        list10.add("dancing");
        list10.add("playing");
        TextAnalyzerFRQ ta10 = new TextAnalyzerFRQ(list10);
        System.out.println("Test 10: " + ta10.getWords());
        System.out.println("  removeSuffix(\"ing\"): " + ta10.removeSuffix("ing"));
        System.out.println("  Expected: [sing, danc, play]");
        System.out.println();

        System.out.println("===== ALL TESTS COMPLETE =====");
    }
}
```

## ContactListFRQ.java

```java
import java.util.ArrayList;

public class ContactListFRQ
{
    private ArrayList<Contact> contacts;

    // Constructor
    public ContactListFRQ()
    {
        contacts = new ArrayList<Contact>();
    }

    // Method to add a contact
    public void addContact(Contact c)
    {
        contacts.add(c);
    }

    /**
     * Returns true if any two contacts in contacts have the
     * same email address, and false otherwise.
     * Preconditions: contacts is not null.
     *   No elements of contacts are null.
     * Postcondition: contacts is unchanged.
     */
    public boolean hasDuplicateEmails()
    {
        // TODO: Complete this method

        return false; // placeholder
    }

    // Main method for testing
    public static void main(String[] args)
    {
        // Test Case 1: List with duplicates
        ContactListFRQ list1 = new ContactListFRQ();
        list1.addContact(new Contact("Alice", "alice@mail.com"));
        list1.addContact(new Contact("Bob", "bob@work.com"));
        list1.addContact(new Contact("Carol", "alice@mail.com"));
        list1.addContact(new Contact("Dave", "dave@home.com"));
        list1.addContact(new Contact("Eve", "bob@work.com"));

        System.out.println("Test 1 - Has duplicates:");
        System.out.println("Expected: true");
        System.out.println("Actual: " + list1.hasDuplicateEmails());
        System.out.println();

        // Test Case 2: List with no duplicates
        ContactListFRQ list2 = new ContactListFRQ();
        list2.addContact(new Contact("Alice", "alice@mail.com"));
        list2.addContact(new Contact("Bob", "bob@work.com"));
        list2.addContact(new Contact("Dave", "dave@home.com"));

        System.out.println("Test 2 - No duplicates:");
        System.out.println("Expected: false");
        System.out.println("Actual: " + list2.hasDuplicateEmails());
        System.out.println();

        // Test Case 3: Empty list
        ContactListFRQ list3 = new ContactListFRQ();

        System.out.println("Test 3 - Empty list:");
        System.out.println("Expected: false");
        System.out.println("Actual: " + list3.hasDuplicateEmails());
        System.out.println();

        // Test Case 4: Single contact
        ContactListFRQ list4 = new ContactListFRQ();
        list4.addContact(new Contact("Alice", "alice@mail.com"));

        System.out.println("Test 4 - Single contact:");
        System.out.println("Expected: false");
        System.out.println("Actual: " + list4.hasDuplicateEmails());
    }
}

class Contact
{
    private String name;
    private String email;

    // Constructor
    public Contact(String name, String email)
    {
        this.name = name;
        this.email = email;
    }

    /** Returns the name of the contact */
    public String getName()
    {
        return name;
    }

    /** Returns the email address of the contact */
    public String getEmail()
    {
        return email;
    }

    public String toString()
    {
        return name + " (" + email + ")";
    }
}
```

## TaskQueueFRQ.java

```java
import java.util.ArrayList;

/**
 * Task class - represents a single task with a name and priority
 */
class Task
{
    private String name;
    private int priority;
    
    public Task(String name, int priority)
    {
        this.name = name;
        this.priority = priority;
    }
    
    /** Returns the name of the task */
    public String getName()
    {
        return name;
    }
    
    /** Returns the priority of the task (higher number = higher priority) */
    public int getPriority()
    {
        return priority;
    }
    
    public String toString()
    {
        return name + "(" + priority + ")";
    }
}

/**
 * TaskQueueFRQ class - manages a queue of tasks
 */
public class TaskQueueFRQ
{
    private ArrayList<Task> tasks;
    
    public TaskQueueFRQ()
    {
        tasks = new ArrayList<Task>();
    }
    
    public void addTask(Task t)
    {
        tasks.add(t);
    }
    
    /**
     * Rotates the task list to the left by n positions.
     * The first n elements are moved to the end of the list
     * in their original order.
     * Precondition: 0 < n < tasks.size()
     */
    public void rotateLeft(int n)
    {
        // TODO: Implement this method for Part (a)
    }
    
    /**
     * Moves all tasks with priority greater than threshold
     * to the front of the list, maintaining their relative
     * order. All other tasks remain at the back of the list,
     * maintaining their relative order.
     * Precondition: tasks contains at least one task with
     *   priority > threshold and at least one with
     *   priority <= threshold.
     * Postcondition: No elements are added or removed.
     */
    public void promoteTasks(int threshold)
    {
        // TODO: Implement this method for Part (b)
    }
    
    /**
     * Prints the current state of the task queue
     */
    public void printTasks()
    {
        System.out.print("Tasks: [");
        for (int i = 0; i < tasks.size(); i++)
        {
            System.out.print(tasks.get(i));
            if (i < tasks.size() - 1)
            {
                System.out.print(", ");
            }
        }
        System.out.println("]");
    }
    
    /**
     * Returns the task at the specified index (for testing)
     */
    public Task getTask(int index)
    {
        return tasks.get(index);
    }
    
    /**
     * Returns the number of tasks (for testing)
     */
    public int size()
    {
        return tasks.size();
    }
    
    // Main method for testing
    public static void main(String[] args)
    {
        System.out.println("=== Testing Part (a): rotateLeft ===\n");
        
        // Test 1: Basic rotation
        TaskQueueFRQ queue1 = new TaskQueueFRQ();
        queue1.addTask(new Task("Email", 2));
        queue1.addTask(new Task("Report", 5));
        queue1.addTask(new Task("Call", 1));
        queue1.addTask(new Task("Meeting", 4));
        queue1.addTask(new Task("Review", 3));
        
        System.out.println("Before rotateLeft(2):");
        queue1.printTasks();
        
        queue1.rotateLeft(2);
        
        System.out.println("After rotateLeft(2):");
        queue1.printTasks();
        System.out.println("Expected: [Call(1), Meeting(4), Review(3), Email(2), Report(5)]");
        
        // Test 2: Rotate by 1
        System.out.println("\n--- Test 2: Rotate by 1 ---");
        TaskQueueFRQ queue2 = new TaskQueueFRQ();
        queue2.addTask(new Task("A", 1));
        queue2.addTask(new Task("B", 2));
        queue2.addTask(new Task("C", 3));
        queue2.addTask(new Task("D", 4));
        
        System.out.println("Before rotateLeft(1):");
        queue2.printTasks();
        
        queue2.rotateLeft(1);
        
        System.out.println("After rotateLeft(1):");
        queue2.printTasks();
        System.out.println("Expected: [B(2), C(3), D(4), A(1)]");
        
        // Test 3: Rotate by size-1
        System.out.println("\n--- Test 3: Rotate by size-1 ---");
        TaskQueueFRQ queue3 = new TaskQueueFRQ();
        queue3.addTask(new Task("A", 1));
        queue3.addTask(new Task("B", 2));
        queue3.addTask(new Task("C", 3));
        
        System.out.println("Before rotateLeft(2):");
        queue3.printTasks();
        
        queue3.rotateLeft(2);
        
        System.out.println("After rotateLeft(2):");
        queue3.printTasks();
        System.out.println("Expected: [C(3), A(1), B(2)]");
        
        System.out.println("\n=== Testing Part (b): promoteTasks ===\n");
        
        // Test 4: Basic promotion
        TaskQueueFRQ queue4 = new TaskQueueFRQ();
        queue4.addTask(new Task("Email", 2));
        queue4.addTask(new Task("Report", 5));
        queue4.addTask(new Task("Call", 1));
        queue4.addTask(new Task("Meeting", 4));
        queue4.addTask(new Task("Review", 3));
        
        System.out.println("Before promoteTasks(3):");
        queue4.printTasks();
        
        queue4.promoteTasks(3);
        
        System.out.println("After promoteTasks(3):");
        queue4.printTasks();
        System.out.println("Expected: [Report(5), Meeting(4), Email(2), Call(1), Review(3)]");
        
        // Test 5: Different threshold
        System.out.println("\n--- Test 5: Threshold = 1 ---");
        TaskQueueFRQ queue5 = new TaskQueueFRQ();
        queue5.addTask(new Task("Low", 1));
        queue5.addTask(new Task("High", 5));
        queue5.addTask(new Task("Med", 3));
        queue5.addTask(new Task("VeryLow", 0));
        
        System.out.println("Before promoteTasks(1):");
        queue5.printTasks();
        
        queue5.promoteTasks(1);
        
        System.out.println("After promoteTasks(1):");
        queue5.printTasks();
        System.out.println("Expected: [High(5), Med(3), Low(1), VeryLow(0)]");
        
        // Test 6: Only one high priority
        System.out.println("\n--- Test 6: Single high priority task ---");
        TaskQueueFRQ queue6 = new TaskQueueFRQ();
        queue6.addTask(new Task("A", 1));
        queue6.addTask(new Task("B", 1));
        queue6.addTask(new Task("C", 5));
        queue6.addTask(new Task("D", 1));
        
        System.out.println("Before promoteTasks(2):");
        queue6.printTasks();
        
        queue6.promoteTasks(2);
        
        System.out.println("After promoteTasks(2):");
        queue6.printTasks();
        System.out.println("Expected: [C(5), A(1), B(1), D(1)]");
        
        System.out.println("\n=== All Tests Complete ===");
    }
}
```

## PlaylistManagerFRQ.java

```java
import java.util.ArrayList;

/**
 * Represents a song with a title and artist.
 */
class Song
{
    private String title;
    private String artist;

    /**
     * Constructs a Song with the given title and artist.
     * @param title the title of the song
     * @param artist the artist of the song
     */
    public Song(String title, String artist)
    {
        this.title = title;
        this.artist = artist;
    }

    /**
     * Returns the title of the song.
     * @return the title of the song
     */
    public String getTitle()
    {
        return title;
    }

    /**
     * Returns the artist of the song.
     * @return the artist of the song
     */
    public String getArtist()
    {
        return artist;
    }

    /**
     * Returns a string representation of the song.
     * @return a string in the format "Title" by Artist
     */
    public String toString()
    {
        return "\"" + title + "\" by " + artist;
    }
}

/**
 * Manages a playlist of songs with rotation and deduplication capabilities.
 */
public class PlaylistManagerFRQ
{
    private ArrayList<Song> playlist;

    /**
     * Constructs an empty PlaylistManagerFRQ.
     */
    public PlaylistManagerFRQ()
    {
        playlist = new ArrayList<Song>();
    }

    /**
     * Adds a song to the playlist.
     * @param song the song to add
     */
    public void addSong(Song song)
    {
        playlist.add(song);
    }

    /**
     * Returns the current playlist.
     * @return the ArrayList of songs
     */
    public ArrayList<Song> getPlaylist()
    {
        return playlist;
    }

    /**
     * Prints the current playlist with index, title, and artist.
     */
    public void printPlaylist()
    {
        System.out.println("Current Playlist:");
        System.out.println("Index\tTitle\t\tArtist");
        System.out.println("-----\t-----\t\t------");
        for (int i = 0; i < playlist.size(); i++)
        {
            Song s = playlist.get(i);
            System.out.println(i + "\t\"" + s.getTitle() + "\"\t\t" + s.getArtist());
        }
        System.out.println();
    }

    /**
     * Rotates the playlist to the right by n positions.
     * The last n elements are moved to the front of the list
     * in their original order.
     * Precondition: 0 < n < playlist.size()
     *
     * @param n the number of positions to rotate right
     */
    public void rotateRight(int n)
    {
        // TODO: Student implementation goes here



    }

    /**
     * Removes songs from playlist so that no two consecutive
     * songs have the same artist.
     * When two consecutive songs have the same artist,
     * the second one is removed.
     * The process repeats until no two consecutive songs
     * have the same artist.
     */
    public void removeConsecutiveDuplicateArtists()
    {
        // TODO: Student implementation goes here



    }

    /**
     * Main method to test PlaylistManagerFRQ.
     * Tests both rotateRight and removeConsecutiveDuplicateArtists methods.
     */
    public static void main(String[] args)
    {
        // Test Part (a): rotateRight
        System.out.println("===== TESTING PART (a): rotateRight =====\n");

        PlaylistManagerFRQ manager1 = new PlaylistManagerFRQ();
        manager1.addSong(new Song("Sunny", "Ava"));
        manager1.addSong(new Song("Rain", "Ben"));
        manager1.addSong(new Song("Fire", "Cara"));
        manager1.addSong(new Song("Storm", "Dan"));
        manager1.addSong(new Song("Dawn", "Eve"));

        System.out.println("Before rotateRight(2):");
        manager1.printPlaylist();

        manager1.rotateRight(2);

        System.out.println("After rotateRight(2):");
        manager1.printPlaylist();

        System.out.println("Expected order: Storm, Dawn, Sunny, Rain, Fire\n");

        // Additional test for rotateRight
        PlaylistManagerFRQ manager2 = new PlaylistManagerFRQ();
        manager2.addSong(new Song("A", "Artist1"));
        manager2.addSong(new Song("B", "Artist2"));
        manager2.addSong(new Song("C", "Artist3"));
        manager2.addSong(new Song("D", "Artist4"));

        System.out.println("Before rotateRight(1):");
        manager2.printPlaylist();

        manager2.rotateRight(1);

        System.out.println("After rotateRight(1):");
        manager2.printPlaylist();

        System.out.println("Expected order: D, A, B, C\n");

        // Test Part (b): removeConsecutiveDuplicateArtists
        System.out.println("===== TESTING PART (b): removeConsecutiveDuplicateArtists =====\n");

        PlaylistManagerFRQ manager3 = new PlaylistManagerFRQ();
        manager3.addSong(new Song("Sunny", "Ava"));
        manager3.addSong(new Song("Rain", "Ava"));
        manager3.addSong(new Song("Fire", "Ben"));
        manager3.addSong(new Song("Storm", "Ben"));
        manager3.addSong(new Song("Dawn", "Ben"));
        manager3.addSong(new Song("Wave", "Ava"));

        System.out.println("Before removeConsecutiveDuplicateArtists():");
        manager3.printPlaylist();

        manager3.removeConsecutiveDuplicateArtists();

        System.out.println("After removeConsecutiveDuplicateArtists():");
        manager3.printPlaylist();

        System.out.println("Expected: Sunny (Ava), Fire (Ben), Wave (Ava)\n");

        // Additional test for removeConsecutiveDuplicateArtists
        PlaylistManagerFRQ manager4 = new PlaylistManagerFRQ();
        manager4.addSong(new Song("Song1", "X"));
        manager4.addSong(new Song("Song2", "X"));
        manager4.addSong(new Song("Song3", "X"));
        manager4.addSong(new Song("Song4", "Y"));
        manager4.addSong(new Song("Song5", "Y"));
        manager4.addSong(new Song("Song6", "Z"));

        System.out.println("Before removeConsecutiveDuplicateArtists():");
        manager4.printPlaylist();

        manager4.removeConsecutiveDuplicateArtists();

        System.out.println("After removeConsecutiveDuplicateArtists():");
        manager4.printPlaylist();

        System.out.println("Expected: Song1 (X), Song4 (Y), Song6 (Z)\n");

        // Edge case: No consecutive duplicates
        System.out.println("===== EDGE CASE: No consecutive duplicates =====\n");

        PlaylistManagerFRQ manager5 = new PlaylistManagerFRQ();
        manager5.addSong(new Song("A", "X"));
        manager5.addSong(new Song("B", "Y"));
        manager5.addSong(new Song("C", "Z"));

        System.out.println("Before removeConsecutiveDuplicateArtists():");
        manager5.printPlaylist();

        manager5.removeConsecutiveDuplicateArtists();

        System.out.println("After removeConsecutiveDuplicateArtists():");
        manager5.printPlaylist();

        System.out.println("Expected: A (X), B (Y), C (Z) - unchanged\n");
    }
}
```
