[Algo 풀자] <이것이 코딩테스트다>Part2.ch4 "게임개발"(python)

KIM 쥬얼리 (vs0610)·2020년 12월 30일
1
post-thumbnail

💁🏻‍♂️ 문제풀이 시리즈를 시작하며

개발 블로그를 시작한 지 채 한달도 지나지 않았는데 벌써 시리즈를 4개나 만들었다.(일을 벌이고만 있다.) 사실 지금은 글의 개수가 시리즈의 개수와 동일하다.🤭 시리즈 하나에 한개의 포스트 밖에 없다. 앞으로는 시리즈 개수를 늘리기 보다는 시리즈의 포스팅의 양을 늘리는데 조금 더 치중을 해보려고 한다.

얼마 전 주변 아는 착한 형님☀️이 블로그 정기 구독 서비스를 알려주었고 그런 좋은 서비스가 있다니 감탄하며 바로 서비스를 신청하였다. <블로그 구독 서비스 링크> 매일 아침 10시 조금 넘어서 최근에 올라온 읽어보면 좋을 블로그 글들을 추려서 메일로 보내준다. 나는 그 서비스가 마음에 들었고 새로운 습관이 생겼다.

아침 일과를 시작하기 전에 블로그를 읽어보는 습관이 생겼는데 처음 블로그를 읽으면서 가졌던 목표는 이분들처럼 블로그에 글을 잘 쓰고 싶다 였고 최대한 배우려는 마음으로 블로그를 읽었다. 하지만 아직 글을 쓰는 경험이 부족한 탓인지 그 매력적인 글들과 무의식적으로 비교하다보니 가벼운 글도 시작하기가 망설여진다.

하지만 망설임을 딛고 천천히 그리고 세심하게 글을 작성해보려고 한다. 문제풀이는 여기 계신 분들(SW 사관학교 정글)도 그렇고 블로그 구독 서비스에서도 간간이 문제 풀이를 올리는 분들이 의외로 많아서 따라해보고자 시작하게 되었다. 분명 자신이 풀었던 문제를 공유하고 피드백도 받고 한번 더 글로 작성함으로써 더 명확히 개념을 정립하고 또 나중에 다시 볼 경우 유용하게 사용되는 등의 이유로 작성을 하는 것이라 생각한다. 그 큰 뜻을 깨닫고 나도 문제 풀이를 해보겠다고 다짐했다.

문제 풀이는 필자가 생각했을 때 앞서 언급한 문제풀이 포스팅의 장점을 얻을 수 있도록 해주는 문제 위주로 포스팅 할 예정이고 최대한 문제 풀이를 하는 과정과 한 줄 한 줄 코드들의 쓰임새에 대해 논리적이고 구체적이게 설명을 하려고 따로 과정 설명과 코드 주석을 사용하면서 노력할 예정이다.

🧑🏻‍🏫 이번 포스팅에서 다룰 문제

이번 문제는 현재 읽고 있는 책인
<이것이 취업을 위한 코딩 테스트다 with 파이썬> <교보문고 도서 구입 링크>
에서 Part2 chapter4 구현에 있는 문제인 "게임 개발" 이라는 문제이다. 책의 저자는 문제이름 아래에 출처를 적어주는데 이 문제는 출처가 적혀있지 않았다.

난이도는 쉬운 편이고 문제에서 주어진 대로 코드를 작성할 수 있는지를 물어보는 문제라고 한다.

💁🏻‍♂️ 문제 설명

<문제>

현민이는 게임 캐릭터가 맵 안에서 움직이는 시스템을 개발 중이다. 캐릭터가 있는 장소는 1 X 1 크기의 정사각형으로 이뤄진 N X M 크기의 직사각형으로, 각각의 칸은 육지 또는 바다이다. 캐릭터는 동서남북 중 한 곳을 바라본다.

맵의 각 칸은 (A, B)로 나타낼 수 있고, A는 북쪽으로부터 떨어진 칸의 개수, B는 서쪽으로부터 떨어진 칸의 개수이다. 캐릭터는 상하좌우로 움직일 수 있고, 바다로 되어 있는 공간에는 갈 수 없다. 캐릭터의 움직임을 설정하기 위해 정해 놓은 매뉴얼은 이러하다.

현재 위치에서 현재 방향을 기준으로 왼쪽 방향(반시계 방향으로 90도 회전한 방향)부터 차례대로 갈 곳을 정한다.

캐릭터의 바로 왼쪽 방향에 아직 가보지 않은 칸이 존재한다면, 왼쪽 방향으로 횐전한 다음 왼쪽으로 한 칸을 전진한다. 왼쪽 방향에 가보지 않은 칸이 없다면, 왼쪽 방향으로 회전만 수행하고 1단계로 돌아간다.

만약 네 방향 모두 이미 가본 칸이거나 바다로 되어 있는 칸인 경우에는, 바라보는 방향을 유지한 채로 한 칸 뒤로 가고 1단계로 돌아간다. 단, 이때 뒤쪽 방향이 바다인 칸이라 뒤로 갈 수 없는 경우에는 움직임을 멈춘다.

현민이는 위 과정을 반복적으로 수행하면서 캐릭터의 움직임에 이상이 있는지 테스트하려고 한다. 메뉴얼에 따라 캐릭터를 이동시킨 뒤에, 캐릭터가 방문한 칸의 수를 출력하는 프로그램을 만드시오.

<입력 조건>

첫째 줄에 맵의 세로 크기 N과 가로 크기 M을 공백으로 구분하여 입력한다.
(3 <= N, M <= 50)

둘째 줄에 게임 캐릭터가 있는 칸의 좌표 (A, B)와 바라보는 방햔 d가 각각 서로 공백으로 구분하여 주어진다. 방향 d의 값으로는 다음과 같이 4가지가 존재한다.

0 : 북쪽
1 : 동쪽
2 : 남쪽
3 : 서쪽

셋째 줄부터 맵이 육지인지 바다인지에 대한 정보가 주어진다. N개의 줄에 맵의 상태가 북쪽부터 남쪽 순서대로, 각 줄의 데이터는 서쪽부터 동쪽 순서대로 주어진다. 맵의 외각은 항상 바다로 되어 있다.

0 : 육지
1 : 바다
처음에 게임 캐릭터가 위치한 칸의 상태는 항상 육지이다.

<출력 조건>

첫째 줄에 이동을 마친 후 캐릭터가 방문한 칸의 수를 출력한다.

<입력 예시>

4 4
1 1 0 // (1, 1)에 북쪽(0)을 바라보고 서 있는 캐릭터
1 1 1 1
1 0 0 1
1 1 0 1
1 1 1 1

<출력 예시>
3

⁈ 논리 과정

(0) 문제 분석
게임 캐릭터는 바다와 육지로 이루어진 맵에서 태어난다. 게임 캐릭터는 물론 육지에서 태어나고 태어날 때부터 바라보고 있는 방향이 정해져있다. 그 방향은 0, 1, 2, 3 순서로 북, 동, 남, 서의 순서를 갖게 되고 4가지 방향 중 한 방향을 보고있다.

게임 캐릭터의 목표는 본인이 태어난 맵에서 자신이 밟을 수 있는 땅(육지)의 개수를 세는 것인데 게임 캐릭터의 이동 알고리즘은 정해져있다.
< 이동 알고리즘 >
1 . 내가 보고 있는 방향에 육지가 있으면 그 육지로 이동한다.
2 . 육지가 아니라면 왼쪽으로(북 -> 서, 서->남 등) 회전한다.

(1) 논리 과정
1 . 태어난 위치와 방향을 변수에 저장을 한다.
2 . 반복문에서 현재 방향에서 다음 육지로 갈 수 있는지 확인하는 조건문을 생성한다.
3 . 반복문은 다음 육지로 갈 수 없으면 왼쪽으로 회전할 수 있도록 하는 반복문이다.
4 . 만약 4개의 방향으로 모두 갈 수 없다면 종료할 수 있도록 장치를 마련해둔다.

(2) 구체적 장치
1 . 문제에서 방향은 4가지였고 각각을 숫자로 표현했다.(0:북,1:동,2:남,3:서) 그래서 나는 그 문제에서 나온 숫자를 그대로 이용하고 싶었다. 그래서 0부터 3번까지의 인덱스를 갖는 리스트를 만들었고 그 안에 튜플형태로 방향 이동을 할 수 있게 만들었다.(direction 리스트)

2 . 그래서 인덱스가 1씩 증가하는 반복문을 만들게 되면 북 -> 동 -> 남 -> 서 순으로 회전을 하게된다.(시계방향) 하지만 문제는 반시계방향으로 회전을 하도록 하였기 때문에 반복문을 1씩 감소하도록(-1) 만들어 문제에서 요구하는 순리에 따르도록 만들었다.

3 . 한번 자리에서 회전을 할 때마다 이동을 했는지 체크하는 변수를 하나 만들었다. (di_count) 이는 bool형태로 만들어도 상관은 없다. 나는 초기에 변수에 0을 저장하고 이동을 하면 1을 추가시켰다. 그래서 반복문 최종에 di_count가 그대로 0이라면 이동을 멈춘 것으로 판단하고 반복문을 종료시켰다.

4 . 게임 캐릭터는 바다를 만났을 때 뿐만 아니라 맵 바깥쪽을 만났을 때에도 이동을 할 수 없다. 그래서 맵 바깥쪽에 대한 처리를 해주었어야 한다. 그때 x좌표와 y좌표가 범위 바깥으로 나가는지에 대한 처리를 해주어야 하는데 그 부분을 생각하면 머리가 굉장히 지끈거렸고 그래서 아예 맵 바깥쪽에 바다를 더 만들어주는 처리를 하였다. 맵이 원래 3행4열의 2차원 배열이었다면 바다를 맵 바깥쪽에 둘러 5행6열의 배열로 만들었다. (상,하,좌,우에 모두 바다가 있어야 하므로 3+2, 4+2 의 배열이 생긴다)

코드는 아래와 같다.

풀이를 마치며

복잡한 조건도 없고 단순한 규칙에 의해 게임캐릭터가 움직이기 때문에 어려운 문제는 아니었다. 하지만 고민을 상당히 오래, 많이 했다. 그 이유는 조금 더 간단하고 쉽고 깔끔한 코드에 대한 고민을 해서 그렇다. 앞으로 경험이 쌓여 이러한 고민들이 살이 돼 나의 밑거름이 되길 바란다.

앞으로 풀이를 올릴 때에는 서두의 언급처럼 많은 이야기를 담지는 않고 문제 풀이 본질에 더 집중해 보려고 한다. 그리고 하고 싶은 이야기는 주저리주저리 시리즈에 담아보도록 하겠다. 또 따로 깃을 파서 소스코드를 공개해보도록 하겠다. 준비가 되면 이 글도 수정하리라 다짐하며 글을 마친다.

0개의 댓글