문제
틱택토는 3x3 크기의 게임판에서 하는 3목 게임입니다. 두 명이 번갈아가며 o와 x를 게임판의 빈 칸에 쓰되, 먼저 같은 글자를 가로, 세로 혹은 대각선으로 3개 쓰이도록 하는 쪽이 이깁니다. 예를 들어, 다음 게임판은 x가 이긴 게임판입니다.
xoo
.x.
..x
게임은 항상 x부터 시작합니다.
틱택토 게임판의 현재 상태가 주어집니다. 두 사람 모두 최선을 다한다고 가정할 때, 어느쪽이 이길지 판단하는 프로그램을 작성하세요.
입력
입력의 첫 줄에는 테스트 케이스의 수 C(<= 50)가 주어집니다. 각 테스트 케이스는 세 줄에 각 세 글자로 게임판의 각 위치에 쓰인 글자가 주어집니다. 글자가 없는 칸은 마침표(.)로 표현합니다.
출력
각 테스트 케이스마다 한 줄을 출력합니다. 두 사람이 모두 최선을 다할 경우 비긴다면 TIE를, 아닌 경우 이기는 사람의 글자를 출력합니다
난이도는 하라고 하지만 그래도 어려운 문제이다. 게임판에 x, o, . 총 세가지가 9개 올 수 있기 때문에 3^9개의 배열을 사용해 문자판 자체를 메모이제이션한다. 그러기 위해 bijection함수를 통해 게임판을 정수로 전환한다. 게임의 승,패 여부는 canWin함수를 통해 계산한다. 기저사례로 상대방에 의해 게임이 종료되면 패배하기 때문에 -1을 반환한다. 그 후엔 게임판의 빈 공간에 직접 칸을 채우며 점수를 계산한다.
코드 원본 : https://github.com/chosh95/STUDY/blob/master/Algospot/TICTACTOE.cpp
chosh95/STUDY
알고리즘 문제풀이. Contribute to chosh95/STUDY development by creating an account on GitHub.
github.com
C++ 코드
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
using namespace std;
int C;
int dp[19628]; //3^9
int bijection(const vector<string>& board)
{
int res = 0;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
res *= 3;
if (board[i][j] == 'o') ++res;
else if (board[i][j] == 'x') res += 2;
}
}
return res;
}
bool isFinished(const vector<string>& board, char turn)
{
//°¡·Î
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
if (board[i][j] != turn) break;
if (j == 2) return true;
}
}
//¼¼·Î
for (int i = 0; i < 3; i++){
for (int j = 0; j < 3; j++){
if (board[j][i] != turn)break;
if (j == 2) return true;
}
}
//¢Ù
for (int i = 0; i < 3; i++){
if (board[i][i] != turn) break;
if (i == 2) return true;
}
// ¢×
for (int i = 0; i < 3; i++){
if (board[i][2 - i] != turn) break;
if (i == 2) return true;
}
return false;
}
int canWin(vector<string>& board, char turn)
{
if (isFinished(board, 'o'+'x'-turn)) return -1;
int& res = dp[bijection(board)];
if (res != -2) return res;
int minValue = 2;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == '.') {
board[i][j] = turn;
minValue = min(minValue, canWin(board, 'o'+'x'-turn));
board[i][j] = '.';
}
}
}
if (minValue == 2 || minValue == 0) return res = 0;
return res = -minValue;
}
int main()
{
cin >> C;
while (C--) {
int cnt = 0;
vector<string> board;
string tmp;
for (int i = 0; i < 19628; i++) dp[i] = -2;
for (int i = 0; i < 3; i++) {
cin >> tmp;
for (int j = 0; j < 3; j++) {
if (tmp[j] != '.') cnt++;
}
board.push_back(tmp);
}
char start = 'x';
if (cnt % 2 == 1) start = 'o';
int res = canWin(board, start);
if (res == 1) cout << start << endl;
else if (res == 0) cout << "TIE" << endl;
else cout << (char)('x' + 'o' - start) << endl;
}
}
'알고리즘 > Algospot' 카테고리의 다른 글
[Algospot] 블록 게임 (문제 ID : BLOCKGAME) (0) | 2020.01.17 |
---|---|
[Algospot] 숫자 게임 (문제 ID : NUMBERGAME) (0) | 2020.01.17 |
[Algospot] 실험 데이터 복구하기 (문제 ID : RESTORE) (0) | 2020.01.16 |
[Algospot] 웨브바짐 (문제 ID : ZIMBABWE) (0) | 2020.01.16 |
[Algospot] 드래곤 커브 (문제 ID : DRAGON) (0) | 2020.01.15 |