[우테코 프리코스] 6기 최종 코딩테스트 OnCall(개발자 비상근무) 문제 풀이-JS

osohyun0224·2024년 6월 8일
1
post-thumbnail

안녕하세요! 대학생 프론트엔드 개발자 오소현입니다~~

작년 10-11월을 생각하면 바로 우테코에 입학하기 위해 프리코스에 몰입했었는데요! (뭉클)

학교 공학관 동아리실에서 한 달동안 맨날 밤새면서 문제 풀었었는데 이제 다 추억이네요 ㅎㅎㅎ

결국 최종 코테도 못 가고 탈락했었지만 오랜만에 프리코스에서 출제되는 쌩 바닐라JS 문제를 풀어보고 싶어서작년 최종 코테 문제를 풀어보려고 합니다 :)

1. 기능 구현목록 작성하기

미션 - 개발자 비상근무 레포는 바로 여기에 있습니다 !

우테코 문제는 먼저 문제를 읽고, 구현하기 전 기능 구현 목록을 작성해야하기에 먼저 작성해보았습니다.

✨ 기능 구현 목록

1) 입력 관련 기능

  • 사용자에게 월과 시작 요일 입력 받기
  • 비상 근무를 배정할 월과 시작 요일을 입력 받기
    • 입력 예: 5,월
    • 유효한 월(1월 ~ 12월)과 요일(일, 월, 화, 수, 목, 금, 토)만을 허용
  • 평일 근무자 명단 입력 받기
    • 평일 비상 근무 순번대로 사원의 닉네임을 입력받는 기능
    • 입력 예: 준팍,도밥,고니,수아,루루,글로,솔로스타,우코,슬링키,참새,도리
  • 휴일 근무자 명단 입력 받기
  • 휴일 비상 근무 순번대로 사원의 닉네임을 입력받는 기능
    • 입력 예: 수아,루루,글로,솔로스타,우코,슬링키,참새,도리,준팍,도밥,고니

2) 비상 근무표 생성 기능

  • 비상 근무 일정 생성
    • 입력받은 정보를 기반으로 월별 비상 근무 일정을 생성하는 기능
  • 근무자 배정
    • 평일과 휴일에 따라 다른 근무자 명단에서 순차적으로 근무자를 배정하는 기능
  • 연속 근무 방지
    • 같은 근무자가 연속으로 근무하지 않도록 조정하는 기능

3) 출력 기능

  • 비상 근무표 출력
  • 생성된 비상 근무 일정을 월 일 요일 사원 형식으로 출력하는 기능
  • 법정 공휴일에는 요일 뒤에 (휴일)을 추가하여 표시하는 기능

🥅 예외 처리

1) 입력 유효성 검사

  • 월과 시작 요일이 유효한지 확인하는 기능

    • 월이 1~12의 숫자가 아닌 경우
    • 시작 요일이 월~일이 아닌 경우
  • 평일 및 휴일 근무자 명단에 중복 또는 유효하지 않은 입력이 있는지 검사하는 기능

    • 근무자의 닉네임이 5자 초과이거나, 중복되는 경우
    • 근무자의 인원수가 35명 초과인 경우

2) 입력 오류 메시지 출력

  • 입력 값이 유효하지 않을 경우 [ERROR] 유효하지 않은 입력 값입니다. 다시 입력해 주세요. 메시지를 출력하고 재입력을 요청하는 기능

✅ 테스트 코드 구현

입력 유효성 검사 기능에 대한 테스트 코드 작성

  • 월과 시작 요일 입력, 평일 및 휴일 근무자 명단 입력의 유효성 검사 관련 테스트 코드를 작성

비상 근무표 생성 로직에 대한 테스트 코드 작성

  • 근무 일정 생성 및 근무자 배정 로직의 정확성을 검증하는 테스트 코드 작성

🚨 고려해야할 사항

1) 공휴일 목록

  • 신정(1.1) / 삼일절(3.1) / 어린이날(5.5) / 현충일(6.6)
  • 광복절 (8.15) / 개천절 (10.3) / 한글날 (10.9) / 성탄절 (12.25)

2) 입력 고려 사항

  • 매년 2월은 28일까지만 있다고 가정합
  • 비상 근무를 배정할 월과 시작 요일의 입력 값이 올바르지 않은 경우,
    '비상 근무를 배정할 월과 시작 요일'부터 다시 입력받기
  • 평일과 휴일 순번의 입력 값이 올바르지 않을 때, '평일 순번'부터 다시 입력 받기

2. 미션 구현

1) 초기 필요한 변수 선언하기

import { MissionUtils } from '@woowacourse/mission-utils';

const holidayDates = {
    1: [1], 2: [], 3: [1], 4: [], 5: [5], 6: [6], 7: [],
    8: [15], 9: [], 10: [3, 9], 11: [], 12: [25]
};

const daysInMonth = {
    1: 31, 2: 28, 3: 31, 4: 30, 5: 31, 6: 30, 7: 31,
    8: 31, 9: 30, 10: 31, 11: 30, 12: 31
};

const weekDays = ['월', '화', '수', '목', '금', '토', '일'];

class App {
    currentIndices = [0, 0];
    weekdaySwapRegistry = {};
    weekendSwapRegistry = {};
}

휴일과 달 마다 마지막 날짜, 그리고 요일 변수를 선언해보았습니다.

2) 입력 기능 구현(월, 요일)

async requestMonthAndWeekday() {
    while (true) {
        try {
            const input = await MissionUtils.Console.readLineAsync('비상 근무를 배정할 월과 시작 요일을 입력하세요> ');
            return this.parseMonthAndWeekday(input);
        } catch (e) {
            MissionUtils.Console.print(e.message);
        }
    }
}

parseMonthAndWeekday(input) {
    if (input === '') {
        throw new Error('[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.');
    }
    let [month, weekday] = input.split(',').map(item => item.trim());
    month = Number(month);
    if (!this.isValidMonth(month) || !this.isValidWeekday(weekday)) {
        throw new Error('[ERROR] 유효하지 않은 날짜입니다. 다시 입력해 주세요.');
    }
    return [month, weekday];
}

isValidMonth(month) {
    return month >= 1 && month <= 12;
}

isValidWeekday(weekday) {
    return weekDays.includes(weekday);
}

사용자에게 월과 요일을 입력하는 기능을 구현한다.

3) 근무자 목록 입력받는 기능 구현

async requestWorkerLists() {
    try {
        const weekdayInput = await MissionUtils.Console.readLineAsync('평일 비상 근무 순번대로 사원 닉네임을 입력하세요> ');
        const weekendInput = await MissionUtils.Console.readLineAsync('휴일 비상 근무 순번대로 사원 닉네임을 입력하세요> ');
        return [this.parseWorkers(weekdayInput), this.parseWorkers(weekendInput)];
    } catch (e) {
        MissionUtils.Console.print(e.message);
        return this.requestWorkerLists();
    }
}

parseWorkers(input) {
    if (input === '') {
        throw new Error('[ERROR] 유효하지 않은 입력 값입니다. 다시 입력해 주세요.');
    }
    const workers = input.split(',').map(worker => worker.trim());
    if (!this.validateWorkers(workers)) {
        throw new Error('[ERROR] 유효하지 않은 입력 값입니다. 다시 입력해 주세요.');
    }
    return workers;
}

validateWorkers(workers) {
    const isUnique = new Set(workers).size === workers.length;
    const isProperLength = workers.every(worker => worker.length <= 5);
    const isValidCount = workers.length <= 35 && workers.length >= 5;
    return isUnique && isProperLength && isValidCount;
}

평일 비상 근무 > 휴일 비상 근무 순번대로 구현하고, 유효하지 않을 때를 고려해 주세요!
입력받을 때 검증하는 기능을 추가해주세요

4) 출력 기능 (근무 일정 출력)

displaySchedule(month, startDay) {
   const totalDays = daysInMonth[month];
   const startIndex = weekDays.indexOf(startDay);
   for (let i = 1; i <= totalDays; i++) {
       const dayOfWeek = weekDays[(startIndex + i - 1) % 7];
       const dayType = this.determineDayType(month, i, dayOfWeek);
       const worker = this.getNextWorker('', dayType);
       const dayLabel = dayType === 'Holiday' ? '(휴일)' : '';
       MissionUtils.Console.print(`${month}${i}${dayOfWeek}${dayLabel} ${worker}`);
   }
}

determineDayType(month, date, weekday) {
   if (['토', '일'].includes(weekday) || holidayDates[month].includes(date)) {
       return 'Holiday';
   }
   return 'Weekday';
}

getNextWorker(previousWorker, dayType) {
   const workers = dayType === 'Weekday' ? this.weekdayWorkers : this.weekendWorkers;
   let index = dayType === 'Weekend' ? this.currentIndices[1] : this.currentIndices[0];
   let worker = workers[index];
   if (worker === previousWorker) {
       index = (index + 1) % workers.length;
       worker = workers[index];
   }
   this.currentIndices[dayType === 'Weekend' ? 1 : 0] = (index + 1) % workers.length;
   return worker;
}

3. 실행 화면 (결과)

오랜만에 보는 테스트 성공 화면입니다 ㅎㅎ 엄청 뿌듯하네요

profile
Garden / Junior Frontend Developer

0개의 댓글