티스토리 뷰
문제 - (https://www.acmicpc.net/problem/3190)
어렸을 때 오래된 게임기로 해봤던 게임이다. Dummy라는 도스 게임인데 전형적인 꼬리잡기 게임을 구현하는 문제였다.
이동하면서 '사과'를 먹으면 몸의 길이가 늘어나고 계속해서 이동하다가 벽이나 자신의 몸에 부딪히면 게임이 끝난다.
- 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
- 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
- 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.
- 뱀의 머리가 몸이나 벽에 닿으면 게임은 끝난다
📌 개선
- 뱀은 먼저 몸의 길이를 늘린 다음에 갈 곳에 사과가 있는지, 벽이 있는지, 자신의 몸이 있는지 확인한다는 것을 염두
== 항상 문제 확인을 섬세하게 해라 - 처음 문제 풀이를 시작할 때, 자료구조 선택이 정말 중요하다는 것을 느꼈다. Deque를 사용했으면 풀이시간을 단축할 수 있었을 거라 생각한다
- 뱀이 회전하는 것은 0 1 2 3 으로 둬서 차례로 오른쪽, 아래, 왼쪽, 위로 회전하도록 설정해도 됨. 왜냐면 오른쪽으로 회전하면 0123 순서고 왼쪽으로 회전하면 3210 순서니까 그리고 이것은 %4 를 해줌으로써 간단히 구현할 수 있다
나는 회전 코드를 노가다로 구현했는데 %하나로 처리가 가능했다 ㅠㅠ
if (!turn.isEmpty() && time == Integer.parseInt(turn.get(0)[0])) {
if (turn.get(0)[1].equals("L")) dir--; // 왼쪽 회전
else dir++; // 오른쪽 회전
if (dir < 0) dir = 3;
else if (dir > 3) dir = 0;
turn.remove(0);
}
// 위처럼 할 필요가 없다!
dir = (dir + 1) % 4; // 오른쪽 회전
dir = (dir + 3) % 4; // 왼쪽 회전
- dy, dx를 좀 더효율적으로 사용할 수 있도록 연습해야 겠다.
나는 moveFromDir이라는 함수를 만들어서 뱀이 가려는 방향에 따라 switch문 별로 이동할 곳을 찾았는데,
다른 블로그를 찾아보니 더 효율적인 방법이 있었다.
회전 방향을 0,1,2,3으로 정했으니 그 방향별로 dx, dy 배열을 만들어버리면 된다.
int[] dx = {-1, 0, 1, 0};
int[] dy = {0, 1, 0, -1};
int nx = snake.getHead()[0] + dx[snakeDir];
int ny = snake.getHead()[1] + dy[snakeDir];
// snakeDir이 1이면 -1,0 (위로 이동)
// snakeDir이 2이면 0,1 (우로 이동) ... 이런식
😅실수
- 저번과 똑같은 실수를 저질렀다... 배열의 값이 아니라 주소를 참조해버려서 값을 연쇄적으로 변경시켜 버린것... 이 실수는 항상 머릿속에 넣어두고 코딩해야겠다.. 왠만하면 주소참조 자체를 안하는 방향으로 코드를 짜야겠다. (아마 필요한 경우엔 인지할 수 있을 것이다. 나는 자꾸 인지도 못한채 주소참조해버려서 문제가 된 것)
- 문제에서 짜라는 대로 짜면 되는데 거길 대강 확인하고 넘어가서 실수하는 바람에 디버깅하느라 시간을 다 날렸다
"먼저 뱀은 몸길이를 늘린 다음에 머리를 다음 칸에 위치시킨다"는 조건을 놓쳐서 오답원인을 찾는 것에 시간을 많이 썼다
코드를 보려면 '더보기' 클릭
더보기
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.StringTokenizer;
/**
* 2시간 14분 .. 시뮬레이션 문제 너무 오래걸린다
*/
public class _3190_Snake {
static int[][] map;
static int N;
static ArrayList<String[]> turn;
static int[] right = {0, 1}, left = {0, -1}, up = {-1, 0}, down = {1, 0};
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
N = Integer.parseInt(br.readLine());
map = new int[N + 2][N + 2];
// 맵 바깥은 -1
for (int i = 0; i < N + 2; i++)
for (int j = 0; j < N + 2; j++)
if (i == 0 || j == 0 || i == N + 1 || j == N + 1) map[i][j] = -1;
int K = Integer.parseInt(br.readLine());
StringTokenizer st;
for (int i = 0; i < K; i++) {
st = new StringTokenizer(br.readLine());
int x = Integer.parseInt(st.nextToken());
int y = Integer.parseInt(st.nextToken());
map[x][y] = 1;
}
int L = Integer.parseInt(br.readLine());
String[] _turn = new String[2];
turn = new ArrayList<>();
for (int i = 0; i < L; i++) {
st = new StringTokenizer(br.readLine());
turn.add(new String[]{st.nextToken(), st.nextToken()});
}
System.out.println(dummy());
}
static int dummy() {
Snake snake = new Snake(new int[]{1, 1});
int time = 0;
int dir = 0; // 0:right, 1:
while (true) {
// 시간 경과
time++;
// 뱀을 이동시킨다
int[] movedPos = moveFromDir(dir, snake.getHead()); // 이동할 위치
// System.out.println(movedPos[0] + "," + movedPos[1]);
if (map[movedPos[0]][movedPos[1]] == 1) { // 사과가 있음
snake.move(movedPos, true);
map[movedPos[0]][movedPos[1]] = 0; // 사과를 먹음
} else if (map[movedPos[0]][movedPos[1]] == -1) { // 벽임
break;
} else { // 빈 칸임 그냥 이동
snake.move(movedPos, false);
}
// 뱀이 이동했는데 몸을 만남
if (snake.isMeetBody()) {
break;
}
// 뱀의 머리를 미리 회전시켜 놓는다
if (!turn.isEmpty() && time == Integer.parseInt(turn.get(0)[0])) {
if (turn.get(0)[1].equals("L")) dir--; // 왼쪽 회전
else dir++; // 오른쪽 회전
if (dir < 0) dir = 3;
else if (dir > 3) dir = 0;
turn.remove(0);
}
}
return time;
}
static int[] moveFromDir(int dir, int[] pos) { // 뱀의 이동방향 확인
int[] movingDir;
int[] ret = new int[2]; /* pos가 snake body 요소 배열의 주소를 참조하기 때문에 함부로 변경해선 안됨 */
switch (dir) {
case 0:
movingDir = right;
break;
case 2:
movingDir = left;
break;
case 3:
movingDir = up;
break;
case 1:
movingDir = down;
break;
default:
throw new IllegalStateException("Unexpected value: " + dir);
}
for (int i = 0; i < 2; i++) {
ret[i] = pos[i] + movingDir[i];
}
return ret;
}
static class Snake {
ArrayList<int[]> body;
int[] preCutTail;
Snake(int[] start) {
body = new ArrayList<>();
body.add(start);
}
void move(int[] pos, boolean eatApple) {
if (eatApple) {
body.add(0, pos);
} else {
body.add(0, pos);
preCutTail = body.remove(body.size() - 1);
}
}
int[] getHead() {
return body.get(0);
}
int[] getTail() {
return body.get(body.size() - 1);
}
boolean isMeetBody() {
if (body.size() < 4) return false;
int[] head = {getHead()[0], getHead()[1]};
for (int i = 1; i < body.size(); i++) {
if (head[0] == body.get(i)[0] && head[1] == body.get(i)[1]) {
return true;
}
}
if (preCutTail != null && preCutTail[0] == head[0] && preCutTail[1] == head[1]) return true;
return false;
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 17144 / Java / 미세먼지 안녕! - 시뮬레이션 (0) | 2020.05.26 |
---|---|
[백준] 15683번 / Java / 감시 - 완전탐색 (0) | 2020.05.21 |
[백준] 14889번 / Java / 스타트와 링크 - 재귀풀이 (0) | 2020.05.20 |
[백준] 14501번 / Java / 퇴사 - 재귀풀이 (0) | 2020.05.19 |
[백준] 12100번 / Java / 2048 (Easy) (0) | 2020.05.13 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 자바
- 큰 수 만들기
- header
- java
- 완전탐색
- Access-Control-Allow-Origin
- 14891
- 인구이동
- 시뮬레이션
- 아기상어
- 백준
- 구명보트
- 드래곤 커브
- 코딩테스트
- 프로그래머스
- Greedy
- 구현
- 16234
- dfs
- 배열순회
- 우선순위큐
- 코테
- 브라우저 요청
- 톱니바퀴
- 사다리 조작
- withCredentials
- 코딩테스트 연습
- BOJ
- 그리디
- 재귀
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
글 보관함