由於程式很小,我就直接把 code 跟我的感想等等混合說明如下:
% R91922034 Hung-Te Lin, AI Project 2 % Utility Functions
我的想法是,Prolog 會自己找答案,那我就想辦法讓它去自動著色,然後 做檢查把不合的拿掉。 著色有兩種方式,可以照區域上色,也可以對 Edge 兩邊。 本來我是寫成對 Edge 兩邊上色再去 match,不過後來考慮到題目要求 的格式是照 Region 輸出的,代表最後還是要做一次找 Region 的作; 所以 後來還是改成照 Region 上色。 所以,第一步是先寫出從給定的 Edge List 中找出所有 region 的部份。 我稱之為 extract_regions:
% extract_regions: extract region data from assigned map % usage: extract_regions(EdgeList, [], Regions). % unify the bindings and regions extract_regions([], Regions, Regions). % recursive rules extract_regions([ [S,T] | Rest ], Bindings, Regions) :- member(S, Bindings) -> (member(T, Bindings) -> % both S and T in Regions extract_regions( Rest, Bindings, Regions ) ; % S in Regions while T is not extract_regions( Rest, [T|Bindings], Regions)) ; % S not in Regions (member(T, Bindings) -> % T in Regions while S in not extract_regions( Rest, [S|Bindings], Regions) ; % both S and T are not in Regions extract_regions(Rest, [S,T|Bindings], Regions)).
本來對建 region 有點頭痛,找了一下網路上的 prolog source 發現到有 if then else 的結構; 於是改寫成上面的形式,好寫多了。
% paint_colors: paint colors to regions % usage: paint_colors(Regions, Colors, Paintings). % first rule: if no region, just return nothing paint_colors([], _, []). % search rule: paint_colors([Rgn | Rest], Colors, [[Rgn,C] | Paintings]) :- member(C, Colors), paint_colors(Rest, Colors, Paintings).
後面就很好寫了: paint_colors 直接讓 Prolog 從 Colors 中拿出所有可以用的色表來上色。
% utility to display all paintings. %list-paintings(Regions, Colors) :- % paint_colors(Regions, Colors, Paintings), % write(Paintings),nl, % fail. % same_color: check if any adjacent edges have same_color % usage: same_color(EdgeList, Colors, Paintings). same_color(EdgeList, Colors, Paintings) :- member(C, Colors), member([S, T], EdgeList), member([S, C], Paintings), member([T, C], Paintings).
同樣,same_color 是我對所有的 EdgeList 去找有沒有違規的情形。 接下來測試一下各 utility 都沒有問題就可以來寫最後符合題目要求的 input 跟 output。 這裡有點小技巧,之前找不到 not,後來看到 \+ 可以達到類似的需求。
% the final program, in term project #2 specified format. color(EdgeList, Colors, Coloring) :- extract_regions(EdgeList, [], Regions_BeforeSorting), sort(Regions_BeforeSorting, Regions), paint_colors(Regions, Colors, Coloring), \+ same_color(EdgeList, Colors, Coloring). list-color(EdgeList, Colors, Coloring) :- extract_regions(EdgeList, [], Regions_BeforeSorting), sort(Regions_BeforeSorting, Regions), paint_colors(Regions, Colors, Coloring), \+ same_color(EdgeList, Colors, Coloring), write(Coloring), nl, fail.
list-color 是我用來自動 (不用按 ;)把所有解列出來的函式。
這次作業滿有趣的, Prolog 有很多好處,不過一開始想很麻煩。 它的 debug 之類也沒那麼直覺。 還有就是我本來寫了一堆的東西, 後來多半無用,因為之前忘了 Prolog 會去幫我找答案。 最後是因為 Google 幫我找到一堆好程式,看了他們的寫法後才變成這麼精簡。