[JAVA] Baekjoon -19237 어른상어

hyng·2022년 6월 14일
0

Baekjoon

목록 보기
5/5

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);
      }
    }
  }
}
profile
공부하고 알게 된 내용을 기록하는 블로그

0개의 댓글