Programming/알고리즘 & 코테

[구현] 게임 개발 (실전문제, 이것이 코딩테스트다 with 파이썬)

kk_______yy 2023. 12. 15. 14:58

구현

  • 코딩테스트에서 자주 출제되는 유형
  • (1) 정확한 풀이 방법, (2) 프로그래밍 언어 문법의 이해를 바탕으로 완벽한 구현
  • 구현 : '풀이를 떠올리는 것은 쉽지만 소스코드로 옮기기 어려운 문제'
  • 알고리즘 설계 후, 먼저 풀 문제가 없을 때 푸는 문제
  • 피지컬을 요구하는 문제
  • 언어의 문법(라이브러리)을 잘 이해하고 경험이 있어야만 바로 떠올릴 수 있는 해결 방법
  • 코테에서 1~2번 문제는 대부분 그리디 or 구현 → 합격을 좌우

구현하기 어려운 문제

  • 코드가 지나칠 만큼 길어지는 문제
  • 특정 소수점 자리까지 출력해야 하는 문제
  • 문자열이 입력으로 주어졌을 때 한 문자 단위로 끊어서 리스트에 넣어야 하는(파싱) 문제 등

유형

  • 완전 탐색 : 모든 경우의 수를 주저 없이 다 계산하는 해결 방법
  • 시뮬레이션 : 문제에서 제시한 알고리즘을 한 단계씩 차례대로 직접 수행

 

문제

- (0, 0)으로부터 떨어진 위치 (A, B)

- 상하좌우 이동, 바다는 못 감

- 맵의 외곽은 항상 바다

- 게임 캐릭터가 위치한 칸의 상태는 항상 육지

 

1. 왼쪽부터!

2. 캐릭터의 바로 왼쪽 방향 안 가봤으면 -> 왼쪽 회전 후 직진

3. 네 방향 모두 가봤거나, 바다 -> 방향 유지하고 한 칸 뒤로

ㄴ반복

ㄴ뒤쪽도 바다면 스탑

 

입력

N M (맵의 세로 가로 크기)

A, B (캐릭터가 있는 칸 좌표) d (바라보는 방향)

N개 줄의 0, 1 (0 육지, 1 바다)

 

출력

마친 후 캐릭터가 방문한 칸의 수

 

풀이

# 변수 : N M 맵의 세로 가로 크기
# N, M을 공백으로 구분하여 입력받기
n, m = map(int, input().split())

# 변수 : d 방문 위치 표시맵
# 방문한 위치를 저장하기 위한 맵을 생성하여 0으로 초기화
d = [[0] * m for _ in range(n)]    # 리스트 컴프리헨션 문법으로 2차원 리스트 초기화

# 변수 : x y 현재 좌표, direction 바라보는 방향 (0 북 1 동 2 남 3 서)
# 현재 캐릭터의 X, Y 좌표, 방향을 입력받기
x, y, dirextion = map(int, input().split())
d[x][y] = 1 # 현재 좌표 방문 처리

# 변수 : N개 줄의 0, 1
array = []
for i in range(n):
    array.append(list(map(int, input().split())))
    
# 북, 동, 남, 서 방향 정의
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]

# 왼쪽으로 회전
def turn_left():
    global direction     # direction 변수가 함수 바깥에서 선언된 전역변수라서
    direction -= 1       # 왼쪽으로 회전
    if direction == -1:  # 북쪽에서 회전하면 서쪽 : -1 → 3
        direction = 3

# 시뮬레이션 시작
count = 1    # 첫
trun_time = 0
while True:
    # 왼쪽으로 회전
    turn_left()
    nx = x + dx(direction]
    ny = y + dy[direction]
    # 회전한 이후 정면에 가보지 않은 칸이 존재하는 경우 이동
    if d[nx][ny] == 0 and array[nx][ny] == 0:    # d 방문위치, array 바다위치
        d[nx][ny] = 1
        x = nx
        y = ny
        count += 1
        turn_time = 0
        continue
    # 회전한 이후 정면에 가보지 않은 칸이 없거나 바다인 경우
    else:
        turn_time += 1    # 한번 더 회전
    # 네 방향 모두 갈 수 없는 경우
    if turn_time == 4:    # 3의 경우 : 바라보는 방향 유지, 한 칸 뒤로
        nx = x - dx[direction]
        ny = y - dy[direction]
        # 뒤로 갈 수 있다면 이동하기
        if array[nx][ny] == 0:
            x = nx
            y = ny
        # 뒤가 바다로 막혀있는 경우
        else:
            break    # 빠져나감
        turn_time = 0     # 다시 1의 경우로 돌아감
    
# 정답 출력
print(count)

 

해석

시뮬레이션 유형 : 문제에서 요구하는 내용을 오류 없이 성실하게 구현하면 풀 수 있음. 단, 소스코드로 옮기는 과정이 간단하지 않으므로 반복적인 숙달 필요

 

변수 : N M 맵의 세로 가로 크기, d 방문 위치 표시맵, x y 현재 좌표, direction 바라보는 방향 (0 북 1 동 2 남 3 서)

 

1. 맵의 크기(N, M) 입력받기

2. 방문위치 맵(d) 생성 및 초기화

3. 현재 좌표(x, y)와 방향(direction) 입력받기

4. 현재 좌표(d[x][y]) 방문 처리 : 1

5. 전체 맵_바다(array) 입력받기

6. 북, 동, 남, 서 방향(dx, dy) 정의

7. 회전 함수 정의 : (0 북 1 동 2 남 3 서), direction -= 1

-----시뮬레이션-----

8. 횟수 +1 : 현재 위치 방문

9. 왼쪽으로 회전, 직진 : turn_time += 1

ㄴ 가보지 않은 칸 and 육지 >> 이동, 횟수 +1

ㄴ 가본 칸 or 바다 >> 회전

     ㄴ네번 회전 점검했음에도 이동 불가 : turn_time == 4 >> 뒤로 이동

          ㄴ뒤가 바다 >> 게임 끝

10. 8로 돌아가 처음부터 다시 회전 : trun_time = 0

-----게임 끝-----

11. 횟수 출력

 

 

* 방향을 설정해서 이동하는 문제 유형

일반적으로 dx, dy라는 별도의 리스트 만들어 방향 정하는 것이 효과적

ex) 북쪽 이동 → x와 y좌표를 dx[0], dy[0] 더하기 = (-1, 0)만큼 이동

 

* 리스트 컴프리헨션 문법

대괄호[ ] 안에 조건문과 반복문을 넣는 방식으로 리스트 초기화

ex)

# 0부터 19까지의 수 중에서 홀수만 포함하는 리스트
array = [i for i in range(20) if i % 2 == 1]
print(array)
# [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]


# 1부터 9까지의 수의 제곱 값을 포함하는 리스트
array = [i * i for i in range(1, 10)]
print(array)
# [1, 4, 9, 16, 25, 36, 49, 64, 81]

 

특히, 코테에서 2차원 리스트 초기화할 때 효과적

이 경우 무조건 리스트 컴프리헨션 사용해야 함.

그렇지 않으면 의도하지 않은 결과가 나올 수 있음

# N X M 크기의 2차원 리스트 초기화
n = 3
m = 4
array = [[0] * m for _ in range(n)]
print(array)
# [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]


# 틀린! N X M 크기의 2차원 리스트 초기화
n = 3
m = 4
array = [[0] * m] * n
print(array)
# [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

array[1][1] = 5
print(array)
# [[0, 5, 0, 0], [0, 5, 0, 0], [0, 5, 0, 0]]

 

* global 키워드

정수형 변수 direction 이 함수 바깥에서 선언된 전역변수이기 때문

 

* 예외처리

3 3

1 1 0

1 1 1

1 0 0

1 1 0

이 경우 맵 외곽은 바다로 구성된다는 설정이 고려되지 않아 에러발생.

→ 실무 코딩은 예외 고려해서 코드 짜야 함. 코테는 입력값 대체로 주어지므로 예외처리하지 않고 빠르게 코드 작성.

=> 차이점을 알아 두자!