166 자
1 분
Java 영화관 예매 프로그램 완성본 소스코드
예전에 작업하던 영화 예매 프로그램 중간과정의 마지막 단계인 예매 파트 완성.
코드 난잡하게 널려있던 부분을 모두 정리했다.
- 상영관 관리 프로그램 O
- 영화 상형일정 관리 프로그램 O
- 영화 티켓 예매 프로그램 O
- 균일한 출력 및 사용법 O
예외처리 할 것이 아직 남은 것 같긴 한데 최대한 처리를 했으니 사용하는데 큰 무리는 없을 것이라 생각된다.
아래는 각 클래스의 소스코드.
InputClosedException
/** * 입력 스트림이 닫혔을 때(Ctrl+D, Ctrl+Z 등) 프로그램을 안전하게 종료하기 위한 예외. */public class InputClosedException extends RuntimeException{ private static final long serialVersionUID = 1L;
public InputClosedException() { super("입력 스트림이 종료되었습니다."); }}ConsoleUI
import java.util.List;
/** * 콘솔 출력 전용 유틸리티. (제목, 안내/오류 메시지, 표 출력) * <p> * 한글은 콘솔에서 영문보다 2배 넓게 표시되므로, 표를 정렬할 때 글자 수가 아닌 "표시 폭"을 기준으로 맞춘다. */public class ConsoleUI{ public static final int WIDTH = 64;
private ConsoleUI() { }
public static void title(String text) { System.out.println(); System.out.println(repeat('=', WIDTH)); System.out.println(center(text, WIDTH)); System.out.println(repeat('=', WIDTH)); }
public static void section(String text) { System.out.println(); String head = "---- " + text + " "; System.out.println(head + repeat('-', Math.max(4, WIDTH - displayWidth(head)))); }
public static void success(String message) { System.out.println(" [완료] " + message); }
public static void error(String message) { System.out.println(" [오류] " + message); }
public static void info(String message) { System.out.println(" [안내] " + message); }
/** 헤더와 행 데이터를 받아 테두리가 있는 표로 출력한다. */ public static void printTable(String[] headers, List<String[]> rows) { int[] widths = new int[headers.length]; for (int i = 0; i < headers.length; i++) { widths[i] = displayWidth(headers[i]); } for (String[] row : rows) { for (int i = 0; i < headers.length; i++) { widths[i] = Math.max(widths[i], displayWidth(row[i])); } }
String border = buildBorder(widths); System.out.println(border); System.out.println(buildRow(headers, widths)); System.out.println(border); for (String[] row : rows) { System.out.println(buildRow(row, widths)); } System.out.println(border); }
private static String buildBorder(int[] widths) { StringBuilder sb = new StringBuilder(" +"); for (int w : widths) { sb.append(repeat('-', w + 2)).append('+'); } return sb.toString(); }
private static String buildRow(String[] cells, int[] widths) { StringBuilder sb = new StringBuilder(" |"); for (int i = 0; i < widths.length; i++) { sb.append(' ').append(pad(cells[i], widths[i])).append(" |"); } return sb.toString(); }
/** 문자열의 콘솔 표시 폭 (한글/전각 문자는 2칸) */ public static int displayWidth(String s) { int width = 0; for (int i = 0; i < s.length(); i++) { width += isWide(s.charAt(i)) ? 2 : 1; } return width; }
private static boolean isWide(char c) { return (c >= 0x1100 && c <= 0x115F) // 한글 자모 || (c >= 0x2E80 && c <= 0xA4CF) // CJK || (c >= 0xAC00 && c <= 0xD7A3) // 한글 음절 || (c >= 0xF900 && c <= 0xFAFF) || (c >= 0xFE30 && c <= 0xFE4F) || (c >= 0xFF00 && c <= 0xFF60) // 전각 문자 || (c >= 0xFFE0 && c <= 0xFFE6); }
/** 표시 폭 기준으로 오른쪽을 공백으로 채운다. */ public static String pad(String s, int width) { StringBuilder sb = new StringBuilder(s); for (int w = displayWidth(s); w < width; w++) { sb.append(' '); } return sb.toString(); }
public static String center(String s, int width) { int left = Math.max(0, (width - displayWidth(s)) / 2); return repeat(' ', left) + s; }
public static String repeat(char c, int n) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < n; i++) { sb.append(c); } return sb.toString(); }}ConsoleInput
import java.util.NoSuchElementException;import java.util.Scanner;
/** * 콘솔 입력 전용 유틸리티. * <p> * - 프로그램 전체가 하나의 Scanner 를 공유한다. (System.in 에 Scanner 를 여러 개 만들면 입력이 유실될 수 있음) * - 모든 입력을 한 줄 단위(nextLine)로 읽어서, nextInt() 뒤에 남는 개행 문제를 없앤다. * - 숫자 입력에 문자가 들어오거나 범위를 벗어나면 예외로 죽지 않고 다시 입력받는다. */public class ConsoleInput{ private static final Scanner SCANNER = new Scanner(System.in);
private ConsoleInput() { }
/** 한 줄을 읽어 앞뒤 공백을 제거해 돌려준다. */ public static String readLine(String prompt) { System.out.print(" " + prompt); try { return SCANNER.nextLine().trim(); } catch (NoSuchElementException | IllegalStateException e) { throw new InputClosedException(); } }
/** min ~ max 범위의 정수를 입력받는다. 올바른 값이 들어올 때까지 반복한다. */ public static int readInt(String prompt, int min, int max) { while (true) { String line = readLine(prompt); if (line.isEmpty()) { ConsoleUI.error("값이 입력되지 않았습니다. " + min + " ~ " + max + " 사이의 숫자를 입력해주세요."); continue; } try { int value = Integer.parseInt(line); if (value < min || value > max) { ConsoleUI.error(value + "은(는) 범위를 벗어났습니다. " + min + " ~ " + max + " 사이의 숫자를 입력해주세요."); continue; } return value; } catch (NumberFormatException e) { ConsoleUI.error("'" + line + "'은(는) 숫자가 아닙니다. " + min + " ~ " + max + " 사이의 숫자를 입력해주세요."); } } }
/** y/n 질문. 한글 자판 상태에서 누른 ㅛ/ㅜ 도 허용한다. */ public static boolean confirm(String prompt) { while (true) { String line = readLine(prompt + " (y/n) : ").toLowerCase(); if (line.equals("y") || line.equals("yes") || line.equals("ㅛ")) { return true; } if (line.equals("n") || line.equals("no") || line.equals("ㅜ")) { return false; } ConsoleUI.error("y(예) 또는 n(아니오)로 입력해주세요."); } }}Screen
public class Screen{ private String name; private int rowNum; private int seatNum;
public Screen(String name, int rowNum, int seatNum) { this.name = name; this.rowNum = rowNum; this.seatNum = seatNum; }
/** 총 좌석 수 */ public int getTotalSeats() { return rowNum * seatNum; }
/** 예) 5열 x 10석 */ public String getLayoutText() { return rowNum + "열 x " + seatNum + "석"; }
@Override public String toString() { return "Screen [name=" + name + ", rowNum=" + rowNum + ", seatNum=" + seatNum + "]"; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getRowNum() { return rowNum; }
public void setRowNum(int rowNum) { this.rowNum = rowNum; }
public int getSeatNum() { return seatNum; }
public void setSeatNum(int seatNum) { this.seatNum = seatNum; }}ScreenManager
import java.util.ArrayList;import java.util.List;
public class ScreenManager{ public static final int MAX_ROWS = 20; public static final int MAX_SEATS_PER_ROW = 20; private static final int MAX_NAME_WIDTH = 20;
private Screen[] screens; private int maxCount; private int count; private TimetableManager tm; // 상영일정이 걸린 상영관은 삭제하지 못하도록 확인용
public ScreenManager(int maxCount) { this.maxCount = maxCount; this.screens = new Screen[maxCount]; count = 0; }
public void setTimetableManager(TimetableManager tm) { this.tm = tm; }
public void add() { ConsoleUI.section("상영관 등록"); if (count == maxCount) { ConsoleUI.error("상영관을 더 이상 등록할 수 없습니다. (최대 " + maxCount + "개)"); ConsoleUI.info("사용하지 않는 상영관을 삭제한 뒤 다시 시도해주세요."); return; }
String name; while (true) { name = ConsoleInput.readLine("상영관 이름 (예: 1관, 빈 입력 시 취소) : "); if (name.isEmpty()) { ConsoleUI.info("상영관 등록을 취소했습니다."); return; } if (ConsoleUI.displayWidth(name) > MAX_NAME_WIDTH) { ConsoleUI.error("이름이 너무 깁니다. (한글 10자 / 영문 20자 이내)"); continue; } if (findByName(name) != null) { ConsoleUI.error("'" + name + "'은(는) 이미 등록된 상영관입니다. 다른 이름을 입력해주세요."); continue; } break; } int rowNum = ConsoleInput.readInt("좌석 열 수 (1~" + MAX_ROWS + ") : ", 1, MAX_ROWS); int seatNum = ConsoleInput.readInt("한 열의 좌석 수 (1~" + MAX_SEATS_PER_ROW + ") : ", 1, MAX_SEATS_PER_ROW);
Screen screen = new Screen(name, rowNum, seatNum); addScreen(screen); ConsoleUI.success("'" + name + "' 상영관이 등록되었습니다. (" + screen.getLayoutText() + ", 총 " + screen.getTotalSeats() + "석) [" + count + "/" + maxCount + "]"); }
/** 입력 없이 상영관을 추가한다. (샘플 데이터용) */ public boolean addScreen(Screen screen) { if (count == maxCount || findByName(screen.getName()) != null) { return false; } screens[count] = screen; count++; return true; }
public void list() { ConsoleUI.section("상영관 목록 (" + count + "/" + maxCount + ")"); if (count == 0) { ConsoleUI.info("등록된 상영관이 없습니다. 1번(등록)으로 상영관을 추가해보세요."); return; } printScreenTable(); }
private void printScreenTable() { List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < count; i++) { MovieTimetable mt = (tm == null) ? null : tm.findByScreen(screens[i]); rows.add(new String[] { String.valueOf(i + 1), screens[i].getName(), screens[i].getLayoutText(), screens[i].getTotalSeats() + "석", mt == null ? "-" : mt.getMovie().getTitle() }); } ConsoleUI.printTable(new String[] {"번호", "상영관", "좌석 배치", "총 좌석", "상영 중인 영화"}, rows); }
public void remove() { ConsoleUI.section("상영관 삭제"); if (count == 0) { ConsoleUI.info("삭제할 상영관이 없습니다."); return; } printScreenTable(); int select = ConsoleInput.readInt("삭제할 상영관 번호 (0. 취소) >> ", 0, count); if (select == 0) { ConsoleUI.info("삭제를 취소했습니다."); return; }
int index = select - 1; Screen target = screens[index]; if (tm != null && tm.findByScreen(target) != null) { ConsoleUI.error("'" + target.getName() + "'에는 상영일정이 등록되어 있어 삭제할 수 없습니다."); ConsoleUI.info("상영일정 관리에서 해당 일정을 먼저 삭제해주세요."); return; } if (!ConsoleInput.confirm("'" + target.getName() + "' 상영관을 삭제할까요?")) { ConsoleUI.info("삭제를 취소했습니다."); return; }
// 뒤의 원소를 한 칸씩 당긴다. (j + 1 이 배열 범위를 넘지 않도록 count - 1 까지만) for (int j = index; j < count - 1; j++) { screens[j] = screens[j + 1]; } screens[count - 1] = null; count--; ConsoleUI.success("'" + target.getName() + "' 상영관이 삭제되었습니다."); }
public void screenManagerMain() { while (true) { ConsoleUI.title("상영관 관리 (등록 " + count + "/" + maxCount + ")"); System.out.println(" 1. 상영관 등록"); System.out.println(" 2. 상영관 목록"); System.out.println(" 3. 상영관 삭제"); System.out.println(" 0. 메인 메뉴로"); int input = ConsoleInput.readInt("메뉴 선택 >> ", 0, 3); switch (input) { case 1: add(); break; case 2: list(); break; case 3: remove(); break; case 0: return; default: break; } } }
public Screen findByName(String name) { for (int i = 0; i < count; i++) { if (screens[i].getName().equals(name)) { return screens[i]; } } return null; }
public Screen getScreen(int index) { if (index < 0 || index >= count) { throw new IndexOutOfBoundsException("상영관 번호가 범위를 벗어났습니다: " + index); } return screens[index]; }
public Screen[] getScreens() { if (count == 0) { return null; } return screens; }
public int getMaxCount() { return maxCount; }
public int getCount() { return count; }}Movie
public class Movie{ private String title; private String openDate; private int playtime; private String grade;
public Movie(String title, String openDate, int playtime, String grade) { this.title = title; this.openDate = openDate; this.playtime = playtime; this.grade = grade; }
/** 예) 2014-11-06 개봉 / 169분 / 12세이상관람가 */ public String getSummary() { return openDate + " 개봉 / " + playtime + "분 / " + grade; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getOpenDate() { return openDate; }
public void setOpenDate(String openDate) { this.openDate = openDate; }
public int getPlaytime() { return playtime; }
public void setPlaytime(int playtime) { this.playtime = playtime; }
public String getGrade() { return grade; }
public void setGrade(String grade) { this.grade = grade; }}MovieTimetable
import java.util.Arrays;
/** * 한 상영관에서 한 영화를 상영하는 일정. (상영 시작시간 여러 개) */public class MovieTimetable{ private static final int MINUTES_OF_DAY = 24 * 60;
private Movie movie; private Screen screen; private String[] times;
public MovieTimetable(Movie movie, Screen screen, String[] times) { this.movie = movie; this.screen = screen; this.times = times; }
/** * "10:00 13:30 17:00" 형태의 문자열을 검사한 뒤 정렬된 시간 배열로 변환한다. * 형식이 틀리거나, 중복되거나, 러닝타임 때문에 회차가 겹치면 IllegalArgumentException 을 던진다. */ public static String[] parseTimes(String input, int playtime) { String trimmed = input.trim(); if (trimmed.isEmpty()) { throw new IllegalArgumentException("상영 시작시간을 하나 이상 입력해주세요."); }
String[] tokens = trimmed.split("[\\s,]+"); int[] minutes = new int[tokens.length]; for (int i = 0; i < tokens.length; i++) { minutes[i] = toMinutes(tokens[i]); } Arrays.sort(minutes);
for (int i = 1; i < minutes.length; i++) { if (minutes[i] == minutes[i - 1]) { throw new IllegalArgumentException(formatMinutes(minutes[i]) + " 이(가) 중복 입력되었습니다."); } if (minutes[i] - minutes[i - 1] < playtime) { throw new IllegalArgumentException(formatMinutes(minutes[i - 1]) + " 회차(종료 " + formatMinutes(minutes[i - 1] + playtime) + ")와 " + formatMinutes(minutes[i]) + " 회차가 겹칩니다. (러닝타임 " + playtime + "분)"); } }
String[] result = new String[minutes.length]; for (int i = 0; i < minutes.length; i++) { result[i] = formatMinutes(minutes[i]); } return result; }
private static int toMinutes(String time) { if (!time.matches("\\d{1,2}:\\d{2}")) { throw new IllegalArgumentException("'" + time + "'은(는) 올바른 시간 형식이 아닙니다. 예) 09:30 13:00"); } String[] parts = time.split(":"); int hour = Integer.parseInt(parts[0]); int minute = Integer.parseInt(parts[1]); if (hour > 23 || minute > 59) { throw new IllegalArgumentException("'" + time + "'은(는) 존재하지 않는 시간입니다. (00:00 ~ 23:59)"); } return hour * 60 + minute; }
/** 분 단위 값을 HH:mm 으로. 다음날로 넘어가면 (+1) 표시 */ private static String formatMinutes(int total) { int m = total % MINUTES_OF_DAY; String text = String.format("%02d:%02d", m / 60, m % 60); if (total >= MINUTES_OF_DAY) { text += "(+1)"; } return text; }
/** 시작시간으로부터 러닝타임을 더한 종료시간 */ public String getEndTime(String startTime) { return formatMinutes(toMinutes(startTime) + movie.getPlaytime()); }
public boolean hasTime(String time) { for (String t : times) { if (t.equals(time)) { return true; } } return false; }
/** 예) 10:00, 13:30, 17:00 */ public String getTimesText() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < times.length; i++) { if (i > 0) { sb.append(", "); } sb.append(times[i]); } return sb.toString(); }
public void showTime() { System.out.print(getTimesText()); }
public Movie getMovie() { return movie; }
public void setMovie(Movie movie) { this.movie = movie; }
public Screen getScreen() { return screen; }
public void setScreen(Screen screen) { this.screen = screen; }
public String[] getTimes() { return times; }
public void setTimes(String[] times) { this.times = times; }}TimetableManager
import java.time.LocalDate;import java.time.format.DateTimeFormatter;import java.time.format.DateTimeParseException;import java.util.ArrayList;import java.util.List;
public class TimetableManager{ private static final String[] GRADES = {"전체관람가", "12세이상관람가", "15세이상관람가", "청소년관람불가"}; private static final int MAX_TITLE_WIDTH = 30; private static final int MAX_PLAYTIME = 600;
private MovieTimetable[] table; private ScreenManager sm; private TicketManager ticketManager; // 잔여석 표시, 예매가 있는 일정 삭제 방지용 private int pos;
public TimetableManager(int n, ScreenManager sm) { table = new MovieTimetable[n]; this.sm = sm; pos = 0; }
public void setTicketManager(TicketManager ticketManager) { this.ticketManager = ticketManager; }
// ------------------------------------------------------------------ 등록
public void add() { ConsoleUI.section("상영일정 등록"); if (sm.getCount() == 0) { ConsoleUI.error("등록된 상영관이 없습니다."); ConsoleUI.info("메인 메뉴 1번(상영관 관리)에서 상영관을 먼저 등록해주세요."); return; } if (isFull()) { ConsoleUI.error("상영일정이 가득 찼습니다. (최대 " + table.length + "개)"); ConsoleUI.info("기존 상영일정을 삭제한 뒤 다시 시도해주세요."); return; } if (getAvailableScreens().isEmpty()) { ConsoleUI.error("모든 상영관에 이미 상영일정이 있습니다. (상영관 1곳당 영화 1편)"); ConsoleUI.info("상영관을 새로 등록하거나 기존 상영일정을 삭제해주세요."); return; }
Movie movie = selectOrCreateMovie(); if (movie == null) { ConsoleUI.info("상영일정 등록을 취소했습니다."); return; }
int added = 0; while (true) { if (isFull()) { ConsoleUI.info("상영일정이 가득 차서 더 이상 등록할 수 없습니다."); break; } List<Screen> available = getAvailableScreens(); if (available.isEmpty()) { ConsoleUI.info("일정을 추가할 수 있는 빈 상영관이 더 없습니다."); break; }
System.out.println(); System.out.println(" '" + movie.getTitle() + "'을(를) 상영할 상영관을 선택하세요. (비어 있는 상영관만 표시)"); List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < available.size(); i++) { Screen sc = available.get(i); rows.add(new String[] {String.valueOf(i + 1), sc.getName(), sc.getLayoutText(), sc.getTotalSeats() + "석"}); } ConsoleUI.printTable(new String[] {"번호", "상영관", "좌석 배치", "총 좌석"}, rows);
String zeroLabel = (added == 0) ? "0. 취소" : "0. 등록 마치기"; int select = ConsoleInput.readInt("상영관 번호 (" + zeroLabel + ") >> ", 0, available.size()); if (select == 0) { break; } Screen screen = available.get(select - 1);
String[] times = readTimes(movie); if (times == null) { ConsoleUI.info("'" + screen.getName() + "' 일정 입력을 취소했습니다."); continue; }
MovieTimetable mt = new MovieTimetable(movie, screen, times); addTimetable(mt); added++; ConsoleUI.success(screen.getName() + "에 '" + movie.getTitle() + "' " + times.length + "회차가 등록되었습니다."); for (String t : times) { System.out.println(" " + t + " ~ " + mt.getEndTime(t)); } }
if (added == 0) { ConsoleUI.info("등록된 상영일정이 없습니다."); } else { ConsoleUI.success("총 " + added + "개 상영관에 '" + movie.getTitle() + "' 일정이 등록되었습니다. [" + pos + "/" + table.length + "]"); } }
/** 기존 영화 중 선택하거나 새 영화를 입력받는다. 취소하면 null */ private Movie selectOrCreateMovie() { List<Movie> movies = getMovies(); if (movies.isEmpty()) { ConsoleUI.info("등록된 영화가 없어 새 영화 정보를 입력합니다."); return createMovie(); }
System.out.println(" 등록된 영화 목록"); List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < movies.size(); i++) { Movie m = movies.get(i); rows.add(new String[] {String.valueOf(i + 1), m.getTitle(), m.getOpenDate(), m.getPlaytime() + "분", m.getGrade()}); } ConsoleUI.printTable(new String[] {"번호", "제목", "개봉일", "러닝타임", "등급"}, rows); int select = ConsoleInput.readInt("영화 번호 (0. 새 영화 등록) >> ", 0, movies.size()); if (select == 0) { return createMovie(); } return movies.get(select - 1); }
private Movie createMovie() { String title; while (true) { title = ConsoleInput.readLine("영화 제목 (빈 입력 시 취소) : "); if (title.isEmpty()) { return null; } if (ConsoleUI.displayWidth(title) > MAX_TITLE_WIDTH) { ConsoleUI.error("제목이 너무 깁니다. (한글 15자 / 영문 30자 이내)"); continue; } break; } Movie existing = findMovie(title); if (existing != null) { ConsoleUI.info("'" + title + "'은(는) 이미 등록된 영화입니다. 기존 정보(" + existing.getSummary() + ")를 사용합니다."); return existing; }
String openDate = readDate("개봉일 (예: 2026-09-24 또는 20260924) : "); int playtime = ConsoleInput.readInt("러닝타임 (분, 1~" + MAX_PLAYTIME + ") : ", 1, MAX_PLAYTIME);
System.out.print(" 등급 -"); for (int i = 0; i < GRADES.length; i++) { System.out.print(" " + (i + 1) + "." + GRADES[i]); } System.out.println(); int gradeNo = ConsoleInput.readInt("등급 번호 (1~" + GRADES.length + ") : ", 1, GRADES.length);
Movie movie = new Movie(title, openDate, playtime, GRADES[gradeNo - 1]); ConsoleUI.success("새 영화 '" + title + "' 정보가 입력되었습니다. (" + movie.getSummary() + ")"); return movie; }
private String readDate(String prompt) { while (true) { String input = ConsoleInput.readLine(prompt); try { LocalDate date = input.contains("-") ? LocalDate.parse(input, DateTimeFormatter.ISO_LOCAL_DATE) : LocalDate.parse(input, DateTimeFormatter.BASIC_ISO_DATE); return date.toString(); } catch (DateTimeParseException e) { ConsoleUI.error("'" + input + "'은(는) 올바른 날짜가 아닙니다. 예) 2026-09-24"); } } }
/** 상영 시작시간을 입력받는다. 빈 입력이면 null */ private String[] readTimes(Movie movie) { System.out.println(" 상영 시작시간을 공백으로 구분해 입력하세요. (러닝타임 " + movie.getPlaytime() + "분, 회차끼리 겹칠 수 없음)"); while (true) { String input = ConsoleInput.readLine("시작시간 (예: 10:00 13:30, 빈 입력 시 취소) : "); if (input.isEmpty()) { return null; } try { return MovieTimetable.parseTimes(input, movie.getPlaytime()); } catch (IllegalArgumentException e) { ConsoleUI.error(e.getMessage()); } } }
/** 입력 없이 상영일정을 추가한다. (샘플 데이터 및 add() 내부에서 사용) */ public boolean addTimetable(MovieTimetable mt) { if (isFull() || findByScreen(mt.getScreen()) != null) { return false; } table[pos] = mt; pos++; sort(); return true; }
/** 영화 제목 → 상영관 이름 순으로 정렬 (버블 정렬) */ private void sort() { for (int i = 0; i < pos - 1; i++) { for (int j = 0; j < pos - 1 - i; j++) { int cmp = table[j].getMovie().getTitle().compareTo(table[j + 1].getMovie().getTitle()); if (cmp == 0) { cmp = table[j].getScreen().getName().compareTo(table[j + 1].getScreen().getName()); } if (cmp > 0) { MovieTimetable temp = table[j]; table[j] = table[j + 1]; table[j + 1] = temp; } } } }
// ------------------------------------------------------------------ 목록
public void list() { ConsoleUI.section("상영일정 목록 (" + pos + "/" + table.length + ")"); if (pos == 0) { ConsoleUI.info("등록된 상영일정이 없습니다. 1번(등록)으로 추가해보세요."); return; }
List<Movie> movies = getMovies(); for (int i = 0; i < movies.size(); i++) { Movie m = movies.get(i); System.out.println(); System.out.println(" [" + (i + 1) + "] " + m.getTitle() + " " + m.getSummary()); for (int k = 0; k < pos; k++) { if (table[k].getMovie() != m) { continue; } Screen sc = table[k].getScreen(); System.out.println(" - " + sc.getName() + " (" + sc.getLayoutText() + ")"); for (String t : table[k].getTimes()) { String line = " " + t + " ~ " + table[k].getEndTime(t); if (ticketManager != null) { int remain = sc.getTotalSeats() - ticketManager.countReserved(sc, t); line += " " + (remain == 0 ? "매진" : "잔여 " + remain + "/" + sc.getTotalSeats() + "석"); } System.out.println(line); } } } }
// ------------------------------------------------------------------ 삭제
public void remove() { ConsoleUI.section("상영일정 삭제"); if (pos == 0) { ConsoleUI.info("삭제할 상영일정이 없습니다."); return; }
List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < pos; i++) { int ticketCount = (ticketManager == null) ? 0 : ticketManager.countTickets(table[i].getScreen()); rows.add(new String[] { String.valueOf(i + 1), table[i].getMovie().getTitle(), table[i].getScreen().getName(), table[i].getTimesText(), ticketCount + "건" }); } ConsoleUI.printTable(new String[] {"번호", "영화", "상영관", "상영시간", "예매"}, rows);
int select = ConsoleInput.readInt("삭제할 일정 번호 (0. 취소) >> ", 0, pos); if (select == 0) { ConsoleUI.info("삭제를 취소했습니다."); return; } int index = select - 1; MovieTimetable target = table[index]; String label = "'" + target.getMovie().getTitle() + "' / " + target.getScreen().getName();
if (ticketManager != null && ticketManager.countTickets(target.getScreen()) > 0) { ConsoleUI.error(label + " 일정에 예매 내역이 있어 삭제할 수 없습니다."); ConsoleUI.info("티켓 예매 메뉴에서 해당 예매를 먼저 취소해주세요."); return; } if (!ConsoleInput.confirm(label + " 상영일정을 삭제할까요?")) { ConsoleUI.info("삭제를 취소했습니다."); return; }
for (int j = index; j < pos - 1; j++) { table[j] = table[j + 1]; } table[pos - 1] = null; pos--; ConsoleUI.success(label + " 상영일정이 삭제되었습니다."); }
public void timetableManagerMain() { while (true) { ConsoleUI.title("상영일정 관리 (등록 " + pos + "/" + table.length + ")"); System.out.println(" 1. 상영일정 등록"); System.out.println(" 2. 상영일정 목록"); System.out.println(" 3. 상영일정 삭제"); System.out.println(" 0. 메인 메뉴로"); int input = ConsoleInput.readInt("메뉴 선택 >> ", 0, 3); switch (input) { case 1: add(); break; case 2: list(); break; case 3: remove(); break; case 0: return; default: break; } } }
// ------------------------------------------------------------------ 조회용
/** 중복 없는 영화 목록 (정렬 순서 유지) */ public List<Movie> getMovies() { List<Movie> movies = new ArrayList<Movie>(); for (int i = 0; i < pos; i++) { if (!movies.contains(table[i].getMovie())) { movies.add(table[i].getMovie()); } } return movies; }
private Movie findMovie(String title) { for (int i = 0; i < pos; i++) { if (table[i].getMovie().getTitle().equals(title)) { return table[i].getMovie(); } } return null; }
public MovieTimetable findByScreen(Screen screen) { for (int i = 0; i < pos; i++) { if (table[i].getScreen() == screen) { return table[i]; } } return null; }
private List<Screen> getAvailableScreens() { List<Screen> result = new ArrayList<Screen>(); for (int i = 0; i < sm.getCount(); i++) { Screen sc = sm.getScreen(i); if (findByScreen(sc) == null) { result.add(sc); } } return result; }
private boolean isFull() { return pos == table.length; }
public int getPos() { return pos; }
public int getMaxCount() { return table.length; }
public MovieTimetable[] getMT() { return table; }}Seat
public class Seat{ private int rowNo, seatNo;
public Seat(int rowNo, int seatNo) { this.rowNo = rowNo; this.seatNo = seatNo; }
/** 예) 3열 5번 */ @Override public String toString() { return rowNo + "열 " + seatNo + "번"; }
public int getRowNo() { return rowNo; }
public void setRowNo(int rowNo) { this.rowNo = rowNo; }
public int getSeatNo() { return seatNo; }
public void setSeatNo(int seatNo) { this.seatNo = seatNo; }}Ticket
public class Ticket{ private String ticketNo; private Movie movie; private Screen screen; private String playHour; private Seat[] seats;
public Ticket(String ticketNo, Movie movie, Screen screen, String playHour, Seat seats[]) { this.ticketNo = ticketNo; this.movie = movie; this.screen = screen; this.playHour = playHour; this.seats = seats; }
/** 예) 3열 4번, 3열 5번 */ public String getSeatsText() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < seats.length; i++) { if (i > 0) { sb.append(", "); } sb.append(seats[i]); } return sb.toString(); }
/** 이 티켓이 해당 상영관/시간의 해당 좌석을 차지하고 있는지 */ public boolean occupies(Screen screen, String playHour, int rowNo, int seatNo) { if (this.screen != screen || !this.playHour.equals(playHour)) { return false; } for (Seat seat : seats) { if (seat.getRowNo() == rowNo && seat.getSeatNo() == seatNo) { return true; } } return false; }
public String getTicketNo() { return ticketNo; }
public void setTicketNo(String ticketNo) { this.ticketNo = ticketNo; }
public Movie getMovie() { return movie; }
public void setMovie(Movie movie) { this.movie = movie; }
public Screen getScreen() { return screen; }
public void setScreen(Screen screen) { this.screen = screen; }
public String getPlayHour() { return playHour; }
public void setPlayHour(String playHour) { this.playHour = playHour; }
public Seat[] getSeats() { return seats; }
public void setSeats(Seat[] seats) { this.seats = seats; }}TicketManager
import java.util.ArrayList;import java.util.List;import java.util.TreeSet;
public class TicketManager{ private static int serialCode = 10000; private TimetableManager tm; private Ticket[] tickets; private int pos;
public TicketManager(int n, TimetableManager tm) { tickets = new Ticket[n]; this.tm = tm; pos = 0; }
// ------------------------------------------------------------------ 예매
public void add() { ConsoleUI.section("티켓 예매"); if (tm.getPos() == 0) { ConsoleUI.error("예매할 수 있는 상영일정이 없습니다."); ConsoleUI.info("메인 메뉴 2번(상영일정 관리)에서 상영일정을 먼저 등록해주세요."); return; } if (pos == tickets.length) { ConsoleUI.error("예매 가능 건수(최대 " + tickets.length + "건)를 모두 사용했습니다."); ConsoleUI.info("기존 예매를 취소한 뒤 다시 시도해주세요."); return; }
// 1) 상영 회차 선택 : 영화/상영관/시간을 직접 타이핑하는 대신 번호로 고른다. List<MovieTimetable> sessionTables = new ArrayList<MovieTimetable>(); List<String> sessionTimes = new ArrayList<String>(); List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < tm.getPos(); i++) { MovieTimetable mt = tm.getMT()[i]; for (String t : mt.getTimes()) { sessionTables.add(mt); sessionTimes.add(t); int remain = remainingSeats(mt.getScreen(), t); rows.add(new String[] { String.valueOf(sessionTables.size()), mt.getMovie().getTitle(), mt.getMovie().getGrade(), mt.getScreen().getName(), t + " ~ " + mt.getEndTime(t), remain == 0 ? "매진" : remain + "/" + mt.getScreen().getTotalSeats() }); } } ConsoleUI.printTable(new String[] {"번호", "영화", "등급", "상영관", "상영시간", "잔여석"}, rows);
MovieTimetable mt; String time; while (true) { int select = ConsoleInput.readInt("회차 번호 (0. 취소) >> ", 0, sessionTables.size()); if (select == 0) { ConsoleUI.info("예매를 취소했습니다."); return; } mt = sessionTables.get(select - 1); time = sessionTimes.get(select - 1); if (remainingSeats(mt.getScreen(), time) == 0) { ConsoleUI.error("매진된 회차입니다. 다른 회차를 선택해주세요."); continue; } break; } Screen screen = mt.getScreen();
// 2) 좌석 선택 System.out.println(); System.out.println(" " + mt.getMovie().getTitle() + " / " + screen.getName() + " / " + time + " ~ " + mt.getEndTime(time)); int row; int[] seatNos; while (true) { printSeatMap(screen, time, 0, null); row = ConsoleInput.readInt("열 번호 (1~" + screen.getRowNum() + ", 0. 취소) >> ", 0, screen.getRowNum()); if (row == 0) { ConsoleUI.info("예매를 취소했습니다."); return; } String input = ConsoleInput.readLine("좌석 번호 (예: 3 4 5 또는 3-5, 빈 입력 시 열 다시 선택) : "); if (input.isEmpty()) { continue; } try { seatNos = parseSeats(input, screen.getSeatNum()); } catch (IllegalArgumentException e) { ConsoleUI.error(e.getMessage()); continue; }
List<Integer> taken = new ArrayList<Integer>(); for (int no : seatNos) { if (isReserved(screen, time, row, no)) { taken.add(no); } } if (!taken.isEmpty()) { ConsoleUI.error(row + "열 " + joinNumbers(taken) + "번 좌석은 이미 예매되었습니다. 다른 좌석을 선택해주세요."); continue; }
printSeatMap(screen, time, row, seatNos); System.out.println(" 선택한 좌석 : " + row + "열 " + joinNumbers(seatNos) + "번 (" + seatNos.length + "명)"); if (ConsoleInput.confirm("이 좌석으로 예매할까요?")) { break; } ConsoleUI.info("좌석을 다시 선택합니다."); }
// 3) 발권 Seat[] seats = new Seat[seatNos.length]; for (int i = 0; i < seatNos.length; i++) { seats[i] = new Seat(row, seatNos[i]); } String ticketNo = "T" + serialCode; serialCode++; Ticket ticket = new Ticket(ticketNo, mt.getMovie(), screen, time, seats); tickets[pos] = ticket; pos++;
ConsoleUI.success("예매가 완료되었습니다."); printTicket(ticket); ConsoleUI.info("예매번호 [" + ticketNo + "]는 예매 확인/취소 시 필요하니 꼭 기억해주세요."); }
/** * "3 4 5", "3-5", "1,2 7-9" 형태의 입력을 좌석 번호 배열로 변환한다. * 숫자가 아니거나, 범위를 벗어나거나, 중복되면 IllegalArgumentException 을 던진다. */ private int[] parseSeats(String input, int maxSeat) { TreeSet<Integer> result = new TreeSet<Integer>(); for (String token : input.split("[\\s,]+")) { int from, to; if (token.matches("\\d{1,3}")) { from = to = Integer.parseInt(token); } else if (token.matches("\\d{1,3}-\\d{1,3}")) { String[] parts = token.split("-"); from = Integer.parseInt(parts[0]); to = Integer.parseInt(parts[1]); if (from > to) { throw new IllegalArgumentException("'" + token + "' 범위가 잘못되었습니다. 작은 번호를 앞에 써주세요. 예) 3-5"); } } else { throw new IllegalArgumentException("'" + token + "'은(는) 올바른 좌석 번호가 아닙니다. 예) 3 4 5 또는 3-5"); }
for (int no = from; no <= to; no++) { if (no < 1 || no > maxSeat) { throw new IllegalArgumentException(no + "번 좌석은 없습니다. (1 ~ " + maxSeat + "번)"); } if (!result.add(no)) { throw new IllegalArgumentException(no + "번 좌석이 중복 입력되었습니다."); } } }
int[] arr = new int[result.size()]; int i = 0; for (int no : result) { arr[i++] = no; } return arr; }
/** * 좌석 배치도 출력. [ ] 빈 좌석, [X] 예매 완료, [O] 지금 선택한 좌석 */ private void printSeatMap(Screen screen, String time, int selectedRow, int[] selectedSeats) { int cols = screen.getSeatNum(); int mapWidth = 6 + cols * 3;
System.out.println(); System.out.println(" " + ConsoleUI.center("[ S C R E E N ]", mapWidth)); StringBuilder header = new StringBuilder(" "); for (int c = 1; c <= cols; c++) { header.append(String.format("%2d ", c)); } System.out.println(header);
for (int r = 1; r <= screen.getRowNum(); r++) { StringBuilder line = new StringBuilder(String.format(" %3d열 ", r)); for (int c = 1; c <= cols; c++) { if (r == selectedRow && contains(selectedSeats, c)) { line.append("[O]"); } else if (isReserved(screen, time, r, c)) { line.append("[X]"); } else { line.append("[ ]"); } } System.out.println(line); } String legend = " [ ] 예매 가능 [X] 예매 완료"; if (selectedSeats != null) { legend += " [O] 선택한 좌석"; } System.out.println(legend + " (잔여 " + remainingSeats(screen, time) + "/" + screen.getTotalSeats() + "석)"); }
// ------------------------------------------------------------------ 확인
public void list() { ConsoleUI.section("예매 확인"); if (pos == 0) { ConsoleUI.info("예매 내역이 없습니다."); return; } Ticket ticket = readTicket(); if (ticket != null) { printTicket(ticket); } }
public void listAll() { ConsoleUI.section("전체 예매 내역 (" + pos + "/" + tickets.length + ")"); if (pos == 0) { ConsoleUI.info("예매 내역이 없습니다."); return; } List<String[]> rows = new ArrayList<String[]>(); for (int i = 0; i < pos; i++) { Ticket t = tickets[i]; rows.add(new String[] { t.getTicketNo(), t.getMovie().getTitle(), t.getScreen().getName(), t.getPlayHour(), t.getSeatsText(), t.getSeats().length + "명" }); } ConsoleUI.printTable(new String[] {"예매번호", "영화", "상영관", "시간", "좌석", "인원"}, rows); }
/** 예매번호를 입력받아 티켓을 찾는다. 숫자만 입력해도(10000) 찾을 수 있다. */ private Ticket readTicket() { String input = ConsoleInput.readLine("예매번호 (예: T10000, 빈 입력 시 취소) : "); if (input.isEmpty()) { ConsoleUI.info("취소했습니다."); return null; } String ticketNo = input.matches("\\d+") ? "T" + input : input; int index = indexOf(ticketNo); if (index < 0) { ConsoleUI.error("'" + input + "' 예매번호를 찾을 수 없습니다."); ConsoleUI.info("4번(전체 예매 내역)에서 예매번호를 확인할 수 있습니다."); return null; } return tickets[index]; }
private void printTicket(Ticket t) { String start = t.getPlayHour(); MovieTimetable mt = tm.findByScreen(t.getScreen()); String end = (mt == null) ? "" : " ~ " + mt.getEndTime(start);
String[] lines = { "예매번호 : " + t.getTicketNo(), "영 화 : " + t.getMovie().getTitle() + " (" + t.getMovie().getGrade() + ")", "상 영 관 : " + t.getScreen().getName(), "상영시간 : " + start + end, "좌 석 : " + t.getSeatsText(), "인 원 : " + t.getSeats().length + "명" }; int width = 30; for (String line : lines) { width = Math.max(width, ConsoleUI.displayWidth(line)); } String border = " +" + ConsoleUI.repeat('-', width + 2) + "+";
System.out.println(); System.out.println(border); System.out.println(" | " + ConsoleUI.pad(ConsoleUI.center("MOVIE TICKET", width), width) + " |"); System.out.println(border); for (String line : lines) { System.out.println(" | " + ConsoleUI.pad(line, width) + " |"); } System.out.println(border); }
// ------------------------------------------------------------------ 취소
public void remove() { ConsoleUI.section("예매 취소"); if (pos == 0) { ConsoleUI.info("취소할 예매 내역이 없습니다."); return; } Ticket ticket = readTicket(); if (ticket == null) { return; } printTicket(ticket); if (!ConsoleInput.confirm("이 예매를 취소할까요?")) { ConsoleUI.info("예매 취소를 중단했습니다. 예매는 그대로 유지됩니다."); return; }
int index = indexOf(ticket.getTicketNo()); for (int j = index; j < pos - 1; j++) { tickets[j] = tickets[j + 1]; } tickets[pos - 1] = null; pos--; ConsoleUI.success("예매번호 " + ticket.getTicketNo() + " 예매가 취소되었습니다."); }
public void ticketManagerMain() { while (true) { ConsoleUI.title("티켓 예매 (예매 " + pos + "/" + tickets.length + ")"); System.out.println(" 1. 예매하기"); System.out.println(" 2. 예매 확인 (예매번호로 조회)"); System.out.println(" 3. 예매 취소"); System.out.println(" 4. 전체 예매 내역"); System.out.println(" 0. 메인 메뉴로"); int input = ConsoleInput.readInt("메뉴 선택 >> ", 0, 4); switch (input) { case 1: add(); break; case 2: list(); break; case 3: remove(); break; case 4: listAll(); break; case 0: return; default: break; } } }
// ------------------------------------------------------------------ 조회용
private int indexOf(String ticketNo) { for (int i = 0; i < pos; i++) { if (tickets[i].getTicketNo().equalsIgnoreCase(ticketNo)) { return i; } } return -1; }
/** 같은 상영관 + 같은 시간 회차에서 해당 좌석이 예매되었는지 */ public boolean isReserved(Screen screen, String time, int row, int seatNo) { for (int i = 0; i < pos; i++) { if (tickets[i].occupies(screen, time, row, seatNo)) { return true; } } return false; }
/** 해당 회차에 예매된 좌석 수 */ public int countReserved(Screen screen, String time) { int total = 0; for (int i = 0; i < pos; i++) { if (tickets[i].getScreen() == screen && tickets[i].getPlayHour().equals(time)) { total += tickets[i].getSeats().length; } } return total; }
private int remainingSeats(Screen screen, String time) { return screen.getTotalSeats() - countReserved(screen, time); }
/** 해당 상영관의 예매 건수 */ public int countTickets(Screen screen) { int total = 0; for (int i = 0; i < pos; i++) { if (tickets[i].getScreen() == screen) { total++; } } return total; }
public int getPos() { return pos; }
public int getMaxCount() { return tickets.length; }
private static boolean contains(int[] arr, int value) { if (arr == null) { return false; } for (int v : arr) { if (v == value) { return true; } } return false; }
private static String joinNumbers(int[] numbers) { List<Integer> list = new ArrayList<Integer>(); for (int n : numbers) { list.add(n); } return joinNumbers(list); }
private static String joinNumbers(List<Integer> numbers) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < numbers.size(); i++) { if (i > 0) { sb.append(", "); } sb.append(numbers.get(i)); } return sb.toString(); }}Main
/** * 영화관 예매 시스템 (콘솔) * <p> * 사용 순서 : 1. 상영관 등록 -> 2. 상영일정(영화+시간) 등록 -> 3. 티켓 예매 * 자세한 사용법은 프로그램 실행 후 메인 메뉴 9번 또는 README.md 참고. */public class Main{ private static final int MAX_SCREENS = 5; private static final int MAX_TIMETABLES = 5; private static final int MAX_TICKETS = 10;
private static ScreenManager screenManager; private static TimetableManager timetableManager; private static TicketManager ticketManager;
public static void main(String[] args) { screenManager = new ScreenManager(MAX_SCREENS); timetableManager = new TimetableManager(MAX_TIMETABLES, screenManager); ticketManager = new TicketManager(MAX_TICKETS, timetableManager); screenManager.setTimetableManager(timetableManager); timetableManager.setTicketManager(ticketManager);
ConsoleUI.title("영화관 예매 시스템"); System.out.println(" 처음이라면 9번(사용 방법)을 확인하거나, 8번(샘플 데이터)으로 바로 체험해보세요.");
try { run(); } catch (InputClosedException e) { System.out.println(); ConsoleUI.info("입력이 종료되어 프로그램을 종료합니다."); } }
private static void run() { while (true) { printMainMenu(); int menu = ConsoleInput.readInt("메뉴 선택 >> ", 0, 9); try { switch (menu) { case 1: screenManager.screenManagerMain(); break; case 2: timetableManager.timetableManagerMain(); break; case 3: ticketManager.ticketManagerMain(); break; case 8: loadSampleData(); break; case 9: printHelp(); break; case 0: if (ConsoleInput.confirm("프로그램을 종료할까요? (입력한 데이터는 저장되지 않습니다)")) { ConsoleUI.info("이용해주셔서 감사합니다."); return; } break; default: ConsoleUI.error(menu + "번 메뉴는 없습니다. 목록에 있는 번호를 입력해주세요."); break; } } catch (InputClosedException e) { throw e; } catch (RuntimeException e) { // 예상하지 못한 버그가 있어도 프로그램 전체가 죽지 않도록 메인 메뉴로 복귀 ConsoleUI.error("예기치 못한 오류가 발생했습니다: " + e); ConsoleUI.info("메인 메뉴로 돌아갑니다. 입력한 데이터는 유지됩니다."); } } }
private static void printMainMenu() { ConsoleUI.title("메인 메뉴"); System.out.println(" 현재 상태 : 상영관 " + screenManager.getCount() + "/" + MAX_SCREENS + " 상영일정 " + timetableManager.getPos() + "/" + MAX_TIMETABLES + " 예매 " + ticketManager.getPos() + "/" + MAX_TICKETS); System.out.println(); System.out.println(" 1. 상영관 관리 (상영관 등록 / 목록 / 삭제)"); System.out.println(" 2. 상영일정 관리 (영화와 상영시간 등록 / 목록 / 삭제)"); System.out.println(" 3. 티켓 예매 (예매 / 예매 확인 / 예매 취소)"); System.out.println(" 8. 샘플 데이터 불러오기"); System.out.println(" 9. 사용 방법"); System.out.println(" 0. 종료"); System.out.println(); System.out.println(" " + nextStepHint()); }
/** 현재 상태에 맞춰 다음에 할 일을 안내 */ private static String nextStepHint() { if (screenManager.getCount() == 0) { return ">> 먼저 1번에서 상영관을 등록하세요. (또는 8번 샘플 데이터)"; } if (timetableManager.getPos() == 0) { return ">> 다음은 2번에서 상영할 영화와 시간을 등록하세요."; } if (ticketManager.getPos() == 0) { return ">> 3번에서 티켓을 예매할 수 있습니다."; } return ">> 3번에서 예매 확인/취소, 추가 예매를 할 수 있습니다."; }
private static void printHelp() { ConsoleUI.title("사용 방법"); String[] help = { "[사용 순서]", " 1) 상영관 관리 > 상영관 등록", " 상영관 이름과 좌석 배치(열 수, 한 열의 좌석 수)를 입력합니다.", " 2) 상영일정 관리 > 상영일정 등록", " 영화 정보(제목, 개봉일, 러닝타임, 등급)를 입력한 뒤", " 상영할 상영관과 시작시간을 지정합니다. 한 영화를 여러 상영관에 걸 수 있습니다.", " 3) 티켓 예매 > 예매하기", " 상영 회차를 번호로 고르고, 좌석 배치도를 보면서 열과 좌석을 선택합니다.", " 예매가 끝나면 예매번호(예: T10000)가 발급됩니다. 확인/취소할 때 필요합니다.", "", "[입력 방법]", " - 메뉴와 목록은 앞에 붙은 번호를 입력해 선택합니다.", " - 번호 선택 화면에서 0 을 입력하면 취소(또는 이전 단계)입니다.", " - 글자 입력 화면에서 아무것도 입력하지 않고 Enter 를 누르면 취소입니다.", " - 개봉일 : 2026-09-24 또는 20260924", " - 상영시간 : 24시간 형식, 공백으로 구분 예) 10:00 13:30 17:00", " - 좌석 번호 : 공백으로 구분하거나 범위로 입력 예) 3 4 5 또는 3-5", " - 예/아니오 : y 또는 n", "", "[규칙]", " - 상영관 1곳에는 영화 1편만 편성할 수 있습니다.", " - 같은 상영관의 회차끼리는 러닝타임만큼 간격이 있어야 합니다.", " - 한 번의 예매는 같은 열의 좌석만 선택할 수 있습니다.", " - 상영일정이 있는 상영관, 예매가 있는 상영일정은 삭제할 수 없습니다.", " (예매 취소 -> 상영일정 삭제 -> 상영관 삭제 순서로 지웁니다)", " - 최대 등록 수 : 상영관 " + MAX_SCREENS + "개, 상영일정 " + MAX_TIMETABLES + "개, 예매 " + MAX_TICKETS + "건", " - 데이터는 파일로 저장되지 않으며 프로그램을 종료하면 사라집니다.", "", "[좌석 배치도 기호]", " [ ] 예매 가능 [X] 예매 완료 [O] 지금 선택한 좌석", }; for (String line : help) { System.out.println(" " + line); } }
private static void loadSampleData() { ConsoleUI.section("샘플 데이터 불러오기"); if (screenManager.getCount() > 0 || timetableManager.getPos() > 0 || ticketManager.getPos() > 0) { ConsoleUI.error("이미 입력된 데이터가 있어 샘플 데이터를 불러올 수 없습니다."); ConsoleUI.info("샘플 데이터는 프로그램을 처음 실행했을 때(데이터가 비어 있을 때)만 불러올 수 있습니다."); return; }
Screen s1 = new Screen("1관", 5, 8); Screen s2 = new Screen("2관", 6, 10); Screen s3 = new Screen("3관", 4, 6); screenManager.addScreen(s1); screenManager.addScreen(s2); screenManager.addScreen(s3);
Movie m1 = new Movie("인터스텔라", "2014-11-06", 169, "12세이상관람가"); Movie m2 = new Movie("기생충", "2019-05-30", 132, "15세이상관람가"); Movie m3 = new Movie("인사이드 아웃 2", "2024-06-12", 96, "전체관람가"); timetableManager.addTimetable(new MovieTimetable(m1, s1, MovieTimetable.parseTimes("10:00 13:30 17:00", 169))); timetableManager.addTimetable(new MovieTimetable(m2, s2, MovieTimetable.parseTimes("11:00 14:00 19:30", 132))); timetableManager.addTimetable(new MovieTimetable(m3, s3, MovieTimetable.parseTimes("09:30 12:00", 96)));
ConsoleUI.success("상영관 3개, 영화 3편, 상영일정 3개를 불러왔습니다."); ConsoleUI.info("메인 메뉴 3번(티켓 예매)에서 바로 예매해볼 수 있습니다."); }} 공유하기
이 글이 도움이 되었다면 더 많은 분들께 공유해 주세요!
Java 영화관 예매 프로그램 완성본 소스코드
https://nirobase.me/posts/190517-java-movie-ticket-booking/ 일부 정보가 오래되었을 수 있습니다
관련 글 스마트 추천
1
scanner와 while를 이용한 구구단 출력
개발 2017-07-12
2
scanner와 for를 이용한 구구단 출력
개발 2017-07-12
3
GSC 크롤링 Bot 관련 오류
개발 사실 Google Search Console 문제가 아니라 내 문제였다. 크롤링 안될 때, 해결 방법
4
정보처리기사 자격증 합격 후기
개발 2026 정보처리기사 2회 자격증 합격 후기
5
Astro Blog 글 작성을 문서편집기 처럼 편하게. WYSIWYG With FrontMatter CMS
개발 Astro Blog 사용 시 Markdown 만으로 작성하는게 불편할 때 FrontMatter CMS 를 통해 Word 처럼 편리하게 작성하는 방법