알고리즘/문제풀이
[백준/Gold4] Swift - 주사위 굴리기
피자식빵
2025. 6. 22. 14:15
2025.06.22 기준 Gold4
https://www.acmicpc.net/problem/14499
알고리즘
구현, 시뮬레이션
문제 요약
- 크기가 N×M인 2차원 지도 위에 주사위가 놓여 있다.
- 주사위의 초기 위치는 (x, y)이고, 이동 명령이 순서대로 주어진다.
- 주사위는 지도 바깥으로는 나갈 수 없으며, 나가려고 하면 그 명령은 무시된다.
- 주사위를 굴릴 때마다 윗면에 적힌 숫자를 출력해야 한다.
- 지도의 좌표는 (r, c)로 나타내며, r는 북쪽으로부터 떨어진 칸의 개수, c는 서쪽으로부터 떨어진 칸의 개수이다.
주사위 전개도
2
4 1 3
5
6
- 가장 처음에 주사위에는 모든 면에는 0이 적혀져 있다.
- 1이 윗면, 3은 동쪽을 바라보도록 놓여있다.
지도 규칙
- 주사위가 이동한 칸이 0이라면, 주사위 바닥면의 숫자를 해당 칸에 복사한다.
- 0이 아니라면, 해당 칸의 숫자를 주사위 바닥면에 복사하고, 해당 칸은 0으로 바뀐다.
- 주사위를 놓은 칸에 쓰여 있는 수는 항상 0이다.
- 지도의 각 칸에 쓰여 있는 수는 10 미만의 자연수 또는 0이다.
명령어는 최대 1,000개가 주어지며, 각 숫자의 의미는 다음과 같다:
- 1: 동쪽
- 2: 서쪽
- 3: 북쪽
- 4: 남쪽
제약 조건
첫 줄: N, M, x, y, K
다음 N줄: 지도 정보 (각 줄 M개 숫자)
마지막 줄: 명령어 K개
- N: 세로크기 (1 ≤ N ≤ 20)
- M: 가로 크기 (1 ≤ M ≤ 20)
- x, y: 주사위를 놓은 곳의 좌표 (0 ≤ x ≤ N-1, 0 ≤ y ≤ M-1)
- K: 명령어 개수 (1 ≤ K ≤ 1,000)
입출력 예
// 입력
4 2 0 0 8
0 2
3 4
5 6
7 8
4 4 4 1 3 3 3 2
// 출력
0
0
3
0
0
8
6
3
// 입력
2 2 0 0 16
0 2
3 4
4 4 4 4 1 1 1 1 3 3 3 3 2 2 2 2
// 출력
0
0
0
0
아이디어
2초의 시간 제한이 있지만, 명령어의 최대 개수가 1000개이기 때문에 요구사항을 잘 구현하기만 하면 된다고 생각함.
1. 주사위 굴리는 범위 확인
지도 바깥으로 나가면 모두 무시되기 때문에 가장 먼저 주사위를 굴릴 수 있는 범위인지 확인
- 주사위를 굴릴 수 있다면 현재 위치 업데이트 및 true 반환
- 주사위를 굴릴 수 없다면 false 번환
func diceCheck(_ command: Int) -> Bool {
var y = diceY
var x = diceX
switch command {
case 1:
x += 1
case 2:
x -= 1
case 3:
y -= 1
case 4:
y += 1
default:
break
}
if (0..<height).contains(y) && (0..<width).contains(x) {
diceY = y
diceX = x
return true
} else {
return false
}
}
2. 주사위 굴리기
주사위를 굴렸을 때, 하단과 상단의 값을 관리하는 배열을 생성

주어진 전개도를 기준으로 주사위를 굴렸을 때 상태 변화 확인 후
만든 배열의 값을 수정하는 diceRoll이라는 함수 구현
func diceRoll(_ command: Int) -> [Int] {
var temp = diceInfo // 1: 상 2: 하 3: 동 4: 서 5: 북 6: 남
switch command {
case 1: // 동쪽
temp[1] = diceInfo[4]
temp[2] = diceInfo[3]
temp[3] = diceInfo[1]
temp[4] = diceInfo[2]
case 2: // 서쪽
temp[1] = diceInfo[3]
temp[2] = diceInfo[4]
temp[3] = diceInfo[2]
temp[4] = diceInfo[1]
case 3: // 북쪽
temp[1] = diceInfo[6]
temp[2] = diceInfo[5]
temp[5] = diceInfo[1]
temp[6] = diceInfo[2]
case 4: // 남쪽
temp[1] = diceInfo[5]
temp[2] = diceInfo[6]
temp[5] = diceInfo[2]
temp[6] = diceInfo[1]
default:
break
}
return temp
}
3. 명령어 수행
이 후 명령어에 따라 주사위를 굴리고, 이동한 위치의 값이 0인지 아닌지에 따라 구현
풀이
// 주사위 굴리기, 구현
import Foundation
let input = readLine()!.split(separator: " ").map{Int(String($0))!}
let height = input[0], width = input[1]
var diceY = input[2], diceX = input[3]
let command = input[4]
var maps: [[Int]] = []
for _ in 0..<height {
maps.append(readLine()!.split(separator: " ").map{Int(String($0))!})
}
let commands = readLine()!.split(separator: " ").map{Int(String($0))!}
var dices = [0, 0, 0, 0, 0, 0, 0]
var diceInfo = [0, 1, 6, 3, 4, 2, 5] // 상단, 하단, 동쪽, 서쪽, 북쪽, 남쪽
func diceCheck(_ command: Int) -> Bool {
var y = diceY
var x = diceX
switch command {
case 1:
x += 1
case 2:
x -= 1
case 3:
y -= 1
case 4:
y += 1
default:
break
}
if (0..<height).contains(y) && (0..<width).contains(x) {
diceY = y
diceX = x
return true
} else {
return false
}
}
func diceRoll(_ command: Int) -> [Int] {
var temp = diceInfo // 1: 상 2: 하 3: 동 4: 서 5: 북 6: 남
switch command {
case 1: // 동쪽
temp[1] = diceInfo[4]
temp[2] = diceInfo[3]
temp[3] = diceInfo[1]
temp[4] = diceInfo[2]
case 2: // 서쪽
temp[1] = diceInfo[3]
temp[2] = diceInfo[4]
temp[3] = diceInfo[2]
temp[4] = diceInfo[1]
case 3: // 북쪽
temp[1] = diceInfo[6]
temp[2] = diceInfo[5]
temp[5] = diceInfo[1]
temp[6] = diceInfo[2]
case 4: // 남쪽
temp[1] = diceInfo[5]
temp[2] = diceInfo[6]
temp[5] = diceInfo[2]
temp[6] = diceInfo[1]
default:
break
}
return temp
}
for c in commands {
if diceCheck(c) { // 명령어가 유효하면
diceInfo = diceRoll(c) // 주사위 굴리기
let diceBottom = diceInfo[2]
if maps[diceY][diceX] == 0 { // 이동한 칸이 0일때, 주사위 바닥면 수를 복사
maps[diceY][diceX] = dices[diceBottom]
} else { // 그렇지 않으면 이동 칸 숫자를 주사위 바닥면에 복사
dices[diceBottom] = maps[diceY][diceX]
maps[diceY][diceX] = 0
}
print(dices[diceInfo[1]])
}
}
개선점
dy, dx 배열을 사용하여 diceCheck를 단순화 할 수 있음
let dy = [0, 0, 0, -1, 1] // 동, 서, 북, 남 순
let dx = [0, 1, -1, 0, 0]
실수 포인트
이동한 칸이 0이 아닐 때, 주사위 바닥면에 값을 복사하고 해당 칸은 0이 된다는 조건을 놓침