๐Ÿ“‘ํ”„๋กœ์ ํŠธ-A star ์•Œ๊ณ ๋ฆฌ์ฆ˜

์œ ๋ น๊ฐœยท2021๋…„ 11์›” 19์ผ
0

ํ”„๋กœ์ ํŠธ

๋ชฉ๋ก ๋ณด๊ธฐ
2/5

#### 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 ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ด์šฉํ•ด ์ตœ์ ์˜ ๊ธธ์ฐพ๊ธฐ๋ฅผ ํ–ˆ๋Š”์ง€ ํŒ๋ณ„ํ•ด์ฃผ๋Š” ์‹œ์Šคํ…œ์ด๋‹ค.

A-Star Logic

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

์•„๊นŒ ํ”ผํƒ€๊ณ ๋ผ์Šค์˜ ์ •๋ฆฌ๋กœ ์ˆ˜ํ‰๊ณผ ์ˆ˜์ง ๊ฒฝ๋กœ์˜ ๊ฐ€์ค‘์น˜๋ฅผ ์„ค์ •ํ–ˆ์œผ๋‹ˆ ๊ทธ๊ฒƒ ๋˜ํ•œ ๋˜‘๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

A-Star ๋ฏธ๋กœ๊ตฌํ˜„

๋ฏธ๋กœ๋Š” 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))  # ์ตœ์†Œ ๋น„์šฉ ์ถœ๋ ฅ
profile
ํ•œ๋ฆผ๋Œ€ํ•™๊ต ์ •๋ณด๊ณผํ•™๋Œ€ 2ํ•™๋…„ ์žฌํ•™์ค‘ / ์œก๊ตฐ ์ •๋ณด๋ณดํ˜ธ๋ณ‘ 22-2๊ธฐ

0๊ฐœ์˜ ๋Œ“๊ธ€