이 문제는 "동시성" 처리가 가장 중요하다. 톱니바퀴를 하나씩 바로바로 돌려버리면, 다음 바퀴가 회전 여부를 판단할 때 이미 돌아가버린 극을 참조하게 되어 오답이 발생한다.
따라서 다음과 같은 3단계 로직으로 설계했다.
check 또는 direct 함수를 만들어 4개의 톱니바퀴가 각각 어느 방향으로 돌지 저장할 배열(int[] dir)을 만든다.i-1)으로 가면서, 내 9시(index 6)와 왼쪽의 3시(index 2)를 비교한다.i+1)으로 가면서, 내 3시(index 2)와 오른쪽의 9시(index 6)를 비교한다.dir[i] = -dir[기준] (반대 방향), 극이 같으면 break (전파 중단).dir 배열을 확인하여 실제로 배열을 회전시킨다.temp를 이용해 뒤에서 앞으로 이동.temp를 이용해 앞에서 뒤로 이동.index 0)을 확인한다.1 << i)을 활용해 합산한다.import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static int[][] arr;
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st;
arr = new int[4][8];
for(int i=0; i<4; i++) {
st = new StringTokenizer(br.readLine());
String line = st.nextToken();
for(int j=0; j<8; j++) {
arr[i][j] = line.charAt(j) - '0';
}
}
st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
for(int i=0; i<n; i++) {
st = new StringTokenizer(br.readLine());
int num = Integer.parseInt(st.nextToken());
int di = Integer.parseInt(st.nextToken());
int[] dir = new int[4];
direct(num-1, di, dir);
rotate(dir);
}
int answer = 0;
for(int i=0; i<4; i++) {
if(arr[i][0] == 1) {
answer += (1 << i);
}
}
System.out.println(answer);
}
static void rotate(int[] dir) {
for(int i=0; i<4; i++) {
if(dir[i] == 1) {
int temp = arr[i][7];
for(int j=7; j>0; j--) {
arr[i][j] = arr[i][j-1];
}
arr[i][0] = temp;
}
else if(dir[i] == -1) {
int temp = arr[i][0];
for(int j=0; j<7; j++) {
arr[i][j] = arr[i][j+1];
}
arr[i][7] = temp;
}
}
}
static void direct(int num, int di, int[] dir) {
dir[num] = di;
for(int i = num-1; i >= 0; i--) {
if(arr[i+1][6] != arr[i][2]) {
dir[i] = dir[i+1] * -1;
}
else {
break;
}
}
for(int i = num+1; i < 4; i++) {
if(arr[i-1][2] != arr[i][6]) {
dir[i] = dir[i-1] * -1;
}
else {
break;
}
}
}
}
처음에는 단순히 기준 방향(di)에 -1을 곱해서 전파시켰는데, 이렇게 하면 1 -> -1 -> 1로 이어져야 할 흐름이 1 -> -1 -> -1로 끊기는 오류가 발생했다.
기준이 되는 di가 아니라, "내 바로 옆 톱니바퀴(dir[i+1] or dir[i-1])의 반대 방향"으로 설정해야 올바르게 연쇄 작용이 일어난다는 점을 깨달았다.
"일단 돌리고 나서 옆을 확인하자"라고 생각하면 꼬이기 쉬운 문제다. "누가 돌지 다 정해놓고(dir 배열), 마지막에 한꺼번에 돌린다"는 시뮬레이션의 정석 패턴을 익힐 수 있었다.
점수 계산 시 Math.pow 대신 1 << i를 사용하니 코드가 훨씬 간결해졌다.