[java,백준5373]큐빙 - 3D 큐브의 2D 시뮬레이션 구현

3차원 루빅스 큐브를 2차원 배열로 변환하여 각 면의 회전을 시뮬레이션하는 구현 문제입니다.

큐빙(백준5373)


예시 시각화:

아래 큐브 전개도가 변하는 모습을 이해한다면 충분히 풀 수 있을 것이다!
         [w][w][w]
         [w][w][w]
         [w][w][w]
[g][g][g][r][r][r][b][b][b][o][o][o]
[g][g][g][r][r][r][b][b][b][o][o][o]
[g][g][g][r][r][r][b][b][b][o][o][o]
         [y][y][y]
         [y][y][y]
         [y][y][y]

R+ 를 한다면?
         [w, w, r]
         [w, w, r]
         [w, w, r]
[g, g, g][r, r, y][b, b, b][w, o, o]
[g, g, g][r, r, y][b, b, b][w, o, o]
[g, g, g][r, r, y][b, b, b][w, o, o]
         [y, y, o]
         [y, y, o]
         [y, y, o]
         
U+ 를 한다면?
         [w, w, w]
         [w, w, w]
         [r, r, r]
[r, r, y][b, b, b][w, o, o][g, g, g]
[g, g, g][r, r, y][b, b, b][w, o, o]
[g, g, g][r, r, y][b, b, b][w, o, o]
         [y, y, o]
         [y, y, o]
         [y, y, o]



풀이

구현 시 주의사항

💡 3차원 큐브를 2차원으로 표현하는 과정에서 방향 설정이 매우 중요함. 회전 시 면과 인접한 면들의 변화를 정확히 파악하자!
디버깅 꼭꼭 하자!!!! => 추천 링크: 루빅큐브 회전모습 확인

💡 -방향은 +를 3번한 것과 동일하다. (시계 방향 3번 = 반시계 방향 1번)


핵심 구현 사항

  • 각 면을 3x3 2차원 배열로 표현 (총 6개)
  • 시계 방향 회전만 구현하자 (총 6개 = R+ L+ U+ D+ F+ B+)
    • 반시계는 해당 함수를 3번 사용하면 되기 때문!
  • 회전 시 인접면들의 변화 처리 꼭! 꼭! 다시 체크!!
    • 디버깅 코드도 있으니까 디버깅으로 더블체크 하길 강조한다.


면 회전 구현

//회전로직은 시계방향: B[x][y]=A[N-1-y][x] 를 이용하면 된다.
private static void rotate(char[][] value) {
  char[][] temp = new char[3][3];
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      temp[i][j] = value[i][j]; //copy
    }
  }
  for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 3; j++) {
      value[i][j] = temp[3-1-j][i];
    }
  }
}


반시계 방향 처리

if (roll.charAt(0) == 'U') {
  UPlus();
  //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
  if (roll.charAt(1) == '-') {
    UPlus();
    UPlus();
  }
}



전체 코드

U+ L+ R+ L+ F+ B+ 함수를 구현하는게 가장 중요하다.
해당 함수 코드는 참고로만 확인하고, 직접 전개도의 움직임을 보고 짜는게 구현하기 더 수월할 것이다.

public class 큐빙_5373 {
  static int N;
  static String[] rolling; //input
  static char[][] front = new char[3][3];
  static char[][] up = new char[3][3];
  static char[][] left = new char[3][3];
  static char[][] right = new char[3][3];
  static char[][] down = new char[3][3];
  static char[][] back = new char[3][3];

  private static void solve() {
    for (int i = 0; i < N; i++) {
      String roll=rolling[i];
      if (roll.charAt(0) == 'U') {
        UPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          UPlus();
          UPlus();
        }
      }else if (roll.charAt(0) == 'D') {
        DPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          DPlus();
          DPlus();
        }
      }else if (roll.charAt(0) == 'F') {
        FPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          FPlus();
          FPlus();
        }
      }else if (roll.charAt(0) == 'B') {
        BPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          BPlus();
          BPlus();
        }
      }else if (roll.charAt(0) == 'L') {
        LPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          LPlus();
          LPlus();
        }
      }else if (roll.charAt(0) == 'R') {
        RPlus();
        //반시계 방향의 경우 "시계방향x3" 이므로 2번 더 돌려야 함
        if (roll.charAt(1) == '-') {
          RPlus();
          RPlus();
        }
      }
      //debug 모든 면 출력
//      System.out.println(rolling[i]);
//      allPrint();
    }
  }

  public static void main(String[] args) throws IOException {
    //input
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    int T = Integer.parseInt(br.readLine());
    for (int t = 0; t < T; t++) {
      init(); //매번 큐브배열 초기화
      //input
      N = Integer.parseInt(br.readLine());
      StringTokenizer stk = new StringTokenizer(br.readLine(), " ");
      rolling = new String[N + 1];
      for (int i = 0; i < N; i++) {
        rolling[i] = stk.nextToken();
      }
      //run
      solve();
      //output
      for (int i = 0; i < 3; i++) {
        System.out.print(up[i]);
        System.out.println();
      }
    }
  }

  private static void BPlus() {
    rotate(back);
    //up->right->down->left
    char[] temp = new char[3];
    for (int i = 0; i < 3; i++) {
      temp[i]=up[0][i]; //copy
    }
    for (int i = 0; i < 3; i++) {
      up[0][i]=right[i][2];
    }
    for (int i = 0; i < 3; i++) {
      right[i][2]=down[2][2-i];
    }
    for (int i = 0; i < 3; i++) {
      down[2][i]=left[i][0];
    }
    for (int i = 0; i < 3; i++) {
      left[i][0]=temp[2-i];
    }
  }

  private static void LPlus() {
    rotate(left);
    //front->up->back->down
    char[] temp = new char[3];
    for (int i = 0; i < 3; i++) {
      temp[i] = front[i][0]; //copy
    }
    for (int i = 0; i < 3; i++) {
      front[i][0]=up[i][0];
    }
    for (int i = 0; i < 3; i++) {
      up[i][0]=back[2-i][2];
    }
    for (int i = 0; i < 3; i++) {
      back[2-i][2]=down[i][0];
    }
    for (int i = 0; i < 3; i++) {
      down[i][0]=temp[i];
    }
  }

  private static void DPlus() {
    rotate(down);
    //front->left->back->right
    char[] temp = Arrays.copyOfRange(front[2],0,3); //copy
    for (int i = 0; i < 3; i++) {
      front[2][i]=left[2][i];
    }
    for (int i = 0; i < 3; i++) {
      left[2][i]=back[2][i];
    }
    for (int i = 0; i < 3; i++) {
      back[2][i]=right[2][i];
    }
    for (int i = 0; i < 3; i++) {
      right[2][i]=temp[i];
    }
  }

  private static void FPlus() {
    rotate(front);
    //up->left->down->right
    char[] temp = new char[3];
    for (int i = 0; i < 3; i++) {
      temp[i]=up[2][i]; //copy
    }
    for (int i = 0; i < 3; i++) {
      up[2][i]=left[2-i][2];
    }
    for (int i = 0; i < 3; i++) {
      left[i][2]=down[0][i];
    }
    for (int i = 0; i < 3; i++) {
      down[0][i]=right[2-i][0];
    }
    for (int i = 0; i < 3; i++) {
      right[i][0]=temp[i]; //방향 주의
    }
  }

  private static void RPlus() {
    rotate(right);
    //front->down->back->up
    char[] temp = new char[3];
    for (int i = 0; i < 3; i++) {
      temp[i] = front[i][2]; //copy
    }
    for (int i = 0; i < 3; i++) {
      front[i][2]=down[i][2];
    }
    for (int i = 0; i < 3; i++) {
      down[i][2]=back[2-i][0];
    }
    for (int i = 0; i < 3; i++) {
      back[2-i][0]=up[i][2];
    }
    for (int i = 0; i < 3; i++) {
      up[i][2]=temp[i];
    }
  }

  private static void UPlus() {
    rotate(up);
    //front->right->back->left
    char[] temp = Arrays.copyOfRange(front[0],0,3); //copy
    for (int i = 0; i < 3; i++) {
      front[0][i]=right[0][i];
    }
    for (int i = 0; i < 3; i++) {
      right[0][i]=back[0][i];
    }
    for (int i = 0; i < 3; i++) {
      back[0][i]=left[0][i];
    }
    for (int i = 0; i < 3; i++) {
      left[0][i]=temp[i];
    }
  }

  //회전로직은 시계방향: B[x][y]=A[N-1-y][x] 를 이용하면 된다.
  private static void rotate(char[][] value) {
    char[][] temp = new char[3][3];
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        temp[i][j] = value[i][j]; //copy
      }
    }
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
        value[i][j] = temp[3-1-j][i];
      }
    }
  }

  private static void init() {
    int cnt=0; //debug
    for (int i = 0; i < 3; i++) {
      for (int j = 0; j < 3; j++) {
//        front[i][j]=(char)(++cnt+'0'); //rotate debug 용도
//        up[i][j]=(char)(cnt+'0'); //rotate debug 용도
//        down[i][j]=(char)(cnt+'0'); //rotate debug 용도
//        back[i][j]=(char)(cnt+'0'); //rotate debug 용도
//        left[i][j]=(char)(cnt+'0'); //rotate debug 용도
//        right[i][j]=(char)(cnt+'0'); //rotate debug 용도
//        up[i][j]='w'; //전개도 링크 debug 용도(그림 순서 달라서)
//        down[i][j]='y'; //전개도 링크 debug 용도
//        front[i][j]='g'; //전개도 링크 debug 용도
//        back[i][j]='b'; //전개도 링크 debug 용도
//        left[i][j]='o'; //전개도 링크 debug 용도
//        right[i][j]='r'; //전개도 링크 debug 용도
        up[i][j]='w';
        down[i][j]='y';
        front[i][j]='r';
        back[i][j]='o';
        left[i][j]='g';
        right[i][j]='b';
      }
    }
  }

  private static void allPrint() {
    //전개도로 출력
    for(int i=0; i<3; i++) {
      System.out.print("         ");
      System.out.println(Arrays.toString(up[i]));
    }
    for(int i=0; i<3; i++) {
      System.out.print(Arrays.toString(left[i]));
      System.out.print(Arrays.toString(front[i]));
      System.out.print(Arrays.toString(right[i]));
      System.out.println(Arrays.toString(back[i]));
    }
    for (int i = 0; i < 3; i++) {
      System.out.print("         ");
      System.out.println(Arrays.toString(down[i]));
    }
  }

}

/*
아래 링크 전개도 보고 디버깅 하기.
https://rubiks-cube-solver.com/fr/#
1
3
U+ R+ R+
1
3
R+ U+ U+
1
3
U+ F+ F+
1
3
R+ D+ D+
1
3
D+ L+ L+
1
3
D+ B+ B+
 */

주관적인 생각의 풀이이므로 틀린 부분 지적은 언제나 환영합니다⚡

댓글남기기