2015 FRQ by Paaras Purohit - Question 2
Completing the 2015 AP Computer Science A free-response questions and taking notes - Question 2
Question 2
Type: Classes, Array/ArrayList
Directions: SHOW ALL YOUR WORK. REMEMBER THAT PROGRAM SEGMENTS ARE TO BE WRITTEN IN JAVA.
Notes:
- Assume that the classes listed in the Java Quick Reference have been imported where appropriate.
- Unless otherwise noted in the question, assume that parameters in method calls are not null and that methods are called only when their preconditions are satisfied.
- In writing solutions for each question, you may use any of the accessible methods that are listed in classes defined in that question. Writing significant amounts of code that can be replaced by a call to one of these methods will not receive full credit.
Consider a guessing game in which a player tries to guess a hidden word. The hidden word contains only capital letters and has a length known to the player. A guess contains only capital letters and has the same length as the hidden word.
After a guess is made, the player is given a hint that is based on a comparison between the hidden word and the guess. Each position in the hint contains a character that corresponds to the letter in the same position in the guess. The following rules determine the characters that appear in the hint.
The HiddenWord class will be used to represent the hidden word in the game. The hidden word is passed to the constructor. The class contains a method, getHint, that takes a guess and produces a hint.
For example, suppose the variable puzzle is declared as follows.
HiddenWord puzzle = new HiddenWord(“HARPS”);
The following table shows several guesses and the hints that would be produced.
Write the complete HiddenWord class, including any necessary instance variables, its constructor, and the method, getHint, described above. You may assume that the length of the guess is the same as the length of the hidden word.
Skills I’m Familiar With:
- Input and output
- Treating strings as lists
- Comparing elements between more than one list
Skills I’m Unfamiliar With:
- Checking if an element exists in an array efficiently
- Adding an element to a primitive list
Questions I Have:
- May I write more methods than are required? For example, if I must write a method to swap variables if I was dealing with sorting, would I be allowed to, regardless of credit?
- When the instructions say to write the “complete” class, am I also to write the main method to test the code? Or is it assumed that CollegeBoard has their own class to test the class I wrote?
- Can I use methods such as toCharArray()? Although they are not in the Java Quick Reference, they are built-in Java methods.
My Solution (Without Research)
public class HiddenWord {
public String hiddenWord;
public HiddenWord(String _hiddenWord) {
hiddenWord = _hiddenWord;
}
public boolean letterExistsInBoth(char guess, String hidden) {
for (int i = 0; i < hidden.length; i++) {
if (guess == hidden[i]) {
return true;
}
}
return false;
}
public String getHint(String guess) {
String hint = "";
for (int i = 0; i < hiddenWord.length, i++) {
if (guess[i] == hiddenWord[i]) {
hint.add(guess[i]); // I do not know the correct Java syntax for adding an element to a list
}
else if (letterExistsInBoth(guess[i], hiddenWord)) {
hint.add("+"); // I do not know the correct Java syntax for adding an element to a list
}
else {
hint.add("*"); // I do not know the correct Java syntax for adding an element to a list
}
}
return hint;
}
}
My Solution (With Research)
public class HiddenWord {
public String hiddenWord;
public HiddenWord(String _hiddenWord) {
hiddenWord = _hiddenWord;
}
// Method to check if a letter exists in both the guess and hidden word
public boolean letterExistsInBoth(char guess, String hidden) {
for (int i = 0; i < hidden.length(); i++) {
if (guess == hidden.toCharArray()[i]) {
return true;
}
}
return false;
}
public String getHint(String guess) {
ArrayList<Character> hintList = new ArrayList<>();
for (int i = 0; i < hiddenWord.length(); i++) {
if (guess.toCharArray()[i] == hiddenWord.toCharArray()[i]) {
hintList.add(guess.toCharArray()[i]);
} else if (letterExistsInBoth(guess.toCharArray()[i], hiddenWord)) {
hintList.add('+');
} else {
hintList.add('*');
}
}
// Convert the ArrayList to a char array
char[] hintArray = new char[hintList.size()];
for (int i = 0; i < hintList.size(); i++) {
hintArray[i] = hintList.get(i);
}
// Convert the char array to a String and return
return new String(hintArray);
}
}
/* KEY ALGORITHM
The key algorithm here is manipulating an ArrayList through its built-in methods, which effectively completes the understanding of the type of FRQ it is, Array/ArrayList.
*/
To Test My Code
public class Main {
public static void main(String[] args) {
// Example usage and testing for HiddenWord class
HiddenWord hiddenWordObj = new HiddenWord("HARPS");
// Testing letterExistsInBoth method
char guess1 = 'H';
char guess2 = 'P';
char guess3 = 'E';
System.out.println(guess1 + " exists in both: " + hiddenWordObj.letterExistsInBoth(guess1, hiddenWordObj.hiddenWord));
System.out.println(guess2 + " exists in both: " + hiddenWordObj.letterExistsInBoth(guess2, hiddenWordObj.hiddenWord));
System.out.println(guess3 + " exists in both: " + hiddenWordObj.letterExistsInBoth(guess3, hiddenWordObj.hiddenWord));
// Testing getHint method
String guessA = "HELLO";
String guessB = "WORLD";
String guessC = "HARPS";
System.out.println("Hint for " + guessA + ": " + hiddenWordObj.getHint(guessA));
System.out.println("Hint for " + guessB + ": " + hiddenWordObj.getHint(guessB));
System.out.println("Hint for " + guessC + ": " + hiddenWordObj.getHint(guessC));
}
}
Main.main(null);
H exists in both: true
P exists in both: true
E exists in both: false
Hint for HELLO: H****
Hint for WORLD: **R**
Hint for HARPS: HARPS
Notes:
- Although you can consider Strings as char arrays, you have to use the
toCharArray()
method to do the conversion, then treat it like a char array. - Study the code of how to convert an
ArrayList<String>
to a char array, you may need it depending on if you’re allowed to do it. - Instead of returning an initialized String variable when dealing with strings, create a new instance of String with the parameter as the char array you may have created, assuming you are dealing with a similar question.
From APCSA FRQs to Our Project
How this List algorithm relates to our in-class project
It is really hard to write good Java code without the use of List/ArrayList algorithms. That’s why whether we use them or not in our own code is out of the question, as there are too many examples to list here of the applications of these algorithms. However, one key example is found in our Employee database, where employees represent users in our project. While the employee POJO doesn’t need to use list algorithms, the controller and servicing class do. Below is a demonstration of how that works:
EmployeeController.java
package com.nighthawk.spring_portfolio.mvc.linkr;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import com.nighthawk.spring_portfolio.mvc.person.Person;
import com.nighthawk.spring_portfolio.mvc.person.PersonDetailsService;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
// Using lombok to automatically generate a logger
@Slf4j
@RestController
@RequestMapping("/api/employees") // Base URL for all endpoints in this controller
public class EmployeeController {
private final EmployeeService employeeService; // Service for employee-related operations
private final ModelMapper modelMapper; // For entity-to-DTO mapping
private final PersonDetailsService personDetailsService; // Service for managing person details
@Autowired
public EmployeeController(EmployeeService employeeService, ModelMapper modelMapper, PersonDetailsService personDetailsService) {
this.employeeService = employeeService;
this.modelMapper = modelMapper;
this.personDetailsService = personDetailsService;
}
// Endpoint to get all employees
@GetMapping
public ResponseEntity<List<EmployeeDTO>> getAllEmployees() {
// Retrieving all employees and mapping them to DTOs
List<Employee> employees = employeeService.getAllEmployees();
List<EmployeeDTO> employeeDTOs = employees.stream()
.map(employee -> modelMapper.map(employee, EmployeeDTO.class))
.collect(Collectors.toList());
return new ResponseEntity<>(employeeDTOs, HttpStatus.OK); // Returning DTO list with OK status
}
// Endpoint to get an employee by their ID
@GetMapping("/{employeeId}")
public ResponseEntity<Employee> getEmployeeById(@PathVariable Long employeeId) {
log.info("Attempting to retrieve employee with ID: {}", employeeId); // Logging the attempt
Optional<Employee> employee = employeeService.getEmployeeById(employeeId); // Retrieving employee by ID
if (employee.isPresent()) { // If employee is found
log.info("Found employee with ID: {}", employeeId); // Logging successful retrieval
return ResponseEntity.ok().body(employee.get()); // Returning employee with OK status
} else { // If employee is not found
log.warn("Employee with ID {} not found", employeeId); // Logging warning for not found
return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); // Returning NOT_FOUND status
}
}
// Endpoint to add a new employee
@PostMapping
public ResponseEntity<Employee> addEmployee(@RequestBody Employee employee) {
log.info("Attempting to add employee: {}", employee); // Logging the attempt
Employee addedEmployee = employeeService.createEmployee(employee); // Creating the employee
log.info("Employee added successfully: {}", addedEmployee); // Logging successful addition
// Creating a Person object and saving person details
Person p6 = new Person();
p6.setName("No Name");
p6.setEmail(employee.getEmail());
p6.setPassword(employee.getPassword());
try {
Date d = new SimpleDateFormat("MM-dd-yyyy").parse("05-15-2007");
p6.setDob(d);
} catch (Exception e) {
}
personDetailsService.save(p6); // Saving person details
System.out.println("Hello"); // Printing a message
return new ResponseEntity<>(addedEmployee, HttpStatus.CREATED); // Returning the added employee with CREATED status
}
// Endpoint to delete an employee by their ID
@DeleteMapping("/{employeeId}")
public ResponseEntity<Void> deleteEmployee(@PathVariable Long employeeId) {
log.info("Attempting to delete employee with ID: {}", employeeId); // Logging the attempt
employeeService.deleteEmployee(employeeId); // Deleting the employee
log.info("Employee with ID {} deleted successfully", employeeId); // Logging successful deletion
return ResponseEntity.noContent().build(); // Returning NO_CONTENT status
}
}
EmployeeRepository.java
package com.nighthawk.spring_portfolio.mvc.linkr;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@Service
public class EmployeeService {
private final EmployeeRepository employeeRepository;
@Autowired
public EmployeeService(EmployeeRepository employeeRepository) {
this.employeeRepository = employeeRepository;
}
// Method to retrieve all employees
public List<Employee> getAllEmployees() {
return employeeRepository.findAll();
}
// Method to retrieve an employee by their ID
public Optional<Employee> getEmployeeById(Long employeeId) {
return employeeRepository.findById(employeeId);
}
// Method to create a new employee
public Employee createEmployee(Employee employee) {
// If the employee ID is not provided, generate a new ID
if(employee.getId() == null){
employee.setId(generateNextId());
}
return employeeRepository.save(employee); // Save the employee and return it
}
// Method to delete an employee by their ID
public void deleteEmployee(Long employeeId) {
employeeRepository.deleteById(employeeId);
}
// Method to load user by username (email) for authentication purposes
public Employee loadUserByUsername(String email) throws UsernameNotFoundException {
Employee person = employeeRepository.findByEmail(email); // Retrieve user by email from the database
if(person==null) { // If user is not found
throw new UsernameNotFoundException("User not found with username: " + email); // Throw exception
}
// make sure it recognizes User and Authorities
return new Employee(null, null, person.getEmail(), person.getPassword());
}
// Method to generate the next ID for a new employee
private Long generateNextId() {
// Generate the next ID by retrieving the maximum ID and incrementing it
return employeeRepository.getMaxId() + 1;
}
}
As you can see in the code, the lists in each class are being manipulated with the same algorithmic conceptual thinking as in the FRQ, proving the connection between the FRQ and our project.