풀이 소요시간 : 약 2시간
꽤나 복잡한 시뮬레이션
문제였다. 이 문제를 풀면서 함수화의 중요성을 더욱 크게 느낄 수 있었다. 방향전환, 총의 교체, 이동 가능성 체크 등의 함수화가 정말 중요한 문제였고, 이정도 수준의 시뮬레이션 문제는 함수화를 하지 않을 경우 디버깅해서 오류를 찾아낼 수 조차 없다.
struct Player {
int x;
int y;
int d;
int s;
int gun;
int point;
};
vector<Player> Vector;
위와 같이 현재 들고있는 총, 현재 플레이어의 포인트 등의 공통 사항을 저장하며 풀이했다.
bool Check_Move_180(int nx, int ny, int dir) {
if(nx < 1 || ny < 1 || nx > N || ny > N) return false;
return true;
}
bool Check_Move_90(int num, int nx, int ny, int dir) {
if(nx < 1 || ny < 1 || nx > N || ny > N) return false;
for(int i = 0; i < Vector.size(); i++)
{
if(i == num) continue;
if(Vector[i].x == nx && Vector[i].y == ny) return false;
}
return true;
}
위와같은 함수화로 main()
함수의 반복문 코드 수를 줄일 수 있었다.
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int N, M, K;
vector<int> Map[21][21];
int dx[4] = {-1 ,0, 1, 0};
int dy[4] = {0, 1, 0, -1};
//상 우 하 좌
struct Player {
int x;
int y;
int d;
int s;
int gun;
int point;
};
vector<Player> Vector;
void Input() {
cin >> N >> M >> K;
//총 정보
for(int i = 1; i <= N; i++)
{
for(int j = 1; j <= N; j++)
{
int gun;
cin >> gun;
Map[i][j].push_back(gun);
}
}
//플레이어 정보
for(int i = 1; i <= M; i++)
{
int x, y, d, s;
cin >> x >> y >> d >> s;
Vector.push_back({x, y, d, s, 0, 0});
}
}
int Change_180(int dir) {
if(dir == 0) return 2;
if(dir == 1) return 3;
if(dir == 2) return 0;
if(dir == 3) return 1;
}
int Change_90(int dir) {
if(dir == 0) return 1;
if(dir == 1) return 2;
if(dir == 2) return 3;
if(dir == 3) return 0;
}
bool Check_Move_180(int nx, int ny, int dir) {
if(nx < 1 || ny < 1 || nx > N || ny > N) return false;
return true;
}
bool Check_Move_90(int num, int nx, int ny, int dir) {
if(nx < 1 || ny < 1 || nx > N || ny > N) return false;
for(int i = 0; i < Vector.size(); i++)
{
if(i == num) continue;
if(Vector[i].x == nx && Vector[i].y == ny) return false;
}
return true;
}
pair<int, int> Check_Conflict(int num, int x, int y) {
for(int i = 0; i < Vector.size(); i++)
{
if(i == num) continue;
if(x == Vector[i].x && y == Vector[i].y)
{
int Gap = abs((Vector[num].s + Vector[num].gun) - (Vector[i].s + Vector[i].gun));
if(Vector[num].s + Vector[num].gun > Vector[i].s + Vector[i].gun)
{
Vector[num].point += Gap;
return {num, i};
}
else if(Vector[num].s + Vector[num].gun < Vector[i].s + Vector[i].gun)
{
Vector[i].point += Gap;
return {i, num};
}
else if(Vector[num].s > Vector[i].s) return {num, i};
else return {i, num};
}
}
return {-1, -1};
}
//해당 칸에서 총 교체
void Change_Gun(int num, int x, int y) {
//현재 플레이어가 총을 가진 경우
if(Vector[num].gun > 0)
{
Map[x][y].push_back(Vector[num].gun);
}
sort(Map[x][y].rbegin(), Map[x][y].rend());
Vector[num].gun = Map[x][y][0];
Map[x][y].erase(Map[x][y].begin());
}
int main() {
Input();
while(K--)
{
for(int i = 0; i < Vector.size(); i++)
{
//1-1. 플레이어 이동
while(Check_Move_180(Vector[i].x + dx[Vector[i].d], Vector[i].y + dy[Vector[i].d], Vector[i].d) == false)
{
Vector[i].d = Change_180(Vector[i].d);
}
Vector[i].x += dx[Vector[i].d];
Vector[i].y += dy[Vector[i].d];
//2. 충돌 확인 및 점수 처리
pair<int, int> Pair = Check_Conflict(i, Vector[i].x, Vector[i].y);
int win = Pair.first;
int lose = Pair.second;
//2-2-1
if(win == -1 && lose == -1)
{
if(Map[Vector[i].x][Vector[i].y].size() > 0)
{
Change_Gun(i, Vector[i].x, Vector[i].y);
}
continue;
}
//2-2-2
if(Vector[lose].gun > 0)
{
Map[Vector[lose].x][Vector[lose].y].push_back(Vector[lose].gun);
Vector[lose].gun = 0;
sort(Map[Vector[lose].x][Vector[lose].y].rbegin(), Map[Vector[lose].x][Vector[lose].y].rend());
}
while(Check_Move_90(lose, Vector[lose].x + dx[Vector[lose].d], Vector[lose].y + dy[Vector[lose].d], Vector[lose].d) == false)
{
Vector[lose].d = Change_90(Vector[lose].d);
}
Vector[lose].x += dx[Vector[lose].d];
Vector[lose].y += dy[Vector[lose].d];
if(Map[Vector[lose].x][Vector[lose].y].size() > 0)
{
Change_Gun(lose, Vector[lose].x, Vector[lose].y);
}
//2-2-3
if(Map[Vector[win].x][Vector[win].y].size() > 0)
{
Change_Gun(win, Vector[win].x, Vector[win].y);
}
}
}
for(auto E : Vector)
{
cout << E.point << ' ';
}
cout << endl;
}