迷宮 可以用遞迴
-- 迷宮用 2D 陣列表示:0=通道, 1=牆壁, S=起點, E=終點
create table maze (
row_idx int not null
, col_idx int not null
, cell char(1) not null check(cell in ('0', '1', 'S', 'E'))
, primary key (row_idx, col_idx)
);
-- 範例迷宮 (7×7)
-- S 0 1 0 0 0 0
-- 0 0 1 0 1 1 0
-- 1 0 0 0 0 0 0
-- 0 0 1 1 1 0 1
-- 0 0 0 0 1 0 0
-- 1 1 1 0 0 0 1
-- 0 0 0 0 1 E 0
insert into maze
select r, c
, case
when r = 0 and c = 0 then 'S'
when r = 6 and c = 5 then 'E'
when (r,c) in ((0,2),(1,2),(1,4),(1,5),(2,0)
,(3,2),(3,3),(3,4),(3,6),(4,4),(5,0),
(5,1),(5,2),(5,6),(6,4)) then '1'
else '0'
end
from generate_series(0,6) r
, generate_series(0,6) c;
--
with recursive bfs as (
-- 起點
select row_idx
, col_idx
, 0 as distance
, array[row(row_idx, col_idx)] as path
from maze
where cell = 'S'
union all
select m.row_idx
, m.col_idx
, b.distance + 1
, b.path || row(m.row_idx, m.col_idx)
from bfs b
join maze m
on (m.row_idx = b.row_idx + 1 and m.col_idx = b.col_idx)
or (m.row_idx = b.row_idx - 1 and m.col_idx = b.col_idx)
or (m.row_idx = b.row_idx and m.col_idx = b.col_idx + 1)
or (m.row_idx = b.row_idx and m.col_idx = b.col_idx - 1)
where m.cell <> '1' -- 不是牆壁
and not row(m.row_idx, m.col_idx) = any(b.path)
)
select distance
, path
from bfs
where (row_idx, col_idx) =
(select row_idx, col_idx
from maze
where cell = 'E')
order by distance;

with recursive bfs as (
-- 起點
select row_idx
, col_idx
, 0 as distance
, array[row(row_idx, col_idx)] as path
from maze
where cell = 'S'
union all
select m.row_idx
, m.col_idx
, b.distance + 1
, b.path || row(m.row_idx, m.col_idx)
from bfs b
join maze m
on abs(m.row_idx - b.row_idx) + abs(m.col_idx - b.col_idx) = 1
-- 這裡改寫
where m.cell <> '1' -- 不是牆壁
and not row(m.row_idx, m.col_idx) = any(b.path)
), pickone as (
select path
from bfs
where (row_idx, col_idx) =
(select row_idx, col_idx
from maze
where cell = 'E')
order by distance
limit 1
), path_cells as (
select p.r
, p.c
from pickone
join lateral unnest(path) as p(r int, c int)
on true
), disp_rows as (
select row_idx
, string_agg(
case
when exists (
select 1
from path_cells pc
where pc.r = row_idx
and pc.c = col_idx
) then case
when m.cell in ('S', 'E') then m.cell
else '.'
end
when m.cell = '1' then 'X'
else m.cell
end
, ' ' order by col_idx
) as row_display
from maze m
group by m.row_idx
order by m.row_idx
)
select string_agg(row_display, E'\n') as maze_display
from disp_rows;
maze_display
---------------
S . X 0 0 0 0
0 . X 0 X X 0
X . . . . . 0
0 0 X X X . X
0 0 0 0 X . 0
X X X 0 0 . X
0 0 0 0 X E 0
X 代表牆壁, . 代表路線, 0 代表其他沒有走的.