实现(Mnesia样式/通配符/不关心)元组匹配(Erlang)的正确方法

实现(Mnesia样式/通配符/不关心)元组匹配(Erlang)的正确方法,erlang,mnesia,Erlang,Mnesia,我正在执行一个象棋游戏,中国象棋,又名。香旗,确切地说是二郎 工件由{Color,Type}元组表示,点即位置由{File,Rank}元组表示。电路板由点对点映射表示,即{point=>piece} 有一个查询板上某一点是否被工件占用的功能: is_point_occupied_simple(Board, Point) -> ensure_is_point(Point), case maps:find(Point, Board) of {ok, _} -&g

我正在执行一个象棋游戏,中国象棋,又名。香旗,确切地说是二郎

工件由{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参数中输入“u”,或者等效地调用is_point_occulated/2:

我不喜欢上面的实现,因为复制和粘贴的比例很大,所以我简化了上面的功能,如下所示:

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.
函数为\u通配符/1只是一行:

is_wildcard(Wildcard) -> Wildcard =:= '_'.
现在,我想进一步用TargetPiece替换TargetColor,这是一个{TargetColor,TargetType}元组。无、一个或两个元组元素可以是通配符“\u1”。我发现写案例条款很困难。我还注意到,要以这种方式匹配n元组,需要2n子句。因此,显然这不是实现这一目标的正确方式

有人有更好的主意吗


PS:我没有包括所有函数的源代码,因为我认为那些我没有包括的函数实现起来很简单。如果您感兴趣,请在下面留下评论。谢谢

我的解决方案是实现一个辅助匹配函数,将上面提到的2n个case子句变成n个orelse子句加上n-1和also子句:

主要功能变化不大:

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.

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

我会改变棋盘的表示,用一块{颜色,类型}或没有一块{none,none}填充整个棋盘,这样你的代码可以更规则:

-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).

谢谢你的回答!那么,这是否意味着你的棋盘需要8 x 8=64个象棋元素和9 x 10=90个中国象棋元素?由于内存消耗在这里很重要,我认为这可能不是一个好方法。此外,为了匹配n元组{E1,E2,…,En},必须编写2^n match/2子句。正如我提到的,我怀疑这样做是否正确。顺便说一下,国际象棋在这里只是作为一个例子,我主要关注的是不在乎风格匹配。是否必须更改董事会定义?有没有比我更优雅的解决方案来实现这一点?谢谢
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.
-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).