지하철

권재현·2021년 4월 4일
0

문제풀이

목록 보기
5/8
post-thumbnail

희두형이 말한대로 내가 진짜 엄청 디테일하게 설명해가면서 해볼 예정이다. 한번 뜯어보자
선생님 주신 문제 지하철은 아래 와 같다.

지금 풀이는 내가 푼게 아닌 선생님의 코드를 분석해보는 글이다.

  1. 역은 장승배기, 연신내, 강남, 양재, 평택 으로 총 5역이다.
  2. 지하철의 차량 총 4대이고, 각 탑승정원은 4명까지다.
  3. 탑승 시 목적지 지정, 목적지 도착 시 자동하차
  4. 이동 시 역마다 정차

내가 생각한 필요한 기능은

탑승 시 : 어느 호차에 탈건지, 각 호차에 빈자리 체크, 탑승 시 목적지 설정

이동 시 : 이동을 어떻게 할건지, 목적지 도착시 내리기, 하차 한 사람 반영해 빈자리 변경

상태 : 목적지 확인,각호수 정원확인

public class SubwayServiceMy {
	String[] station = {"장승백이","연신내","강남","양재","평택"};
	int now = 0; //현재 위치
	// 인덱스 값에 절대 나올 수 없는 숫자 -1, 지하철에서 -1은 비어있는 숫자다.
	int [][] trail = {{-1, -1, -1, -1}, //1호차
			 {-1, -1, -1, -1}, //2호차
			 {-1, -1, -1, -1}, //3호차
			 {-1, -1, -1, -1}}; //4호차
	int pos = -1; //방향 전환을 위한 변수
	Scanner sc = new Scanner(System.in);
    

  위에 코드를 먼저 보면 선생님은 station이라는 배열은 생성했다. 배열을 사용하신 이유는 내가 해석 하자면 역들은 고정적으로 정해진 값이기 때문에 사용한 것을 보인다.   변수 now는 이동 후 하차 할때 now와 목적지로 설정한 값이 같다면 하차되고 다르면 자동으로 하차를 안한다. 그래서 만든 것 같다.

 선생님은 지하철을 2차원배열을 사용하셨다. 첫번째 배열은 각 지하철 호수가 되고, 다음은 호수의 자리 수를 나타낸다. -1은 빈자리을 의미한다. 선생님이 말씀하시길 -1을 사용한 이유는 일단 절대 나올 수 없는 이고,만약 -1이나 양수을 사용하게 되면 정원이 4명이 아닌 증가가 되면 수정이 불가피해진다. 밑에 pos는 아직까지 왜 사용하는 지 불분명하지만, 나중에 방향전환을 위한 키가 되는 변수이다. 그리고 스캐너는 입력을 받기 위해 무조건 사용해야하는클래스다.

run 메소드

public void run() {
	boolean flag =true;
		
	while (flag) {
		System.out.println("=================================");
		System.out.println("현재역은"+ station[now]+ "입니다.");
		System.out.println("=================================");
		System.out.println("메뉴를 선택하세요.");
		System.out.println("1.탑승 2.상세보기 3.이동 9.종료");
			
	switch(sc.nextLine()) {
		case "1" : join(); //탑승
					break;
		case "2" : status(); //상세보기
					break;
		case "3" : move(); //이동
					break;
		case "9" : flag = false;
			System.out.println("열차운행을 종료합니다."); //종료
					break;
			default : System.out.println("잘못입력하셨습니다.");
			}
		}

​ 처음 쓴 코드는 지하철에 필요한 변수들을 만든 곳이고, 여기는 이제 본격적인 실행을 위한 로직이 쓰여진다. 메소드 이름을 보면 알 수 있다. 바로 run이다. flag 변수는 반복문인 while문 조건문을 위해 사용되고, while문 종료 시 값을 false로 초기화 해줘야한다.

switch문은 입력값을 받아서 각각의 이제 우리가 만든 메소드로 실행되게 해준다. 꼭 연속 실행이 발생되지 않게, break문을 까먹지 말자!!

case 9를 보면 종료 할 수 있게 flag=false 초기화를 확인할 수 있다. 마지막으로 default는 case로 지정한 입력 값 외에 나올 시 실행되는 것이다.

빈자리 개수 카운트 하는 메소드

//checkTrail은 빈자리 개수
	public int checkTrail(int num) {
		int cnt = 0;
				
		for(int target : trail[num]) {
		if(target == -1) { //-1 카운트, 즉 빈자리 개수 카운트
				cnt++;
				}
			}
			return cnt;
		}

 제일 밑에 있지만, 사실 checkTrail 메소드 없이는 다른코드가 설명이 안되고, 이해가 어렵다. 그래서 설명이 먼저 필요한 메소드라고 판단해 갖고왔다. 코드를 분석해보면 빈자리 개수를 체크해, int타입으로 선언되고 인자값으로도 int를 받는다. 카운트를 세기위해 cnt변수가 선언 됐다.

​  for문을 설명하면 trail[num]은 각 호수를 말한다. 그래서 각 호수의 값이 target 변수로 초기화 되고, if문에서 초기화된 값이 -1 과 같다면 cnt가 1씩 증가된다. FYI 지만 -1은 처음에 지하철 배열을 만들때 -1로 빈자리를 표시했다. 즉, if문은 호수 마다 빈자리가 얼마나 있나 확인 하는 작업니다. 마지막으로 메소드에 void가 없기에 return으로 cnt(int형)을 돌려준다.

join메소드

탑승에 필요한 기능을 정의한 메소드다. 위에서 내가 생각한 기능이 들어가 있는 지 확인하고, 추가적으로 필요했지만 내가 생각하지 못했던 기능이 있나 살펴보자. 탑승 메소드가 길어서 아주 잘게 분해해서 살펴 볼 예정이다.

public void join() {
	int imp = 0;  //빈자리가 없는 개수
	System.out.println("-----탑승 가능 현황-----");
	//trail.length는 1차원 배열 trail 길이 4칸이다.
	for(int i = 0; i < trail.length; i++) {
		System.out.print((i + 1) + "호차 : ");
		if(checkTrail(i) > 0) { 
    //빈자리 >0 즉, 빈자리가 있다는 얘기,각 호차별로 확인 후 cnt으로 값을 돌려줌
		System.out.println("가능");
		} else {
			System.out.println("불가능");
			imp++; //빈자리가 없을 때  1씩 올라간다.
			}
		}

  맨 위에 선언된 imp변수는 호수에 탑승해 있는 사람 수를 나타낸다. for문 조건식에서 trail.length는 4이다. 조건식이 0부터 3까지이고, 호차에 대한 프린트는 1호차 부터라서 +1을 해줬다. if문을 살펴보면 빈자리 개수를 확인하는 checkTrail 메소드가 0보다 크면 조건 성립이다. 이말은 checkTrail 메소드에서 리턴하는 cnt 값이 0보다 크면 조건 성립이다. -1이 있으면 cnt가 증가하니까 빈자리 있다면 조건이 성립된다. 여기서 if문은 탑승하기전 먼저 호차별로 빈자리를 확인해 탑승이 가능한지 불가능한지 알려준다.

//imp 와 trail.length길이 같다는 뜻은 4==4란 뜻인데
//자리가 4자리이기때문에 빈자리가 없다는 말이다.
	if(imp == trail.length) { 
	//빈자리없는 개수 == 지하철 자리 4칸 즉, 빈자리가 없다. 
		System.out.println("탑승가능 열차가 없습니다.");
		} else { //빈자리가 비어있는 경우
			System.out.println("어느 열차에 탑승하시겠습니까?");
			
		for(int i = 0; i < trail.length; i++) {
			System.out.print((i+1)+ "."+ (i+1)+ "호차");
		}
		System.out.println(); //띄어쓰기

 아까 맨처음 선언된 imp변수가 if문에 trail.length 같다면 조건 성립인데 풀어서 설명하면 imp는 탑승해 있는 손님 수, 그리고 각 호수의 지하철 길이 4이다.
 즉, 손님수==4라는 뜻은 지하철 호수에 빈자리가 없다는 뜻이다. 그래서 프린트문도 System.out.println("탑승가능 열차가 없습니다."); else문은 빈자리가 있는 조건이 성립되기에 System.out.println("어느 열차에 탑승하시겠습니까?");라고 써있다. 밑에 for문은 입력 값을 받기위한 화면에 호차별로 보기를 보여주는 반복문이다.

지하철 호차 입력값

String input = sc.nextLine();
	int t = Integer.parseInt(input) -1; 
   //지하철호차 도 0부터 시작하기 때문에 -1해줘야 내가 원하는 호차 선택가능 
	if(checkTrail(t)> 0) { //빈자리개수 >0  
		System.out.println("목적지를 선택해 주세요");
           // 장승백이 = 0, 연신내 = 1, 강남 = 2, 역삼 = 3, 평택 = 4
		for(int i = 0; i <station.length; i++) {
			if(now != i) { 
       //현재위치와 목적지가 다르면 조건 성립, 같은 위치면 조건문이 false이다.
			System.out.print((i+1) + "." + station[i]+ " ");
					}
				}

 이제 드디어 입력 값을 받는 부분이 나왔다. 위에서 호차별로 탑승가능한 자리를 체크해서 이제 탑승 할 호차을 입력값을 통해 결정한다. 호차를 결정했으면, 이제 위에 조건 중 하나인 탑승 시 목적지 지정하는 부분이 나온다. 내가 혼자 문제를 풀었을 때 다른 부분도 어려웠지만, 특히 이부분이 정말 어려웠다. 잘 살펴봐보자!!

  if문의 조건이 now != i 을 설명하면, now는 현재위치이고, i 값은 0부터 4까지 증가하는데, 사실 이 부문을 이해하기 위해서 밑에 지하철의 이동 메소드를 봐야 이해 할 수 있는데, 일단 내가 간략히 설명하자면 now와 i의 값이 같지 않다는 말은 현재위치가 목적지 다르면 성립한다. 만약 현재위치가 0이고, i의 값이 0이라면 조건 성립이 안된다. 그래서 실행하면 자연스럽게 선택할때 자기가 현재 위치한 역은 보기에 없다.

목적지 입력 값

System.out.println();
	String input2 = sc.nextLine(); //목적지 설정
	int s = Integer.parseInt(input2)-1; 
    	//목적지 인덱스 값 0부터시작해서 -1
				
	if(s == now) {
		System.out.println("목적지로 현재역은 안됩니다.");
			} else {
		for(int i= 0; i < trail[t].length; i++) {
			if(trail[t][i] == -1) {//호차의 빈자리 체크
				trail[t][i] = s;
			break; //한번에 한명씩 탑승 break;를 걸어줘야한다.
					}
				}
			}
		} else {//if문의 반대문
			System.out.println("탑승이 불가합니다.");
			}
		}
		
	}

 드디어 목적지를 입력값으로 받는 부분이 나왔다. 먼저 if문은 보면 s==now라는조건은 s가 목적지 변수인데 현재위치 변수인 now 같다는 말은 현재위치가 목적지이기 때문에 안된다. else문을 보자면 조건식이 위에 for문들의 조건식 보다 한가지가 다르다. 바로 위에서 입력값으로 받은 호차 번호의 길이가 지정된다. 왜냐하면 호차를 지정한 순간 그 호차만 빈자리가 있는 지 확인하면된다.

 if문의 조건은 선택한 호차의 각자리가 비었는지 확인 하는 작업이다. 그래서 -1이 다시 등장한다. 조건식이 성립 된다면, 빈자리를 앞 부터 채우고, -1의 숫자를 드디어 우리가 목적지로 입력한 값으로 초기화를 해준다. 그리고 밑에 break; 가 사용됐는데, 이유는 탑승은 한명씩만 가능해서 사용됐다. 만약 break를 사용 안하면, 한번 호차에 다 탑승하는 상황이 생긴다.

상태

public void status() {
	System.out.println("------열차현황------");
		//1호차 = 0 2호차 = 1 3호차 = 2 4호차 = 3 
		for(int i= 0; i < trail.length; i++) {
		System.out.println((i+1) + "호차 : ");
		for(int j : trail[i]) {//목적지 표시
		if(j > -1) {
      // 장승백이 = 0, 연신내 = 1, 강남 = 2, 역삼 = 3, 평택 = 4.
		System.out.print("["+ station[j] + "]");
					}
				}
				System.out.println();
			}

첫번 째 for문은 i가 0부터 3까지 돌고 출력문은 i + 1를 통해 1호차부터 4호차까지 출력이된다. 두번 째 for문은 지하철에 탑승한 승객의 목적지표시를 위해 쓰인다. 일단 순차적으로 담긴 데이터 trail[i] 여기서 i는 각 호차를 출력한다.i = 0 일 때 trail[0] 즉, 1호차안에 있는 값들이 순차적으로 int j 을 초기화한다. 밑에 if문에 조건식이 j > -1 의미는 목적지가 있는 승객은 최소 값이 0부터 시작한다. 그래서 -1 보다는 크다는 빈자리가는 아닌 자리가 있는 승객이고, 그 목적지를 station[j] 으로 표시해준다.

이동

public void move() {
				
	if(now == station.length -1 || now ==0) {
		pos*= -1; // now 0일때 pos는 -1  곱한결과 1
				}	
          // now 4일때 pos는 1 그래서 곱한결과 -1
				
		now += pos;
	//장승백이 =0 연신내 =1 강남=2 양재 =3 평택=4
	int cnt = 0; //하차 수 카운트
	for(int i = 0; i< trail.length; i++) {//각 호차
		for(int j =0; j < trail[i].length; j++) {
            		//호차별 자리 
			if(trail[i][j] == now) {
				cnt++; 
                //배열속의 값이 역의 인덱스 값과 같으면 하차
				trail[i][j] = -1; //내려서 다시 빈자리 -1
					}
				}
			}
				
			if(cnt > 0) {
			System.out.println(cnt + "명이 하차하였습니다.");
				}
			}

 마지막 이동 메소드다. 드디어 맨위에서 작성한 변수 pos가 사용된다. 바로 방향 전환을 위해 !! 일단 if문을 살펴 보면, now == station.length -1은 4를 의미하고,마지막역 평택의 인덱스 값이 4다. 0은 장승백이를 의미한다. 그리고 if 문 안에 || 논리합이 사용됐는데, or 의 의미다. 둘 중 하나만 조건이 맞으면 ture다. 위치가 0 이거나 4이면 조건식이 true가 된다. pos =-1은 처음 시작위치에서 pos는 우리가 -1로 선언 해놨고, 역들의 인덱스 값이 0,1,2,3,4 이니 1씩 증가한다. -1 -1 은 1이다. 즉,now + =1 이고, now 는 더해지면서 값이 초기화된다. 반대로 now위치가 4일때는 다시 if문 조건이 성립해 pos=-1 발동되는데, pos의 값이 1 이다. 그래서 1 -1= -1로 pos값이 -1로 초기화된다. 그래서 풀이하면 4 +(-1) = now 값이 되 1씩 감소해 다시 장승백이 까지 갈 수 있다.

 for문들은 역에 도착할 때마다 각호수 별로 if 문을 통해 목적지를 체크한다. 예를 들어 trail [1][0] 면 1호차의 1번째 자리을 뜻하고, now을 통해서 현재 위치한 역의 인덱스 값과 같은면 하차를 하게된다. 위에 목적지 입력 값에서 초기화를 시켜놨기에 -1이 아닌 목적지 인덱스 값을 갖고있다. cnt는 하차한 승객의 수를 체크 하고 프린트 문으로 출력해서 보여주고, 하차한 승객의 자리는 빈자리를 의미하는 -1로다시 초기화 작업도 잊지 말아야한다.

실행 클래스

public class SubwayController {

	public static void main(String[] args) {
		SubwayService ss = new SubwayService(); 
        //객체생성,ss는 주소값만 품고 있다.
		System.out.println("---- Welcome Subway ----");
		
		ss.run(); //메소드 실행
	}

}

 지하철에 필요한 기능을 입력했던 메소드 클래스을 SubWayService ss = new SubwayService( ); 로 객체 생성을 해준다.

 다음 SubwayService의 주소값을 품고 있는 ss가 join,status,move 메소드를 품고있는 run 메소드 호출해 실행 시킨다.

종합

내가 생각했던 필요한 기능은 역시 선생님은 다 만드셨고, 적절히 활용하셨다. 그리고 운이 좋게 내가 생각하지 못한 기능은 없었다.
그래도 확실히 이렇게 세세하게 뜯어서 설명하듯이 하니까 조금 더 지하철에 파악이 잘된 것 같아 좋은 것 같다.
오늘 시험인데,, 일단 최선을 다해서 시험을 보자!!

profile
호텔리어 출신 비전공자

0개의 댓글