평균 : 180'
sol : 180' 53''
Learnings
- tuple 대신 struct 사용
- 공통 행동을 함수화해서 재사용
- 상태 갱신 책임을 더 명확히 분리
- 변수명/함수명으로 의도를 드러내기
- “정답 코드”에서 한 단계 더 나아가 “읽기 좋은 코드” 만들기
#include <iostream>
#include <tuple>
#include <vector>
#include <queue>
#define MAX_N 21
using namespace std;
int n, m, k, num;
priority_queue<int> gunGrid[MAX_N][MAX_N];
int playerGrid[MAX_N][MAX_N];
int x, y, d, s;
int ds[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
// i좌표, j좌표, 방향, 초기 능력치, gun 공격력
vector<tuple<int, int, int, int, int>> player;
vector<int> scoreBoard;
void Init() {
player.resize(m + 1);
scoreBoard.resize(m + 1);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> num;
if (num > 0) gunGrid[i][j].push(num);
}
}
for (int i = 1; i <= m; i++) {
cin >> x >> y >> d >> s;
player[i] = make_tuple(x, y, d, s, 0);
playerGrid[x][y] = i;
}
}
bool InGrid(int i, int j) {
return 1 <= i && i <= n && 1 <= j && j <= n;
}
void PlayerGridDebug() {
cout << endl << "DEBUG" << endl;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cout << playerGrid[i][j] << ' ';
}
cout << endl;
}
cout << "DEBUG FIN" << endl;
}
pair<int, int> Fight(int p1, int p2) {
int p1s, p1g, p2s, p2g;
int winner, loser;
tie(ignore, ignore, ignore, p1s, p1g) = player[p1];
tie(ignore, ignore, ignore, p2s, p2g) = player[p2];
// p1의 총합이 더 쌘 경우
if (p1s + p1g > p2s + p2g) {
winner = p1;
loser = p2;
}
// p2의 총합이 더 쌘 경우
else if (p1s + p1g < p2s + p2g) {
winner = p2;
loser = p1;
}
// 총합이 같은 경우
else {
if (p1s > p2s) {
winner = p1;
loser = p2;
}
else {
winner = p2;
loser = p1;
}
}
return { winner, loser };
}
void LoserPenalty(int loser) {
int i, j, d, s, g;
tie(i, j, d, s, g) = player[loser];
// 본인이 가진 총을 내려놓는다.
if (g != 0) {
gunGrid[i][j].push(g);
g = 0;
}
// 원래 가지고 있던 방향으로 한 칸 이동한다.
int ni = i + ds[d][0], nj = j + ds[d][1];
// 만약 다른 플레이어가 있거나, 격자 범위 바깥이라면 오른쪽으로 90도씩 회전하여
while (!InGrid(ni, nj) || playerGrid[ni][nj] > 0) {
d = (d + 1) % 4;
ni = i + ds[d][0], nj = j + ds[d][1];
}
// 빈 칸이 보이는 순간 이동한다.
playerGrid[ni][nj] = loser;
// 만약 이동한 칸에 총이 있다면
if (!gunGrid[ni][nj].empty()) {
// 가장 강한 총을 먹는다.
g = gunGrid[ni][nj].top();
gunGrid[ni][nj].pop();
}
// loser 정보 갱신
player[loser] = make_tuple(ni, nj, d, s, g);
}
void WinnerAward(int winner) {
int i, j, d, s, g;
tie(i, j, d, s, g) = player[winner];
// 바닥에 총들이 있을 경우
if (!gunGrid[i][j].empty()) {
// 바닥에 있는 총들과 본인이 가진 총 중에 가장 쎈 총을 획득하고 나머지는 내려놓는다.
if (gunGrid[i][j].top() > g) {
int temp = gunGrid[i][j].top();
gunGrid[i][j].pop();
gunGrid[i][j].push(g);
g = temp;
}
}
// loser 정보 갱신
player[winner] = make_tuple(i, j, d, s, g);
}
void Play() {
for (int p = 1; p <= m; p++) {
int ci, cj, cd, cs, cg;
tie(ci, cj, cd, cs, cg) = player[p];
// 1-1. check
int ni = ci + ds[cd][0], nj = cj + ds[cd][1];
if (!InGrid(ni, nj)) {
cd = (cd + 2) % 4;
ni = ci + ds[cd][0], nj = cj + ds[cd][1];
}
// 방향 보정
player[p] = make_tuple(ci, cj, cd, cs, cg);
// 플레이어가 있을 경우
if (playerGrid[ni][nj] > 0) {
// 승패 확인
int winner, loser;
tie(winner, loser) = Fight(p, playerGrid[ni][nj]);
// 점수 계산
int wi, wj, wd, ws, wg, li, lj, ld, ls, lg;
tie(wi, wj, wd, ws, wg) = player[winner];
tie(li, lj, ld, ls, lg) = player[loser];
scoreBoard[winner] += (ws + wg - ls - lg);
// 가만히 있던 플레이어가 진 경우
// 움직인 플레이어가 이긴 경우
if (ni == li && nj == lj) {
// 승리자의 기존 위치 삭제
playerGrid[ci][cj] = 0;
// 승리자의 위치를 다음 위치로 업데이트
player[winner] = make_tuple(ni, nj, wd, ws, wg);
playerGrid[ni][nj] = winner;
}
// 가만히 있던 플레이어가 이긴 경우
// 움직인 플레이어가 진 경우
else if (ni == wi && nj == wj) {
// 진 유저의 이동 중심을 승리자의 좌표로 설정해주어야 함
player[loser] = make_tuple(ni, nj, ld, ls, lg);
// 기존 위치는 삭제
playerGrid[ci][cj] = 0;
}
LoserPenalty(loser);
WinnerAward(winner);
}
else {
// 이동하려는 칸에 총이 있을 경우
if (!gunGrid[ni][nj].empty()) {
// 원래 갖고 있던 총보다 강한 총일 경우
if (gunGrid[ni][nj].top() > cg) {
// 더 강한 총을 먹고, 기존 총을 내려놓는다.
int betterGun = gunGrid[ni][nj].top();
gunGrid[ni][nj].pop();
gunGrid[ni][nj].push(cg);
cg = betterGun;
}
}
// p번째 player 정보 갱신
player[p] = make_tuple(ni, nj, cd, cs, cg);
playerGrid[ci][cj] = 0;
playerGrid[ni][nj] = p;
}
}
}
int main() {
cin >> n >> m >> k;
Init();
for (int round = 1; round <= k; round++) {
Play();
}
for (int p = 1; p <= m; p++) {
cout << scoreBoard[p] << ' ';
}
return 0;
}