#### A-Star ์๊ณ ๋ฆฌ์ฆ
์๊ฐ๋ณด๋ค ๊ณ ๋ฑํ๊ต๋๋ ํ์ด์ฌ ์์ฃผ๋ก ํ๋ก๊ทธ๋จ์ ๋ง์ด ์งฐ๋ ๊ฒ ๊ฐ๋ค. VS code์ highlight๋ ์ฌ๋ฌ ํ
์คํธ์๋ํฐ๋ฅผ ๊น์๋๊ณ ์ฝ๋ฉ์ ํ๋ฉด ๊ฐ์ง๊ฐ ๋์ ๊ทธ๋ฌ์๊น ใ
ใ
ํ์ด์ฌ์ผ๋ก ์ฝ๋ฉํ๋ ์ฝ๋๊ฐ ๋ช๊ฐ ๋ณด์กด๋์ด ์๊ธธ๋ ์ค๋์ ๊ณ ๋ฑํ๊ต ๋ ํ๋๊ฑธ ์ ๋ฆฌํ๋ฉด์ A-Star
์๊ณ ๋ฆฌ์ฆ์ผ๋ก ๋ฏธ๋ก๋ฅผ ๋ง๋ค์๋๊ฑธ ์ ์ด๋ณด๋ ค๊ณ ํ๋ค.
์ฐธ๊ณ ๋ก ์ ๋ฌธ์ ์ธ ๊ธธ์ฐพ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ์ฐธ๊ณ ํ๊ธฐ์ ์ด ๊ธ์ ์ ์ ํ์ง ์๋ค. ์ด๋ค ๋๋์ธ์ง ๊ฐ๋ง ์ก๊ณ ์ถ์ ์ด๋ณด ํ๋ก๊ทธ๋๋จธ๋ค์ด ํ๋ฒ ์ฏค ๊ฑฐ์ณ๊ฐ๋ฉด ์ข์ ๊ธ์ธ ๊ฒ ๊ฐ๋ค.
A-Star ์๊ณ ๋ฆฌ์ฆ?
์ฒ์์ A-Star
์๊ณ ๋ฆฌ์ฆ์ด๋ผ๊ณ ๋ค์์๋๋ ์ ํ ๊ฐ์ด ์ค์ง ์์๋ค. ๋น์์๋ ํฅํ์ ๋์ฌ ์ฌ๊ท์ฉ๋ฒ์ ์ปค๋
DFS
,BFS
๋ฐ Dijkstra
๋ฑ ๊ธธ์ฐพ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ๊ดํ ๊ธฐ๋ณธ ์ง์๋ ์์์ผ๋ฉฐ (์ง๊ธ๋ ์์ง๋ง ใ
ใ
) ์ด๋ป๊ฒ ์ฝ๋ฉํด์ผํ ์ง ์ ํ ๊ฐ์ ์ก์ง ๋ชปํ๋ค. ๊ทธ๋์ ๋ฌด์์ ๊ตฌ๊ธ๋งํด๋ณด๋ฉฐ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์๋ ๊ธฐ์ต์ด ๋๋ค.
๋ง๋ฅ ์ง์ ์ ์๋์ธ ์ํค๋ฐฑ๊ณผ๋ฅผ ๋ณด๋ฉด A-Star
์ ๋ํด ์ด๋ ๊ฒ ๊ธฐ์ ํด๋์๋ค.
A* ์๊ณ ๋ฆฌ์ฆ์ ์ฃผ์ด์ง ์ถ๋ฐ ๊ผญ์ง์ ์์๋ถํฐ ๋ชฉํ ๊ผญ์ง์ ๊น์ง ๊ฐ๋ ์ต๋จ ๊ฒฝ๋ก๋ฅผ ์ฐพ์๋ด๋ (๋ค์ ๋งํด ์ฃผ์ด์ง ๋ชฉํ ๊ผญ์ง์ ๊น์ง ๊ฐ๋ ์ต๋จ ๊ฒฝ๋ก์์ ํ๋จํ ์ ์๋ ํ
์คํธ๋ฅผ ํต๊ณผํ๋) ๊ทธ๋ํ ํ์ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋์ด๋ค. ์ด ์๊ณ ๋ฆฌ์ฆ์ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ๊ณผ ์ ์ฌํ๋ ์ฐจ์ด์ ์ ๊ฐ ๊ผญ์ง์ x์ ๋ํด ๊ทธ ๊ผญ์ง์ ์ ํต๊ณผํ๋ ์ต์์ ๊ฒฝ๋ก๋ฅผ ์ถ์ ํ๋ ์์๊ฐ์ธ "ํด๋ฆฌ์คํฑ ์ถ์ ๊ฐ " h(x) ์ ๋งค๊ธฐ๋ ๋ฐฉ๋ฒ์ ์ด์ฉํ๋ค๋ ๊ฒ์ด๋ค.
์ฒ์์ ์ด ๊ธ์ ๋ณด๊ณ ๋ฌด์จ ์๋ฆฐ์ง ์ดํด๊ฐ ์๊ฐ์ผ๋ ๊ตฌ๊ธ๋ง์ ํด๋ณด๋ฉฐ ์ฐจ๊ทผ์ฐจ๊ทผ ์ดํดํด๊ฐ๋ณด๋ ค ํ๋ค.
์ผ๋จ ์ด A-Star ์๊ณ ๋ฆฌ์ฆ์ "ํด๋ฆฌ์คํฑ"๊ธฐ๋ฒ์ด๋ค. ๊ทธ๋์ ์ด ํด๋ฆฌ์คํฑ์ด ๋ญ๋?
์ฐ๊ธฐ
๊ทธ๋ฅ ๋๋์ค์ผ๋ก ๋ณด๊ณ ๋๋ ค๋ง์ถ๋๊ฑฐ๋์ ์ ๋ ์ ๋ชฐ๋ผ์ ใ ใ
๋์ถฉ ์ฌ์ ์ ์ ์๋ก๋
๋์ถฉ ์ด๋ฆผ์ง์ํ๊ธฐ, ๊ฒฝํ์ด ๋ถ์กฑํ๊ฑฐ๋ ํฉ๋ฆฌ์ ํ๋จ์ด ํ์ํ์ง ์์ผ๋ฉฐ ๋น ๋ฅด๊ฒ ํ๋จํ๊ณ ์ถ์ ๋ ์ฌ์ฉ
์ด๋ผ๋๋ฐ ์ด๊ฒ ์ฐ๊ธฐ๋ ๋ฌด์จ ์ฐจ์ด๊ฐ ์์ผ๋ ค๋
๊ทธ๋ฌ๋ ๋์ค์ ์๋ณด๋๊น ์ ์ ์ ์๊ณ ๋ฆฌ์ฆ
์ด๋ ๋ค์ต์คํธ๋ผ
์๊ณ ๋ฆฌ์ฆ ๋ฑ ๊ตต์งํ ์๊ณ ๋ฆฌ์ฆ๋ ์ด๋ฐ ํด๋ฆฌ์คํฑ์ ๊ธฐ๋ฐํ์ฌ ์ฌ์ฉํ๋ ๊ผญ ์์๋๋ฉด ์ข์ ๊ฐ๋
์ด๋ค.
๋ค์ ๋ณธ๋ก ์ผ๋ก ๋์์์ A-Star
์๊ณ ๋ฆฌ์ฆ์ด ํด๋ฆฌ์คํฑ์ ๊ธฐ๋ฐํ์ผ๋ฉฐ, ์ฃผ์ด์ง ๊ผญ์ง์ (๋
ธ๋)๋ง๋ค ์ต๋จ ๊ฒฝ๋ก์์ ํ๋จํ ํ ์ด๋ํ๋ ๊ทธ๋ํ ํ์ ์๊ณ ๋ฆฌ์ฆ์์ ์ ์ ์์๋ค.
A-Star ์๊ณ ๋ฆฌ์ฆ์ ํต์ฌ์ F=G+H์ด๋ค. F๋ ์ถ๋ฐ ์ง์ ์์ ๋ชฉ์ ์ง๊น์ง์ ์ด ๊ฐ, G๋ ํ์ฌ ์ง์ ์์ ์ถ๋ฐ ์ง์ ๊น์ง์ ์ด ๊ฐ, H๋ ํ์ฌ ์ง์ ์์ ๋ชฉ์ ์ง๊น์ง์ ๊ฐ์ธ๋ฐ ์๋ง ๋ชฉ์ ์ง๋ ๋น์ฅ์ ์ ์ ์์ผ๋ ์ถ์ ๊ฐ์ด ์๋๊น ์ถ๋ค. ์ฐธ๊ณ ๋ก ์ฌ๊ธฐ์ H๋ ์ผ๋ฐ์ ์ผ๋ก ํด๋ฆฌ์คํฑ์ ์ฝ์๋ผ๊ณ ํ๋ค.
์ฌ๊ธฐ์ ํ๋์์ ์ถ๋ฐ์ง์ , ์ฃผํฉ์์ ๋์ฐฉ์ง์ ์ด๋ผ๊ณ ํด๋ณด์.
๊ทธ๋ฆฌ๊ณ ์ค๊ฐ์ ๊ทธ์ด์ ธ ์๋ ์ ์ ์ ๋ฏฟ๊ธฐ์ง ์๊ฒ ์ง๋ง ์ฅ์ ๋ฌผ์ด๋ค.
๊ฒ์์ ๋ค๋ชจ๋ค์ ๊ธธ์ด๋ค. ์์ง์ผ๋๋ง๋ค 1๊ฐ์ฉ ์๋ชจ๋๋ค.
์ฌ๊ธฐ์ ํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ ์๋ ๋
ธ๋์ ๊ฐ์ด 3์ด๋ผ๊ณ ์๊ฐํด๋ณด์.
๋์ถฉ ๊ทธ๋ ธ์ง๋ง ์ด๋ ๊ฒ ์๊ฒผ์ ๊ฒ์ด๋ค. ๊ทธ๋ผ ์ฐ๋ฆฌ๊ฐ 3์ ์ ์์ผ๋๊น F=G+H์ค์์ G๋ 3์ด ๋๋ค?
๊ทธ๋ผ ์ด์ ์ฐ๋ฆฐ ํด๋ฆฌ์คํฑ๋ง ๊ตฌํด์ฃผ๋ฉด A-Star๋ฅผ ์ดํดํ ์ ์๋ค.
๊ทธ๋ฆผ์ ๊ฑฐ์ง๊ฐ์ด ๊ทธ๋ ค์ ์ด์ํด๋ณด์ผ์ง ๋ชฐ๋ผ๋ ๋์ถฉ ์์ผ๋ก 3์นธ, ์๋ก ํ์นธ์ด๋ค.
์คํ๊ต ์์ ๋ ๋ฐฐ์์จ ์ฌ๋์ด๋ผ๋ฉด ๋๋ถ๋ถ ์๊ฑฐ๋ค. ํผํ๊ณ ๋ผ์ค ๊ณต์
๊ทธ๋ ๊ฒ ์ฒ์ ๋์จ G=3๊ณผ ํผํ๊ณ ๋ผ์ค๋ฅผ ์ด์ฉํ์ฌ ๊ตฌํ H=โ10์ ๋ํ๋ฉด ๋์ถฉ ๋์ฐฉ์ง์ ์ธ 7 ๊ทผ์ฌ๊ฐ์ด ๋์ค๋ ๊ฑธ ํ์ธํ ์ ์๋ค. ์!
์ฌ๊ธฐ์ ์ฃผ์ํ ์ ์ ๊ทผ์ ๊ฑฐ๋ฆฌ๊ฐ ๊ฐ์ด ํด ๊ฒฝ์ฐ์๋ ๋ค์ต์คํธ๋ผ ์๊ณ ๋ฆฌ์ฆ์ฒ๋ผ ์๋ํ ์๋ ์๋ค๊ณ ํ๋ค.
์ด๋ณด ํ๋ก๊ทธ๋๋จธ์ธ ๋ด๊ฐ ์ ๊ฒฝ ์ธ ๊ฑด ์๋๊ฒ ๊ฐ์ง๋ง...
A-Star
๋ ์๊ฐ๋ณด๋ค ๋ง์ ๊ณณ์์ ์ฐ์ธ๋ค. ์๋ ๋ถ์ด ์์ด๋๋น ํ์ฌ์ ๋ค๋์๋๋ฐ ํ ๋ ์ฐ์ด์
จ๋ค๊ณ ํ๊ณ , ๋ค์ต์คํธ๋ผ์ ๋๋ถ์ด ํ์ฉ๋๊ฐ ๋์ ๊ธธ์ฐพ๊ธฐ ์๊ณ ๋ฆฌ์ฆ ์ค ํ๋์ด๋ ๊ฐ๋
์ด๋ผ๋ ๊ผญ ์ง๊ณ ๋์ด๊ฐ ํ์์ฑ์ด ์๋ค.
๊ทธ๋ผ A-Star์ ๊ธฐ๋ณธ์ ์ธ ๊ฑธ ์ตํ์ผ๋ ์ด๊ฑธ ์ฝ๋๋ก ๊ตฌํํด ๋ณด์.
์ฝ๋์ ๊ฐ๋
์ฑ์ ์ํด A-Star ์๊ณ ๋ฆฌ์ฆ๊ณผ ๋ฏธ๋ก ์์ฑ ๋ถ๋ถ์ ๋๋ด๋ค. ์ด๋ฒ์ ๋ง๋ค์ด ๋ณผ ๊ฒ์ ๋ฏธ๋ก๋ฅผ
์์ฑํ ๋ค A-Star ์๊ณ ๋ฆฌ์ฆ์ ์ด์ฉํด ์ต์ ์ ๊ธธ์ฐพ๊ธฐ๋ฅผ ํ๋์ง ํ๋ณํด์ฃผ๋ ์์คํ
์ด๋ค.
def astar(maze, start, end):
start_node = Node(None, start) # ์์ ๋
ธ๋ ์์ฑ
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end) # ๋์ฐฉ ๋
ธ๋ ์์ฑ
end_node.g = end_node.h = end_node.f = 0
open_list = [] # ์คํ ๋ฆฌ์คํธ
closed_list = [] # ๋ซํ ๋ฆฌ์คํธ
์๊น ํ๋ ๊ฒ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์์๋ ธ๋์ ๋์ฐฉ๋ ธ๋๋ฅผ ์์ฑํด์ฃผ์๋ค.
while len(open_list) > 0: # ์คํ ๋ฆฌ์คํธ์ ๋
ธ๋๊ฐ ์์๋ ์ข
๋ฃ
current_node = open_list[0]
current_index = 0
# ์คํ ๋ฆฌ์คํธ ๋
ธ๋๋ค์ค์ ๊ฐ์ฅ ์ต์ ๋น์ฉ F๋ฅผ ๊ฐ์ง ๋
ธ๋๋ฅผ ์ฐพ๋๋ค
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
open_list.pop(current_index) # ์คํ ๋ฆฌ์คํธ์ ํด๋นํ๋ ๋
ธ๋ pop
closed_list.append(current_node) # ๋ซํ ๋ฆฌ์คํธ์ ํด๋น ๋
ธ๋ input
if current_node == end_node: # ๋์ฐฉ ๋
ธ๋๊น์ง ํ์์ด ์๋ฃ๋ ๊ฒฝ์ฐ
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return path[::-1] # ์ญ์์ผ๋ก ์ถ๋ ฅ๋๊ฒ ๋ฐ์ ์ํ๋ก ๋ฆฌํด ์ํจ๋ค
๋ฆฌ์คํธ๋ฅผ ํ์ฉํ์ฌ ๋ง๋ค์ด๋ณด๋ ค๊ณ ํ๋ค.
์๊น ์ค๋ช ํ๋ฉด์ ์ง์ ํ ๊ฒ๊ณผ๋ ๋ฌ๋ฆฌ, ๋ฏธ๋ก์์ ํ๋ ์ด์ด๊ฐ ์์ง์ผ ๋๋ ํญ์ ์ ๋์ ์ผ๋ก ๊ฐ์ด ๋ฐ๋๊ธฐ์ ํ์ฌ ๋ ธ๋์ค ๊ฐ์ฅ ์ต์ ๋น์ฉ์ ๊ฐ์ง ๋ ธ๋๋ฅผ ๋ฐ๋ก๋ฐ๋ก ์ฐพ์์ค์ผํ๋ค.
๊ทธ๊ฒ F๊ณ ๋์ฐฉ ๋ ธ๋๊น์ง ํ์์ด ์๋ฃ๋ ๊ฒฝ์ฐ์๋ ์ญ์ผ๋ก ์ถ๋ ฅ๋๋๋ก ์ฝ๋ฉํด๋์๋ค.
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 \
or node_position[1] > (len(maze[len(maze) - 1]) - 1) or node_position[1] < 0:
continue
if maze[node_position[0]][node_position[1]] == 1: # ์ด๋๋ ์ง์ ์ด ๋ฒฝ์ผ๋
continue
elif node_position[1] == start[1]-1 and current_node.position == start_node.position:
continue
์ด๋ฐ์ฉ์ผ๋ก ๋ฏธ๋ก ๋ฒฝ ๋ฐ์ผ๋ก ๋๊ฐ์๋ ๋ฃจํ๋ฅผ ๋ค์ ๋๊ฒ๋ ๋ง๋ค์ด ์ ์์ ์ผ๋ก ์ถ๋ ฅ๋๊ฒ ํด์ฃผ์์ผ๋ฉฐ
if check == False:
child.g = current_node.g + 1
child.h = ((child.position[0] - end_node.position[1]) ** 2) + (
(child.position[1] - end_node.position[0]) ** 2)
child.f = child.g + child.h
์๊น ํผํ๊ณ ๋ผ์ค์ ์ ๋ฆฌ๋ก ์ํ๊ณผ ์์ง ๊ฒฝ๋ก์ ๊ฐ์ค์น๋ฅผ ์ค์ ํ์ผ๋ ๊ทธ๊ฒ ๋ํ ๋๊ฐ์ด ์ค์ ํด์ฃผ์๋ค.
๋ฏธ๋ก๋ pygame์ผ๋ก ์ ์ํ๋ค.
ํ์ด์ฌ์ ์ ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ค์์ ๊ฐ๋ณ๊ฒ ๋ง๋ค์ด๋ณด๊ธฐ์ pygame๋งํ๊ฒ ์๋ ๊ฒ ๊ฐ๋ค
import pygame
import sys
from time import sleep
import A_star_logic
white = (255, 255, 255)
gold = (255, 204, 0)
green = (0, 255, 0)
dark_green = (0, 153, 0)
black = (0, 0, 0)
size = [800, 600] # setup game size
box_size = 45 # setup box size
player_size = 20 # setup player size
start_point = (0, 1) # start y,x
end_point = (9, 15) # end y,x
maze_x = 17 # max maze x
maze_y = 11 # max maze y
make_maze = [[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
๋ฏธ๋ก๋ฅผ ๋ง๋ค์ด์ฃผ๊ณ ์ด๊ธฐ๊ฐ์ ์น ์ค์ ํด์ฃผ์๋ค.
def __init__(self):
pygame.init()
self.display = pygame.display.set_mode(size) # display setup
pygame.display.set_caption('maze') # caption setup
self.fps = pygame.time.Clock() # fps setup
self.player_x = 70 # pixcel x
self.player_y = 20 # pixecl y
self.x = start_point[1] # real x
self.y = start_point[0] # real y
self.font = pygame.font.SysFont("Arial", 40) # font setup
self.cnt = 0 # move count check
self.path = [start_point, ] # add move path
self.maze()
๊ทธ ๋ค ํ์ด๊ฒ์์ ๊ธฐ๋ณธ ์บก์ ๊ณผ fps, ํฝ์ x,y๊ฐ์ ์ค์ ํด์ฃผ์์ผ๋ฉฐ
if key[pygame.K_RIGHT]: # move right
if make_maze[self.y][self.x + 1] == 1:
pass
elif make_maze[self.y][self.x + 1] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_x += box_size
self.x += 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_x += box_size
self.x += 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_LEFT]: # move left
if make_maze[self.y][self.x - 1] == 1:
pass
elif make_maze[self.y][self.x - 1] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_x -= box_size
self.x -= 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_x -= box_size
self.x -= 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_UP]: # move up
if make_maze[self.y - 1][self.x] == 1:
pass
elif make_maze[self.y - 1][self.x] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_y -= box_size
self.y -= 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_y -= box_size
self.y -= 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_DOWN]: # move down
if make_maze[self.y + 1][self.x] == 1:
pass
elif make_maze[self.y + 1][self.x] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_y += box_size
self.y += 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_y += box_size
self.y += 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
ํค๋ณด๋๋ฅผ ๋๋ฅด๋ฉด ์ด๋ํ๊ฒ๋ ์ค์
์ผ์ถ ๋ค ๋๊ฒ ๊ฐ์ผ๋ ์คํํด๋ณด๋ฉด ๋ ๊ฒ ๊ฐ์๋ค.
์คํ๋ ์ ๋๊ณ
์ต์ ๋ฃจํธ์ผ๋์ ๊ฐ๋, ์๋๋์ ๊ฐ๋ ์ ์ถ๋ ฅ๋๋ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
๊ณ ๋ฑํ๊ต๋ ๋ด๊ฐ ์ด๊ฑธ ์ด๋ป๊ฒ ๋ง๋ค์๋์ง ๋ชจ๋ฅด๊ฒ ๋ค ใ
ใ
ใ
๋น์์ ์๋ ์ ๋ฐฐ๋ ์ธํฐ๋ท ๋์ ๋ฐ์๊ฐ๋ฉด์ ๊พธ์ญ ๊พธ์ญ ๋ง๋ค์๋๋ฐ ์ด์ ์์ ์ฝ๋๋ฅผ ๋ณด๋ ๋ค์ ๊ณต๋ถํด์ผ๊ฒ ๋ค๋ ์๊ฐ์ด ์์ผ ๋ค์๋ค.
์๋์ ์ฝ๋ ์ ๋ฌธ์ ์ฒจ๋ถํ์ผ๋ ์ธ์ ๊ฐ๋ ์ดํด๋ณด๊ฒ ์ง..?
import pygame
import sys
from time import sleep
import A_star_logic
white = (255, 255, 255)
gold = (255, 204, 0)
green = (0, 255, 0)
dark_green = (0, 153, 0)
black = (0, 0, 0)
size = [800, 600] # setup game size
box_size = 45 # setup box size
player_size = 20 # setup player size
start_point = (0, 1) # start y,x
end_point = (9, 15) # end y,x
maze_x = 17 # max maze x
maze_y = 11 # max maze y
make_maze = [[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1],
[1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 3, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
class MAZE:
def __init__(self):
pygame.init()
self.display = pygame.display.set_mode(size) # display setup
pygame.display.set_caption('maze') # caption setup
self.fps = pygame.time.Clock() # fps setup
self.player_x = 70 # pixcel x
self.player_y = 20 # pixecl y
self.x = start_point[1] # real x
self.y = start_point[0] # real y
self.font = pygame.font.SysFont("Arial", 40) # font setup
self.cnt = 0 # move count check
self.path = [start_point, ] # add move path
self.maze()
def maze(self): # draw maze
mx = 0
my = 0
for i in range(0, maze_x * maze_y):
if make_maze[my][mx] == 3:
pygame.draw.rect(
self.display, gold, (mx * box_size, my * box_size, box_size, box_size))
if make_maze[my][mx] == 2:
pygame.draw.rect(self.display, green, (mx *
box_size, my * box_size, box_size, box_size))
if make_maze[my][mx] == 1:
pygame.draw.rect(
self.display, white, (mx * box_size, my * box_size, box_size, box_size), 2)
mx += 1
if mx == maze_x:
mx = 0
my += 1
def Character(self): # setup character
self.player = pygame.Rect(
self.player_x, self.player_y, player_size, player_size)
def move(self): # check the key press and move
key = pygame.key.get_pressed()
speed = 0.3
if key[pygame.K_RIGHT]: # move right
if make_maze[self.y][self.x + 1] == 1:
pass
elif make_maze[self.y][self.x + 1] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_x += box_size
self.x += 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_x += box_size
self.x += 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_LEFT]: # move left
if make_maze[self.y][self.x - 1] == 1:
pass
elif make_maze[self.y][self.x - 1] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_x -= box_size
self.x -= 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_x -= box_size
self.x -= 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_UP]: # move up
if make_maze[self.y - 1][self.x] == 1:
pass
elif make_maze[self.y - 1][self.x] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_y -= box_size
self.y -= 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_y -= box_size
self.y -= 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
elif key[pygame.K_DOWN]: # move down
if make_maze[self.y + 1][self.x] == 1:
pass
elif make_maze[self.y + 1][self.x] == 2:
make_maze[self.y][self.x] = 0
self.cnt -= 1
pygame.draw.circle(self.display, green,
(self.player_x, self.player_y), player_size)
self.player_y += box_size
self.y += 1
sleep(speed)
else:
make_maze[self.y][self.x] = 2
pygame.draw.circle(self.display, white,
(self.player_x, self.player_y), player_size)
self.player_y += box_size
self.y += 1
self.cnt += 1
self.path.append((self.y, self.x))
sleep(speed)
def show(self): # display Move count string
showcount = self.font.render("Move:" + str(self.cnt), False, white)
self.display.blit(showcount, (650, 500))
def run(self):
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
self.fps.tick(60)
self.display.fill(black)
self.move()
self.maze()
self.Character()
self.show()
pygame.draw.circle(self.display, green, (self.player.left,
self.player.top), player_size) # draw character
pygame.draw.circle(self.display, dark_green, (self.player.left - 1,
self.player.top - 1), player_size) # draw gradation
if self.x == end_point[1] and self.y == end_point[0]:
print("๋์ฐฉ!")
print("๋์ฐฉ์ง๊น์ง์ ๋ค์ ๋น์ฉ์ : " +str(self.cnt))
if self.cnt == answer:
print("\n์ต์ ์ ๊ฒฝ๋ก ๊ฐ์
๋๋ค!")
print("A * ์๊ณ ๋ฆฌ์ฆ์ด ์ฐพ์ ๊ฒฝ๋ก๋ : " +str(answer_path))
print("ํ๋ ์ด์ด๊ฐ ์ฐพ์ ๊ฒฝ๋ก๋ : " +str(self.path))
else:
print("\n์ต์ ์ ๊ฒฝ๋ก ๊ฐ์ ์๋๋๋ค...")
sys.exit()
# draw last move point
if (self.x == start_point[1] and self.y == start_point[0]) and self.cnt > 0:
self.cnt = 0
mx = 0
my = 0
for i in range(0, maze_x * maze_y):
if make_maze[my][mx] == 2:
make_maze[my][mx] = 0
pygame.draw.rect(
self.display, white, (mx * box_size, my * box_size, box_size, box_size), 2)
mx += 1
if mx == maze_x:
mx = 0
my += 1
pygame.display.update()
if __name__ == "__main__": # start main
global answer_path, answer
answer_path = A_star_logic.main(
make_maze, start_point, end_point) # a star ์๊ณ ๋ฆฌ์ฆ ๊ฒฝ๋ก
answer = len(answer_path)-1 # a star ์๊ณ ๋ฆฌ์ฆ ๊ฒฝ๋ก ๊ธธ์ด ๊ฐ
MAZE().run()
class Node():
def __init__(self, parent=None, position=None):
self.parent = parent # ๋ถ๋ชจ ๋
ธ๋
self.position = position # ๋
ธ๋ ์์น
# ๋
ธ๋์ g,h,f
self.g = 0
self.h = 0
self.f = 0
def __eq__(self, other):
return self.position == other.position
def astar(maze, start, end):
start_node = Node(None, start) # ์์ ๋
ธ๋ ์์ฑ
start_node.g = start_node.h = start_node.f = 0
end_node = Node(None, end) # ๋์ฐฉ ๋
ธ๋ ์์ฑ
end_node.g = end_node.h = end_node.f = 0
open_list = [] # ์คํ ๋ฆฌ์คํธ
closed_list = [] # ๋ซํ ๋ฆฌ์คํธ
open_list.append(start_node) # ์คํ ๋ฆฌ์คํธ ์ฒ์์ ์์ ๋
ธ๋ ๊ฐ์ผ๋ก
while len(open_list) > 0: # ์คํ ๋ฆฌ์คํธ์ ๋
ธ๋๊ฐ ์์๋ ์ข
๋ฃ
current_node = open_list[0]
current_index = 0
# ์คํ ๋ฆฌ์คํธ ๋
ธ๋๋ค์ค์ ๊ฐ์ฅ ์ต์ ๋น์ฉ F๋ฅผ ๊ฐ์ง ๋
ธ๋๋ฅผ ์ฐพ๋๋ค
for index, item in enumerate(open_list):
if item.f < current_node.f:
current_node = item
current_index = index
open_list.pop(current_index) # ์คํ ๋ฆฌ์คํธ์ ํด๋นํ๋ ๋
ธ๋ pop
closed_list.append(current_node) # ๋ซํ ๋ฆฌ์คํธ์ ํด๋น ๋
ธ๋ input
if current_node == end_node: # ๋์ฐฉ ๋
ธ๋๊น์ง ํ์์ด ์๋ฃ๋ ๊ฒฝ์ฐ
path = []
current = current_node
while current is not None:
path.append(current.position)
current = current.parent
return path[::-1] # ์ญ์์ผ๋ก ์ถ๋ ฅ๋๊ฒ ๋ฐ์ ์ํ๋ก ๋ฆฌํด ์ํจ๋ค
children = []
for new_position in [(0, -1), (0, 1), (-1, 0), (1, 0)]: # ๋์๋จ๋ถ ๊ทธ๋ฆฌ๊ณ ๋๊ฐ์ ๋ฐฉํฅ์ผ๋ก ํ์นธ์ฉ ์ด๋
node_position = (current_node.position[0] + new_position[0], current_node.position[1] + new_position[1])
if node_position[0] > (len(maze) - 1) or node_position[0] < 0 \
or node_position[1] > (len(maze[len(maze) - 1]) - 1) or node_position[1] < 0: # ์ด๋๋ ์ง์ ์ด maze ๋ฐ๊นฅ์ผ๋
continue
if maze[node_position[0]][node_position[1]] == 1: # ์ด๋๋ ์ง์ ์ด ๋ฒฝ์ผ๋
continue
elif node_position[1] == start[1]-1 and current_node.position == start_node.position:
continue
new_node = Node(current_node, node_position)
children.append(new_node) # ์์ ๋
ธ๋์ ์ด๋ํ ์ง์ ์ฆ ์ด๋ ๋
ธ๋ ๊ฐ ๋์
for child in children:
check = False
for closed_child in closed_list:
if child == closed_child: # ํ์์ค์ธ ์์ ๋
ธ๋๊ฐ ๋ซํ ๋ฆฌ์คํธ์ ๊ฐ์ ๊ฐ์ผ ๊ฒฝ์ฐ
check = True
if check == False:
child.g = current_node.g + 1
child.h = ((child.position[0] - end_node.position[1]) ** 2) + (
(child.position[1] - end_node.position[0]) ** 2) # ํผํ๊ณ ๋ผ์ค ์ ๋ฆฌ์ ์ํด ์ํ๊ณผ ์์ง ๊ฒฝ๋ก์ ๊ฐ์ค์น ์ค์
child.f = child.g + child.h
# for open_node in open_list:
# if child == open_node and child.g > open_node.g:
# continue
open_list.append(child)
def main(maze, start, end):
path = astar(maze, start, end) # a star ํ์ ๊ฒฐ๊ณผ
return path
#print("๋์ฐฉ์ง๊น์ง์ ์ต์ ๊ฒฝ๋ก๋ : ", path) # ๊ฒฝ๋ก ์ถ๋ ฅ
#print("๊ฒฝ๋ก์ ๋๋ ๋น์ฉ์ : ", len(path)) # ์ต์ ๋น์ฉ ์ถ๋ ฅ