컴퓨터는 잘못이 없다..
[알고리즘]구현_게임게발(파이썬 2차원리스트를 리스트 컴프리헨션 문법으로 초기화/append()와 extend()/함수 내 global변수) 본문
[알고리즘]구현_게임게발(파이썬 2차원리스트를 리스트 컴프리헨션 문법으로 초기화/append()와 extend()/함수 내 global변수)
도토리까꿍v 2020. 12. 4. 02:03['게임개발' 문제 설명]
-난이도 : ★★☆
-풀이시간 : 40분
-시간 제한 : 1초
-메모리 제한 : 128MB
-출처 : 이것이 코딩테스트다(p.118)
-문제 :
현민이는 게임 캐릭터가 맵 안에서 움직이는 시스템을 개발중이다. 캐릭터가 있는 장소는 1x1 크기의 정사각형으로 이뤄진 NxM 크기의 직사각형으로, 각각의 칸은 육지 또는 바다이다. 캐릭터는 동서남북 중 한 곳을 바라본다.
맵의 각 칸은 (A,B)로 나타낼 수 있고, A는 북쪽으로부터 떨어진 칸의 개수, B는 서쪽으로부터 떨어진 칸의 개수이다.
캐릭터는 상하좌우로 움직일 수 있고, 바다로 되어 있는 공간에는 갈 수 없다.
캐릭터의 움직임을 설정하기 위해 정해 놓은 메뉴얼은 이러하다.
1. 현재 위치에서 현재 방향을 기준으로 왼쪽 방향(반시계 방향으로 90도 회전한 방향)부터 차례대로 갈 곳을 정한다.
2. 캐릭터의 바로 왼쪽 방향에 아직 가보지 않은 칸이 존재한다면, 왼쪽 방향으로 회전한 다음 왼쪽으로 한 칸을 전진한다. 왼쪽 방향에 가보지 않은 칸이 없다면, 왼쪽 방향으로 회전만 수행하고 1단계로 돌아간다.
3. 만약 네 칸이 모두 이미 가본 칸이거나 바다로 되어 있는 칸인 경우에는, 바라보는 방향을 유지한 채로 한 칸 뒤로 가고 1단계로 돌아간다. 단, 이때 뒤쪽 방향이 바다인 칸이라 뒤로 갈 수 없는 경우에는 움직임을 멈춘다.
현민이는 위 과정을 반복적으로 수행하면서 캐릭터의 움직임에 이상이 있는지 테스트하려고 한다. 메뉴얼에 따라 캐릭터를 이동시킨 뒤에 캐릭터가 방문한 칸의 수를 출력하는 프로그램을 만드시오.
-입력조건:
첫째 줄에 맵의 세로 크기 N과 가로 크기 M을 공백으로 구분하여 입력한다. (3<=N,M<=50)
둘째 줄에 게임 캐릭터가 있는 칸의 좌표(A,B) 와 바라보는 방향 d가 각각 서로 공백으로 구분하여 주어진다.
방향 d의 값으로는 다음과 같이 4가지가 존재한다.
-0:북쪽
-1:동쪽
-2:남쪽
-3:서쪽
셋째 줄부터 맵이 육지인지 바다인지에 대한 정보가 주어진다. N개의 줄에 맵의 상태가 북쪽부터 남쪽 순서대로, 각 줄의 데이터는 서쪽부터 동쪽 순서대로 주어진다. 맵의 외곽은 항상 바다로 되어있다.
-0:육지
-1:바다
처음에 게임 캐릭터가 위치한 칸의 상태는 항상 육지이다.
-출력조건: 첫째 줄에 이동을 마친 후 캐릭터가 방문한 칸의 수를 출력한다.
-입력예시1
4 4 #4x4 맵 생성
1 1 0 #1,1에 북쪽을 바라보고 있는 캐릭터
1 1 1 1
1 0 0 1
1 1 0 1
1 1 1 1
-출력예시1
3
['게임개발' 답안1]
#n,m을 공백으로 구분하여 입력받기
n, m = map(int, input().split())
#방문한 위치를 저장하기 위한 맵을 생성하여 0으로 초기화하기,2차원 리스트
d = [[0]*m for _ in range(n)] #n*m 행렬만들고 0으로 채워넣기 방문안함:0,방문함:1
#현재 캐릭터의 x,y 좌표와 방향을 입력받기
x, y, direction = map(int, input().split())
#2차원 리스트인 d에 현재 위치 방문처리하기
d[x][y] = 1
#전체 맵 정보를 입력받기
#빈 리스트를 만들기
array = []
for i in range(n):
# 이런식으로 array.append()하면
# [[1,1,1,1],[1,0,0,1],[1,1,0,1],[1,1,1,1]]
# 로 2차원 배열이 만들어 질것임!!
array.append(list(map(int, input().split())))
#북, 동, 남, 서에 따른 방향크기를 정의한다.
#북은 위쪽, 동은 오른쪽, 남은 아래쪽, 서는 왼쪽임
#(행x, 열y)의 이동에 따른 증감을 생각해보자!
dx = [-1, 0, 1, 0]
dy = [0, 1, 0, -1]
#왼쪽으로 회전
def turn_left():
#함수 안에서 전역변수의 값을 변경하려면 global 키워드를 써야한다.
#global 키워드를 쓰지 않으면 direction은
#turn_left 함수의 지역변수가 되어버린다.
global direction
direction -=1
if direction == -1 :
direction = 3
#direction은 북 0 ,동 1,남 2,서 3
#동,서,남,북 왼쪽으로 회전할 수록 수가 작아짐!
#단, 북쪽에서 왼쪽으로 turn 하면 -1이 되므로 그때만 서쪽인 3으로 고정해주기
#시뮬레이션 시작
count =1 #시작지점은 count하고 시작
turn_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[nx][ny] = 1 #방문처리
x, y = nx, ny #실제로 이동
count+=1 #카운트 증가
turn_time=0 #turn_time은 다시 0
continue
#회전한 이후 정면에 가보지 않은 칸이 없거나 바다인 경우
else :
#증가시키고 아래 if문에서 걸리지 않는다면
#무한루프 이므로 맨위로 돌아가서 turn_left()부터 수행한다.
turn_time +=1 #turn_time을 증가시키기
#네 방향 모두 갈 수 없는 경우
if turn_time == 4 :
#바라보는 방향 그대로 하고 뒤로 한칸 가기
nx = x-dx[direction] #바라보는 방향 반대이므로 부호 바꾸고 더해주면 된다.
ny = y-dy[direction]
#뒤로 갈 수 있다면 이동하기, 땅이라면 이동가능
if array[nx][ny] == 0 :
x,y = nx, ny
#뒤가 바다로 막혀있다면 움직임을 멈춘다.
else :
#반복문을 빠져나간다.
break
#뒤로 갈 수 있다면 이동 후 turn_time을 초기화 해주어야한다.
turn_time=0
#count 출력
print(count)
[설명]
문제풀이를 위한 중요한 테크닉
현재 캐릭터가 북쪽을 바라보고 있을 때는 북쪽으로 이동하기 위해 x 와 y 좌표를 각각 dx[0], dy[0] 만큼 더한다.
다시 말해 현재 위치에서 (-1, 0) 만큼 이동시키는 것이다. 이처럼 코드를 작성해보자!
[파이썬]
-리스트 컴프리헨션 문법1 : d=[[0]*3 for _ in range(5)] 의 의미(★뒷숫자가 행, 앞숫자가 열, 뒤에서부터 읽어서 5*3)
[[0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0], [0, 0, 0]]
다르게 표현하면
[[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0],
[0, 0, 0]]
-> 5*3 행,열을 만들고 내용물은 0으로 채워넣어라
-리스트 컴프리헨션 문법2 : d=[[0] for _ in range(5)] 의 의미(★뒤에서부터 읽어서 5*1)
[[0], [0], [0], [0], [0]]
다르게 표현하면
[[0],
[0],
[0],
[0],
[0]]
-> 5*1 행,열을 만들고 내용물은 0으로 채워넣어라
-2차원 리스트에서
-append() 함수와 extend() 함수
d = [1,2] 에
d.append([3,4])를 하면 [1,2,[3,4]] 로 들어가고
d.extend([3,4])를 하면 [1,2,3,4] 로 들어가진다.
-함수 내 global변수
▲
방법1) global direction으로 선언해주면 함수 호출 시 함수밖의 direction을 변경할 수 있다.
방법2) global direction으로 하고 싶지 않다면 direction 연산 후 return하여 함수밖의 direction에 대입해주는 방식으로 사용해야 한다.
방법1의 경우 함수를 호출하기만 하면 함수밖의 direction이 변경되고
방법2의 경우 함수를 호출하여 그 리턴값을 함수밖의 direction에 대입해주어야 함수밖의 direction이 변경된다.
#방법1사용
a=3
def sum():
global a
a+=2 #이때 a는 바깥 a
sum()
print(a) #5출력
# 방법2사용
a=3
def sum():
b = a+2 #이때 a는 바깥 a
return b
a=sum()
print(a) #5출력
# 오류나는 경우
a=3
def sum():
a+=2 #a에 빨간줄이 뜬다.
return a #a에 빨간줄이 뜬다.
a=sum()
print(a) #5출력
#추가로 알아둘 것
1. 함수 바깥에 선언한 변수를 함수 안에서도 사용가능
x = 10 # 전역 변수
def foo():
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
#결과
10
10
▲코드 설명
파이썬은 함수 바깥의 부분을 모두 전역범위로 보고 전역 변수라고 본다.
따라서 함수 바깥에 선언한 변수를 함수 안에서도 쓸 수 있다.
2. 함수 바깥에 선언한 변수의 값을 사용할 수는 있지만 직접 값을 바꿀 순 없다. 아래 예제를 보자.
x = 10 # 전역 변수
def foo():
x=3
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
#결과
3
10
▲함수 안에서 x의 값을 바꾸어주었지만 함수바깥의 변수 x는 변하지 않았다. 이렇게 할 경우 함수 안의 x는 지역변수가 된다.
3. 함수 바깥의 변수의 값을 함수 내에서 바꾸어주고싶다면? -> global!
x = 10 # 전역 변수
def foo():
global x
x=3
print(x) # 전역 변수 출력
foo()
print(x) # 전역 변수 출력
▲이처럼 함수 내에서 global x로 먼저 선언하면 바깥의 전역변수를 의미하며 함수 내, 함수 바깥의 변수 x가 동일하게 바뀌는 것을 확인할 수 있다.
'공부 > 알고리즘(파이썬)' 카테고리의 다른 글
[알고리즘]프로그래머스_두 정수 사이의 합(파이썬 두 변수 내 값 교환하기) (0) | 2020.12.04 |
---|---|
[알고리즘]구현_왕실의 나이트(행,열 이동에 따른 증감),(파이썬 ord()) (0) | 2020.12.03 |
[알고리즘]구현_시각(파이썬 포함연산자 in, not in/숫자를 문자로 바꾸는 메소드 str()과 연결연산자 +) (1) | 2020.12.02 |