문제
3×3 틱택토 보드의 최종 상태가 주어졌을 때, 그것이 유효한 게임 결과인지 판별하는 문제다.
핵심 아이디어
- X가 선공이므로 항상
X 개수 >= O 개수여야 한다. - X와 O의 차이는 최대 1이다.
- 승리 조건 8가지(가로 3, 세로 3, 대각선 2)를 미리 테이블로 정의한다.
- 다음 케이스들을 구분하여 유효성을 판별한다:
- X만 승리: O는 X보다 적어야 한다 (X가 마지막 수)
- O만 승리: X와 O 개수가 같아야 한다 (O가 마지막 수)
- 둘 다 승리: 불가능
- 아무도 안 이김: 빈 칸이 0이어야 유효 (무승부)
풀이
#include <iostream>
#include <string>
using namespace std;
int t[8][9] = {
{1,1,1, 0,0,0, 0,0,0}, // 가로 1행
{0,0,0, 1,1,1, 0,0,0}, // 가로 2행
{0,0,0, 0,0,0, 1,1,1}, // 가로 3행
{1,0,0, 1,0,0, 1,0,0}, // 세로 1열
{0,1,0, 0,1,0, 0,1,0}, // 세로 2열
{0,0,1, 0,0,1, 0,0,1}, // 세로 3열
{1,0,0, 0,1,0, 0,0,1}, // 대각선 ↘
{0,0,1, 0,1,0, 1,0,0} // 대각선 ↙
};
bool check_winner(string& board, char type) {
for (int i = 0; i < 8; i++) {
int w = 0;
for (int j = 0; j < 9; j++) {
if (t[i][j] && type == board[j]) w++;
}
if (w == 3) return true;
}
return false;
}
int main() {
while (true) {
int x, o, blank;
x = o = blank = 0;
string board;
cin >> board;
if (board == "end") break;
for (int i = 0; i < 9; i++) {
if (board[i] == 'X') x++;
else if (board[i] == 'O') o++;
else blank++;
}
// O가 X보다 많을 수 없다
if (o > x) { cout << "invalid" << endl; continue; }
// 차이는 1 이하
if (abs(x - o) > 1) { cout << "invalid" << endl; continue; }
bool x_win = check_winner(board, 'X');
bool o_win = check_winner(board, 'O');
if (o_win && !x_win) {
cout << (o < x ? "invalid" : "valid") << endl;
} else if (x_win && !o_win) {
cout << (o >= x ? "invalid" : "valid") << endl;
} else if (o_win && x_win) {
cout << "invalid" << endl;
} else {
// 아무도 안 이겼으면 보드가 꽉 차야 유효
cout << (blank == 0 ? "valid" : "invalid") << endl;
}
}
return 0;
}
주요 포인트
- 승리 패턴을 2D 배열로 미리 정의하면 코드가 깔끔해진다.
- X가 이겼을 때
o >= x이면 O가 추가로 수를 둔 것이므로 invalid다. - O가 이겼을 때
o < x이면 X가 추가로 수를 둔 것이므로 invalid다.
복잡도
- 시간: O(T × 8 × 9) — T: 테스트 케이스 수
- 공간: O(1)
모든 예외 케이스를 빠짐없이 처리해야 하는, 꼼꼼한 구현이 필요한 문제다.
댓글