2022_하_A_1_L14

Nitroblue 1·약 7시간 전

삼성 기출 풀이

목록 보기
58/58

싸움땅

Simulation

평균 : 180'


sol : 180' 53''

  • 수행 시간 : 8ms
  • 메모리 : 0MB

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;
}

0개의 댓글