출처
https://www.acmicpc.net/problem/3190
문제
'Dummy' 라는 도스게임이 있다. 이 게임에는 뱀이 나와서 기어다니는데, 사과를 먹으면 뱀 길이가 늘어난다. 뱀이 이리저리 기어다니다가 벽 또는 자기자신의 몸과 부딪히면 게임이 끝난다.
게임은 NxN 정사각 보드위에서 진행되고, 몇몇 칸에는 사과가 놓여져 있다. 보드의 상하좌우 끝에 벽이 있다. 게임이 시작할때 뱀은 맨위 맨좌측에 위치하고 뱀의 길이는 1 이다. 뱀은 처음에 오른쪽을 향한다.
뱀은 매 초마다 이동을 하는데 다음과 같은 규칙을 따른다.
- 먼저 뱀은 몸길이를 늘려 머리를 다음칸에 위치시킨다.
- 만약 이동한 칸에 사과가 있다면, 그 칸에 있던 사과가 없어지고 꼬리는 움직이지 않는다.
- 만약 이동한 칸에 사과가 없다면, 몸길이를 줄여서 꼬리가 위치한 칸을 비워준다. 즉, 몸길이는 변하지 않는다.
사과의 위치와 뱀의 이동경로가 주어질 때 이 게임이 몇 초에 끝나는지 계산하라.
입력
첫째 줄에 보드의 크기 N이 주어진다. (2 ≤ N ≤ 100) 다음 줄에 사과의 개수 K가 주어진다. (0 ≤ K ≤ 100)
다음 K개의 줄에는 사과의 위치가 주어지는데, 첫 번째 정수는 행, 두 번째 정수는 열 위치를 의미한다. 사과의 위치는 모두 다르며, 맨 위 맨 좌측 (1행 1열) 에는 사과가 없다.
다음 줄에는 뱀의 방향 변환 횟수 L 이 주어진다. (1 ≤ L ≤ 100)
다음 L개의 줄에는 뱀의 방향 변환 정보가 주어지는데, 정수 X와 문자 C로 이루어져 있으며. 게임 시작 시간으로부터 X초가 끝난 뒤에 왼쪽(C가 'L') 또는 오른쪽(C가 'D')로 90도 방향을 회전시킨다는 뜻이다. X는 10,000 이하의 양의 정수이며, 방향 전환 정보는 X가 증가하는 순으로 주어진다.
출력
첫째 줄에 게임이 몇 초에 끝나는지 출력한다.
예제
번호 | 입력 | 출력 |
1 | 6 3 3 4 2 5 5 3 3 3 D 15 L 17 D |
9 |
2 | 10 4 1 2 1 3 1 4 1 5 4 8 D 10 D 11 D 13 L |
21 |
3 | 10 5 1 5 1 3 1 2 1 6 1 7 4 8 D 10 D 11 D 13 L |
13 |
풀이
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class BOJ3190
{
static int map [][]; // 사과 위치 저장할 2차원 배열
static int n; // 배열의 크기 n X n
static int l; // 방향 전환하는 횟수
static LinkedList <Pos>snake; // 뱀의 몸통의 위치를 머리부터 순서대로 저장할 LinkedList
static int dx []={0,1,0,-1}; // 전환할 뱡향값
static int dy []={1,0,-1,0};
static int nowDir; // time 초 일때 나아가야할 방향
static int time; // 현재 시간(시작한지 time 초가 지남)
static LinkedList <DirInfo>dirQ;// 시간별 방향 정보 저장
public static void main (String[] args) throws java.lang.Exception
{
// Scanner가 아닌 BufferedReader, BufferWriter를 쓸 예정이다.(다들 이거 많이 써서ㅎ.ㅎ)
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
n=Integer.parseInt(br.readLine());
map=new int[n][n]; //int인 경우 이렇게 2차원배열 할당 가능한가봐
int k=Integer.parseInt(br.readLine());
//사과 있는 곳 저장
for(int i=0;i<k;i++)
{
StringTokenizer st = new StringTokenizer(br.readLine());
int x=Integer.parseInt(st.nextToken());
int y=Integer.parseInt(st.nextToken());
map[x-1][y-1]=1; //나는 n x n 배열이니까 x-1, y-1과 같이 1씩 빼줘야해
// n+1 x n+1 배열이었으면 그럴 필요 없겠지만.
}
l=Integer.parseInt(br.readLine());
dirQ=new LinkedList<DirInfo>();
for(int i=0;i<l;i++)
{
StringTokenizer st = new StringTokenizer(br.readLine());
int dir_t=Integer.parseInt(st.nextToken());
; char dir_c=st.nextToken().charAt(0);
int dir_i;
if(dir_c=='L') dir_i=-1;
else dir_i=1;
DirInfo DirInfo_node=new DirInfo(dir_t,dir_i);
dirQ.add(DirInfo_node);
}
// 뱀의 처음위치는 (0,0)
snake=new LinkedList<Pos>();
Pos first=new Pos(0,0);
snake.add(first);
// 처음 방향은 오른쪽(->)
nowDir=0;
time=1;
onGoing();
br.write(time+"\n");
br.close();
bw.flush();
bw.close();
}
static class DirInfo
{
int time;
int dir;
DirInfo(int time,int dir)
{
this.time=time;
this.dir=dir;
}
}
static class Pos
{
int x;
int y;
Pos(int x, int y)
{
this.x=x;
this.y=y;
}
//LinkedList의 contains 함수가 제대로 동작안해서 잠깐 만들어본 equals 오버라이딩한 함수
@Override
public boolean equals(Object o)
{
Pos temp=(Pos)o;
if(this.x==temp.x&&this.y==temp.y) return true;
else return false;
}
}
static void onGoing()
{
// 벽이나 몸통에 충돌할때까지 반복
while(true)
{
/ 앞으로 나아가는건 머리니까 현재 머리값 확인
Pos head=snake.peekFirst();
// 머리가 현재 방향(nowDir)으로 나아갔을 때
Pos go=new Pos(head.x+dx[nowDir], head.y+dy[nowDir]);
// 벽이나 몸통에 충돌하는지 확인
if(!isOk(go)) break; // 충돌하면 끝(break)
// 충돌하지 않은 snake 값에 앞 머리 추가
snake.addFirst(go);
// 사과가 있다면
if(map[go.x][go.y]==1)
{
//사과를 먹고, 꼬리값 유지
map[go.x][go.y]=0;
}
else snake.pollLast(); //사과가 없다면 꼬리값 poll
// 이동이 끝났으니 time초 후의 방향 확인
checkDir(time);
// 방향 확인 후에 time 증가(time 증가 위치는 코드에 따라 다름)
time++;
}
}
static boolean isOk(Pos go)
{
/*
// LinkedList의 contains 함수가 제대로 동작하지 않아 잠시 사용했던 코드
// Iterator를 이용해 snake에 Pos go 객체가 포함되어있는지 확인 하는 용도
Iterator<Pos> itr=snake.iterator();
while(itr.hasNext())
{
Pos temp=itr.next();
if(go.equals(temp)) return false;
}
*/
// 벽이나 몸통에 부딪이는지 확인
if(go.x>=0&&go.x<n&&go.y>=0&&go.y<n && !snake.contains(go)) return true;
else return false;
}
static void checkDir(int c_time)
{
// 더이상 방향정보가 있는지 확인(Empty라면 방향 바꿀 필요 없음)
if(dirQ.isEmpty()) return;
//앞쪽의 시간별 방향 값 확인(not poll)
DirInfo DirInfo_node=dirQ.peekFirst();
// 현재시간이 방향을 바꿀시간이라면
if(c_time==DirInfo_node.time)
{
// 그 방향값은 이제 제외
dirQ.pollFirst();
// 현재 방향값 바꿔주기
nowDir+=DirInfo_node.dir;
if(nowDir==-1)nowDir=3;
}
}

'IT > 정보보안' 카테고리의 다른 글
정보보안기사 | 애플리케이션 보안 | FTP 보안 | FTP 취약점과 바운스 공격 (0) | 2021.07.30 |
---|---|
정보보안기사 | 애플리케이션 보안 | FTP 보안 | FTP Active 모드와 Passive 모드 (0) | 2021.07.30 |