AP CSA Exam Format
Section I: Multiple Choice
40 Questions | 1 Hour 30 Minutes | 50% of Exam Score
The multiple-choice section includes mostly individual questions, occasionally with 1–2 sets of questions (2 questions per set). Computational Thinking Practices 1, 2, 4, and 5 are all assessed in the multiple-choice section.
Section II: Free Response
4 Questions | 1 Hour 30 Minutes | 50% of Exam Score
All free-response questions assess Computational Thinking Practice 3: Code Implementation, with the following focus:
- Question 1: Methods and Control Structures—Students will be asked to write program code to create objects of a class and call methods, and satisfy method specifications using expressions, conditional statements, and iterative statements.
- Question 2: Classes—Students will be asked to write program code to define a new type by creating a class and satisfy method specifications using expressions, conditional statements, and iterative statements.
- Question 3: Array/ArrayList—Students will be asked to write program code to satisfy method specifications using expressions, conditional statements, and iterative statements and create, traverse, and manipulate elements in 1D array or ArrayList objects.
- Question 4: 2D Array—Students will be asked to write program code to satisfy method specifications using expressions, conditional statements, and iterative statements and create, traverse, and manipulate elements in 2D array objects.
Question 4 - 2D Array
- From the 2023 FRQ Question 4: Click Here
PART A
moveCandyToFirstRow is a method that moves a piece of candy to the first row of a 2D box (grid/table with rows and columns) of candies. *Write the purpose:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// method that belongs to BoxOfCandy class, move candy to first row of 2d box (2d array)
// takes parameter specified column number col
public boolean moveCandyToFirstRow(int col)
{
// check if element at row 0 (first row) and specified col already has candy - CB CRITERIA
if(box[0][col] != null)
{
// if there is candy, no need to move anything
return true;
}
// iterate through remaining rows and cols - CB CRITERIA
// start from row 1 (second row)
for(int row = 1; row < box.length; row++)
{
// check if current row and col has candy - CB CRITERIA
if(box[row][col] != null)
{
// if there is candy
// move candy to row 0 and specified col - CB CRITERIA
box[0][col] = box[row][col];
// set prev location of candy to null (remove it from og position) - CB CRITERIA
box[row][col] = null;
// return true to indicate move success
return true;
}
}
// no candy found in specified col
// return false to indicate move unsuccess
return false;
}
Here are some key learning points:
- Conditional checking: checks if there is already candy in first row and specified column. If there is, then no changes are made.
- Iterative process: Iterates through rows of 2D candy box, using for loop
- Moving+removing/manipulate elements in array: When candy found, it’s moved to the first row and the specified column, and removed from the original position. This demonstrates data manipulation in an array.
- Return values: Method returns true if successfully moves candy and false if it doesn’t, indicating success or failure of an operation with return values
Collegeboard Criteria and Grading: 4/4
- Accesses all needed elements of col of box (NO BOUND ERRORS-> trying to access element outside the bound of the array cause errors)
- Compare candy box element (row 0 and specified col) to null, must use != or equivalent
- Move identified candy to first row if necessary and replaced the moved candy with null
- Return true when non-empty square identified (candy already in row 0 and specified col) and false if non-empty square not identified in loop (candy never found in specified col)
PART B
removeNextByFlavor is a method that removes and returns the next piece of candy with a specific flavor from a 2D box (grid/table with rows and columns) of candies.
class="highlight">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// method that belongs to BoxOfCandy class, remove candy with specified flavor
// takes parameter specified flavor
public Candy removeNextByFlavor(String flavor)
{
// nested loops to traverse candy box starting from last row, moving up
// traverse - visit each element in array - CB CRITERIA
for(int row = box.length - 1; row >= 0; row--)
{
for(int col = 0; col < box[0].length; col++)
{
// check if current box element has candy AND if flavor matches specified flavor- CB CRITERIA
// call getFlavor on Candy object to check flavor - CB CRITERIA
if(box[row][col] != null &&
box[row][col].getFlavor().equals(flavor))
{
// store selected candy
Candy selected = box[row][col];
// remove candy from box by set box element to null - CB CRITERIA
box[row][col] = null;
// return the removed selected candy
return selected;
}
}
}
// no candy with specified flavor found
// return false to indicate flavor search unsuccess
return null;
}
Here are some key learning points:
- Nested loops: uses to traverse the 2D candy box, visiting each element in a multi-dimensional array
- Conditional checking: within loops, checks if candy in current box element matches the specified flavor, filitering and selecting specific elements in a data structure
- Return values: Indicates result if selected candy is found or not found, same indication (success/failure) as above
Collegeboard Criteria and Grading: 5/5
- traverse box in specified order with no bound errors (bottom to top (row–) and left to right (col++))
- guard against method call on null element of candy box (result in NullPointerExceptions), must use != or equivalent
- call getFlavor on Candy object
- Compare candy object flavor with flavor parameter
- Replace candy object with null and return the candy
class="highlight">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import java.util.Scanner;
// This question involves pieces of candy in a box. The Candy class represents a single piece of candy.
class Candy {
String flavor; // class member
// constructor for default flavor (for when no input flavor yet)
public Candy() {
flavor = "empty";
}
// constructor for input flavor
public Candy(String inputflavor) {
flavor = inputflavor;
}
// initialize flavor with specified input flavor
void setFlavor(String inputflavor) {
flavor = inputflavor;
}
public String getFlavor() {
return flavor;
}
}
public class BoxOfCandy {
private Candy[][] box;
Scanner input = new Scanner(System.in); // scanner for user input
// allocate/assign memory
public BoxOfCandy(int row, int col) {
box = new Candy[row][];
for (int j = 0; j<row; j++) {
box[j] = new Candy[col];
}
}
// fill random places in box with random candy flavors
public void fillBoxWithRandomCandy() {
String[] possibleFlavors = {"Orange", "Lime", "Lemon"};
Random random = new Random();
for (int row = 0; row < box.length; row++) {
for (int col = 0; col < box[0].length; col++) {
// probability for how many boxes get filled (0.3 is 30% chance filled)
if (random.nextDouble() < 0.3) {
int randomIndex = random.nextInt(possibleFlavors.length);
String randomFlavor = possibleFlavors[randomIndex];
box[row][col] = new Candy(randomFlavor);
}
}
}
}
// PART A
// method, move candy to first row of 2d box (2d array)
public boolean moveCandyToFirstRow(int col) {
// check if element at row 0 (first row) and specified col already has candy
if (box[0][col] != null) {
// if there is candy, no need to move anything
return true;
}
// iterate through remaining rows and cols
// start from row 1 (second row)
for (int row = 1; row < box.length; row++) {
// check if current row and col has candy
if (box[row][col] != null) {
// if there is candy
// move candy to row 0 and specified col
box[0][col] = box[row][col];
// set prev location of candy to null (remove it from og position)
box[row][col] = null;
// return true to indicate move success
return true;
}
}
// no candy found in specified col
// return false to indicate move unsuccess
return false;
}
// PART B
// method that removes specific candy by flavor
public Candy removeNextByFlavor(String flavor) {
// traverse candy box starting from last row, moving up
// traverse - visit each element in array
for (int row = box.length - 1; row >= 0; row--) {
for (int col = 0; col < box[0].length; col++) {
// check if current box element has candy AND if flavor matches specified flavor
if (box[row][col] != null &&
box[row][col].getFlavor().equals(flavor)) {
// store selected candy
Candy selected = box[row][col];
// remove candy from box by set box element to null
box[row][col] = null;
// return the removed selected candy
return selected;
}
}
}
// no candy with specified flavor found
// return false to indicate flavor search unsuccess
return null;
}
// Main method for testing
public static void main(String[] args) {
BoxOfCandy candyBox = new BoxOfCandy(5, 5); // initiating object candyBox, 5 by 5 box of candy
// fill box with candy flavors
candyBox.fillBoxWithRandomCandy();
// Get user input for specified column and move candy to the first row
// make sure input is valid so no bound errors - *TODO
System.out.print("Enter the column index(0-4): ");
int col = candyBox.input.nextInt();
boolean moveSuccess = candyBox.moveCandyToFirstRow(col);
System.out.println(col);
if (moveSuccess) {
System.out.println("Candy moved successfully to the first row.");
} else {
System.out.println("No candy found in the specified column.");
}
// PART B
// Get user input and remove candy by flavor
System.out.print("\nEnter the flavor of candy to remove: ");
String flavor = candyBox.input.next();
Candy removeSuccess = candyBox.removeNextByFlavor(flavor);
System.out.println(flavor);
if (removeSuccess!=null) {
System.out.println("Removed candy with flavor sucessfully.");
} else {
System.out.println("No candy with the specified flavor found.");
}
}
}
BoxOfCandy.main(null)
class="highlight">1
2
3
4
5
Enter the column index(0-4): 2
Candy moved successfully to the first row.
Enter the flavor of candy to remove: Orange
Removed candy with flavor sucessfully.
*Did extra for running code:
- Part B: Previously, my constructor sets all the candies flavor as “emtpy” automatically to indicate a spot with no candy. This means there’s no specified flavor and it will never choose out a desired flavored candy. So, I created a method “fillBoxWithRandomCandy”. After creating an instance of “BoxOfCandy”, I can call this method to randomly fill the box with some flavors of candies after and leave some boxes empty to simulate a candy box that isn’t completely full and has random flavors of candy.
*TODO - Things to improve with overall program:
- Part A: When the user enters the specified column, they have a chance of entering a number that is too large, which will result in a bound error, or something other than an integer, and the program will crash. I could do error checking with an if statement to make sure their input is valid. I could do the same with the flavor in Part B, but an “invalid” input wouldn’t crash the program so it isn’t as critcal of an error.
A new version of content is available.