Skip to content

Commit 1286844

Browse files
committed
[level 3] Title: 사라지는 발판, Time: 233.21 ms, Memory: 16.4 MB -BaekjoonHub
1 parent 79b9da9 commit 1286844

2 files changed

Lines changed: 244 additions & 0 deletions

File tree

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
# [level 3] 사라지는 발판 - 92345
2+
3+
[문제 링크](https://school.programmers.co.kr/learn/courses/30/lessons/92345)
4+
5+
### 성능 요약
6+
7+
메모리: 16.4 MB, 시간: 233.21 ms
8+
9+
### 구분
10+
11+
코딩테스트 연습 > 2022 KAKAO BLIND RECRUITMENT
12+
13+
### 채점결과
14+
15+
정확성: 100.0<br/>합계: 100.0 / 100.0
16+
17+
### 제출 일자
18+
19+
2025년 04월 18일 22:03:31
20+
21+
### 문제 설명
22+
23+
<h5>문제 설명</h5>
24+
25+
<p>플레이어 A와 플레이어 B가 서로 게임을 합니다. 당신은 이 게임이 끝날 때까지 양 플레이어가 캐릭터를 몇 번 움직이게 될지 예측하려고 합니다.</p>
26+
27+
<p>각 플레이어는 자신의 캐릭터 하나를 보드 위에 올려놓고 게임을 시작합니다. 게임 보드는 1x1 크기 정사각 격자로 이루어져 있으며, 보드 안에는 발판이 있는 부분과 없는 부분이 있습니다. 발판이 있는 곳에만 캐릭터가 서있을 수 있으며, 처음 캐릭터를 올려놓는 곳은 항상 발판이 있는 곳입니다. 캐릭터는 발판이 있는 곳으로만 이동할 수 있으며, 보드 밖으로 이동할 수 없습니다. 밟고 있던 발판은 그 위에 있던 캐릭터가 다른 곳으로 이동하여 다른 발판을 밞음과 동시에 사라집니다. 양 플레이어는 번갈아가며 자기 차례에 자신의 캐릭터를 상하좌우로 인접한 4개의 칸 중에서 발판이 있는 칸으로 옮겨야 합니다.</p>
28+
29+
<p>다음과 같은 2가지 상황에서 패자와 승자가 정해지며, 게임이 종료됩니다.</p>
30+
31+
<ul>
32+
<li>움직일 차례인데 캐릭터의 상하좌우 주변 4칸이 모두 발판이 없거나 보드 밖이라서 이동할 수 없는 경우, 해당 차례 플레이어는 패배합니다.</li>
33+
<li>두 캐릭터가 같은 발판 위에 있을 때, 상대 플레이어의 캐릭터가 다른 발판으로 이동하여 자신의 캐릭터가 서있던 발판이 사라지게 되면 패배합니다.</li>
34+
</ul>
35+
36+
<p>게임은 항상 플레이어 A가 먼저 시작합니다. 양 플레이어는 최적의 플레이를 합니다. 즉, 이길 수 있는 플레이어는 최대한 빨리 승리하도록 플레이하고, 질 수밖에 없는 플레이어는 최대한 오래 버티도록 플레이합니다. '이길 수 있는 플레이어'는 실수만 하지 않는다면 항상 이기는 플레이어를 의미하며, '질 수밖에 없는 플레이어'는 최선을 다해도 상대가 실수하지 않으면 항상 질 수밖에 없는 플레이어를 의미합니다. 최대한 오래 버틴다는 것은 양 플레이어가 캐릭터를 움직이는 횟수를 최대화한다는 것을 의미합니다.</p>
37+
38+
<p>아래 그림은 초기 보드의 상태와 각 플레이어의 위치를 나타내는 예시입니다.</p>
39+
40+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/f6c72518-3c10-467e-a2c4-ecbe418c1dd4/02_2022_%E1%84%80%E1%85%A9%E1%86%BC%E1%84%8E%E1%85%A2%E1%84%86%E1%85%AE%E1%86%AB%E1%84%8C%E1%85%A6_%E1%84%89%E1%85%A1%E1%84%85%E1%85%A1%E1%84%8C%E1%85%B5%E1%84%82%E1%85%B3%E1%86%AB%E1%84%87%E1%85%A1%E1%86%AF%E1%84%91%E1%85%A1%E1%86%AB_01.png" title="" alt="02_2022_공채문제_사라지는발판_01.png"></p>
41+
42+
<p>위와 같은 경우, 플레이어 A는 실수만 하지 않는다면 항상 이길 수 있습니다. 따라서 플레이어 A는 이길 수 있는 플레이어이며, B는 질 수밖에 없는 플레이어입니다. 다음은 A와 B가 최적의 플레이를 하는 과정을 나타냅니다.</p>
43+
44+
<ol>
45+
<li>플레이어 A가 초기 위치 (1, 0)에서 (1, 1)로 이동합니다. <strong>플레이어 A가 (0, 0)이나 (2, 0)으로 이동할 경우 승리를 보장할 수 없습니다. 따라서 무조건 이길 방법이 있는 (1, 1)로 이동합니다.</strong></li>
46+
<li>플레이어 B는 (1, 1)로 이동할 경우, 바로 다음 차례에 A가 위 또는 아래 방향으로 이동하면 발판이 없어져 패배하게 됩니다. <strong>질 수밖에 없는 플레이어는 최대한 오래 버티도록 플레이하기 때문에 (1, 1)로 이동하지 않습니다.</strong> (1, 2)에서 위쪽 칸인 (0, 2)로 이동합니다.</li>
47+
<li>A가 (1, 1)에서 (0, 1)로 이동합니다.</li>
48+
<li>B에게는 남은 선택지가 (0, 1)밖에 없습니다. 따라서 (0, 2)에서 (0, 1)로 이동합니다.</li>
49+
<li>A가 (0, 1)에서 (0, 0)으로 이동합니다. 이동을 완료함과 동시에 B가 서있던 (0, 1)의 발판이 사라집니다. B가 패배합니다.</li>
50+
<li>만약 과정 2에서 B가 아래쪽 칸인 (2, 2)로 이동하더라도 A는 (2, 1)로 이동하면 됩니다. 이후 B가 (2, 1)로 이동, 다음 차례에 A가 (2, 0)으로 이동하면 B가 패배합니다.</li>
51+
</ol>
52+
53+
<p>위 예시에서 양 플레이어가 최적의 플레이를 했을 경우, 캐릭터의 이동 횟수 합은 5입니다. 최적의 플레이를 하는 방법은 여러 가지일 수 있으나, 이동한 횟수는 모두 5로 같습니다.</p>
54+
55+
<p>게임 보드의 초기 상태를 나타내는 2차원 정수 배열 <code>board</code>와 플레이어 A의 캐릭터 초기 위치를 나타내는 정수 배열 <code>aloc</code>, 플레이어 B의 캐릭터 초기 위치를 나타내는 정수 배열 <code>bloc</code>이 매개변수로 주어집니다. 양 플레이어가 최적의 플레이를 했을 때, 두 캐릭터가 움직인 횟수의 합을 return 하도록 solution 함수를 완성해주세요.</p>
56+
57+
<hr>
58+
59+
<h5>제한사항</h5>
60+
61+
<ul>
62+
<li>1 ≤ <code>board</code>의 세로 길이 ≤ 5</li>
63+
<li>1 ≤ <code>board</code>의 가로 길이 ≤ 5</li>
64+
<li><code>board</code>의 원소는 0 또는 1입니다.
65+
66+
<ul>
67+
<li>0은 발판이 없음을, 1은 발판이 있음을 나타냅니다.</li>
68+
<li>게임 보드의 좌측 상단 좌표는 (0, 0), 우측 하단 좌표는 (<code>board</code>의 세로 길이 - 1, <code>board</code>의 가로 길이 - 1)입니다.</li>
69+
</ul></li>
70+
<li><code>aloc</code>과 <code>bloc</code>은 각각 플레이어 A의 캐릭터와 플레이어 B의 캐릭터 초기 위치를 나타내는 좌표값이며 [r, c] 형태입니다.
71+
72+
<ul>
73+
<li>r은 몇 번째 행인지를 나타냅니다.</li>
74+
<li>0 ≤ r &lt; <code>board</code>의 세로 길이</li>
75+
<li>c는 몇 번째 열인지를 나타냅니다.</li>
76+
<li>0 ≤ c &lt; <code>board</code>의 가로 길이</li>
77+
<li>초기 보드의 <code>aloc</code>과 <code>bloc</code> 위치는 항상 발판이 있는 곳입니다.</li>
78+
<li><code>aloc</code>과 <code>bloc</code>이 같을 수 있습니다.</li>
79+
</ul></li>
80+
<li>상대 플레이어의 캐릭터가 있는 칸으로 이동할 수 있습니다.</li>
81+
</ul>
82+
83+
<hr>
84+
85+
<h5>입출력 예</h5>
86+
<table class="table">
87+
<thead><tr>
88+
<th>board</th>
89+
<th>aloc</th>
90+
<th>bloc</th>
91+
<th>result</th>
92+
</tr>
93+
</thead>
94+
<tbody><tr>
95+
<td>[[1, 1, 1], [1, 1, 1], [1, 1, 1]]</td>
96+
<td>[1, 0]</td>
97+
<td>[1, 2]</td>
98+
<td>5</td>
99+
</tr>
100+
<tr>
101+
<td>[[1, 1, 1], [1, 0, 1], [1, 1, 1]]</td>
102+
<td>[1, 0]</td>
103+
<td>[1, 2]</td>
104+
<td>4</td>
105+
</tr>
106+
<tr>
107+
<td>[[1, 1, 1, 1, 1]]</td>
108+
<td>[0, 0]</td>
109+
<td>[0, 4]</td>
110+
<td>4</td>
111+
</tr>
112+
<tr>
113+
<td>[[1]]</td>
114+
<td>[0, 0]</td>
115+
<td>[0, 0]</td>
116+
<td>0</td>
117+
</tr>
118+
</tbody>
119+
</table>
120+
<hr>
121+
122+
<h5>입출력 예 설명</h5>
123+
124+
<p><strong>입출력 예 #1</strong></p>
125+
126+
<p>문제 예시와 같습니다.</p>
127+
128+
<p><strong>입출력 예 #2</strong></p>
129+
130+
<p>주어진 조건을 그림으로 나타내면 아래와 같습니다.</p>
131+
132+
<p><img src="https://grepp-programmers.s3.ap-northeast-2.amazonaws.com/files/production/0319028e-d27c-42d1-b048-027c1ba6a2c7/02_2022_%E1%84%80%E1%85%A9%E1%86%BC%E1%84%8E%E1%85%A2%E1%84%86%E1%85%AE%E1%86%AB%E1%84%8C%E1%85%A6_%E1%84%89%E1%85%A1%E1%84%85%E1%85%A1%E1%84%8C%E1%85%B5%E1%84%82%E1%85%B3%E1%86%AB%E1%84%87%E1%85%A1%E1%86%AF%E1%84%91%E1%85%A1%E1%86%AB_02.png" title="" alt="02_2022_공채문제_사라지는발판_02.png"></p>
133+
134+
<p>항상 이기는 플레이어는 B, 항상 지는 플레이어는 A입니다.</p>
135+
136+
<p>다음은 B가 이기는 방법 중 하나입니다.</p>
137+
138+
<ol>
139+
<li>A가 (1, 0)에서 (0, 0)으로 이동</li>
140+
<li>B가 (1, 2)에서 (2, 2)로 이동</li>
141+
<li>A가 (0, 0)에서 (0, 1)로 이동</li>
142+
<li>B가 (2, 2)에서 (2, 1)로 이동</li>
143+
<li>A가 (0, 1)에서 (0, 2)로 이동</li>
144+
<li>B가 (2, 1)에서 (2, 0)으로 이동</li>
145+
<li>A는 더 이상 이동할 수 없어 패배합니다.</li>
146+
</ol>
147+
148+
<p>위와 같이 플레이할 경우 이동 횟수 6번 만에 게임을 B의 승리로 끝낼 수 있습니다.</p>
149+
150+
<p>B가 다음과 같이 플레이할 경우 게임을 더 빨리 끝낼 수 있습니다. 이길 수 있는 플레이어는 최대한 빨리 게임을 끝내려 하기 때문에 위 방법 대신 아래 방법을 선택합니다.</p>
151+
152+
<ol>
153+
<li>A가 (1, 0)에서 (0, 0)으로 이동</li>
154+
<li>B가 (1, 2)에서 (0, 2)로 이동</li>
155+
<li>A가 (0, 0)에서 (0, 1)로 이동</li>
156+
<li>B가 (0, 2)에서 (0, 1)로 이동</li>
157+
<li>A는 더 이상 이동할 수 없어 패배합니다.</li>
158+
</ol>
159+
160+
<p>위와 같이 플레이할 경우 이동 횟수 4번 만에 게임을 B의 승리로 끝낼 수 있습니다. 따라서 4를 return 합니다.</p>
161+
162+
<p><strong>입출력 예 #3</strong></p>
163+
164+
<p>양 플레이어는 매 차례마다 한 가지 선택지밖에 고를 수 없습니다. 그 결과, (0, 2)에서 어디로도 이동할 수 없는 A가 패배합니다. 양 플레이어가 캐릭터를 움직인 횟수의 합은 4입니다.</p>
165+
166+
<p><strong>입출력 예 #4</strong></p>
167+
168+
<p>게임을 시작하는 플레이어 A가 처음부터 어디로도 이동할 수 없는 상태입니다. 따라서 A의 패배이며, 이동 횟수의 합은 0입니다.</p>
169+
170+
<hr>
171+
172+
<h5>제한시간 안내</h5>
173+
174+
<ul>
175+
<li>정확성 테스트 : 10초</li>
176+
</ul>
177+
178+
179+
> 출처: 프로그래머스 코딩 테스트 연습, https://school.programmers.co.kr/learn/challenges
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Foundation
2+
3+
struct Location {
4+
var x:Int,y:Int
5+
}
6+
7+
struct GameResult {
8+
var count:Int,isWinnerA:Bool
9+
}
10+
11+
func solution(_ board:[[Int]], _ aloc:[Int], _ bloc:[Int]) -> Int {
12+
let wrapBoard = wrapBoardEdges(board)
13+
let aLoc = Location(x: aloc[0]+1, y: aloc[1]+1)
14+
let bLoc = Location(x: bloc[0]+1, y: bloc[1]+1)
15+
let result = move(wrapBoard, 0, aLoc, bLoc)
16+
return result.count
17+
}
18+
19+
func wrapBoardEdges(_ board:[[Int]]) -> [[Int]] {
20+
var wrapBoard = board
21+
for i in 0..<board.count {
22+
wrapBoard[i].insert(0, at: 0)
23+
wrapBoard[i].append(0)
24+
}
25+
wrapBoard.insert(Array(repeating: 0, count: board[0].count+2), at: 0)
26+
wrapBoard.append(Array(repeating: 0, count: board[0].count+2))
27+
return wrapBoard
28+
}
29+
30+
func move(_ board:[[Int]], _ count:Int,_ aLoc:Location,_ bLoc:Location) -> GameResult {
31+
let isTurnA = count%2 == 0 ? true : false
32+
let loc = isTurnA ? aLoc : bLoc
33+
var minCount = Int.max
34+
var maxCount = 0
35+
36+
if board[loc.x][loc.y] == 0 {
37+
return GameResult(count: count, isWinnerA: isTurnA)
38+
}
39+
40+
for l in makeLRUD(loc).filter({board[$0.x][$0.y] != 0}) {
41+
var newBoard = board
42+
newBoard[loc.x][loc.y] = 0
43+
let moved = isTurnA ? move(newBoard,count+1,l,bLoc) : move(newBoard,count+1,aLoc,l)
44+
let result = isTurnA ? moved.isWinnerA :!moved.isWinnerA
45+
if result {
46+
maxCount = max(maxCount,moved.count)
47+
}else {
48+
minCount = min(minCount,moved.count)
49+
}
50+
}
51+
52+
if minCount == Int.max && maxCount == 0 {
53+
return GameResult(count: count, isWinnerA: isTurnA)
54+
}
55+
56+
if minCount != Int.max {
57+
return GameResult(count: minCount, isWinnerA: !isTurnA)
58+
}
59+
60+
return GameResult(count: maxCount, isWinnerA: isTurnA)
61+
}
62+
63+
func makeLRUD(_ loc:Location) -> [Location] {
64+
return [Location(x: loc.x-1, y: loc.y),Location(x: loc.x+1, y: loc.y),Location(x: loc.x, y: loc.y-1),Location(x: loc.x, y: loc.y+1)]
65+
}

0 commit comments

Comments
 (0)