Academic Integrity: tutoring, explanations, and feedback — we don’t complete graded work or submit on a student’s behalf.

I need to edit the following code using the instructions printed below it. impor

ID: 3594431 • Letter: I

Question

I need to edit the following code using the instructions printed below it.

import java.io.PrintWriter;

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.Scanner;

public class ElevationVisualizer extends JFrame
{
    // Panel that displays the elevation data
    private class DisplayPanel extends JPanel
    {
        private int[][] data;       // Elevation data stored in a 2D array
        private int[] path;         // Path data - element i in this array corresponds to the row of
                                    // column i that should be chosen to try to minimize elevation differences

        public void setData(int[][] data)
        {
            this.data = data;
        }

        public void setPath(int[] path)
        {
            this.path = path;
        }

        // Overrides the Swing paintComponent method -- defines how to draw this panel
        public void paintComponent(Graphics g)
        {
            if (dataLoaded)
            {
                int max = findMax(data);
                for (int r = 0; r < data.length; r++)   // Each pixel on the panel = 1 value in the data array
                {
                    for (int c = 0; c < data[r].length; c++)
                    {
                        int h = (int)((double)data[r][c]/max*255); // lighter = higher, darker = lower
                        g.setColor(new Color(h, h, h));
                        g.drawRect(c, r, 1, 1);
                    }
                }
            }

            if (pathRequested)
            {
                for (int i = 0; i < path.length; i++)
                {
                    g.setColor(Color.GREEN);
                    g.drawRect(i, path[i], 1, 1);
                }
            }
        }
    }

    // Event handler for button presses
    private class ButtonHandler implements ActionListener
    {
        // actionPerformed gets called whenever an "action event" (e.g., button press) occurs
        public void actionPerformed(ActionEvent e)
        {
            Object src = e.getSource();
            if (src == bLoadFile)
                chooseFile();
            else if (src == bFindPath)
                findPath();
        }
    }

    private DisplayPanel    pDisplay = new DisplayPanel();
    private JButton         bLoadFile = new JButton("Load new data file"),
                            bFindPath = new JButton("Find a path");
    private JLabel          lStatus = new JLabel("Use the Load button to open a data file");
    private boolean         dataLoaded = false,     // Has the user loaded map data yet?
                            pathRequested = false; // Has the user requested a path yet?

    // Constructor - handles GUI construction tasks
    public ElevationVisualizer()
    {
        ButtonHandler bh = new ButtonHandler(); // Register event handler for buttons
        bLoadFile.addActionListener(bh);
        bFindPath.addActionListener(bh);

        JPanel cp = new JPanel();       // Content pane
        cp.setLayout(new BorderLayout());

        JPanel bp = new JPanel();       // Panel to hold load/path buttons
        bp.setLayout(new GridLayout(1, 2));
        bp.add(bLoadFile);
        bp.add(bFindPath);

        cp.add(BorderLayout.NORTH, lStatus);
        cp.add(BorderLayout.CENTER, pDisplay);
        cp.add(BorderLayout.SOUTH, bp);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("Elevation Data Visualizer");
        setContentPane(cp);
        setSize(600, 600);
        setVisible(true);
    }

    private void resetLoadState()
    {
        dataLoaded = pathRequested = false;
        pDisplay.setData(null);
        lStatus.setText("Use the Load button to open a data file.");
        repaint();
    }
  
    // Opens a file chooser dialog to read elevation data, and calls
    // readElevationData to import that data into the application
    private void chooseFile()
    {
        resetLoadState();
      
        JFileChooser fc = new JFileChooser();
        fc.setCurrentDirectory(new File("."));
        int returnVal = fc.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION)
        {
            File f = fc.getSelectedFile();
            try
            {
                pDisplay.setData(readElevationData(f));
                dataLoaded = true;
                repaint();      // Triggers the paintComponent method to be called
                lStatus.setText(f.getName() + " successfully opened!");
            }
            catch (FileNotFoundException e)
            {
                lStatus.setText("Can't find " + f.getName());
            }
            catch (ArrayIndexOutOfBoundsException e)
            {
                lStatus.setText(f.getName() + " seems to have inconsistent rows and columns");
            }
            catch (NumberFormatException e)
            {
                lStatus.setText(f.getName() + " seems to contain non-integer data");
            }
        }
    }
  
    private void findPath()
    {
        if (!dataLoaded)
            lStatus.setText("Can't find path yet, must load a data file first!");
        else
        {
            pDisplay.setPath(findPath(pDisplay.data));
            pathRequested = true;
            repaint();      // Triggers the paintComponent method to be called
            lStatus.setText("West-east path computed!");
        }
    }

    // **** COMPLETE THIS METHOD ****
    // Reads elevation data from the specified file into a 2-D array, and
    // returns the array created
    // Throws: FileNotFoundException if file isn't found
    //          ArrayIndexOutOfBoundsException if each row in the file doesn't have the same number of columns
    //          NumberFormatException if file contains non-integer data
    private int[][] readElevationData(File f) throws FileNotFoundException, ArrayIndexOutOfBoundsException, NumberFormatException
    {
        return null;    // Replace with the array that you return
    }

    // **** COMPLETE THIS METHOD ****
    // Finds and returns a west-east path through the area whose elevation is stored in data
    private int[] findPath(int[][] data)
    {
        return null;    // Replace with the array that you return
    }

    // **** COMPLETE THIS METHOD ****
    // Finds and returns the max element from the 2D array a
    public static int findMax(int[][] a)
    {
        return 10;       // Replace with the max value that you find
    }

    // **** COMPLETE THIS METHOD ****
    // Finds and returns the index of the min element from column c of the 2D array a
    public static int indexOfMinFromCol(int[][] a, int c)
    {
        return 10;       // Replace with the index that you find
    }

    public static void main(String[] args)
    {
        new ElevationVisualizer();
    }
}

1. (2 pts) Complete the method findMax(int[][] a). This method should find and return the maximum element from the 2D array a.

2. (3 pts) Complete the method indexOfMinFromCol(int[][] a, int c). This method should find and return the index of the minimum element from column c of the 2D array a. Note that you want to get the index of the minimum element (i.e., which row is the minimum in?), rather than the minimum element itself.

Reading the Data

3. (10 pts) Complete the method readElevationData(File f). This method should read the elevation data from file f into a 2D int array and return that array. Note that your method should work for any data file formatted the same way as the provided input file. The number of rows in the data file does not necessarily have to match the number of columns. However, a valid data file should have the same number of columns for every row.

Hints for this method: Look at the file format carefully to determine how to read it. If you’re using Notepad, turn off word wrap. To convert a String to an int value, you can call the static method parseInt from the Integer class (see the API for details). parseInt throws a NumberFormatException if you pass it an argument that cannot be read as an integer.

As indicated in the comments, also make this method throw three possible types of exceptions:

a. FileNotFoundException if the file is not found

b. ArrayIndexOutOfBoundsException if the file doesn’t have a consistent number of columns in each row

c. NumberFormatException if the file contains non-integer data

Finding a Path

4. (10 pts) Suppose you want to find the best west-east route across this terrain. We’ll define the “best” route as one that minimizes your cumulative elevation change across the route. By “cumulative elevation change,” I mean the sum of all individual changes over all steps of the route, not just the difference between your starting and ending points. Here’s a simple algorithm that tries to accomplish this:

a. Start from the minimum-elevation point on the western edge of the terrain. b. Move east one column at a time. Each time you do this, you will have three choices (northeast, due east, or southeast), as sketched below.

3011 2900 2852
2972 2937 2886
3137 2959 2913

Current position:   2972

Options for next position: 2900 (NE, elevation change = -72)     2937 (E, elevation change = -35)     2959 (SE, elevation change = -13)

To determine which way to go, pick the option that results in the lowest elevation change (which could be an increase or decrease in elevation). In this example, 2959 has the least elevation change, so we head southeast from 2972. If two or more options give the same smallest elevation change, pick any of them.

In this example, following the algorithm gives the path below. Be sure to prevent going beyond the bounds of the array!

3011 2900 2852
2972 2937 2886
3137 2959 2913

This is an example of a greedy algorithm – it always makes what appears to be the best choice at each step. Since our goal here is to minimize the cumulative elevation change across the entire route, the algorithm always picks the direction that results in the lowest change from the current position. Greedy algorithms sometimes (but not always) result in the best overall solution.

Complete the findPath(int[][] a) method in the code. This method should implement the greedy algorithm above using the data in the 2D array a. It should return a 1D array containing the row indices of each point on the resulting path, heading west to east. In the example above, the returned array would be {1, 2, 2} (since 2972 is in row 1, 2959 is in row 2, 2913 is in row 2).

Something interesting to think about if you have time (optional): Is the greedy algorithm guaranteed to provide the optimal solution in this problem? You may want to consider a smaller example to better understand the situation. Can you come up with a better algorithm?

Explanation / Answer

ElevationVisualizer.java
---------------------------------------------------------------
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.Scanner;

public class ElevationVisualizer extends JFrame {

    // panel that displays the elevation data
    private class DisplayPanel extends JPanel {
        private int[][] data;       // elevation data stored in a 2D array
        private int[] path;         // path data - element i in this array corresponds to the row of
        // column i that should be chosen to try to minimize elevation differences

        public void setData(int[][] data) {
            this.data = data;
        }

        public void setPath(int[] path) {
            this.path = path;
        }

        // overrides the Swing paintComponent method -- defines how to draw this panel
        public void paintComponent(Graphics g) {
            if (dataLoaded) {
                int max = findMax(data);
                for (int r = 0; r < data.length; r++) {       // each pixel on the panel = 1 value in the data array
                    for (int c = 0; c < data[r].length; c++) {
                        int h = (int)((double)data[r][c]/max*255); // lighter = higher, darker = lower
                        g.setColor(new Color(h, h, h));
                        g.drawRect(c, r, 1, 1);
                    }
                }
            }

            if (pathRequested) {
                for (int i = 0; i < path.length; i++) {
                    g.setColor(Color.GREEN);
                    g.drawRect(i, path[i], 1, 1);
                }
            }
        }
    }

    // event handler for button presses
    private class ButtonHandler implements ActionListener {
        public void actionPerformed(ActionEvent e) {   // gets called whenever an "action event" (e.g., button press) occurs
            Object src = e.getSource();
            if (src == bLoadFile)
                chooseFile();
            else if (src == bFindPath)
                findPath();
        }
    }

    private DisplayPanel    pDisplay = new DisplayPanel();
    private JButton         bLoadFile = new JButton("Load new data file"),
            bFindPath = new JButton("Find a path");
    private JLabel          lStatus = new JLabel("Use the Load button to open a data file");
    private boolean         dataLoaded = false,     // has the user loaded map data yet?
            pathRequested = false; // has the user requested a path yet?

    // constructor - handles GUI construction tasks
    public ElevationVisualizer() {
        ButtonHandler bh = new ButtonHandler(); // register event handler for buttons
        bLoadFile.addActionListener(bh);
        bFindPath.addActionListener(bh);

        JPanel cp = new JPanel();       // content pane
        cp.setLayout(new BorderLayout());

        JPanel bp = new JPanel();       // panel to hold load/path buttons
        bp.setLayout(new GridLayout(1, 2));
        bp.add(bLoadFile);
        bp.add(bFindPath);

        cp.add(BorderLayout.NORTH, lStatus);
        cp.add(BorderLayout.CENTER, pDisplay);
        cp.add(BorderLayout.SOUTH, bp);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setTitle("Elevation Data Visualizer");
        setContentPane(cp);
        setSize(600, 600);
        setVisible(true);
    }

    private void chooseFile() {
        JFileChooser fc = new JFileChooser();
        fc.setCurrentDirectory(new File("."));
        int returnVal = fc.showOpenDialog(this);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File f = fc.getSelectedFile();
            try {
                pDisplay.setData(readElevationData(f));
                dataLoaded = true;
                pathRequested = false;
                repaint();      // triggers the paintComponent method to be called
                lStatus.setText(f.getName() + " successfully opened!");
            } catch (FileNotFoundException e) {
                lStatus.setText("Can't find " + f.getName());
            } catch (ArrayIndexOutOfBoundsException e) {
                lStatus.setText(f.getName() + " seems to have inconsistent rows and columns");
            } catch (NumberFormatException e) {
                lStatus.setText(f.getName() + " seems to contain non-integer data");
            }
        }
    }

    // **** COMPLETE THIS METHOD ****
    // reads elevation data from the specified file into a 2-D array

    private int[][] readElevationData(File f) throws FileNotFoundException, ArrayIndexOutOfBoundsException, NumberFormatException {
        //get number of lines so we know how many rows to initialize
        Scanner reader = new Scanner(f);
        int lineCount = 1; //init at 1 because we're stealing first line when counting columns
        int colCount = reader.nextLine().split("\s{3}").length - 1; //first element is empty string, so length - 1 gives true count
        while (reader.hasNextLine())
        {
            lineCount++;
            reader.nextLine();
        }
        int[][] out = new int[lineCount][colCount];
        String[] line = new String[colCount];
        reader = new Scanner(f);
        for (int i = 0; i < lineCount; i++)
        {
            line = reader.nextLine().split("\s{3}");
            //loop to line.length-1 instead of colCount, this will allow for a row with too many columns to pass through
            //but it will be caught by chooseFile
            for (int j = 0; j < line.length-1; j++)
            {
                //j + 1 because line will contain the first element with an empty string, this evens it out
                out[i][j] = Integer.parseInt(line[j+1]);
            }
        }
        return out;
    }

    private void findPath() {
        if (!dataLoaded)
            lStatus.setText("Can't find path yet, must load a data file first!");
        else {
            pDisplay.setPath(findPath(pDisplay.data));
            pathRequested = true;
            repaint();      // triggers the paintComponent method to be called
            lStatus.setText("West-east path computed!");
        }
    }

    // **** COMPLETE THIS METHOD ****
    // finds and returns a west-east path through the area whose elevation is stored in data
    private int[] findPath(int[][] data) {
        //we can assume all rows have the same columns by this point
        int[] path = new int[data[0].length];

        //init location var with starting point
        int loc = indexOfMinFromCol(data, 0);
        int here, up, down, right;
        //init first path position, loop won't do it
        path[0] = loc;
        for (int i = 1; i < data.length; i++)
        {
            here = data[loc][i-1];
            //give each direction a -1 if it doesn't exist it won't be chosen later
            //don't consider up if we're at the top
            if (loc - 1 >= 0)
                up = Math.abs(here - data[loc-1][i]);
            else
                up = -1;
            //don't consider down if we're at the bottom
            if (loc + 1 <= data.length)
                down = Math.abs(here - data[loc+1][i]);
            else
                down = -1;
            //right is OK
            right = Math.abs(here - data[loc][i]);

            //look for smallest number, starting with up
            if (up > right && right != -1)// right beats up
            {
                if (right > down && down != -1) //down wins
                {
                    loc++;
                }
                else //right wins
                {
                    //do nothing, next spot will be in same row
                }
            } else if (up > down && down != -1) //down wins (again)
            {
                loc++;
            } else { //up wins
                loc--;
            }
            path[i] = loc;
        }
        return path;
    }

    // **** COMPLETE THIS METHOD ****
    // finds and returns the max element from the array a
    public static int findMax(int[][] a) {
        int max = 0;
        for (int i = 0; i < a.length; i++)
        {
            for (int j = 0; j < a[i].length; j++)
            {
                if (a[i][j] > max)
                    max = a[i][j];
            }

        }
        return max;
    }

    // **** COMPLETE THIS METHOD ****
    // finds and returns the index of the min element from column c of the array a
    public static int indexOfMinFromCol(int[][] a, int c) {
        int minIndex = 0;
        int minValue = a[0][c]; //grab first value from column for init
        for (int i = 1; i < a.length; i++)
        {
            if (a[i][c] < minValue)
            {
                minValue = a[i][c];
                minIndex = i;
            }
        }
        return minIndex;
    }

    public static void main(String[] args) {
        new ElevationVisualizer();
    }
}