한량처럼 살고 싶다

[이것이 코딩테스트다]게임 개발(C++) 본문

PS/이코테

[이것이 코딩테스트다]게임 개발(C++)

투영 2023. 1. 17. 17:01

https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=247882118

 

이것이 취업을 위한 코딩 테스트다 with 파이썬

IT 취준생이라면 누구나 가고 싶어 하는 카카오, 라인, 삼성전자의 2016년부터 2020년까지의 코딩 테스트와 알고리즘 대회의 기출문제를 엄선하여 수록하였다. 최근 5년간의 코딩 테스트 기출문제

www.aladin.co.kr

해당 도서의 구현 단원의 실전문제 3번 '게임 개발'을 풀이한다.

 

문제 조건

  • 현재 위치에서 현재 방향을 기준으로 왼쪽 방향부터 차례대로 갈 곳을 정함
  • 캐릭터의 바로 왼쪽 방향에 아직 안가본 칸이 존재할 경우, 회전 한 뒤 한 칸을 전진
  • 안가본 칸 없을 경우 회전만 하고 1단계로 돌아감
  • 네 방향이 모두 가본 칸이거나 바다면 바라보는 방향 유지한 채 한 칸 뒤로 간 뒤 1단계로 돌아감
  • 뒤쪽 방향이 바다라서 못가면 움직임 멈춤
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

int direction[4][2] = {
	{-1, 0}, //북쪽
	{0, 1}, //동쪽
	{1, 0}, //남쪽
	{0, -1} //서쪽
};

//왼쪽으로 돌기: 북 서 남 동

int N, M; //맵의 세로 크기, 가로 크기
int A, B, d; //입력받은 서있는 칸의 좌표 (A,B)와 방향 d
int na, nb;
int** gameMap;
bool** visit;

void input() {
	scanf("%d %d", &N, &M);
	gameMap = new int* [N];
	for (int i = 0; i < N; i++) gameMap[i] = new int[M];

	visit = new bool* [N];
	for (int i = 0; i < N; i++) visit[i] = new bool[M];

	scanf("%d %d %d", &A, &B, &d); //좌표와 방향
	visit[A][B] = true;

	for (int i = 0; i < N; i++) {
		for (int j = 0; j < M; j++) scanf("%d", &gameMap[i][j]);
	}
}

int turn_left() {
	d -= 1; //왼쪽으로 돌기
	if (d == -1) d = 3; //서쪽일 때 예외처리

	int tmpX = (A + direction[d][0]);
	int tmpY = (B + direction[d][1]);

	if (tmpX >= 0 && tmpX < N && tmpY >= 0 && tmpY < M) { //범위 체크 
		if (visit[tmpX][tmpY] == true) return 1; //방문한 곳이면 회전만 하고 끝
		else {
			if (gameMap[tmpX][tmpY] == 1) return 2;//방문안했는데 바다임
			if (gameMap[tmpX][tmpY] == 0) { //방문하지 않았고, 육지일 때는 전진
				A = tmpX;
				B = tmpY;
				visit[A][B] = true;
				return 3;
			}
		}
	}
	else return 4;
}

void solution() {
	int cnt = 1;
	int turn_cnt = 0;

	while (true) {
		int result = turn_left();
		if (result == 1 || result == 2 || result == 4) { //방문한 곳이거나 바다거나 못가면
			turn_cnt++;
		}

		if (result == 3) { //육지고 방문X한 곳이라 잘 방문했다면
			cnt++;
			turn_cnt = 0;
		}

		if (turn_cnt == 4) { //어느곳으로도 갈 수 없다면
			d++; //돌린 방향 원상복귀
			if (d == 4) d = 0;

			int tmpX = 0, tmpY = 0;
			if (d == 0) {
				tmpX = A + 1;
				tmpY = B;
			}
			if (d == 1) {
				tmpX = A;
				tmpY = B - 1;
			}
			if (d == 2) {
				tmpX = A - 1;
				tmpY = B;
			}
			if (d == 3) {
				tmpX = A;
				tmpY = B + 1;
			}

			if (tmpX < 0 || tmpX >= N || tmpY < 0 || tmpY >= M) break;
			else if (gameMap[tmpX][tmpY] == 1) break;
			else {
				A = tmpX;
				B = tmpY;
			}
		}

	}

	printf("%d", cnt);
}

int main() {
	input();
	solution();
}

🔽솔루션 도출 과정

1) 왼쪽으로 돌고 난 뒤 한 칸 앞으로 갔을 때의 좌표는 무조건 체크를 해야 하므로 turn_left 함수로 작성

2) turn_left(): 왼쪽으로 돌고 난 뒤 '바다거나/방문했거나/좌표가 넘어가면' 회전만 하고 끝내야 하므로 A와 B좌표를 처음부터 재설정 하지 않음

3) 모든 방향을 다 돌았다면 마찬가지로 방향체크, 좌표체크 후 while을 끝낼 지 말 지 결정

 

🔽참고 사항

❓구현 문제는 항상 내가 어려워하는 분야 중 하나

❗풀이의 모든 흐름을 잡을때까지 고민한 뒤 한번에 코드를 작성하는 습관때문에 생긴 문제같음. 구현 문제는 문제가 길고 복잡하기 때문에 하나하나 작성하면서 푸는게 더 잘 맞는 것 같다. (이번것도 그렇게 하니까 빠르게 풀었음)

 

❓회전과 지도 문제는 늘 접근법이 잘 안떠오름

❗여러 문제를 많이 풀어보자(다만 대부분의 풀이는 방향과 맵을 배열에 넣었을 때 풀리더라)