새로운 게임2

입력받을 때, 4번째 줄 StringTokenizer에서 NoSuchElementException 발생하는 이유 : j-for문 없이 공백문자로 구분되는 st.nextToken자체가 x,y,dir이다. 그런데 아래 코드에서는 공백문자로 쪼개는 것을 그것을 3번만 반복하도록 하는 것 같다?

for(int i=1;i<=K;i++) {
			st = new StringTokenizer(br.readLine());
			for(int j=0;j<3;j++) {
				int x = Integer.parseInt(st.nextToken())-1;
				int y = Integer.parseInt(st.nextToken())-1;
				int dir = Integer.parseInt(st.nextToken())-1;
				if(dir==1) dir = 2;
				else if(dir==2) dir = 1;
				
				Horses[HCnt++] = new Horse(i,x,y,dir);
			}
		}

정답 코드 : j-for문 삭제.

for(int i=1;i<=K;i++) {
			st = new StringTokenizer(br.readLine());
			int x = Integer.parseInt(st.nextToken())-1;
			int y = Integer.parseInt(st.nextToken())-1;
			int dir = Integer.parseInt(st.nextToken())-1;
			if(dir==1) dir = 2;
			else if(dir==2) dir = 1;
				
			Horses[HCnt++] = new Horse(i,x,y,dir);
			
}

문제 푸는 방법은 맞았다. 각 케이스별로 조건 처리하는 부분도 어느 정도 맞는 듯하다. 2차원 배열 상의 컬렉션과 클래스 모두 업데이트하는 것도 GOOD✅👍🏻 하지만, 틀린 이유는 꼼꼼하게 정확하게 구현해내는 것이 부족하다. =>나와 가장 유사하게 문제 풀어낸 코드를 참고해서 내 코드의 어느 부분이 구현이 부족한지 간파!

리스트에서 정수 찾을 때, indexOf(k) 하면 숫자 k의 인덱스 바로 리턴해준다!

정답 솔루션

  • 실행 흐름 순 메서드 (Bold체는 객체 또는 리스트를 의미) ① game() ② move(i) ③ actionByColor(cur,nx,ny) ④ updateList(hId,nx,ny) ⑤ removeHorses(list,top,bottom) // top=size-1, bottom=idx

  • boolean move(int i) 메서드 분석⭐️⭐️⭐️⭐️ ⭐️i번째 말을 조건 검사&이동시키고, 이동 후에 게임 종료하는지 boolean 값을 리턴한다. ⭐️(맵 벗어나거나 파란색인 경우, 한번더 이동한 칸에 대해 조건 검사&이동 처리)

    ① i번째 말 조회, (nx,ny) 계산 ② 맵 벗어나거나 파란색인 경우 ③ 맵 벗어나지 않고 파란색 아닌 경우 =>③은 처음에 ①에서 이동한 (nx,ny)와 ②에서 (한번 더) 이동한 (nx,ny) 모두 해당하는 공통로직. 따라서, 순서를 제일 마지막에 위치시킴으로써 공통처리가 가능하다!!!! (②에서 방향 전ㄴ환 후 그 방향으로 1칸 더 이동해야하기 때문에 조건 검사&이동하는 로직인 ③을 수행해야하는 것이다.) ④ ③에서 조건 검사&이동 처리한 후, 게임 종료 조건 검사한 후 게임을 종료하는 조건에 해당하면 true를, 게임을 계속해야하는 경우 false를 리턴한다!

  • void actionByColor(cur,nx,ny) 메서드 분석 1. 이동 전 밑 작업(미리 조회해놓기) ① 2차원 객체 배열에서 현재 위치(cur.x,cur.y)의 리스트와 이동할 위치(nx,ny)의 리스트를 조회 ② 이동할 말의 번호로 현재 위치 리스트 from에서 인덱스 조회 // from.indexOf(cur.id) ③ 현재 위치 리스트, 이동할 위치 리스트 크기 조회 2. switch-case문으로 이동할 칸(nx,ny)의 색(=Map[nx][ny])에 따라 로직 구현 ④ 흰칸인 경우 : 현재 옮기려는 말의 인덱스 idx부터 끝까지 하나식 (nx,ny)로 이동 ⑤ 빨간칸인 경우 : ④와 동일. 순서만 반대. 끝에서부터 idx까지 하나씩 이동

    2-1. 이동 매커니즘(이동마다 갱신해야하는 것) ① 객체 배열 ② 2차원 객체 배열 : 이동 후 위치에 추가, 이동 전 위치에서 삭제 => 코드는 현실 세계와 반대이기 때문에 먼저 추가해주고, 현재 위치에서 삭제시켜야한다. + 코드를 간결하게 하기 위해, 리스트에 추가/삭제하는 것은 따로 메서드로 구현해도 좋다.

2번째 풀었을 때 틀린 이유

  1. 말 이동할 때, idx부터 끝까지 현재 리스트에서 말 추가하고, 삭제할 때 추가하는 것은 for문의 반복변수로 추가하고, 삭제는 메서드로 따로 구현해서 idx부터 끝까지 삭제 처리하는데 삭제 메서드를 for문 안에서 호출&실행을 해버리면 당연히 index 초과 에러난다. 메서드로 따로 빼지 않고 for문 안에서 추가, 삭제, 추가, 삭제,... 이렇게 하는 거면 상관 없지만, 추가하는 것만 for문으로 하나씩 차례로 하고, 삭제하는 것은 메서드로 따로 할 거라면 for문 밖에 빼야지!!!!

  2. 리스트 삭제 메서드 개선 : 리스트 삭제 메서드를 호출하는 코드 흐름에서 이미 from리스트를 가지고 있기 때문에 이 리스트에서 요소를 삭제하는 것이므로, 메서드의 매개변수로 from 리스트를 넣어주면 메서드 내에서는 해당 리스트에서 바로 삭제 연산만 하면 된다. 현재 코드에서는 말의 인덱스로 객체 배열에서 조회한후, 객체의 좌표로 리스트에 접근하는데, 리스트를 바로 넣어주면 추가적인 조회 필요 없이 바로 삭제만 하면 된다!!

//리스트 삭제 메서드
	static void removeHorse(int HId,int idx,int size) {//idx부터 size-1까지 삭제
		Horse cur = Horses[HId];
		for(int i=idx;i<size;i++) {
			HorseMap[cur.x][cur.y].remove(i);
		}
		return;
	}

리팩토링

//리스트 삭제 메서드
	static void removeHorse(LinkedList<Integer> from,int idx,int size) {//idx부터 size-1까지 삭제
		for(int i=idx;i<size;i++) {
			from.remove(i);
		}
		return;
	}

3. 객체 배열 갱신 메서드 개선 : 말의 번호를 매개변수로 넣어주기 때문에 객체 변수를 따로 생성하지 않고 바로 객체 배열에 접근하여 속성값 위치좌표를 갱신할 수 있다! 2-step으로 하지말고, 1-step으로 한번에 하자!

//객체 배열 갱신 메서드
	static void updateHorses(int HId,int nx,int ny) {//현재 객체 배열에서 말 객체의 좌표 갱신!
		Horse cur = Horses[HId];
		cur.x = nx; cur.y = ny;
	}
//객체 배열 갱신 메서드
	static void updateHorses(int HId,int nx,int ny) {//현재 객체 배열에서 말 객체의 좌표 갱신!
		Horses[HId].x = nx;
		Horses[HId].y = ny;
	}

switch-case문 문법 switch {//괄호로 시작 case 값 ://실행문 다음에 꼭 break; 넣어줘야함!

Last updated