
4개의 맞물린 톱니바퀴가 있다. 각 톱니에는 자성(N극, S극)이 있고 지정된 톱니가 지정된 명령대로 회전한다. 그 결과를 구하라
문제는 간단하게 생각할 수 있는 문제였다.
확실히 과거 삼성 기출이 지금보다 훨씬 쉬운거 같다..

필요했던 함수는 크게, 톱니를 회전시키는 함수, 회전 가능한지 확인하는 함수, 실제로 한 톱니가 돌았을 때 결과. 세가지가 필요했다.
우선 톱니가 회전한 결과를 반환하는 함수 rotate()를 작성했다.
def rotate(g : list, direction : int) -> list:
"""
g : gear list
direction : rotate direction, 1 : 시계방향, -1 반시계 방향
return : rotated g
"""
new_g = []
if direction == 1:
new_g = [g[-1]] + g[0:-1]
elif direction == -1:
new_g = g[1:] + [g[0]]
return new_g
여기서 했던 실수중의 하나가,
톱니들이 0번 톱니 (12시 방향)부터 시계방향으로 리스트에 극성이 담긴 형태인데, 슬라이싱을 이용했더니, g[0] 혹은 g[-1]이 값이어서 브라켓을 씌워서 리스트화 한다음 남은 부분과 더하기 했다. (이 방식이 메모리 측면에서는 좋지 못하다는 정보를 봤다)
다음은 마주보는 톱니를 이용해서, 기준이 되는 톱니 base와 compare를 이용해서 기준 톱니 기준 왼쪽인지 오른쪽인지 여부에 따라서 Boolean값을 반환하는 함수 movable을 작성했다.
def moveable(base : list, compare : list, direction : int) -> bool:
"""
base : 기준이 되는 톱니
compare : 움직일 톱니
direction : base 기준 compare 위치,
1 : 왼쪽,
-1 : 오른쪽
"""
# 왼쪽과 비교
if direction == 1:
return base[6] != compare[2]
# 오른쪽과 비교
elif direction == -1:
return base[2] != compare[6]
return "error"
처음에는 비트 연산 ^를 사용했는데, 그냥 달라야지만 움직이는 것으로 변경했다. (또 오른쪽 왼쪽 설정한걸 헷갈려서...오류가 있었다)
마지막으로 하나의 톱니가 돌았을때, 양 옆을 보며 톱니를 회전시키는 함수를 작성했다. 우선 오른쪽, 왼쪽을 나눠서 본다. 이때 코드가 중복되어 수정을 해보는 방안을 고민해 봤는데, 굳이 싶어서 그냥 두번 적었다. (사실 이런건 기술부채인가요...)
def iteration(gear : list, command : tuple) -> list:
"""
gear : gear list
command : (gear number, direction) direction, 1 : 시계방향, -1 반시계 방향
"""
g, base_dir = command[0] -1, command[1]
rotation = [(0,0)] * 4
rotation[g] = (1, base_dir)
# g 기준 왼쪽 오른쪽 분리 (인덱스로)
left = [0,1,2,3][:g][::-1] # 역순으로 슬라이싱해서 루프 돌리기 편하게 함
right = [0,1,2,3][g+1:]
base = gear[g]
dir = base_dir
# base 기준 왼쪽
for idx in left:
if moveable(base, gear[idx], 1):
base = gear[idx]
dir = dir * -1
rotation[idx] = (1, dir)
else:
break
# base기준 오른쪽
base = gear[g]
dir = base_dir
for idx in right:
if moveable(base, gear[idx], -1):
base = gear[idx]
dir = dir * -1
rotation[idx] = (1, dir)
else:
break
new_gear = []
for idx, g in enumerate(gear):
if rotation[idx][0]:
new_gear.append(rotate(g, rotation[idx][1]))
else:
new_gear.append(g)
return new_gear
여기서 코드가 중복되면서 발생했던 문제점은,
기존 톱니가 도는 방향을 dir이라는 변수에 저장했다 (변수명도 적절한 것은 아닌거같다). 이때 왼쪽 기준으로 회전방향에 -1 을 곱해가면서 변경했는데, dir을 다시 기존 방향으로 갱신했어야 하는데 누락되어서 저 멀리 있는 톱니가 돌아가는 불상사가 벌어졌다.
Movable 하지 않으면 바로 루프를 탈출한다.
최종적으로 위의 조건처럼 12시의 톱니를 이용하여 최종 점수를 환산한다.
def sol(gear, K, move):
for i in range(K):
gear = iteration(gear, move[ i])
return gear[0][0] + 2 * gear[1][0] + 4 * gear[2][0] + 8 * gear[3][0]
# 톱니바퀴 https://www.acmicpc.net/problem/14891
import sys
def InputData():
readl = sys.stdin.readline
gear = [[int(x) for x in readl().strip()] for _ in range(4)]
K = int(readl())
move = [tuple(map(int, readl().split())) for _ in range(K)]
return gear, K, move
def rotate(g : list, direction : int) -> list:
"""
g : gear list
direction : rotate direction, 1 : 시계방향, -1 반시계 방향
return : rotated g
"""
new_g = []
if direction == 1:
new_g = [g[-1]] + g[0:-1]
elif direction == -1:
new_g = g[1:] + [g[0]]
return new_g
def moveable(base : list, compare : list, direction : int) -> bool:
"""
base : 기준이 되는 톱니
compare : 움직일 톱니
direction : base 기준 compare 위치,
1 : 왼쪽,
-1 : 오른쪽
"""
# 왼쪽과 비교
if direction == 1:
return base[6] != compare[2]
# 오른쪽과 비교
elif direction == -1:
return base[2] != compare[6]
return "error"
def iteration(gear : list, command : tuple) -> list:
"""
gear : gear list
command : (gear number, direction) direction, 1 : 시계방향, -1 반시계 방향
"""
g, base_dir = command[0] -1, command[1]
rotation = [(0,0)] * 4
rotation[g] = (1, base_dir)
# g 기준 왼쪽 오른쪽 분리 (인덱스로)
left = [0,1,2,3][:g][::-1] # 역순으로 슬라이싱해서 루프 돌리기 편하게 함
right = [0,1,2,3][g+1:]
base = gear[g]
dir = base_dir
# base 기준 왼쪽
for idx in left:
if moveable(base, gear[idx], 1):
base = gear[idx]
dir = dir * -1
rotation[idx] = (1, dir)
else:
break
# base기준 오른쪽
base = gear[g]
dir = base_dir
for idx in right:
if moveable(base, gear[idx], -1):
base = gear[idx]
dir = dir * -1
rotation[idx] = (1, dir)
else:
break
new_gear = []
for idx, g in enumerate(gear):
if rotation[idx][0]:
new_gear.append(rotate(g, rotation[idx][1]))
else:
new_gear.append(g)
return new_gear
def sol(gear, K, move):
for i in range(K):
gear = iteration(gear, move[ i])
return gear[0][0] + 2 * gear[1][0] + 4 * gear[2][0] + 8 * gear[3][0]
gear, K, move = InputData()
print(sol(gear, K, move))