본문으로 바로가기

[BOJ 14499] 주사위 굴리기(C++)

category Algorithms/Implementation 2021. 9. 30. 17:19

주사위 굴리기(Gold 4)

문제

전체 문제 보기

 

14499번: 주사위 굴리기

첫째 줄에 지도의 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20), 주사위를 놓은 곳의 좌표 x y(0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1), 그리고 명령의 개수 K (1 ≤ K ≤ 1,000)가 주어진다. 둘째 줄부터 N개의 줄에 지도

www.acmicpc.net

접근법

문제에서 주어진 주사위의 기능들을 구현하여 시뮬레이션하는 문제입니다. 주사위의 이동 방향(1~4)을 받아서 동서남북으로 주사위를 굴리는 함수 Roll을 구현하여서 해결할 수 있습니다. 주사위가 회전하는 부분은 4개의 면의 값을 변경하여 구현할 수 있습니다. 예를 들어 북쪽으로 이동하는 경우는 다음과 같습니다.

  • temp = top
  • top = left
  • left = bottom
  • bottom = right
  • right = temp

같은 방식으로 다른 방향으로 이동도 구현할 수 있습니다. 이 문제에서 주의할 점은 시작점의 위치입니다. (x, y)로 제시된 주사위 위치를 x축 y축으로 착각하여 (2, 1)로 제시된 입력받고 행:1 열:2 로 계산하여 오답 처리된 경우가 많습니다. 문제에서는 첫 번째 값이 row에 해당하는 행이며, 두 번째 값이 col에 해당하는 열이라고 명시되어 있습니다. 반면, 어디에도 x, y가 x축 y축이라는 말은 없습니다. 이 점을 유의해서 구현해야 합니다.

전체 구현

#include <stdio.h>
#include <vector>

using namespace std;
using Level = vector<vector<int>>;

struct Pos {
    Pos(int _r, int _c) : r(_r), c(_c) {}
    Pos() {}
    int r{};
    int c{};
};

class Dice {
public:
    Dice(Level& _level, Pos _pos);

    int Roll(int dir);

private:
    int top{};
    int front{};
    int left{};
    int right{};
    int back{};
    int bottom{};
    Level& level;
    Pos pos;

    const int MAX_R;
    const int MAX_C;

    bool East();    // 1
    bool Weast();   // 2
    bool North();   // 3
    bool South();   // 4
    void Stamp();
};
Dice::Dice(Level& _level, Pos _pos) 
    : level(_level), pos(_pos), MAX_R(level.size()) ,MAX_C(level[0].size()){

}

int Dice::Roll(int dir)
{
    bool result{};
    switch (dir)
    {
    case 1:
        result = East();
        break;
    case 2:
        result = Weast();
        break;
    case 3:
        result = North();
        break;
    case 4:
        result = South();
        break;
    }
    if (result == false) return -1;

    return top;
}
void Dice::Stamp()
{
    int& cell = level[pos.r][pos.c];
    if (cell == 0)
    {
        cell = bottom;
    }
    else
    {
        bottom = cell;
        cell = 0;
    }
}

bool Dice::East()
{
    // 범위 체크
    if (pos.c == MAX_C - 1) return false;
    pos.c++;

    int temp;
    temp = top;
    top = left;
    left = bottom;
    bottom = right;
    right = temp;
    Stamp();

    return true;
}
bool Dice::Weast()
{
    // 범위 체크
    if (pos.c == 0) return false;
    pos.c--;

    int temp;
    temp = top;
    top = right;
    right = bottom;
    bottom = left;
    left = temp;

    Stamp();

    return true;
}
bool Dice::North()
{
    // 범위 체크
    if (pos.r == 0) return false;
    pos.r--;

    int temp;
    temp = top;
    top = front;
    front = bottom;
    bottom = back;
    back = temp;

    Stamp();

    return true;
}
bool Dice::South()
{
    // 범위 체크
    if (pos.r == MAX_R - 1) return false;
    pos.r++;

    int temp;
    temp = top;
    top = back;
    back = bottom;
    bottom = front;
    front = temp;

    Stamp();

    return true;
}

int main() {

    int N, M; // 세로 크기 N, 가로 크기 M (1 ≤ N, M ≤ 20)
    scanf("%d %d ", &N, &M);
    int r, c; //  r c(0 ≤ r ≤ N-1, 0 ≤ c ≤ M-1)
    scanf("%d %d ", &r, &c);
    int K; // 명령의 개수 K (1 ≤ K ≤ 1,000)
    scanf("%d ", &K);

    // 레벨 생성 및 입력
    Level level(N);
    for (int i = 0; i < N; ++i)
    {
        level[i].resize(M);
        for (int j = 0; j < M; ++j)
        {
            scanf("%d ", &level[i][j]);
        }
    }

    // 주사위 생성
    Dice dice(level, Pos(r, c));

    while (K--)
    {
        int top;
        int cmd;
        scanf("%d ", &cmd);
        top = dice.Roll(cmd);

        if (top == -1)continue;
        printf("%d\n", top);
    }

    return 0;
}