Skip to content

Commit

Permalink
Merge pull request #141 from IJS1016/main
Browse files Browse the repository at this point in the history
[24.04.2W]python ps, codetree
  • Loading branch information
IJS1016 authored Apr 16, 2024
2 parents 8ca66b9 + b6d1a00 commit 4ca9ff9
Show file tree
Hide file tree
Showing 5 changed files with 585 additions and 0 deletions.
99 changes: 99 additions & 0 deletions 정선/python/codetree/루돌프의반란.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
def get_distance_from_r() :
d_list = [] # [d, r, c, idx] # d min으로 정렬, r max, c max로 정렬하기 위해서! d를 -해주면 정렬이 가능
for idx, (sr, sc) in enumerate(santas) :
if santa_status[idx] >= 0 :
d = ((sr - rr) ** 2 + (sc - rc) ** 2)
d_list.append([idx, d, sr, sc])
d_list.sort(key=lambda x:(x[1], -x[2], -x[3])) # d, min으로 정렬 r max, c max 정렬
return d_list[0]

def get_distance_from_s(sr, sc) : # td이 d보다 작아서 가까워질때만 d_list에 넣어줌, idx는 direction 우선순위
direction = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 상우하좌
d_list = []
d = ((sr - rr) ** 2 + (sc - rc) ** 2) # 기존 거리보다 작아야됨
for idx, (dr, dc) in enumerate(direction) :
td = ((sr + dr - rr) ** 2 + (sc + dc - rc) ** 2)
if d > td :
d_list.append([idx, td, dr, dc])
d_list.sort(key=lambda x:(x[1], x[0]))
return d_list

def push_santa(tsr, tsc, mr, mc, sidx) : # 산타가 이동하는 좌표 tsr, tsc 받아서, push 해줌
if 1 <= tsr <= N and 1 <= tsc <= N: # 범위내 있으면 산타 index 변경, 기절 상태로 변경
for siidx, santa in enumerate(santas): # 산타 위치 돌면서 자리에 산타 있는지 확인
if [tsr, tsc] == santa and sidx != siidx: # 산타 겹치는 경우
santas[sidx] = [tsr, tsc] # 기존 산타를 이동
push_santa(tsr+mr, tsc+mc, mr, mc, siidx) # 이동할 산타 옮기기
break
santas[sidx] = [tsr, tsc]
else : # 탈락 라운드 작성(나중에 점수에 +하면 됨), 근데 기절상태라면,,? <0일때만 +로 바꿔주는 함수 넣기
santas[sidx] = [-N, -N] # 존재하지 않는 위치로 변경, distance 가장 높게 나오기 위해서 -N?
santa_status[sidx] = -m
# 입력 ###########################################################
N, M, P, C, D = map(int, input().split(" "))
rr, rc = map(int, input().split(" "))

santas = []
santa_status = [0] * P # -(퇴장라운드), 0, +(기절) 퇴장, 정상, 기절
santa_score = [0] * P # score

for _ in range(P) :
santas.append(list(map(int, input().split(" "))))
santas.sort(key = lambda x : x[0])
santas = [s[1:] for s in santas] # santas [sr, sc]이고 1번부터 P까지 순서대로 있음
######################################################################

for m in range(1, M+1) : # 1번-M번 턴, 남은 산타에 대해서만 +1점
# 기절 산타들 풀어주기
for i in range(P) :
if santa_status[i] > 0 :
santa_status[i] -= 1
# 루돌프 이동, 산타와 가까워지는 방향으로
sidx, dx, sr, sc = get_distance_from_r() # d_list에서 산타 존재하면, 충돌!
dr = (sr - rr) / abs(sr - rr) if rr - sr != 0 else 0
dc = (sc - rc) / abs(sc - rc) if rc - sc != 0 else 0
rr = rr + dr
rc = rc + dc
# 충돌 발생
if [rr, rc] in santas :
santa_score[sidx] += C
tsr, tsc = santas[sidx][0] + dr * C, santas[sidx][1] + dc * C # 루돌프 이동 방향으로 C칸 물러남
if 1 <= tsr <= N and 1 <= tsc <= N : # 범위내 있으면 산타 index 변경, 기절 상태로 변경
santa_status[sidx] = 2
push_santa(tsr, tsc, dr, dc, sidx)
else : # 탈락 라운드 작성(나중에 점수에 +하면 됨), 근데 기절상태라면,,? <0일때만 +로 바꿔주는 함수 넣기
santas[sidx] = [-N, -N] # 존재하지 않는 위치로 변경
santa_status[sidx] = -m

# 산타 거리 계산 후 이동 ###########################3
# 산타 거리 계산할 때...상우하좌
for sidx in range(P):
if santa_status[sidx] == 0: # 정상일 때만 이동
sr, sc = santas[sidx]
condi_list = get_distance_from_s(sr, sc)
mr, mc = 0, 0
for condi in condi_list :
_, _, dr, dc = condi
if [sr+dr, sc+dc] not in santas :
mr, mc = dr, dc # 이동 확정
break
# 산타 이동
sr, sc = sr + mr, sc + mc
if [sr, sc] == [rr, rc] : # 루돌프와 충돌 발생 확인, 루돌프는 반드시 map 범위 안에 있으니 추가 검사 필요하지 않음
santa_score[sidx] += D
tsr, tsc = sr + mr * (-D), sc + mc * (-D)
santa_status[sidx] = 2 # 기절
push_santa(tsr, tsc, -mr, -mc, sidx)
else :
santas[sidx] = [sr, sc]

if max(santa_status) < 0 :
break

# 출력 #############################################
for sidx in range(P) :
if santa_status[sidx] < 0 : # 탈락 산타만 탈락 라운드 점수 더해주기
santa_score[sidx] -= (santa_status[sidx]+1)
else :
santa_score[sidx] += M # 탈락하지 않은 산타는 M 라운드 더해주고
print(santa_score[sidx], end=" ")
168 changes: 168 additions & 0 deletions 정선/python/codetree/메이즈러너.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
# 입력)
# N, M, K
# NxN 미로 정보) 0, (1-9) 벽
# M 참가자 좌표) 초기에는 빈칸에만 존재
# 출구 좌표 -> 빈칸...

# 출력) 모든 참가자들의 이동 거리 합과 출구 좌표를 출력
class Point :
def __init__(self, r, c):
self.r = r-1
self.c = c-1

# 입력 받으면서 -1해서 범위 (0, N-1)로 변경
# 입력 받기 ################################################
N, M, K = map(int, input().split(" "))
mmap = []
persons = []
person_status = [True] * M
total_move = 0
for _ in range(N) :
mmap.append(list(map(int, input().split(" "))))
for _ in range(M) :
r, c = map(int, input().split(" "))
persons.append(Point(r, c))
r, c = map(int, input().split(" "))
exit_p = Point(r, c)
#######################################################
def get_distance(r, c) :
return(abs(exit_p.r-r)+abs(exit_p.c-c))

def check_out_mmap(r, c) :
if (0 <= r < N) and (0 <= c < N) :
return True
return False

def persons_move() :
# 모든 참가자 이동 - 벽 없는 곳, 가까워지는 곳, 우선순위 상하, 중첩 가능, 이동 횟수 +1, 출구 이동 시 탈출
global total_move
directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] # 우선순위 상하
for i, p in enumerate(persons) :
if person_status[i] :
od = get_distance(p.r, p.c) # 이동 전 distance 계산, original_distance : od
for drt in directions :
dr, dc = drt
nr, nc = p.r + dr, p.c + dc
if check_out_mmap(nr, nc) and mmap[nr][nc] == 0: # 맵을 나가지 않고, 벽이 없으면
if od > get_distance(nr, nc) : # 새롭게 얻은 거리가 더 작으면
persons[i].r, persons[i].c = nr, nc # 사람 이동
total_move += 1
break # DBG) 새롭게 얻은 거리가 더 작으면? 무조건 1차이 아님? 틀리면 break 빼기
if [persons[i].r, persons[i].c] == [exit_p.r, exit_p.c] : # 출구 이동 시 탈출, REVIEW : class 비교 꺼내서 해야됨 바로 X
person_status[i] = False

# 정사각형을 어떻게 잡을지
# 같은 사람을 포함하는 정사각형이 어려개 있을 수 있음
# 크기 먼저..., r,c 범위
# DBG) 맵 범위? 상관 있음 - 사람이 오른쪽 하단에? 상관 없나..? 우선 해보고 틀리면 생각
# mmap slicing할 떄 범위 [min_r, max_r+1] 주의
def search_rectangle() :
er, ec = exit_p.r, exit_p.c
rectangles = [] # [l, r, c]로 저장
dlist = []
for i, p in enumerate(persons) :
if person_status[i] :
dr, dc = p.r - er, p.c - ec # P - E
l = max([abs(dr), abs(dc)]) # 정사각형 길이(3이면 2가 저장됨에 유의)
# p에서 좌상단 할 수 있는 케이스 4개 확인
# [0, 0], [0, l], [l, 0], [0, -l], [-l, 0], # REVIEW : 범위 제대로
for dlr in range(-l, l+1) :
for dlc in range(-l, l+1) :
# dlr, dlc = dl # 좌상단 좌표 찾기 위해서...
tr, tc = er + dlr, ec + dlc # 출구 기준 좌상단 tr, tc
if check_out_mmap(tr, tc) and tr <= p.r <= tr + l and tc <= p.c <= tc + l : # 범위 내 사람이 있으면
rectangles.append([l, tr, tc])
tr, tc = p.r + dlr, p.c + dlc # 사람 기준 좌상단 tr, tc
if check_out_mmap(tr, tc) and tr <= er <= tr + l and tc <= ec <= tc + l: # 범위 내 사람이 있으면
rectangles.append([l, tr, tc])
# 최종 sort
rectangles.sort(key=lambda x : (x[0], x[1], x[2])) # 길이 작은 순, r, c 좌표 작은 우선순위
return rectangles[0]

def check_inside_rect(rr, rc, rl, r, c) :
if rr <= r <= rr + rl and rc <= c <= rc + rl:
return True
return False
def rotate_rectangle(rl, rr, rc) :
rotated_infos = [] # 회전된 r, c, value 순으로 저장
# 맵 회전 정보 저장
for tr, line in enumerate(mmap) :
for tc, v in enumerate(line) :
if check_inside_rect(rr, rc, rl, tr, tc) :
# if rr <= tr <= rr + rl and rc <= tc <= rc + rl :
rotated_infos.append([tc - rc + rr, rl - (tr - rr) + rc, max(v-1, 0)]) # shift
if DBG :
print(f"ROTATED ({rr}, {rc}), size {rl}")
# print("rotated_infos")
# for ri in rotated_infos :
# print(ri)
# 저장된 회전 정보 맵에 써주기
for info in rotated_infos :
r, c, v = info
mmap[r][c] = v
# exit, person 회전
for i, p in enumerate(persons) :
if person_status[i] :
if check_inside_rect(rr, rc, rl, p.r, p.c) :
persons[i].r, persons[i].c = p.c - rc + rr, rl - (p.r - rr) + rc # DBG) person[i]말고 p.c = 없는지, 이렇게 해도 되는지 확인하기
exit_p.r, exit_p.c = exit_p.c - rc + rr, rl - (exit_p.r - rr) + rc


def print_mmap() :
print(" ", end="")
for i in range(N) :
print(change_color_y(f" {i}"), end="")
print()
for i, m in enumerate(mmap) :
print(change_color_y(f"{i} "), end="")
ptr_str = ''
for j, mm in enumerate(m) :
flag = True
if [exit_p.r, exit_p.c] == [i, j] :
ptr_str += change_color_b(f"{mm}") + " "
flag = False
for pi, p in enumerate(persons):
if person_status[pi]:
if [p.r, p.c] == [i, j] :
ptr_str += change_bg(f"{mm}") + " "
flag = False
break
if flag :
ptr_str += f"{mm} "
print(ptr_str)

def change_color_y(s) :
return '\033[31m' + str(s) + '\033[0m'
def change_color_b(s) :
return '\033[34m' + str(s) + '\033[0m'
def change_bg(s) :
return '\033[43m' + str(s) + '\033[0m'

bm = 0
DBG = False
for k in range(K) : # K번 실행
if DBG :
print(f"\n\n!! {k+1}초")
print("before rot")
print_mmap()
persons_move()
if DBG :
print(f"people move {total_move-bm}")
print_mmap()

if not max(person_status) :
if DBG : print("NO PP")
break

# 회전할 정사각형 서치 - 사람 한 명이라도 포함해야함, 크기 작은 순, 좌상단 r, c 작은 순 우선
rl, rr, rc = search_rectangle() # rectangle, 이때 길이 3이면 rl에는 2가 저장
# 정사각형 회전 - 출구, 포함된 사람, 벽 모두 회전 => 시계 방향 회전
rotate_rectangle(rl, rr, rc) # 시계 방향 회전을 어떻게 구현(C, N-R)
if DBG:
bm = total_move
print(f"{k+1} after rot")
print_mmap()
# 사람들 없으면 break

print(total_move)
print(exit_p.r+1, exit_p.c+1)
122 changes: 122 additions & 0 deletions 정선/python/codetree/왕실의기사대결.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 입력
# L N Q # L : 체스판 크기, N : 기사 수, Q : 명령
# L개 줄에 겹쳐 LxL 체스판 정보, 0 : 빈칸, 1 : 함정, 2: 벽
# N명 기사 정보(순서대로) : r, c, h, w, k - 위치 (r, c), 방패 (h, w) 체력 k
# Q개 명령 : i, d i번째 기사 d로 한칸 이동(사라진 기사 번호가 주어질 수 있음)
# d (0, 1, 2, 3) : 상 우 하 좌
# 처음에는 기사들끼리 겹쳐지지 않고, 기사와 벽은 겹쳐서 주어지지 않음

# 출력
# Q 명령 후 생존 기사들의 받은 총 데미지 합

DBG = False
class Knight :
def __init__(self, r, c, h, w, k):
self.r = r
self.c = c
self.h = h # 방패 바로 더해주려고 -1 해줌, 인덱싱할 땐 그냥 써야되네;...
self.w = w
self.k = k
self.d = 0
self.status = True
def get_infos(self):
return [self.r, self.c, self.h, self.w]

# 입력 ################################################
L, N, Q = map(int, input().split(" "))
mmap = []
knights = []
orders = []
total_damage = [0] * N
for _ in range(L) :
mmap.append(list(map(int, input().split(" "))))
for _ in range(N) :
r, c, h, w, k = map(int, input().split(" "))
knights.append(Knight(r, c, h, w, k))
for _ in range(Q) :
orders.append(map(int, input().split(" ")))
######################################################

def check_mapout(r, c, h, w) :
if 1 <= r <= L and 1 <= c <= L and 1 <= r+h-1 <= L and 1 <= c+w-1 <= L :
return True
return False
def check_overlap(tr, tc, h, w, other_knight) :
ot_r, ot_c, ot_h, ot_w = other_knight.get_infos()
# 잘못!! 어떤게 더 클지 모르니까 둘다 해줘야되네...
if (tr <= ot_r <= tr+h-1) or (tr <= ot_r+ot_h-1 <= tr+h-1) : # 세로 방향 겹치는지
if (tc <= ot_c <= tc+w-1) or (tc <= ot_c+ot_w-1 <= tc+w-1): # 가로 방향 겹치는지
return True
if (ot_r <= tr <= ot_r+ot_h-1) or (ot_r <= tr+h-1 <= ot_r+ot_h-1): # 세로 방향 겹치는지
if (ot_c <= tc <= ot_c+ot_w-1) or (ot_c <= tc+w-1 <= ot_c+ot_w-1): # 가로 방향 겹치는지
return True

return False

def get_max_value(tr, tc, h, w) :
max_value = 0
for m in mmap[tr - 1:tr + h - 1] : # tr이 1부터 시작하니까
tmp = max(m[tc - 1:tc + w - 1])
if max_value < tmp :
max_value = tmp
return max_value

def get_damage(r, c, h, w) :
damage = 0
for m in mmap[r - 1:r + h - 1] :
for v in m[c - 1:c + w - 1] :
if v == 1 : damage+=1
return damage

# 뭐가 하나라도 안되면 False로 return해서 돌지 않도록
# 최종으로 된다고 하면 True랑 history return해서 위치 바꿔주면서 패널티 세기
def push_knights(knight, kidx, move, history):
# 이동 시 밀 수 있는지 검사
mr, mc = move
tr, tc = knight.r+mr, knight.c+mc
h, w = knight.h, knight.w
if not check_mapout(tr, tc, h, w) : # 맵 범위 밖이거나
if DBG :print(f"NO! knight {kidx+1} - map out")
return False, history # 이동 불가
elif get_max_value(tr, tc, h, w) == 2 : # 벽이 있으면
if DBG : print(f"NO! knight {kidx+1} - wall")
return False, history
# 이동 불가
else : # 벽이 없다면 이동 가능
if DBG :print(f"GO! knight {kidx+1}")
history[kidx] = [tr, tc] # new tr, tc
for idx, other_knight in enumerate(knights): # 기사가 있는지 검사
if other_knight.status : # 기사가 살아있을 때
if idx != kidx and idx not in history.keys(): # 자기 자신이 아니고 다른 기사랑 만났을 때, 본 것들이 아닐 때
if DBG : print(f"-> check knight {idx+1}")
if check_overlap(tr, tc, h, w, other_knight) : # 겹치는 영역이 있으면
if DBG: print(f"overlap knight {idx + 1} info {other_knight.r, other_knight.c, other_knight.h, other_knight.w}")
flag, history = push_knights(other_knight, idx, [mr, mc], history) # 다시 밀어내기
if not flag :
return False, None
return True, history

direct = ['상', '우', '하', '좌']
directions = [[-1, 0], [0, 1], [1, 0], [0, -1]] # 상우하좌
for (kidx, d) in orders :
kidx -= 1
if DBG : print(f"!!! Order Knight : {kidx+1}, {direct[d]}")
if knights[kidx].status : # 기사가 살아있으면
flag, history = push_knights(knights[kidx], kidx, directions[d], {})
if DBG : print(flag, history)
if flag :
for hkidx, (nr, nc) in history.items() : # 좌표 업데이트, 업데이트 하면서 패널티도 받게 하기
knights[hkidx].r, knights[hkidx].c = nr, nc # 좌표값 업데이트
if hkidx != kidx: # 명령 아닌거만 패널티
h, w = knights[hkidx].h, knights[hkidx].w # 쉽게 쓸라고, 노의미
knights[hkidx].d += get_damage(nr, nc, h, w)
if knights[hkidx].k <= knights[hkidx].d :
knights[hkidx].status = False

result = 0
for kidx, knight in enumerate(knights) :
if knight.status :
if DBG : print(f"{kidx+1}D : {knight.d}")
result += knight.d

print(result)
Loading

0 comments on commit 4ca9ff9

Please sign in to comment.