수강신청 프로그램
이번 학기 객체지향프로그래밍 강의의 중간 과제인 수강신청 프로그램 작성 코드입니다. 사용자로하여금 로그인 후 수강신청 및 수강철회등의 기능을 수행하게하고, 관리자로하여금 강의 개설 및 삭제를 수행할 수 있도록 하는 프로그램입니다. 터미널을 통해서 입력을 받고 파일에 수강생과 강의 정보를 저장 및 출력할 수 있는 기능을 포함합니다. 아래는 전체 시스템 설명도와 소스 코드이며 자세한 내용을 확인할 수 있습니다.
시스템 설명도
소스 코드
헤더파일과 cpp 파일을 따로 작성하지는 않았지만, 선언부와 구현부는 구분하여 작성하였습니다. 교수님께서 주신 Skeleton파일(뼈대)을 기반으로 작성했고, 정상 작동되는 코드입니다.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
// File read
void readStudentFile(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes);
void readLectureFile(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits);
// File write
void writeStudentFile(const vector<string>& studentIds, const vector<string>& passwords, const vector<string>& names, const vector<int>& credits, const vector<vector<string>>& appliedLectureCodes);
void writeLectureFile(const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, const vector<int>& limits);
// Get user input
string getInputId();
string getInputPassword();
// Login
int studentLogin(const vector<string>& studentIds, const vector<string>& passwords);
bool adminLogin();
int login(const vector<string>& studentIds, const vector<string>& passwords);
// Common
void printLectures(const vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, const vector<int>& limits, const int& user = -100);
// Admin
void addStudent(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes);
void addLecture(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits);
void deleteLecture(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits, vector<int>& credits, vector<vector<string>>& appliedLectureCodes);
int runAdmin(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits);
// User
void printStudent(const vector<string>& studentIds, const vector<string>& names, const vector<int>& credits, const int& user);
void applyLecture(const vector<string>& studentIds, const vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, vector<int>& limits, const int& user);
void disapplyLecture(const vector<string>& studentIds, const vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, vector<int>& limits, const int& user);
void changePassword(vector<string>& passwords, const int& user);
int runStudent(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits, int user);
int main() {
int user = -1; //user index
int status = -1;
// Student Info
vector<string> studentIds;
vector<string> passwords;
vector<string> names;
vector<int> credits;
vector<vector<string>> appliedLectureCodes;
// Lecture Info
vector<string> lectureCodes;
vector<string> lectureNames;
vector<int> lectureCredits;
vector<int> limits;
// Read from files
readStudentFile(studentIds, passwords, names, credits, appliedLectureCodes);
readLectureFile(lectureCodes, lectureNames, lectureCredits, limits);
// Login phase
while (status == -1) {
user = login(studentIds, passwords);
if (user == -999) { // Login fail
exit(-999);
}
else if (user == -1) { // Exit command
exit(-1);
}
else if (user == -100) { // Admin login success
status = runAdmin(studentIds, passwords, names, credits, appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits);
}
else { // Student login success
status = runStudent(studentIds, passwords, names, credits, appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits, user);
}
}
// Write to files
writeStudentFile(studentIds, passwords, names, credits, appliedLectureCodes);
writeLectureFile(lectureCodes, lectureNames, lectureCredits, limits);
return 0;
}
void readStudentFile(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes) {
ifstream ifsStudents("students.txt");
int lineN = 0;
string s;
while (getline(ifsStudents, s)) {
lineN++;
}
ifsStudents.close();
int lecN;
ifsStudents.open("students.txt");
for (int i = 0; i < lineN; i++) {
ifsStudents >> s;
studentIds.push_back(s);
ifsStudents >> s;
passwords.push_back(s);
ifsStudents >> s;
names.push_back(s);
ifsStudents >> s;
credits.push_back(stoi(s));
ifsStudents >> s;
lecN = stoi(s);
vector<string> v;
for (int j = 0; j < lecN; j++) {
ifsStudents >> s;
v.push_back(s);
}
appliedLectureCodes.push_back(v);
}
ifsStudents.close();
}
void readLectureFile(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits) {
ifstream ifsLectures("lectures.txt");
int lineN = 0;
string s;
while (getline(ifsLectures, s)) {
lineN++;
}
ifsLectures.close();
ifsLectures.open("lectures.txt");
for (int i = 0; i < lineN; i++) {
ifsLectures >> s;
lectureCodes.push_back(s);
ifsLectures >> s;
lectureNames.push_back(s);
ifsLectures >> s;
lectureCredits.push_back(stoi(s));
ifsLectures >> s;
limits.push_back(stoi(s));
}
ifsLectures.close();
}
void writeStudentFile(const vector<string>& studentIds, const vector<string>& passwords, const vector<string>& names, const vector<int>& credits, const vector<vector<string>>& appliedLectureCodes) {
ofstream ofsStudents("students.txt");
for (int i = 0; i < studentIds.size(); i++) {
ofsStudents << studentIds[i] << "\t";
ofsStudents << passwords[i] << "\t";
ofsStudents << names[i] << "\t";
ofsStudents << credits[i] << "\t";
ofsStudents << appliedLectureCodes[i].size() << "\t";
for (int j = 0; j < appliedLectureCodes[i].size(); j++) {
ofsStudents << appliedLectureCodes[i][j] << "\t";
}
ofsStudents << endl;
}
ofsStudents.close();
}
void writeLectureFile(const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, const vector<int>& limits) {
ofstream ofsLectures("lectures.txt");
for (int i = 0; i < lectureCodes.size(); i++) {
ofsLectures << lectureCodes[i] << "\t";
ofsLectures << lectureNames[i] << "\t";
ofsLectures << lectureCredits[i] << "\t";
ofsLectures << limits[i] << "\t";
ofsLectures << endl;
}
ofsLectures.close();
}
string getInputId() {
cout << "아이디: ";
string id;
cin >> id;
return id;
}
string getInputPassword() {
string pass;
cout << "비밀번호: ";
cin >> pass;
return pass;
}
int studentLogin(const vector<string>& studentIds, const vector<string>& passwords) {
int failCount = 0;
while (true) {
if (failCount == 3) {
cout << "3회 실패하여 종료합니다." << endl;
return -1;
}
string id = getInputId();
string pass = getInputPassword();
for (int i = 0; i < studentIds.size(); i++) {
if (id == studentIds[i])
if (pass == passwords[i])
return i;
}
failCount++;
cout << "로그인 " << failCount << "회 실패 (3회 실패시 종료)" << endl;
}
}
bool adminLogin() {
int failCount = 0;
while (true) {
if (failCount == 3) {
cout << "3회 실패하여 종료합니다." << endl;
system("PAUSE");
return -1;
}
string id = getInputId();
string pass = getInputPassword();
if (id == "admin" && pass == "admin")
return true;
failCount++;
cout << "로그인 " << failCount << "회 실패 (3회 실패시 종료)" << endl;
}
}
int login(const vector<string>& studentIds, const vector<string>& passwords) {
cout << "--------------------------------------------------------------------------------" << endl;
cout << "1. 학생 로그인" << endl;
cout << "2. 관리자 로그인" << endl;
cout << "0. 종료" << endl;
cout << "--------------------------------------------------------------------------------" << endl;
int stat;
cout << ">> ";
cin >> stat;
if (stat == 0)
return -1;
else if (stat == 1) {
int tmp = studentLogin(studentIds, passwords);
if (tmp == -1)
return -999;
return tmp;
}
else if (stat == 2) {
if (adminLogin())
return -100;
else
return -999;
}
else
return -999;
}
void printLectures(const vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, const vector<int>& limits, const int& user) {
cout << "--------------------------------------------------------------------------------" << endl;
cout << "과목코드\t강의명\t\t\t학점\t수강가능인원" << endl;
cout << "--------------------------------------------------------------------------------" << endl;
if (user == -100) {
for (int i = 0; i < (lectureCodes.size()); i++) {
cout << lectureCodes[i] << " " << lectureNames[i] << "\t\t " << lectureCredits[i] << "\t\t" << limits[i] << endl;
}
}
else {
for (auto selectedCode : appliedLectureCodes[user]) { //신청한 과목들에 대하여
//해당 과목의 index에 해당하는 과목들의 정보만 출력
for (int i = 0; i < lectureCodes.size(); i++) {
if (lectureCodes[i] == selectedCode)
cout << lectureCodes[i] << " " << lectureNames[i] << "\t\t " << lectureCredits[i] << "\t\t" << limits[i] << endl;
}
}
}
cout << "--------------------------------------------------------------------------------" << endl;
}
void addStudent(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes) {
string newId;
string newPass;
string newName;
bool isOverlap = false;
cout << "--------------------------------------------------------------------------------" << endl;
cout << "학번: ";
cin >> newId;
cout << "비밀번호: ";
cin >> newPass;
cout << "학생 이름: ";
cin >> newName;
cout << "--------------------------------------------------------------------------------" << endl;
// 이미 존재하는 학번인지 검사
for (auto id : studentIds)
if (id == newId)
isOverlap = true;
// 이미 존재하는 학번이라면,
if (isOverlap) {
cout << "이미 존재하는 학번입니다." << endl;
}
// 등록가능한 학번이라면,
else {
studentIds.push_back(newId);
passwords.push_back(newPass);
names.push_back(newName);
credits.push_back(18);
vector<string> v;
appliedLectureCodes.push_back(v);
cout << "성공적으로 등록되었습니다." << endl;
}
system("PAUSE");
}
void addLecture(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits) {
string newCode;
string newName;
int newCredit;
int newLimit;
bool isOverlap = false;
cout << "--------------------------------------------------------------------------------" << endl;
cout << "과목코드: ";
cin >> newCode;
cout << "과목명: ";
cin >> newName;
cout << "학점: ";
cin >> newCredit;
cout << "수강인원: ";
cin >> newLimit;
cout << "--------------------------------------------------------------------------------" << endl;
// 같은 과목코드의 과목이 존재하는지 확인
for (auto code : lectureCodes) {
if (newCode == code) {
isOverlap = true;
}
}
if (isOverlap) {
cout << "이미 존재하는 과목코드입니다." << endl;
}
else {
lectureCodes.push_back(newCode);
lectureNames.push_back(newName);
lectureCredits.push_back(newCredit);
limits.push_back(newLimit);
cout << "성공적으로 강의가 개설되었습니다." << endl;
}
system("PAUSE");
}
void deleteLecture(vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits, vector<int>& credits, vector<vector<string>>& appliedLectureCodes) {
while (true) {
printLectures(appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits);
string selectedCode;
cout << "삭제할 과목 코드(0: 뒤로가기) >> ";
cin >> selectedCode;
// 0 입력시 loop을 빠져나온다.
if (selectedCode == "0")
break;
// 선택한 과목코드에 해당하는 과목의 인덱스 가져오기
int lec_index = -1;
for (int i = 0; i < lectureCodes.size(); i++) {
if (lectureCodes[i] == selectedCode)
lec_index = i;
}
// 일치하는 코드가 없으면 다시 삭제할 과목 코드를 물음
if (lec_index == -1) {
cout << "일치하는 코드가 없습니다." << endl;
}
else { // 아니라면 1. 학생들 수강목록에서 삭제. 2. 학생들한테 학점 돌려줌, 3.해당 과목 삭제함
// 1. 학생들 수강목록에서 삭제
// 해당 과목을 수강중인 학생들을 찾는다.
for (int i = 0; i < appliedLectureCodes.size(); i++) { // 모든 학생들의 수강목록 중
bool isTarget = false;
for (int j = 0; j < appliedLectureCodes[i].size(); j++) {
if (appliedLectureCodes[i][j] == selectedCode)
isTarget = true; // 해당하는 학생의 index가 나오면 isTarget = true;
}
if (isTarget) { // 삭제하려는 강의를 수강하는 학생이 나오면,
vector<string> newAppliedLecture; // 교체될 새로운 벡터 선언
for (auto lecture : appliedLectureCodes[i])
if (lecture != selectedCode)
newAppliedLecture.push_back(lecture); // 삭제하려는 강의를 제외한 과목들을 추가해준다.
credits[i] += lectureCredits[lec_index]; // 2. 해당하는 학생들의 수강가능학점을 + 해줌
appliedLectureCodes[i] = newAppliedLecture; // 해당하는 학생들만 appliedLectureCode를 교체시켜줌.
}
}
// 3. 해당 과목 삭제 (해당 과목이 빠진 벡터로 대체)
vector<string> newCodes;
vector<string> newNames;
vector<int> newCredit;
vector<int> newLimit;
for (int i = 0; i < lectureCodes.size(); i++) {
if (i != lec_index) {
newCodes.push_back(lectureCodes[i]);
newNames.push_back(lectureNames[i]);
newCredit.push_back(lectureCredits[i]);
newLimit.push_back(limits[i]);
}
}
lectureCodes = newCodes;
lectureNames = newNames;
lectureCredits = newCredit;
limits = newLimit;
cout << "성공적으로 강의가 폐쇄되었습니다." << endl;
}
system("PAUSE");
}
}
int runAdmin(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits) {
while (true) {
cout << "--------------------------------------------------------------------------------" << endl;
cout << "1. 학생 추가" << endl;
cout << "2. 강의 개설" << endl;
cout << "3. 강의 삭제" << endl;
cout << "4. 로그아웃" << endl;
cout << "0. 종료" << endl;
cout << "--------------------------------------------------------------------------------" << endl;
int stat;
cout << ">> ";
cin >> stat;
if (stat == 1) {
addStudent(studentIds, passwords, names, credits, appliedLectureCodes);
}
else if (stat == 2) {
addLecture(lectureCodes, lectureNames, lectureCredits, limits);
}
else if (stat == 3) {
deleteLecture(lectureCodes, lectureNames, lectureCredits, limits, credits, appliedLectureCodes);
}
else if (stat == 4) {
return -1;
}
else if (stat == 0) {
return 1;
}
}
}
void printStudent(const vector<string>& studentIds, const vector<string>& names, const vector<int>& credits, const int& user) {
cout << "--------------------------------------------------------------------------------" << endl;
cout << "학번: " << studentIds[user] << "\t\t" << "이름: " << names[user] << "\t" << "수강가능학점: " << credits[user] << endl;
cout << "--------------------------------------------------------------------------------" << endl;
}
void applyLecture(const vector<string>& studentIds, const vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, vector<int>& limits, const int& user) {
while (true) {
printStudent(studentIds, names, credits, user);
printLectures(appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits);
string selectedCode;
bool isOverlapCode = false;
bool isOverlapName = false;
cout << "신청할 과목 코드(0: 뒤로가기) >> ";
cin >> selectedCode;
// 0 입력시 loop을 빠져나온다.
if (selectedCode == "0")
break;
//선택한 과목코드에 해당하는 과목의 인덱스 가져오기
int lec_index = -1;
for (int i = 0; i < lectureCodes.size(); i++) {
if (lectureCodes[i] == selectedCode)
lec_index = i;
}
//선택한 과목코드에 해당하는 과목이 없으면 처음으로 돌아간다.
if (lec_index == -1) {
continue;
}
//선택한 과목코드가 실제로 존재한다면 다음을 검사한다.
// 잔여 인원이 존재하는지 검사
if (limits[lec_index] == 0) {
cout << "수강인원이 모두 찼습니다." << endl;
system("PAUSE");
continue;
}
// 수강가능학점이 충분한지 검사
if (credits[user] < lectureCredits[lec_index]) {
cout << "수강가능학점이 부족합니다." << endl;;
system("PAUSE");
continue;
}
// 과목코드 중복 여부 검사
for (auto code : appliedLectureCodes[user]) {
if (selectedCode == code) {
isOverlapCode = true;
}
}
if (isOverlapCode) {
cout << "이미 동일한 코드의 과목을 신청했습니다." << endl;
system("PAUSE");
continue;
}
// 과목명 중복 여부 검사
for (auto myCode : appliedLectureCodes[user]) {
for (int i = 0; i < lectureCodes.size(); i++) {
if (myCode == lectureCodes[i]) {
if (lectureNames[i] == lectureNames[lec_index])
isOverlapName = true;
}
}
}
if (isOverlapName) {
cout << "이미 동일한 이름의 과목을 신청했습니다." << endl;
system("PAUSE");
continue;
}
// 검사 끝
// 강의 추가
appliedLectureCodes[user].push_back(lectureCodes[lec_index]);
// 수강가능인원 -1
limits[lec_index]--;
// 수강가능학점 차감 -credit
credits[user] -= lectureCredits[lec_index];
cout << "[" << selectedCode << "]" << " " << lectureNames[lec_index] << "(을)를 성공적으로 신청하였습니다." << endl;
system("PAUSE");
}
}
void disapplyLecture(const vector<string>& studentIds, const vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, const vector<string>& lectureCodes, const vector<string>& lectureNames, const vector<int>& lectureCredits, vector<int>& limits, const int& user) {
while (true) {
string selectedCode;
bool hasCode = false;
printStudent(studentIds, names, credits, user);
printLectures(appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits, user);
//////////////////////////////////////////////////////////////////////////////////////////////////수정///
cout << "철회할 과목 코드(0: 뒤로가기) >> ";
cin >> selectedCode;
//0을 입력하면 뒤로간다.
if (selectedCode == "0") {
break;
}
//선택한 과목코드가 존재하는지 검사한다.
for (auto data : appliedLectureCodes[user])
if (selectedCode == data)
hasCode = true;
//선택한 과목코드가 실제로 존재한다면 해당 코드를 삭제한다. + 해당 과목의 잔여인원 +1, 학점 +credit
if (hasCode) {
//선택한 과목코드의 index를 가져온다.
int lec_index = -1;
for (int i = 0; i < lectureCodes.size(); i++) {
if (lectureCodes[i] == selectedCode)
lec_index = i;
}
vector<string> newCodes;
for (auto data : appliedLectureCodes[user]) // selectedCode를 제외한 data를 새로운 벡터에 추가한다.
if (selectedCode != data)
newCodes.push_back(data);
appliedLectureCodes[user] = newCodes;
credits[user] += lectureCredits[lec_index]; // 해당 학생의 수강가능학점을 되돌려준다.
limits[lec_index]++; // 해당 과목의 수강잔여인원을 1 늘려준다.
cout << "[" << selectedCode << "]" << " " << lectureNames[lec_index] << "(을)를 철회했습니다." << endl;
system("PAUSE");
}
else {
cout << "과목코드가 올바르지 않습니다." << endl;
system("PAUSE");
}
}
}
void changePassword(vector<string>& passwords, const int& user) {
while (true) {
string myPass;
cout << "--------------------------------------------------------------------------------" << endl;
cout << "본인 확인을 위해 비밀번호를 한 번 더 입력해주세요." << endl;
cout << "비밀번호: ";
cin >> myPass;
cout << "--------------------------------------------------------------------------------" << endl;
if (myPass == passwords[user]) {
string newPass;
cout << "--------------------------------------------------------------------------------" << endl;
cout << "새로 설정할 비밀번호를 입력하세요." << endl;
cout << "비밀번호: ";
cin >> newPass;
passwords[user] = newPass;
cout << "변경되었습니다." << endl;
cout << "--------------------------------------------------------------------------------" << endl;
system("PAUSE");
break;
}
else {
cout << "비밀번호가 일치하지 않습니다." << endl;
system("PAUSE");
}
}
}
int runStudent(vector<string>& studentIds, vector<string>& passwords, vector<string>& names, vector<int>& credits, vector<vector<string>>& appliedLectureCodes, vector<string>& lectureCodes, vector<string>& lectureNames, vector<int>& lectureCredits, vector<int>& limits, int user) {
while (true) {
cout << "--------------------------------------------------------------------------------" << endl;
cout << "1. 수강 신청" << endl;
cout << "2. 수강 현황" << endl;
cout << "3. 수강 철회" << endl;
cout << "4. 비밀번호 변경" << endl;
cout << "5. 로그아웃" << endl;
cout << "0. 종료" << endl;
cout << "--------------------------------------------------------------------------------" << endl;
int stat;
cout << ">> ";
cin >> stat;
if (stat == 1) {
applyLecture(studentIds, names, credits, appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits, user);
}
else if (stat == 2) {
printStudent(studentIds, names, credits, user);
printLectures(appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits, user);
system("PAUSE");
}
else if (stat == 3) {
disapplyLecture(studentIds, names, credits, appliedLectureCodes, lectureCodes, lectureNames, lectureCredits, limits, user);
}
else if (stat == 4) {
changePassword(passwords, user);
}
else if (stat == 5) {
return -1;
}
else if (stat == 0) {
return 1;
}
/* 내부 호출 함수: applyLecture, printStudent, printLectures, disapplyLecture, changePassword*/
}
}
짧다고 하면 짧은 길이의 프로그램이지만 개인적으로는 지금까지 공부하며 작성했던 프로그램 중 가장 길이가 긴 프로그램이었습니다. 과제를 준비하며 플로우차트와 다이어그램에 대한 기본적인 이해와 더불어 함수를 기능에 따라 나누는 것에 익숙해질 수 있었습니다. 아무튼 좋은 경험이었네요.