Skip to content

Commit f7d4aa3

Browse files
committed
1 parent 220c29a commit f7d4aa3

File tree

1 file changed

+206
-0
lines changed

1 file changed

+206
-0
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
"""
2+
BFS , 구현 , 시뮬레이션
3+
"""
4+
#상 o, 우상, 우, 우하 , 하, 좌하, 좌, 좌상
5+
di = [-1,-1,0,1,1,1,0,-1]
6+
dj = [0,1,1,1,0,-1,-1,-1]
7+
#디버깅 용
8+
def myprint(arr):
9+
for lst in arr:
10+
print(*lst) # 2행 리시트는 1열이 1 instacne
11+
print()
12+
13+
# [0] BFS 로 메듀사 최단경로 : 도로 따라 공원까지 - 상하좌우
14+
# route = find_route(si,sj,ei,ej)
15+
from collections import deque
16+
def find_route(si,sj,ei,ej):
17+
q = deque()
18+
v = [ [0]*N for _ in range(N)] # 방문 여부 & *직전 위치*
19+
20+
q.append((si,sj))
21+
v[si][sj] = (si,sj) # 직전 위치 저장
22+
23+
while q :
24+
ci, cj = q.popleft()
25+
26+
# 목적지 도착 -> 경로 저장
27+
if (ci,cj)==(ei,ej) :
28+
29+
route = []
30+
ci,cj = v[ci][cj]
31+
while (ci,cj) !=(si,sj): # 출발지가 아니면 저장
32+
route.append((ci,cj))
33+
ci,cj = v[ci][cj]
34+
return route[::-1] #역순(메듀사 이동 start- > end 순서대로)
35+
36+
# 4방향(상하좌우), 범위내 , 미방문 ,조건(==0)
37+
for di,dj in ((-1,0),(1,0),(0,-1),(0,1)):
38+
ni, nj = ci+di , cj+ dj
39+
if 0<= ni <N and 0<=nj <N and v[ni][nj]== 0 and arr[ni][nj] ==0:
40+
q.append((ni,nj))
41+
v[ni][nj] = (ci,cj) # 바로 이전 좌표 저장
42+
43+
#여기까지 오면? : 목적지 못찾음
44+
return -1
45+
46+
47+
# mark_line(v,ni,nj,dr)
48+
def mark_line(v,ci,cj,dr): # dir 방향 직선으로 : M ~>1 "w ~2"
49+
50+
while 0<= ci< N and 0 <= cj<N: # 범위 나가는걸 방지
51+
v[ci][cj] = 2 # 시각적 구분을 위해 2로 표기 = safe 존
52+
ci,cj = ci+di[dr],cj+dj[dr] # 다음 dr 방향 칸 이동
53+
54+
55+
56+
def mark_safe(v,si ,sj ,dr,org_dr): # si ,sj : 전사 위치
57+
#[1] 직선방향표기
58+
ci,cj = si+di[dr], sj+dj[dr]
59+
60+
mark_line(v,ci,cj,dr) # v에 dr방향으로 이동 가능 지역 표시
61+
62+
#[2]전사가 바라보는 방향으로 한줄 식 표시 : 전사에게 가려져 이동 가능 지역
63+
ci,cj = si+di[org_dr],sj+dj[org_dr] # 이동한 svf poin 초기화
64+
65+
while 0<=ci<N and 0<=cj<N: # 범위내라면 계속 진행
66+
mark_line(v,ci,cj,dr)
67+
ci,cj = ci+di[org_dr],cj+dj[org_dr] # org_dir로 point(대각선) 위치 이동
68+
69+
70+
# tv , tstone = make_stone(marr , mi , mj dr) >>>tv , tston
71+
72+
def make_stone (marr, mi,mj,dr):
73+
v = [[0]*N for _ in range(N)]
74+
cnt = 0 # stone된 병사 개수
75+
76+
# myprint(marr)
77+
#[1] dr 방향으로 w(>0) 만날때 까지 1 표시 , 이후 2 표시
78+
ni, nj = mi + di[dr] , mj+dj[dr]
79+
80+
while 0<=ni<N and 0<=nj<N : # 범위내리면서 계속 진행
81+
v[ni][nj] = 1
82+
83+
if marr[ni][nj] > 0 : # 병사 w 만남
84+
cnt+=marr[ni][nj] # 해당 영역의 모든 w 석화
85+
ni, nj = ni + di[dr] , nj+dj[dr] # 다음 칸으로 이동
86+
87+
mark_line(v,ni,nj,dr) # v에 dr 방향으로 이동 가능 지역 표시
88+
89+
break
90+
ni, nj = ni + di[dr] , nj+dj[dr]
91+
#[2] dr -1 ,dr +1 방향으로 M의 시선 동일 처리, 대각선 원점 잡고 dr 방향으로 처리
92+
for org_dr in ((dr-1)%8 , (dr+1)%8):
93+
si,sj = mi+di[org_dr], mj+dj[org_dr] # 첫 대각선 위치부터 체크
94+
95+
# 대각선 시야각 영역 확인
96+
while 0<=si <N and 0<=sj <N : # 대각선 방향으로 초기 위치 탐색 후 직선 시선
97+
if v[si][sj] == 0 and marr[si][sj]> 0: # 전사 만남
98+
v[si][sj] = 1
99+
cnt += marr[si][sj]
100+
mark_safe(v,si,sj,dr,org_dr) # 전사가 바라보는 방향으로 safe(이동 가능 범위) 표시
101+
break
102+
# W 가 길 중간에 있는 경우
103+
ci ,cj = si,sj # 첫 위치가 전사가 아닐 경우는 직선으로
104+
while 0 <= ci <N and 0<= cj <N: # 범위 내리면서 계속 진행
105+
if v[ci][cj]==0: # 처음 방문
106+
v[ci][cj] = 1
107+
if marr[ci][cj]>0 : # 전사로 막히면
108+
cnt+= marr[ci][cj]
109+
mark_safe(v, ci,cj,dr,org_dr) # v에서 dr 방향으로 이동 가능 지역 표시
110+
break
111+
else :
112+
break
113+
ci,cj = ci+di[dr], cj+dj[dr]
114+
115+
si,sj = si+di[org_dr], sj+dj[org_dr]
116+
return v, cnt
117+
118+
# move_cnt , attk_cnt = move_men(v,mi,mj)
119+
120+
def move_men(v,mi,mj) :
121+
# [3] 전사의 이동 - (상하좌우)(좌우상하) 메두사 시야 아니면 (!=1)
122+
move , attk = 0,0
123+
for dirs in (((-1,0),(1,0),(0,-1),(0,1)), ((0,-1),(0,1),(-1,0),(1,0))):
124+
for idx in range(len(men)-1,-1,-1):
125+
ci ,cj = men[idx]
126+
if v[ci][cj] == 1 : # 메듀사 시야 내에 있으면 -> 정지
127+
continue
128+
dist = abs(mi-ci) +abs(mj-cj) # 현재 거리
129+
for di,dj in dirs :
130+
ni,nj = ci +di ,cj +dj # w 의 다음 이동 공간
131+
#범위내 메듀사 시야 아니고, 현재 거리보다 더 줄어드는 방향 (상하좌우 우선순위로 이동)
132+
if 0<=ni<N and 0<=nj<N and v[ni][nj]!=1 and dist>abs(mi-ni)+abs(mj-nj):
133+
if (ni,nj) == (mi,mj): # 공격 -> 죽음
134+
attk+=1
135+
men.pop(idx)
136+
else :
137+
men[idx] = [ni,nj]
138+
move += 1
139+
break
140+
return move, attk
141+
142+
###############
143+
# main FLOW
144+
###############
145+
146+
147+
# 0. 입력
148+
# 마을 크기 M , 전산수 N / 메듀사 위치정보s , 공원 위치 정보 e / M명 전사 좌표 N/ 개의 도로 정보
149+
N , M = map(int, input().split())
150+
si , sj , ei , ej = map(int , input().split())
151+
tlist = list(map(int , input().split()))
152+
153+
# 전사 좌표
154+
men = []
155+
for i in range(0, M*2 , 2) :
156+
men.append([tlist[i], tlist[i+1]])
157+
# 필드 정보
158+
arr =[list(map(int, input().split())) for _ in range(N)]
159+
160+
161+
162+
# [0] BFS 로 메듀사 최단경로 : 도로 따라 공원까지 - 상하좌우
163+
164+
route = find_route(si,sj,ei,ej)
165+
166+
167+
168+
if route == -1 : # 길이 없는 경우
169+
print(-1)
170+
else :
171+
for mi,mj in route : # 각 time = idx 별 메듀사 위치
172+
move_cnt , attk_cnt = 0, 0
173+
# [1]메듀사의 이동 : 지정된 최단거리로 한칸 이동 (전사와 만날 경우 , 전사 삭제)
174+
175+
for i in range(len(men)-1,-1,-1) : # 역순 탐색
176+
if men[i] == [mi,mj] :
177+
men.pop(i)
178+
179+
#[2] 메듀사 시선 : 상하좌우 방향중 "가장 많이 stone 되는 방향" 선택
180+
# v[] : 메듀사의 시선 명시해서 이동시 참조(메듀사시선 =1 , 전사에게 가려진 곳 ==2 ,빈땅 ==0)
181+
# mar[][] : 지도에 있는 현재 전사 수 (및 위치) 표시(중복 존재 가능)
182+
marr = [[0]*N for _ in range(N)]
183+
for ti, tj in men :
184+
marr[ti][tj] += 1
185+
186+
187+
max_stone = -1 # 4 방위 중 max stoning 가능한 개수
188+
v= [] #현 필드내 메듀사 시선으로 생기는 영억 속성 설정
189+
190+
# 4방위 바교
191+
for dr in (0,4,6,2) : # 상하좌우 순서대로 처리
192+
tv , tstone = make_stone(marr , mi , mj, dr)
193+
# 최대값 갱신 - max_stone 개수 & 시선 영역 속성 설정
194+
if max_stone < tstone :
195+
max_stone = tstone
196+
v = tv
197+
198+
199+
200+
201+
#[3] 전사의 이동 (한 칸씩 두번) : 메듀사 있는 경우 공격
202+
# 메듀사와 가까워지는 방향으로 접근
203+
move_cnt , attk_cnt = move_men(v,mi,mj)
204+
205+
print(move_cnt, max_stone , attk_cnt)
206+
print(0)

0 commit comments

Comments
 (0)