Solution
- Smell: 냄새를 나타내는 클래스
- isExists(): 냄새의 존재 유무를 구하는 메서드
- 냄새는 상어가 k번 이동하고 나면 사라진다.
- 냄새가 사라질때 smells에서 값을 삭제하는게 아니라 isExists 필드 값을 false로 바꿔준다.
- equals(): 상어가 냄새가 없는 빈 곳이 없어 자신의 냄새가 있는 곳으로 이동해야 할때 이미 smells에 있는 Smell객체의 지속시간(duration) 값을 바꿔줘야 하는데 그때 smells에서 값을 찾을 때 사용한다.
- equals(), hashCode(): 냄새(Smell 클래스)를 저장하는 smells의 컬렉션으로 hashset을 사용하기 때문에 equals, hashcode를 오버라이딩한다.
- reproduce(): 이미 A상어의 냄새가 존재하던 곳으로 다시 A상어가 이동할때 기존에 존재하던 냄새의 지속시간(duation)을 갱신하는 메서드
- reduceDuration(): 상어가 이동할때마다 냄새의 지속시간을 줄이는 메서드
* 냄새의 지속시간이 0이 되면 냄새가 "사라졌음"을 표시하기 위해 isExists 를 false로 둔다.
- Shark: 상어를 나타내는 클래스
* setDirection(): 상어의 방향을 변경하는 메서드
- setPriority(): 상어의 이동 우선순위를 저장하는 메서드
- spreadSmell(): 현재 상어의 위치에 냄새를 뿌리는 메서드
- 만약 이미 자신의 냄새가 뿌려져있는 곳으로 이동한다면 냄새의 지속시간만 갱신하고 아니라면 냄새를 만들어 smells에 저장한다.
- isAlive(): 상어가 살아있는지를 확인하는 메서드
- 한 공간에 여러 상어가 존재한다면 가장 숫자가 작은 상어를 제외하고 모두 격자 밖으로 쫒겨난다. -> 이때 상어가 "죽었음"을 표시하기 위해 isAlive 를 false로 둔다.
- move(): 상어의 이동을 처리하는 메서드
- isAnyShark(): 상어가 이동할 예정인 공간에 다른 상어가 존재하는지 확인하는 메서드
- 만약 존재한다면 canSurvive() 메서드를 호출한다.
- isOutOfArray(): 상어가 이동할 예정인 공간이 격자 밖인지 확인하는 메서드
- die(): canSurvive() 값이 false가 되어 해당 상어가 격자 밖으로 쫒겨날때를 처리하는 메서드
- canSurvive(): 상어가 이동할 예정인 공간에 다른 상어가 존재할 때 해당 상어가 살아남을수 있는지를 확인하는 메서드
- Main:
- solve(): 문제 해결 메서드
- spreadSmell(): 처음 상어들이 자신의 공간에 냄새 뿌림
- moveSharks(): 상어가 움직임
- reduceSmellDuration(): 상어가 한번 이동했으므로 냄새의 지속시간을 1 줄임
Code
import java.util.HashSet;
import java.util.Objects;
import java.util.Scanner;
class Smell {
private final int y;
private final int x;
private final int owner;
private int duration;
private boolean isExists;
public Smell(int y, int x, int owner, int duration) {
this.y = y;
this.x = x;
this.owner = owner;
this.duration = duration;
this.isExists = true;
}
public boolean isExists() {
return isExists;
}
public boolean equals(int y, int x, int owner) {
return this.isExists && this.y == y && this.x == x && this.owner == owner;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Smell smell = (Smell) o;
return y == smell.y && x == smell.x && owner == smell.owner && duration == smell.duration
&& isExists == smell.isExists;
}
@Override
public int hashCode() {
return Objects.hash(y, x, owner, duration, isExists);
}
public void reproduce(int duration) {
this.duration = duration;
}
public void reduceDuration(int smellMap[][]) {
this.duration -= 1;
if (this.duration == 0) {
this.isExists = false;
smellMap[this.y][this.x] = 0;
}
}
}
class Shark {
private final int num;
private int y;
private int x;
private int d;
private boolean isAlive;
private final int priority[][] = new int[Main.DIRECTION_SIZE + 1][Main.DIRECTION_SIZE];
public Shark(int num, int y, int x) {
this.num = num;
this.y = y;
this.x = x;
this.isAlive = true;
}
public void setDirection(int d) {
this.d = d;
}
public void setPriority(int order, int curDirection, int direction) {
priority[curDirection][order] = direction;
}
public void spreadSmell(int[][] smellMap, HashSet smells, int duration) {
if (smellMap[this.y][this.x] == this.num) {
Smell foundSmell = (Smell) smells.stream().filter((obj) -> {
Smell smell = (Smell) obj;
return smell.equals(this.y, this.x, this.num);
})
.findFirst().get();
foundSmell.reproduce(duration);
return;
}
smellMap[this.y][this.x] = this.num;
smells.add(new Smell(this.y, this.x, this.num, duration));
}
public boolean isAlive() {
return isAlive;
}
public void move(int map[][], int newMap[][], int[][] smellMap, Shark sharks[]) {
for (int i = 0; i < Main.DIRECTION_SIZE; i++) {
int newD = priority[this.d][i];
int newY = this.y + Main.dy[newD];
int newX = this.x + Main.dx[newD];
if (isOutOfArray(newY, newX, map.length)) {
continue;
}
if (smellMap[newY][newX] == 0) {
if (isAnyShark(newMap, newY, newX)) {
if (!canSurvive(newMap, newY, newX)) {
this.die();
return;
}
sharks[newMap[newY][newX]].die();
}
newMap[newY][newX] = this.num;
this.y = newY;
this.x = newX;
this.d = newD;
return;
}
}
for (int i = 0; i < Main.DIRECTION_SIZE; i++) {
int newD = priority[this.d][i];
int newY = this.y + Main.dy[newD];
int newX = this.x + Main.dx[newD];
if (isOutOfArray(newY, newX, map.length)) {
continue;
}
if (smellMap[newY][newX] == this.num) {
newMap[newY][newX] = this.num;
this.y = newY;
this.x = newX;
this.d = newD;
return;
}
}
}
private boolean isAnyShark(int map[][], int y, int x) {
return map[y][x] != 0;
}
private boolean isOutOfArray(int y, int x, int length) {
return y <= 0 || y >= length || x <= 0 || x >= length;
}
private void die() {
this.isAlive = false;
Main.aliveSharksSize -= 1;
}
private boolean canSurvive(int map[][], int y, int x) {
return map[y][x] >= this.num;
}
}
class Main {
public static int aliveSharksSize;
public static final int MAX_TIME = 1000;
public static final int DIRECTION_SIZE = 4;
public static final int dy[] = {0, -1, 1, 0, 0};
public static final int dx[] = {0, 0, 0, -1, 1};
private static Shark[] sharks;
private static int[][] smellMap;
private static final HashSet smells = new HashSet();
private static int map[][];
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int K = sc.nextInt();
aliveSharksSize = M;
map = new int[N + 1][N + 1];
sharks = new Shark[M + 1];
smellMap = new int[N + 1][N + 1];
for (int i = 1; i <= N; i++) {
for (int j = 1; j <= N; j++) {
int v = sc.nextInt();
map[i][j] = v;
if (v != 0) {
sharks[v] = new Shark(v, i, j);
}
}
}
for (int i = 1; i <= M; i++) {
sharks[i].setDirection(sc.nextInt());
}
for (int i = 1; i <= M; i++) {
for (int j = 1; j <= DIRECTION_SIZE; j++) {
for (int k = 0; k < DIRECTION_SIZE; k++) {
sharks[i].setPriority(k, j, sc.nextInt());
}
}
}
System.out.println(solve(M, K));
}
private static int solve(int sharkSize, int duration) {
spreadSmell(sharkSize, duration);
for (int time = 1; time <= MAX_TIME; time++) {
int tempMap[][] = new int[map.length][map.length];
moveSharks(sharkSize, tempMap);
reduceSmellDuration();
spreadSmell(sharkSize, duration);
if (aliveSharksSize == 1) {
return time;
}
map = tempMap.clone();
}
return -1;
}
private static void reduceSmellDuration() {
smells.stream().forEach((obj) -> {
Smell smell = (Smell) obj;
if (smell.isExists()) {
smell.reduceDuration(smellMap);
}
});
}
private static void moveSharks(int sharkSize, int[][] tempMap) {
for (int i = 1; i <= sharkSize; i++) {
if (sharks[i].isAlive()) {
sharks[i].move(map, tempMap, smellMap, sharks);
}
}
}
private static void spreadSmell(int sharkSize, int duration) {
for (int i = 1; i <= sharkSize; i++) {
if (sharks[i].isAlive()) {
sharks[i].spreadSmell(smellMap, smells, duration);
}
}
}
}