A grayscale image is represented by a 2-dimensional rectangular array of pixels (picture elements). A pixel is an integer value that represents a shade of gray. In this question, pixel values can be in the range from 0 through 255, inclusive. A black pixel is represented by 0, and a white pixel is represented by 255.
The declaration of the GrayImage
class is shown below. You will write two unrelated methods of the
GrayImage
class.
public class GrayImage{
public static final int BLACK = 0;
public static final int WHITE = 255;
/** The 2-dimensional representation of this image. Guaranteed not to be null.
* All values in the array are within the range [BLACK, WHITE], inclusive.
*/
private int[][] pixelValues;
/** @return the total number of white pixels in this image.
* Postcondition: this image has not been changed.
*/
public int countWhitePixels()
{ /* to be implemented in part (a) */ }
/** Processes this image in row-major order and decreases the value of each pixel at
* position (row, col) by the value of the pixel at position (row + 2, col + 2) if it exists.
* Resulting values that would be less than BLACK are replaced by BLACK.
* Pixels for which there is no pixel at position (row + 2, col + 2) are unchanged.
*/
public void processImage()
{ /* to be implemented in part (b) */ }
}
(a) Write the method countWhitePixels that returns the number of pixels in the image that contain the value WHITE. For example, assume that pixelValues contains the following image.
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 255 | 184 | 178 | 84 | 129 |
1 | 84 | 255 | 255 | 130 | 84 |
2 | 78 | 255 | 0 | 0 | 78 |
3 | 84 | 130 | 255 | 130 | 84 |
A call to countWhitePixels method would return 5 because there are 5 entries that have the value WHITE.
Write the method processImage
that modifies the image by changing the values in the instance variable pixelValues
according to the following description. The pixels in the image are processed one at a time in row-major order. Row-major order processes the first row in the array from left to right and then processes the second row from left to right, continuing until all rows are processed from left to right. The first index of pixelValues
represents the row number, and the second index represents the column number.
The pixel value at position (row, col) is decreased by the value at position (row + 2, col + 2) if such a position exists. If the result of the subtraction is less than the value BLACK
, the pixel is assigned the value of BLACK
. The values of the pixels for which there is no pixel at position (row + 2, col + 2) remain unchanged. You may assume that all the original values in the array are within the range [BLACK, WHITE]
, inclusive.
The following diagram shows the contents of the instance variable pixelValues
before and after a call to processImage
. The values shown in boldface represent the pixels that could be modified in a grayscale image with 4 rows and 5 columns.
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 221 | 184 | 178 | 84 | 135 |
1 | 84 | 255 | 255 | 130 | 84 |
2 | 78 | 255 | 0 | 0 | 78 |
3 | 84 | 130 | 255 | 130 | 84 |
0 | 1 | 2 | 3 | 4 | |
---|---|---|---|---|---|
0 | 221 | 184 | 100 | 84 | 129 |
1 | 0 | 125 | 171 | 130 | 84 |
2 | 78 | 255 | 0 | 0 | 78 |
3 | 84 | 130 | 255 | 130 | 84 |
public class GrayImage {
public static final int BLACK = 0;
public static final int WHITE = 255;
private int[][] pixelValues;
public GrayImage(int[][] pixelValues) {
this.pixelValues = pixelValues;
}
public int countWhitePixels() {
int whitePixelCount = 0;
for (int[] row : this.pixelValues) { // iterating through rows
for (int pv : row) {
if (pv == this.WHITE) { // if pixel is white, increment the count
whitePixelCount++;
}
}
}
return whitePixelCount;
}
public void processImage() {
// Loop through each pixel, excluding the last 2 rows and columns
for (int row = 0; row < this.pixelValues.length - 2; row++) {
for (int col = 0; col < this.pixelValues[0].length - 2; col++) {
// Subtract pixel value from the corresponding pixel 2 rows and 2 columns away
this.pixelValues[row][col] -= this.pixelValues[row + 2][col + 2];
// If the result is less than black, set it to black
if (this.pixelValues[row][col] < BLACK) {
this.pixelValues[row][col] = BLACK;
}
}
}
}
public static void main(String[] args) {
int[][] pixels = {
{255, 0, 235, 0, 218},
{17, 255, 186, 0, 255},
{255, 0, 87, 255, 0},
{0, 75, 255, 128, 255},
{255, 38, 0, 0, 206}
};
GrayImage image = new GrayImage(pixels);
System.out.println("White pixels before processing: " + image.countWhitePixels());
image.processImage();
System.out.println("White pixels after processing: " + image.countWhitePixels());
}
}
GrayImage.main(null)
White pixels before processing: 8
White pixels after processing: 6
public class Matrix {
private final int[][] matrix;
// store matrix
public Matrix(int[][] matrix) {
this.matrix = matrix;
}
// nest for loops to format output of a matrix
public String toString() {
// construct output of matrix using for loops
// outer loop for row
StringBuilder output = new StringBuilder();
for (int[] row : matrix) {
// inner loop for column
for (int cell : row) {
output.append((cell==-1) ? " " : String.format("%x",cell)).append(" ");
}
output.append("\n"); // new line
}
return output.toString();
}
// print it backwards matrix
public String reverse() {
// outer loop starting at end row
StringBuilder output = new StringBuilder();
for (int i = matrix.length; 0 < i; i--) {
// inner loop for column
for (int j = matrix[i-1].length; 0 < j; j--) {
output.append((matrix[i-1][j-1]==-1) ? " " : String.format("%x",matrix[i-1][j-1])).append(" ");
}
output.append("\n"); // new line
}
return output.toString();
}
// declare and initialize a matrix for a keypad
static int[][] keypad() {
return new int[][]{ { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, {-1, 0, -1} };
}
// declare and initialize a random length arrays
static int[][] numbers() {
return new int[][]{ { 0, 1 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } };
}
// tester method for matrix formatting
public static void main(String[] args) {
Matrix m0 = new Matrix(keypad());
System.out.println("Keypad:");
System.out.println(m0);
System.out.println(m0.reverse());
Matrix m1 = new Matrix(numbers());
System.out.println("Numbers Systems:");
System.out.println(m1);
System.out.println(m1.reverse());
}
}
Matrix.main(null);
Keypad:
1 2 3
4 5 6
7 8 9
0
0
9 8 7
6 5 4
3 2 1
Numbers Systems:
0 1
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 a b c d e f
f e d c b a 9 8 7 6 5 4 3 2 1 0
9 8 7 6 5 4 3 2 1 0
1 0
toString()
Method:
public String toString() {
StringBuilder output = new StringBuilder();
for (int[] row : matrix) {
for (int cell : row) {
output.append((cell == -1) ? " " : String.format("%x", cell)).append(" ");
}
output.append("\n");
}
return output.toString();
}
for
loops to iterate over each cell in the matrix.-1
) and appends it to the output
StringBuilder
.reverse()
Method:
public String reverse() {
StringBuilder output = new StringBuilder();
for (int i = matrix.length; 0 < i; i--) {
for (int j = matrix[i - 1].length; 0 < j; j--) {
output.append((matrix[i - 1][j - 1] == -1) ? " " : String.format("%x", matrix[i - 1][j - 1])).append(" ");
}
output.append("\n");
}
return output.toString();
}
for
loops.toString()
, it formats each cell’s value and appends it to the output
StringBuilder
.static int[][] keypad() {
return new int[][]{
{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {-1, 0, -1}
};
}
static int[][] numbers() {
return new int[][]{
{0, 1}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}, {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
};
}
Array.length
is the length method, not Array.length()
(however this is not deducted on the test)arr[i]
and arr.get(i)
These can be hard to spot, but below is an example:
import java.util.ArrayList;
import java.util.List;
public class ConcurrentModificationExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
// Add some elements to the list
numbers.add(1);
numbers.add(2);
numbers.add(3);
// Iterate over the list and try to remove an element within the loop
for (Integer number : numbers) {
System.out.println(number);
// Concurrent modification
numbers.remove(number);
}
}
}
ConcurrentModificationExample.main();
For Methods & Control Structures questions, here are the steps we recommend:
For M&CT questions that involve 2D Arrays, here are the steps we recommend:
Iteration over a 2D array involves traversing through the array’s elements, which are arranged in rows and columns, similar to a matrix. In Java, a 2D array is an array of arrays. To iterate over a 2D array, you typically use nested loops: the outer loop iterates over each row (array), and the inner loop iterates over each element (column) within that row.
Example Scenario: Iterating over a 2D array is particularly useful in scenarios involving grid-like data structures, such as game boards (chess, tic-tac-toe), pixel matrices in images, and in your case, tracking player scores across different levels and attempts in a game. For instance, in a tic-tac-toe game, a 2D array can represent the game board where each cell holds a value indicating an empty spot, a “X”, or a “O”. Iterating over this array allows the program to check for win conditions, draw the board, or update it.
calculateTotalScore
MethodBelow is the implementation of the calculateTotalScore
method. This method takes a 2D array of integers as input, representing player scores across different levels and attempts. It returns the sum of all scores by iterating through each element in the 2D array.
public class GameScoreTracker {
/**
* Calculates the total score from a 2D array of player scores.
* @param scores A 2D array where each row represents a level and each column represents an attempt.
* @return The sum of all scores in the array.
*/
public static int calculateTotalScore(int[][] scores) {
int totalScore = 0; // Initialize total score to 0.
// Outer loop to iterate through each level (row).
for (int level = 0; level < scores.length; level++) {
// Inner loop to iterate through each attempt (column) in the current level.
for (int attempt = 0; attempt < scores[level].length; attempt++) {
// Add the score of the current attempt to the total score.
totalScore += scores[level][attempt];
}
}
// Return the total score after iterating through all levels and attempts.
return totalScore;
}
// Example usage
public static void main(String[] args) {
int[][] playerScores = {
{10, 20, 15}, // Scores from level 1
{25, 30, 20}, // Scores from level 2
{5, 7, 10} // Scores from level 3
};
int total = calculateTotalScore(playerScores);
System.out.println("Total Score: " + total);
}
}
GameScoreTracker.main(null);
Total Score: 142
Explanation:
calculateTotalScore
method is defined with one parameter, scores
, which is a 2D array of integers.totalScore
to 0 to start accumulating the scores from the array.totalScore
.totalScore
holds the sum of all elements in the 2D array, which is then returned.