• From APCSA FRQs to Our Project
  • 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.