더닝 크루거 효과를 아시나요? 특정 분야에 대해서 조금 아는 사람은 자신을 과대평가하고 적당히 아는 사람은 자신을 과소평가한다는 인지 편향이라고 합니다. 구글링 해보면 그 효과에 대해서 공감하는 사람이 너무 많다 보니 정작 실제로 발표된 논문과는 다른, 아주 조금 알 땐 모든 것을 아는 듯 행세하다가 조금 배울수록 급격히 그 자신감이 떨어지는 그래프를 찾아볼 수 있습니다.
최근 JS 공부를 시작하고 나니, 내가 바로 그 아주 조금 알던 사람이었구나 하는 생각이 참 많이 듭니다. 공부를 하면 할수록 천재는 많고 배워야 할 내용또한 많다는 게 느껴집니다.누군가에게 가이드라인을 제시하는 내용도 아니고, 단순한 코드 리뷰로 많이 부족한 내용이지만 찾아오신분께 도움이 되었으면 좋겠습니다.
몇몇 문제를 풀다보니 그때그때 새로운 변수를 만들어서 사용하고 사용되는 리스트를 자꾸 늘려가니 말 그대로 "억지로 푼다"라는 느낌이 들어 최근에는 문제를 풀기 전, 이 문제에서 어떤 모듈을 사용해서 문제를 풀어나갈지 생각해보고 풀게 되었습니다.
만약 풀이 해설을 위해 찾아오신분은 정답 코드에 앞서 어떤 동작을 수행하는 모듈을 만들고자 했는지, 또한 그 모듈을 어떻게 구성했는지를 먼저 보신다면 더욱 좋을 것이라 생각됩니다.
https://www.acmicpc.net/problem/20061
- Given
- 모노도미노는 특수한 형태의 보드에서 진행되며 좌표(x, y)는 x행, y열을 의미한다.
- 사용되는 블록은 1*1 & 1*2 & 2*1 크기의 블록이 사용된다.
- 한 행이 모두 블록으로 채워지면 그 행은 사라지며, 1점을 획득한다.
- 각 블록은 놓아지면 수직으로 떨어지며, 다른 블록과 맞닿으면 그 자리에 멈춘다.
- 만약 0,1번 행에 블록이 놓이면 해당 보드의 6번행은 삭제되며 한 행씩 아래로 밀린다.
- Input
- 첫째 줄에 블록의 갯수 N ( 1 <= N <= 10,000 )가 주어진다
- 둘째 줄부터 N 개의 줄에 걸쳐 데이터 [ t , x , y ] 가 주어지며 각 t의 의미는 다음과 같다
- t = 1 : 1*1 블록을 (x,y) 에 놓는다
- t = 2 : 1*2 블록을 (x,y), (x, y+1)에 놓는다
- t = 3 : 2*1 블록을 (x,y), (x+1, y)에 놓는다
- Output
- 첫째 줄에 모든 블록을 놓았을 때 얻는 점수를 출력하라
- 둘째 줄에 두 보드에 블록에 의해 채워져있는 칸의 개수를 출력하라
- Approach
- 세로방향 보드와 가로방향 보드를 겹쳐놓았지만, 블록이 놓이는 방향을 치환하여 가로방향 보드를 분리하여 접근.
- 가로 세로 모두 사용될 공동 모듈
- 배치된 블록을 떨어뜨리기
- 모두 채워진 행이 있는지 확인 후, 해당 행 지우도 블록 내리기
- 0,1번 행에 타일이 위치하면 6번행 지우기
- 가로 보드에 사용될 치환 모듈
- 주어진 타일을 가로 보드에 맞게 치환하여 배치
- 사용될 데이터 테이블의 타입과 형태
- 블록이 놓일 각 보드의 형태는 Boolean 형태의 2차원 리스트로 설정
- 블록의 Type에 따라 블록이 놓이는 위치 데이터 lot = [[x, y]]
- 사용될 모듈의 순서
- 블록의 배치 후 떨어뜨리기
- 채워진 행 확인 후 점수 획득
- 1,2 행에 위치한 블록이 있는지 확인
- 반복
내 경우엔 이렇게 각각 기능을 나누어서 모듈화 시키는 게 디버그 시간을 많이 줄여주는 것 같다.
# import sys
# input = sys.stdin.readline
# input 을 변환해주면 좀 더 빠르겠지만 정작 나는 변환 안하고 풀었음에도 시간이 넉넉하게 남았었다
n = int(input())
get = []
for i in range(n):
get.append(list(map(int,input().split())))
point = 0
sectorPoint = 0
Block = [[[False]*4 for _ in range(6)] for _ in range(2)] # Block[0] : 초록보드 ,Block[1] : 파란보드
우선 데이터의 선언과 입력부다. BOJ 에서는 input을 readline으로 치환하여 푸는 것이 시간을 절약하는 경우가 많아서 자주 사용하지만, 지금 코드 리뷰를 하며 다시 돌아보니 정작 나는 sys를 import 만 하고 변환하지 않고 풀었음에도 시간이 넉넉히 남았다.
def GtoB(lot):
temp = []
for x,y in lot: #lot = given
temp.append([y,(3-x)])
return temp
def blockdown(t,x,y,block,gnb):
if gnb == 1:
if t == 1:
lot = [[x,y]]
elif t == 2:
lot = [[x,y],[x,y+1]]
else:
lot = [[x,y],[x+1,y]]
lot = GtoB(lot)
else:
if t == 1:
lot = [[x,y]]
elif t == 2:
lot = [[x,y],[x,y+1]]
else:
lot = [[x,y],[x+1,y]]
stopPosition = 5 #블록을 위치시킬 위치
for row,col in lot:#정지위치 찾기
temp = [i[col] for i in block]
for i in range(len(temp)):
if temp[i]:
stopPosition = min(i-1,stopPosition)
for row,col in lot:
if gnb == 1 and t == 2:
block[stopPosition][col],block[stopPosition-1][col] = True, True
return
if t == 3 and gnb != 1:
block[stopPosition][col],block[stopPosition-1][col] = True, True
return
block[stopPosition][col] = True
return
GtoB 모듈은 현재 문제에서 세로 보드인 초록 보드에 놓이는 블록의 모양과 위치를 파란 보드의 기준에 맞게 변환해주는 모듈이다. 딱히 그 이상의 역할은 없다.
blockdown 모듈은 보드를 argument로 넣어주어서 원하는 보드에서 개별적으로 작동할 수 있도록 작성했다.
그래서 gnb를 argument 로 주어서 초록 보드인지 파란 보드인지 알려주어 블록 위치 리스트 (lot)를 구하고 구해진 블록위치 리스트 (lot) 를 통해 이번에 놓인 블록이 정지해야 할 y값 (stopPosition)을 구한다.
마지막으로 두 가지 특수한 상황을 제외하고 블록이 놓여야 할 자리를 True로 바꾸어준다.
def getPoint(block):
global point
flag = False
for i in range(len(block)):
if False in block[i]:
continue
block.remove(block[i])
block.insert(0,[False]*4)
point+=1
flag = True
break
if flag:
getPoint(block)
def CheckTheTopBlock(block):
for i in range(2):
if True in block[i]:
block.pop()
for i in range(6-len(block)):
block.insert(0,[False]*4)
def settle(All):
temp = 0
for sector in All:
for i in sector:
for j in i:
if j:
temp += 1
return temp
각 블록이 배치되고 나서 실행될 채워진 행 확인 모듈 getPoint()와 1,2 행에 위치한 블록을 확인해 줄 CheckTheTopBlock() , 모든 작업이 끝나고 남은 True 블록을 세어주는 settle()의 코드인데 딱히 할 말이 없다. 그냥 인덱스 정해서 해당 칸이 True 혹은 False 이면 반환될 값을 더하거나 해당 행을 지워주는 방식이다.
for t,x,y in get:
for i in range(2):
blockdown(t,x,y,Block[i],i)
getPoint(Block[i])
CheckTheTopBlock(Block[i])
sectorPoint = settle(Block)
print(point)
print(sectorPoint)
[[ 마무리 ]]
구현 문제가 흔히 그런지 모르겠지만 풀 땐 자잘한 디버그 하느라 정신없다가도 다 풀고 나서 리뷰할 땐 너무 보잘것없어서 내가 왜 그렇게 헤맸나 싶기도 합니다. 그래서 그 헤맴을 조금이라도 최소화해주는 게 문제를 푸는데 필요한 기능을 정리하고 그 기능을 수행하는 모듈을 하나씩 만들어가는 방식이 아닐까 싶습니다.
최근댓글