시뮬레이션은 처음이라 문제 읽자마자 당황했는데
풀다보니 나름 할만했다!
격자의 가장 왼쪽 윗 칸은 (1, 1)이고, 가장 오른쪽 아랫 칸은 (N, N)이다. 마법사 상어는 연습을 위해 1번 행과 N번 행을 연결했고, 1번 열과 N번 열도 연결했다. 즉, N번 행의 아래에는 1번 행이, 1번 행의 위에는 N번 행이 있고, 1번 열의 왼쪽에는 N번 열이, N번 열의 오른쪽에는 1번 열이 있다.
이 부분이 조금 헷갈렸는데 배열의 마지막 다음이 첫번째 원소니깐 이 부분은 모듈러 연산을 통해 새로운 위치가 범위 0에서 n-1 사이에 있도록 제한했다.
그리고 nx, ny가 음수일 경우 +n을 해줬다.
var nx = (x + dx[d] * s) % n
var ny = (y + dy[d] * s) % n
if nx < 0 { nx += n }
if ny < 0 { ny += n }
2에서 물이 증가한 칸 (r, c)에 물복사버그 마법을 시전한다. 물복사버그 마법을 사용하면, 대각선 방향으로 거리가 1인 칸에 물이 있는 바구니의 수만큼 (r, c)에 있는 바구니의 물이 양이 증가한다.
이때는 이동과 다르게 경계를 넘어가는 칸은 대각선 방향으로 거리가 1인 칸이 아니다.
예를 들어, (N, 2)에서 인접한 대각선 칸은 (N-1, 1), (N-1, 3)이고, (N, N)에서 인접한 대각선 칸은 (N-1, N-1)뿐이다.
for i in stride(from: 2, through: 8, by: 2) {
let nx = x + dx[i]
let ny = y + dy[i]
if isWithinMap(nx, ny) && map[nx][ny] > 0 {
count += 1
}
}
대각선 방향을 확인하기 위해 stride를 사용해 방향을 뽑아냈고,
func isWithinMap(_ x: Int, _ y: Int) -> Bool {
return x >= 0 && x < n && y >= 0 && y < n
}
isWithinMap함수를 생성해 map을 넘어가는지 아닌지 확인해주었다.
바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어든다. 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
!cloudsMoved.contains(where: { $0 == (x, y) })
contains를 이용해 3에서 구름이 사라진 칸이 아닌 칸에 구름 생성
func isWithinMap(_ x: Int, _ y: Int) -> Bool {
return x >= 0 && x < n && y >= 0 && y < n
}
let input = readLine()!.split(separator: " ").map { Int(String($0))! }
let (n, m) = (input[0], input[1])
var map = [[Int]]()
for _ in 0..<n {
let input = readLine()!.split(separator: " ").map { Int(String($0))! }
map.append(input)
}
var clouds = [(n-1, 0), (n-1, 1), (n-2, 0), (n-2, 1)]
// ←, ↖, ↑, ↗, →, ↘, ↓, ↙
let dx = [0, 0, -1, -1, -1, 0, 1, 1, 1]
let dy = [0, -1, -1, 0, 1, 1, 1, 0, -1]
for _ in 0..<m {
let input = readLine()!.split(separator: " ").map { Int(String($0))! }
let (d, s) = (input[0], input[1])
var cloudsMoved = [(Int, Int)]()
// 모든 구름이 d 방향으로 s칸 이동한다. (1번 행과 N번 행, 1번 열과 N번 열이 연결되어있음)
for (x, y) in clouds {
var nx = (x + dx[d] * s) % n
var ny = (y + dy[d] * s) % n
if nx < 0 { nx += n }
if ny < 0 { ny += n }
cloudsMoved.append((nx, ny))
}
// 구름이 있는 칸의 바구니에 저장된 물의 양이 1 증가
for (x, y) in cloudsMoved {
map[x][y] += 1
}
// 물이 증가한 칸에 대각선 방향으로 거리가 1인 칸에 "물이 있는 / 바구니의 수만큼" 물 증가
for (x, y) in cloudsMoved {
var count = 0
for i in stride(from: 2, through: 8, by: 2) {
let nx = x + dx[i]
let ny = y + dy[i]
if isWithinMap(nx, ny) && map[nx][ny] > 0 {
count += 1
}
}
map[x][y] += count
}
// 바구니에 저장된 물의 양이 2 이상인 모든 칸에 구름이 생기고, 물의 양이 2 줄어듦.
// 이때 구름이 생기는 칸은 3에서 구름이 사라진 칸이 아니어야 한다.
var newClouds = [(Int, Int)]()
for x in 0..<n {
for y in 0..<n {
if map[x][y] >= 2 && !cloudsMoved.contains(where: { $0 == (x, y) }) {
map[x][y] -= 2
newClouds.append((x, y))
}
}
}
clouds = newClouds
}
var sum = 0
for x in 0..<n {
for y in 0..<n {
sum += map[x][y]
}
}
print(sum)