알고리즘/[ADV] 삼성 SW 역량 테스트 A형

[코드트리] 싸움땅 (삼성 SW 역량테스트 2022 하반기 오전 1번)

피로물든딸기 2024. 7. 7. 20:33
반응형

삼성 A형 전체 링크

 

https://www.codetree.ai/training-field/frequent-problems/problems/battle-ground

 

이후 설명 및 입/출력은 링크 참고

 

(r, c)에는 여러 개의 총이 있을 수 있으므로, 2차원 좌표에 1차원 배열을 추가하여 총을 관리한다.

int GUN[MAX][MAX][MAX * MAX];
int gIndex[MAX][MAX];

 

플레이어 정보에는 좌표와 방향, 능력치(s), 들고 있는 총의 power(gun)를 구조체로 관리한다.

typedef struct st
{
	int r;
	int c;
	int dir;
	int s;
	int gun;
}PLAYER;

PLAYER player[30 + 5];

 

방향을 처리하는 배열은 다음과 같이 선언한다.

// ↑, →, ↓, ←
int dr[] = { -1, 0, 1, 0 };
int dc[] = { 0, 1, 0, -1 };

 

점수를 저장할 배열은 다음과 같다.

int SCORE[30 + 5];

 

input에서 총 개수 초기화, 총의 power 입력, SCORE 초기화, player 정보 입력을 한다.

void input()
{
	scanf("%d %d %d", &N, &M, &K);

	for (int r = 1; r <= N; r++)	
		for (int c = 1; c <= N; c++)
			gIndex[r][c] = 0;

	for (int r = 1; r <= N; r++)
	{
		for (int c = 1; c <= N; c++)
		{
			scanf("%d", &GUN[r][c][0]);

			if (GUN[r][c][0]) gIndex[r][c] = 1;		
		}
	}

	for (int m = 1; m <= M; m++) // player 번호는 1번 부터
	{
		SCORE[m] = 0;

		int x, y, d, s;
		
		scanf("%d %d %d %d", &x, &y, &d, &s);

		player[m].r = x;
		player[m].c = y;
		player[m].dir = d;
		player[m].s = s;
		player[m].gun = 0;
	}
}

 

main에서 simulate 후에 SCORE를 출력한다.

int main(void)
{
	// scanf("%d", &T);
	T = 1;
	for (int tc = 1; tc <= T; tc++)
	{
		input();

		for (int k = 0; k < K; k++) simulate();

		for (int m = 1; m <= M; m++) printf("%d ", SCORE[m]);
		putchar('\n');
	}

	return 0;
}

구현

 

매 라운드 마다 현재 player의 위치를 2차원 배열 curPos player 번호를 기록하고 시작한다.

changeDir벽에 부딪히는 경우 방향을 바꾸기 위한 배열이다.

void simulate()
{
	int curPos[MAX][MAX] = { 0 };
	int changeDir[] = { 2, 3, 0, 1 }; // 방향 변경

	// 현재 player의 위치 표기
	for (int m = 1; m <= M; m++)
		curPos[player[m].r][player[m].c] = m;
        
    ...

 

1-1. 플레이어를 이동하고 벽에 부딪힌 경우, 방향을 바꿔서 이동한다.

	// 1-1. 플레이어 순차적으로 이동
	PLAYER p = player[m];

	int nr, nc;
	nr = p.r + dr[p.dir];
	nc = p.c + dc[p.dir];

	// 1-1. 격자를 벗어나는 경우 반대 방향으로 변경 후 이동
	if (nr < 1 || nc < 1 || nr > N || nc > N)
	{
		player[m].dir = p.dir = changeDir[p.dir];

		nr = p.r + dr[p.dir];
		nc = p.c + dc[p.dir];
	}

 

이동할 방향에 다른 플레이어가 없는 경우 (curPos[nr][nc] == 0), 현재 플레이어를 이동한다.

(curPos 갱신, player 좌표 갱신)

 

이동할 방향에 (nr, nc)에 총이 있는 경우 가장 센 총을 선택하고 교체한다.

	// 2-1. 이동할 방향에 플레이어가 있는지 체크, 없는 경우
	if (curPos[nr][nc] == 0)
	{
		// 지도에서 player 이동
		curPos[p.r][p.c] = 0;
		curPos[nr][nc] = m; 

		// 실제 player 이동
		player[m].r = nr;
		player[m].c = nc;
			
		if (gIndex[nr][nc]) // 총이 있는 경우
		{
			int playerGun = player[m].gun;
			int gunIndex = getMaxPowerGunIndex(nr, nc);

			if (playerGun < GUN[nr][nc][gunIndex])
			{
				int tmp = player[m].gun;
				player[m].gun = GUN[nr][nc][gunIndex];
				GUN[nr][nc][gunIndex] = tmp;
			}
		}
	}

 

getMaxPowerGunIndex (r, c)에서 가장 power가 큰 총indexreturn한다.

int getMaxPowerGunIndex(int r, int c)
{
	int max = -1;
	int count = gIndex[r][c];
	int index = 0;
	for (int i = 0; i < count; i++)
	{
		if(max < GUN[r][c][i])
		{ 
			max = GUN[r][c][i];
			index = i;
		}
	}

	return index;
}

 

이동할 방향에 player가 있다면, 싸움을 해야 한다.

이동할 플레이어를 curPos에서 삭제하고, battle 함수를 이용해 winnerloser를 구분한다.

(battle 결과에 따라 두 플레이어의 움직일 위치가 결정되므로 curPos만 먼저 삭제한다.)

	else // 2-2. player가 있는 경우
	{
		int fighter = curPos[nr][nc]; // 만나게 된 player

		int mGun = player[m].gun; // 움직인 player의 총
		int mSkill = player[m].s; // 움직인 player의 skill
			
		int fGun = player[fighter].gun;
		int fSkill = player[fighter].s;

		int loser, winner;

		// map에서 이동한 플레이어 삭제
		curPos[player[m].r][player[m].c] = 0;

		if (battle(player[m], player[fighter]) == 0) // m이 이긴 경우 
		{
			winner = m;
			loser = fighter;
		}
		else 
		{
			winner = fighter;
			loser = m;
		}
        
		...

 

battle 함수는 다음과 같다.

플레이의 능력치가 모두 다르기 때문에 반드시 결판이 난다.

// p1이 이기면 0, p2가 이기면 1
int battle(PLAYER p1, PLAYER p2) 
{
	int gun1 = p1.gun;
	int s1 = p1.s;
	int gun2 = p2.gun;
	int s2 = p2.s;

	int sum1 = gun1 + s1;
	int sum2 = gun2 + s2;

	if (sum1 > sum2) return 0;
	if (sum1 < sum2) return 1;

	if (s1 > s2) return 0;
	if (s1 < s2) return 1;

	return -1; // error
}

 

문제에 제시된 대로 점수를 누적한다.

		// 2-2-1. 점수 획득
		SCORE[winner] 
			+= ((player[winner].gun + player[winner].s)) - ((player[loser].gun + player[loser].s));

 

패배한 player는 총을 버린다.

버린 총은 GUN[nr][nc]추가한다.

그리고 패배한 player를 움직이고, 좌표를 갱신한다.

움직일 공간이 없으면 오른쪽 방향으로 회전해서 움직일 수 있는 방향을 찾아야 한다.

움직인 곳에 총이 있다면 가장 power가 높은 총을 얻는다.

		// 2-2-2. 패배한 플레이어
		int loserGun = player[loser].gun;
		player[loser].gun = 0;

		GUN[nr][nc][gIndex[nr][nc]++] = loserGun;

		for (int d = 0; d < 4; d++)
		{
			int lnr, lnc;

			lnr = nr + dr[player[loser].dir];
			lnc = nc + dc[player[loser].dir];
				
			if (lnr < 1 || lnc < 1 || lnr > N || lnc > N || curPos[lnr][lnc] != 0)
				player[loser].dir = (player[loser].dir + 1) % 4;
			else
			{
				curPos[nr][nc] = 0;
				curPos[lnr][lnc] = loser;

				player[loser].r = lnr;
				player[loser].c = lnc;

				if (gIndex[lnr][lnc]) // 총이 있는 경우
				{
					int gunIndex = getMaxPowerGunIndex(lnr, lnc);
					if (player[loser].gun < GUN[lnr][lnc][gunIndex])
					{
						player[loser].gun = GUN[lnr][lnc][gunIndex];
						GUN[lnr][lnc][gunIndex] = 0;
					}

				}

				break;
			}
		}

 

이긴 플레이어는 현재 위치에서 가장 좋은 총으로 변경하고 curPosplayer좌표를 갱신한다.

		// 2-2-3. 이긴 플레이어는 더 좋은 총으로 변경.
		int gunIndex = getMaxPowerGunIndex(nr, nc);
		if (player[winner].gun < GUN[nr][nc][gunIndex])
		{
			int tmp = player[winner].gun;
			player[winner].gun = GUN[nr][nc][gunIndex];
			GUN[nr][nc][gunIndex] = tmp;
		}

		// 이긴 플레이어의 이동.
		curPos[nr][nc] = winner;
			
		player[winner].r = nr;
		player[winner].c = nc;

전체 코드는 다음과 같다.

#include <stdio.h>

#define MAX (20 + 5)

int T;
int N, M, K, X, Y;

int GUN[MAX][MAX][MAX * MAX];
int gIndex[MAX][MAX];

typedef struct st
{
	int r;
	int c;
	int dir;
	int s;
	int gun;
}PLAYER;

PLAYER player[30 + 5];

// ↑, →, ↓, ←
int dr[] = { -1, 0, 1, 0 };
int dc[] = { 0, 1, 0, -1 };

int SCORE[30 + 5];

void input()
{
	scanf("%d %d %d", &N, &M, &K);

	for (int r = 1; r <= N; r++)	
		for (int c = 1; c <= N; c++)
			gIndex[r][c] = 0;

	for (int r = 1; r <= N; r++)
	{
		for (int c = 1; c <= N; c++)
		{
			scanf("%d", &GUN[r][c][0]);

			if (GUN[r][c][0]) gIndex[r][c] = 1;		
		}
	}

	for (int m = 1; m <= M; m++) // player 번호는 1번 부터
	{
		SCORE[m] = 0;

		int x, y, d, s;
		
		scanf("%d %d %d %d", &x, &y, &d, &s);

		player[m].r = x;
		player[m].c = y;
		player[m].dir = d;
		player[m].s = s;
		player[m].gun = 0;
	}
}

void printMap(int map[MAX][MAX])
{
	putchar('\n');
	for (int r = 1; r <= N; r++)
	{
		for (int c = 1; c <= N; c++)
			printf("%d ", map[r][c]);
		putchar('\n');

	}
	putchar('\n');
}

int getMaxPowerGunIndex(int r, int c)
{
	int max = -1;
	int count = gIndex[r][c];
	int index = 0;
	for (int i = 0; i < count; i++)
	{
		if(max < GUN[r][c][i])
		{ 
			max = GUN[r][c][i];
			index = i;
		}
	}

	return index;
}

// p1이 이기면 0, p2가 이기면 1
int battle(PLAYER p1, PLAYER p2) 
{
	int gun1 = p1.gun;
	int s1 = p1.s;
	int gun2 = p2.gun;
	int s2 = p2.s;

	int sum1 = gun1 + s1;
	int sum2 = gun2 + s2;

	if (sum1 > sum2) return 0;
	if (sum1 < sum2) return 1;

	if (s1 > s2) return 0;
	if (s1 < s2) return 1;

	return -1; // error
}

void simulate()
{
	int curPos[MAX][MAX] = { 0 };
	int changeDir[] = { 2, 3, 0, 1 }; // 방향 변경

	// 현재 player의 위치 표기
	for (int m = 1; m <= M; m++)
		curPos[player[m].r][player[m].c] = m;
	
	for (int m = 1; m <= M; m++)
	{
		// 1-1. 플레이어 순차적으로 이동
		PLAYER p = player[m];

		int nr, nc;
		nr = p.r + dr[p.dir];
		nc = p.c + dc[p.dir];

		// 1-1. 격자를 벗어나는 경우 반대 방향으로 변경 후 이동
		if (nr < 1 || nc < 1 || nr > N || nc > N)
		{
			player[m].dir = p.dir = changeDir[p.dir];

			nr = p.r + dr[p.dir];
			nc = p.c + dc[p.dir];
		}
		
		// 2-1. 이동할 방향에 플레이어가 있는지 체크, 없는 경우
		if (curPos[nr][nc] == 0)
		{
			// 지도에서 player 이동
			curPos[p.r][p.c] = 0;
			curPos[nr][nc] = m; 

			// 실제 player 이동
			player[m].r = nr;
			player[m].c = nc;
			
			if (gIndex[nr][nc]) // 총이 있는 경우
			{
				int playerGun = player[m].gun;
				int gunIndex = getMaxPowerGunIndex(nr, nc);

				if (playerGun < GUN[nr][nc][gunIndex])
				{
					int tmp = player[m].gun;
					player[m].gun = GUN[nr][nc][gunIndex];
					GUN[nr][nc][gunIndex] = tmp;
				}
			}
		}
		else // 2-2. player가 있는 경우
		{
			int fighter = curPos[nr][nc]; // 만나게 된 player

			int mGun = player[m].gun; // 움직인 player의 총
			int mSkill = player[m].s; // 움직인 player의 skill
			
			int fGun = player[fighter].gun;
			int fSkill = player[fighter].s;

			int loser, winner;

			// map에서 이동한 플레이어 삭제
			curPos[player[m].r][player[m].c] = 0;

			if (battle(player[m], player[fighter]) == 0) // m이 이긴 경우 
			{
				winner = m;
				loser = fighter;
			}
			else 
			{
				winner = fighter;
				loser = m;
			}

			// 2-2-1. 점수 획득
			SCORE[winner] 
				+= ((player[winner].gun + player[winner].s)) - ((player[loser].gun + player[loser].s));
			
			// 2-2-2. 패배한 플레이어
			int loserGun = player[loser].gun;
			player[loser].gun = 0;

			GUN[nr][nc][gIndex[nr][nc]++] = loserGun;

			for (int d = 0; d < 4; d++)
			{
				int lnr, lnc;

				lnr = nr + dr[player[loser].dir];
				lnc = nc + dc[player[loser].dir];
				
				if (lnr < 1 || lnc < 1 || lnr > N || lnc > N || curPos[lnr][lnc] != 0)
					player[loser].dir = (player[loser].dir + 1) % 4;
				else
				{
					curPos[nr][nc] = 0;
					curPos[lnr][lnc] = loser;

					player[loser].r = lnr;
					player[loser].c = lnc;

					if (gIndex[lnr][lnc]) // 총이 있는 경우
					{
						int gunIndex = getMaxPowerGunIndex(lnr, lnc);
						if (player[loser].gun < GUN[lnr][lnc][gunIndex])
						{
							player[loser].gun = GUN[lnr][lnc][gunIndex];
							GUN[lnr][lnc][gunIndex] = 0;
						}

					}

					break;
				}
			}
		
			// 2-2-3. 이긴 플레이어는 더 좋은 총으로 변경.
			int gunIndex = getMaxPowerGunIndex(nr, nc);
			if (player[winner].gun < GUN[nr][nc][gunIndex])
			{
				int tmp = player[winner].gun;
				player[winner].gun = GUN[nr][nc][gunIndex];
				GUN[nr][nc][gunIndex] = tmp;
			}

			// 이긴 플레이어의 이동.
			curPos[nr][nc] = winner;
			
			player[winner].r = nr;
			player[winner].c = nc;
		}
		
	}

	// printf("round end\n"); printMap(curPos);
}

int main(void)
{
	// scanf("%d", &T);
	T = 1;
	for (int tc = 1; tc <= T; tc++)
	{
		input();

		for (int k = 0; k < K; k++) simulate();

		for (int m = 1; m <= M; m++) printf("%d ", SCORE[m]);
		putchar('\n');
	}

	return 0;
}
반응형