2014-11-21 51 views
1

我正在Erlang中實施一個國際象棋比賽(準確的說是中國象棋)。適當的方式來實現(Mnesia式/通配符/不關心)元組匹配(Erlang)

一塊由{Color, Type}元組表示,點(即位置)由{File, Rank}元組表示。董事會由點對點地圖(即#{point() => piece()})代表。

有查詢在基板上的特定點是否是由一塊或未被佔用的功能:

is_point_occupied_simple(Board, Point) -> 
    ensure_is_point(Point), 
    case maps:find(Point, Board) of 
     {ok, _} -> 
      true; 
     error -> 
      false 
    end. 

不過,我想補充一個可選的參數檢查塊的顏色 - 如果該點被一段指定的顏色佔據,則該函數返回true;否則返回false。如果我不關心塊的顏色,我只是把'_'TargetColor參數(或等價地,調用is_point_occupied/2):

is_point_occupied(Board, Point) -> 
    is_point_occupied(Board, Point, '_'). 

is_point_occupied(Board, Point, '_') -> 
    ensure_is_point(Point), 
    case maps:find(Point, Board) of 
     {ok, _} -> 
      true; 
     error -> 
      false 
    end; 

is_point_occupied(Board, Point, TargetColor) -> 
    ensure_is_point(Point), 
    ensure_is_color(TargetColor), 
    case maps:find(Point, Board) of 
     {ok, {TargetColor, _}} -> 
      true; 
     {ok, _} -> 
      false; 
     error -> 
      false 
    end. 

我不喜歡大的,因爲上述實施拷貝和粘貼的比例,所以簡化這樣上面的函數:

is_point_occupied_2(Board, Point) -> 
    is_point_occupied_2(Board, Point, '_'). 

is_point_occupied_2(Board, Point, TargetColor) -> 
    ensure_is_point(Point), 
    ensure_is_color_or_wildcard(TargetColor), 
    case maps:find(Point, Board) of 
     {ok, {TargetColor, _}} -> 
      true; 
     {ok, _} -> 
      is_wildcard(TargetColor); 
     error -> 
      false 
    end. 

功能is_wildcard/1是一個簡單的一行程序:

is_wildcard(Wildcard) -> Wildcard =:= '_'. 

現在,我想進一步替換TargetColorTargetPiece,這是一個{TargetColor, TargetType}元組。無,一個或兩個元組元素可能是通配符('_')。我發現很難編寫case子句。我也注意到,爲了匹配允許「不關心」的n元組,​​這樣就需要2 n條款。所以顯然這不是實施這個的正確方法。

有沒有人有更好的想法?

PS:我沒有包括所有功能的來源,因爲我沒有包括這些功能在我看來是微不足道的。如果您有興趣,請在下面留言。謝謝!

回答

0

我此解決方案是實現爲匹配的輔助功能,這使得上述成n 2個Ñcase子句orelse子句加上N-1 andalso子句:

match_piece({Color, Type} = Piece, {TargetColor, TargetType} = TargetPiece) -> 
    ensure_is_piece(Piece), 
    ensure_is_piece_or_wildcard(TargetPiece), 
    (is_wildcard(TargetColor) orelse Color =:= TargetColor) 
     andalso (is_wildcard(TargetType) orelse Type =:= TargetType). 

主要功能沒有按變化不大:

is_point_occupied_3(Board, Point) -> 
    is_point_occupied_3(Board, Point, {'_', '_'}). 

is_point_occupied_3(Board, Point, TargetPiece) -> 
    ensure_is_point(Point), 
    ensure_is_piece_or_wildcard(TargetPiece), 
    case maps:find(Point, Board) of 
     {ok, Piece} -> 
      match_piece(Piece, TargetPiece); 
     error -> 
      false 
    end. 

有沒有更好的/替代的想法?

0

我會改變國際象棋棋盤表示,方法是一塊{顏色,類型}或任何一塊填充整板{無,無},這樣您的代碼可以更加正規:

-module (testmatch). 

-compile([export_all]). 

is_point_occupied(Board,Point) -> not match(maps:find(Point, Board),{none,none}). 
is_point_occupied(Board,Point,Color) -> match(maps:find(Point, Board),{Color,'_'}). 
is_point_occupied(Board,Point,Color,Type) -> match(maps:find(Point, Board),{Color,Type}). 

match({ok,{C,T}},{C,T}) -> true; 
match({ok,{_C,T}},{'_',T}) -> true; 
match({ok,{C,_T}},{C,'_'}) -> true; 
match(_,_) -> false. 

test() -> 
    Board = #{1 =>{none,none}, 2 =>{black,king}, 3 => {white,tower} }, 
    false = is_point_occupied(Board,1), 
    true = is_point_occupied(Board,2), 
    false = is_point_occupied(Board,2,red), 
    true = is_point_occupied(Board,2,black), 
    false = is_point_occupied(Board,3,'_',king), 
    true = is_point_occupied(Board,3,'_',tower), 
    true = is_point_occupied(Board,2,black,king), 
    false = is_point_occupied(Board,2,black,tower), 
    false = is_point_occupied(Board,2,white,king). 
+0

謝謝你你的答案!那麼,這是否意味着您的棋盤需要8 x 8 = 64個棋子(而中國象棋需要9 x 10 = 90個棋子)?由於內存消耗在這裏很重要,我認爲這可能不是一個好方法。此外,爲了匹配一個n元組{E1,E2,...,En},必須寫入2^n個匹配/ 2個子句。正如我所提到的,我懷疑這是否是正確的做法。順便說一句,國際象棋僅僅作爲一個例子,我主要關注的是「不關心」式的匹配。是否必須改變電路板定義?有沒有比我更優雅的解決方案來實現這一目標?謝謝! – 2014-11-22 12:46:11