hw2: functionality completed (I think)

This commit is contained in:
Yuri Tatishchev 2025-02-23 23:35:58 -08:00
parent ff2c9489bb
commit 1e55218f47
Signed by: CaZzzer
GPG Key ID: E0EBF441EA424369
5 changed files with 479 additions and 10 deletions

2
hw2/CL34 Normal file
View File

@ -0,0 +1,2 @@
143,caz
191,caz

2
hw2/Users Normal file
View File

@ -0,0 +1,2 @@
admin,ADMIN,YWRtaW4=,YWRtaW4=
caz,PUBLIC,WXVyaSBU,aGVsbG8=

View File

@ -1,3 +1,9 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.*;
import java.util.stream.Stream;
/**
* In this assignment, you will design and implement an airplane seat reservation system.
* <p>
@ -93,12 +99,361 @@
* E[X]it: All reservations and registered users saved in the data structures will be persisted to CL34 and Users files, respectively. Only valid reservations, without cancelled ones, should be saved. You are free to choose the format of the data in these files.
*/
/**
* Q: does the admin sign in with a password?
* Q: are the user ids numeric or usernames?
*/
public class ReservationSystem {
private static final Scanner stdin = new Scanner(System.in);
private static final String ADMIN_USERNAME = "admin";
private static final String ADMIN_PASSWORD = "admin";
private static Map<String, User> users = new HashMap<>();
private static ArrayList<String> seatReservations = new ArrayList<>(Stream.generate(() -> (String) null).limit(Seat.TOTAL_SEATS).toList());
public static void main(String[] args) {
User user = new User(1, User.Type.ADMIN, "admin", "adm,in");
System.out.println(user.getType());
System.out.println(user.toCsvString());
User user2 = User.fromCsvString(user.toCsvString());
System.out.println(user2.toCsvString());
if (args.length != 2) {
System.out.println("Usage: java ReservationSystem <reservationFilename> <userFilename>");
return;
}
loadFiles(args[0], args[1]);
System.out.println(users.get(ADMIN_USERNAME).toCsvString());
userSelectionMenu();
saveFiles(args[0], args[1]);
}
private static void userSelectionMenu() {
String input = "";
while (!input.equals("A")) {
System.out.println(String.join(";\t ",
"User:\t [A]dministrator",
"[P]ublic User"
));
input = stdin.nextLine().toUpperCase();
switch (input) {
case "A" -> adminMenu(authenticateAdmin());
case "P" -> publicUserMenu(authenticatePublicUser());
default -> System.out.println("Invalid input");
}
}
}
private static User authenticateAdmin() {
System.out.print("Enter admin user id: ");
String username = stdin.nextLine();
System.out.print("Enter admin password: ");
String password = stdin.nextLine();
final User user = users.get(username);
if (user == null || !user.isAdmin() || !user.checkPassword(password)) {
System.out.println("Invalid user id or password");
return authenticateAdmin();
}
return users.get(username);
}
private static User authenticatePublicUser() {
System.out.println(String.join(";\t ",
"[S]ign up",
"[L]og in"
));
String input = stdin.nextLine().toUpperCase();
switch (input) {
case "S" -> {
System.out.print("Enter user id: ");
// can't have commas in a csv because I'm too lazy to do escaping
String id = stdin.nextLine().replace(",", "");
System.out.print("Enter name: ");
String name = stdin.nextLine();
System.out.print("Enter password: ");
String password = stdin.nextLine();
User user = new User(id, User.Type.PUBLIC, name, password);
users.put(id, user);
return user;
}
case "L" -> {
System.out.print("Enter user id: ");
String id = stdin.nextLine();
System.out.print("Enter user password: ");
String password = stdin.nextLine();
final User user = users.get(id);
if (user == null || user.isAdmin() || !user.checkPassword(password)) {
System.out.println("Invalid user id or password");
return authenticatePublicUser();
}
return users.get(id);
}
default -> {
System.out.println("Invalid input");
return authenticatePublicUser();
}
}
}
private static void adminMenu(User user) {
String input = "";
while (true) {
System.out.println(String.join(";\t ",
"Show [M]anifest list",
"E[X]it"
));
input = stdin.nextLine().toUpperCase();
switch (input) {
case "M" -> showManifestList();
case "X" -> {
return;
}
default -> System.out.println("Invalid input");
}
}
}
private static void publicUserMenu(User user) {
String input = "";
while (true) {
System.out.println(String.join(";\t ",
"Check [A]vailability",
"Make [R]eservation",
"[C]ancel Reservation",
"[V]iew Reservations",
"[D]one"
));
input = stdin.nextLine().toUpperCase();
switch (input) {
case "A" -> checkAvailability();
case "R" -> makeReservation(user);
case "C" -> cancelReservation(user);
case "V" -> viewReservations(user);
case "D" -> {
return;
}
default -> System.out.println("Invalid input");
}
}
}
private static void showManifestList() {
System.out.println("First");
for (int seat = 0; seat < Seat.FIRST_CLASS_SEATS; seat++) {
if (seatReservations.get(seat) != null) printManifestReservation(seat);
}
System.out.println("\nEconomy Plus");
for (int seat = Seat.FIRST_CLASS_SEATS; seat < Seat.FIRST_CLASS_SEATS + Seat.ECONOMY_PLUS_SEATS; seat++) {
if (seatReservations.get(seat) != null) printManifestReservation(seat);
}
System.out.println("\nEconomy");
for (int seat = Seat.FIRST_CLASS_SEATS + Seat.ECONOMY_PLUS_SEATS; seat < Seat.TOTAL_SEATS; seat++) {
if (seatReservations.get(seat) != null) printManifestReservation(seat);
}
}
private static void printManifestReservation(Integer seat) {
User user = users.get(seatReservations.get(seat));
System.out.printf("%d%c: %s%n", Seat.getSeatRow(seat), Seat.getSeatColumn(seat), user.getName());
}
private static void checkAvailability() {
System.out.println("Seat Availability\n");
System.out.print("First (price: $1000/seat)");
for (int seat = 0; seat < Seat.FIRST_CLASS_SEATS; seat++) {
if (seat % Seat.ROW_SIZE == 0) {
System.out.println();
System.out.print(Seat.getSeatRow(seat) + ": ");
}
if (seatReservations.get(seat) == null) {
System.out.print(Seat.getSeatColumn(seat) + ", ");
}
}
System.out.print("\n\nEconomy Plus (price: $500/seat)");
for (int seat = Seat.FIRST_CLASS_SEATS; seat < Seat.FIRST_CLASS_SEATS + Seat.ECONOMY_PLUS_SEATS; seat++) {
if (seat % Seat.ROW_SIZE == 0) {
System.out.println();
System.out.print(Seat.getSeatRow(seat) + ": ");
}
if (seatReservations.get(seat) == null) {
System.out.print(Seat.getSeatColumn(seat) + ", ");
}
}
System.out.print("\n\nEconomy (price: $250/seat)");
for (int seat = Seat.FIRST_CLASS_SEATS + Seat.ECONOMY_PLUS_SEATS; seat < Seat.TOTAL_SEATS; seat++) {
if (seat % Seat.ROW_SIZE == 0) {
System.out.println();
System.out.print(Seat.getSeatRow(seat) + ": ");
}
if (seatReservations.get(seat) == null) {
System.out.print(Seat.getSeatColumn(seat) + ", ");
}
}
System.out.print("\n\n");
}
/**
* Make [R]eservation: With this option, the user can make multiple reservations but one seat at a time. The user enters the seat number consisting of a number and a letter (e.g., 1K for a first-class seat). If the seat number is not valid (specifically, not an existing seat number in the plane), the system asks for another one until the user enters a valid one. If the seat is not available, the system prompts an error and asks for another seat. If the seat is available, the system prompts the seat number, the type of service corresponding to this seat, and the price, and asks for the user's confirmation. If the user confirms the reservation, the seat will be reserved. If not, the reservation request will be void. The system asks if the user wants to make another one or not and proceeds with the user's request.
* @param user
*/
private static void makeReservation(User user) {
System.out.print("Enter seat number: ");
String seat = stdin.nextLine().toUpperCase();
try {
int seatNumber = Seat.getSeatNumber(seat);
if (seatReservations.get(seatNumber) != null) {
System.out.println("Seat is already reserved");
makeReservation(user);
return;
}
System.out.printf("Seat: %s\n", seat);
System.out.printf("Service: %s, $%d\n", Seat.getServiceClass(seatNumber), Seat.getSeatPrice(seatNumber));
System.out.println("Confirm reservation? [Y/N]");
String confirm = stdin.nextLine().toUpperCase();
while (!confirm.equals("Y") && !confirm.equals("N")) {
System.out.println("Invalid input");
System.out.println("Confirm reservation? [Y/N]");
confirm = stdin.nextLine().toUpperCase();
}
switch (confirm) {
case "Y" -> {
seatReservations.set(seatNumber, user.getId());
System.out.println("Reservation confirmed");
}
case "N" -> System.out.println("Reservation cancelled");
}
System.out.println("Make another reservation? [Y/N]");
String another = stdin.nextLine().toUpperCase();
while (!another.equals("Y") && !another.equals("N")) {
System.out.println("Invalid input");
System.out.println("Make another reservation? [Y/N]");
another = stdin.nextLine().toUpperCase();
}
if (another.equals("Y")) {
makeReservation(user);
}
} catch (IllegalArgumentException e) {
System.out.println("Invalid seat number");
makeReservation(user);
}
}
/**
* [C]ancel Reservation: With this option, the system first shows all the seats the user reserved. The user can cancel multiple seat reservations but one seat at a time. The user is supposed to enter a seat number from the list. If the user enters an unlisted number, the system asks for another one until the user enters one of the listed numbers.
* @param user
*/
private static void cancelReservation(User user) {
System.out.println("Your reservations:");
for (int seat = 0; seat < seatReservations.size(); seat++) {
if (seatReservations.get(seat) != null && seatReservations.get(seat).equals(user.getId())) {
System.out.printf("%d%c, %s, $%d\n", Seat.getSeatRow(seat), Seat.getSeatColumn(seat), Seat.getServiceClass(seat), Seat.getSeatPrice(seat));
}
}
System.out.print("Enter seat number to cancel: ");
String seat = stdin.nextLine().toUpperCase();
try {
int seatNumber = Seat.getSeatNumber(seat);
if (seatReservations.get(seatNumber) == null || !seatReservations.get(seatNumber).equals(user.getId())) {
System.out.println("Seat is not reserved by you");
cancelReservation(user);
return;
}
seatReservations.set(seatNumber, null);
System.out.println("Reservation cancelled");
System.out.println("Cancel another reservation? [Y/N]");
String another = stdin.nextLine().toUpperCase();
while (!another.equals("Y") && !another.equals("N")) {
System.out.println("Invalid input");
System.out.println("Cancel another reservation? [Y/N]");
another = stdin.nextLine().toUpperCase();
}
if (another.equals("Y")) {
cancelReservation(user);
}
} catch (IllegalArgumentException e) {
System.out.println("Invalid seat number");
cancelReservation(user);
}
}
/**
* [V]iew Reservations: It shows all reservations made by the current transaction. It doesn't show any cancelled reservation. The following format is suggested:
* <p>
* Name: Bill Smith
* Seats: 2I $1000, 17J $500, 42k $250
* Total Balance Due: $1750
* @param user
*/
private static void viewReservations(User user) {
System.out.printf("Name: %s\n Seats:", user.getName());
int totalBalanceDue = 0;
for (int seat = 0; seat < seatReservations.size(); seat++) {
if (seatReservations.get(seat) != null && seatReservations.get(seat).equals(user.getId())) {
System.out.printf("%d%c $%d, ", Seat.getSeatRow(seat), Seat.getSeatColumn(seat), Seat.getSeatPrice(seat));
totalBalanceDue += Seat.getSeatPrice(seat);
}
}
System.out.printf("\nTotal Balance Due: $%d\n", totalBalanceDue);
}
private static void loadFiles(String reservationFilename, String userFilename) {
// check if files exist
File reservationFile = new File(reservationFilename);
File userFile = new File(userFilename);
if (!reservationFile.isFile() || !userFile.isFile()) {
users.put(ADMIN_USERNAME, new User(ADMIN_USERNAME, User.Type.ADMIN, ADMIN_USERNAME, ADMIN_PASSWORD));
try {
reservationFile.createNewFile();
userFile.createNewFile();
try (PrintWriter writer = new PrintWriter(userFile)) {
users.values().forEach(user -> writer.println(user.toCsvString()));
}
System.out.println(reservationFilename + " and " + userFilename + " are now created.");
System.out.println("Admin user created with username: \"" + ADMIN_USERNAME + "\" and password: \"" + ADMIN_PASSWORD + "\"");
} catch (Exception e) {
System.out.println("Error creating files");
return;
}
return;
}
// load reservations from reservationFile
try (Scanner scanner = new Scanner(new File(reservationFilename))) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
String[] parts = line.split(",");
int seatNumber = Integer.parseInt(parts[0]);
String passengerId = parts[1];
seatReservations.set(seatNumber, passengerId);
}
} catch (FileNotFoundException e) {
System.out.println(reservationFilename + " not found");
}
// load users from userFile
try (Scanner scanner = new Scanner(new File(userFilename))) {
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
User user = User.fromCsvString(line);
users.put(user.getId(), user);
}
} catch (FileNotFoundException e) {
System.out.println(userFilename + " not found");
}
System.out.println("Existing Reservations and Users are loaded.");
}
private static void saveFiles(String reservationFilename, String userFilename) {
try (PrintWriter reservationWriter = new PrintWriter(reservationFilename)) {
for (int seatNumber = 0; seatNumber < seatReservations.size(); seatNumber++) {
if (seatReservations.get(seatNumber) != null) {
reservationWriter.println(Seat.toCsvString(seatNumber, seatReservations.get(seatNumber)));
}
}
} catch (FileNotFoundException e) {
System.out.println("Error saving reservations");
}
try (PrintWriter userWriter = new PrintWriter(userFilename)) {
users.values().forEach(user -> userWriter.println(user.toCsvString()));
} catch (FileNotFoundException e) {
System.out.println("Error saving users");
}
System.out.printf("Saved reservations to %s and users to %s%n", reservationFilename, userFilename);
}
}

110
hw2/src/Seat.java Normal file
View File

@ -0,0 +1,110 @@
import java.util.Map;
public class Seat {
public static final int TOTAL_SEATS = 500;
public static final int ROW_SIZE = 10;
public static final int ROW_COUNT = TOTAL_SEATS / ROW_SIZE;
public static final int FIRST_CLASS_SEATS = 40;
public static final int ECONOMY_PLUS_SEATS = 110;
public static final int ECONOMY_SEATS = TOTAL_SEATS - FIRST_CLASS_SEATS - ECONOMY_PLUS_SEATS;
public static final int FIRST_CLASS_PRICE = 1000;
public static final int ECONOMY_PLUS_PRICE = 500;
public static final int ECONOMY_PRICE = 250;
public enum ServiceClass {
FIRST_CLASS,
ECONOMY_PLUS,
ECONOMY,
}
public static int getSeatNumber(int row, char column) {
if (row < 1 || row > ROW_COUNT || column < 'A' || column >= 'A' + ROW_SIZE) {
throw new IllegalArgumentException("Invalid seat number");
}
return (row - 1) * 10 + (column - 'A');
}
public static int getSeatNumber(String seat) {
String seatNumber = seat.substring(0, seat.length() - 1);
char seatColumn = seat.charAt(seat.length() - 1);
return getSeatNumber(Integer.parseInt(seatNumber), seatColumn);
}
public static int getSeatRow(int seatNumber) {
return (seatNumber / 10) + 1;
}
public static char getSeatColumn(int seatNumber) {
return (char) ('A' + seatNumber % 10);
}
public static String toCsvString(int seatNumber, String passengerId) {
return String.format("%d,%s", seatNumber, passengerId);
}
public static ServiceClass getServiceClass(int seatNumber) {
if (seatNumber < FIRST_CLASS_SEATS) {
return ServiceClass.FIRST_CLASS;
} else if (seatNumber < FIRST_CLASS_SEATS + ECONOMY_PLUS_SEATS) {
return ServiceClass.ECONOMY_PLUS;
}
return ServiceClass.ECONOMY;
}
public static int getSeatPrice(int seatNumber) {
switch (getServiceClass(seatNumber)) {
case FIRST_CLASS -> {
return FIRST_CLASS_PRICE;
}
case ECONOMY_PLUS -> {
return ECONOMY_PLUS_PRICE;
}
case ECONOMY -> {
return ECONOMY_PRICE;
}
}
return 0;
}
}
// public class Seat {
// private int seatNumber;
// private User passenger;
//
// public Seat(int seatNumber) {
// this.seatNumber = seatNumber;
// this.passenger = null;
// }
// public Seat(int seatNumber, User passenger) {
// this.seatNumber = seatNumber;
// this.passenger = passenger;
// }
//
// public int getSeatNumber() {
// return seatNumber;
// }
//
// public int getSeatRow() {
// return (seatNumber / 10) + 1;
// }
//
// public char getSeatColumn() {
// return (char) ('A' + seatNumber % 10);
// }
//
// public Optional<User> getPassenger() {
// return Optional.ofNullable(passenger);
// }
//
// public boolean isOccupied() {
// return passenger != null;
// }
//
// public String toCsvString() {
// if (passenger == null) {
// return String.format("%d,", seatNumber);
// }
// return String.format("%d,%d", seatNumber, passenger.getId());
// }
// }

View File

@ -7,12 +7,12 @@ public class User {
PUBLIC,
}
private int id;
private String id;
private Type type;
private String name;
private String password;
public User(int id, Type type, String name, String password) {
public User(String id, Type type, String name, String password) {
this.id = id;
this.type = type;
this.name = name;
@ -29,7 +29,7 @@ public class User {
*/
public static User fromCsvString(String line) {
String[] parts = line.split(",");
int id = Integer.parseInt(parts[0]);
String id = parts[0];
Type type = Type.valueOf(parts[1]);
String name = new String(Base64.getDecoder().decode(parts[2]));
String password = new String(Base64.getDecoder().decode(parts[3]));
@ -40,14 +40,14 @@ public class User {
// don't forget to escape commas in name and password
String csvName = Base64.getEncoder().encodeToString(name.getBytes());
String csvPassword = Base64.getEncoder().encodeToString(password.getBytes());
return String.format("%d,%s,%s,%s", id, type, csvName, csvPassword);
return String.join(",", id, type.toString(), csvName, csvPassword);
}
public Type getType() {
return type;
}
public int getId() {
public String getId() {
return id;
}