我在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 =:= '_'.
现在,我想进一步将TargetColor
替换为TargetPiece
,这是一个{TargetColor, TargetType}
元组。无,元组元素中的一个或两个可以是通配符('_'
)。我发现很难写出case
条款。我还注意到要匹配一个允许“不关心”的n元组。这样,需要2个 n 子句。显然,这不是实现这一目标的正确方法。
有没有人有更好的想法?
PS:我没有包含所有功能的来源,因为我认为没有包含的功能在我看来是微不足道的。如果您有兴趣,请在下面发表评论。谢谢!
答案 0 :(得分:0)
我的解决方案是实现匹配的辅助函数,这使得上面提到的2 n case
子句成为n orelse
子句加n-1 {{ 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).
有没有更好/另类的想法?
答案 1 :(得分:0)
我会更改国际象棋棋盘表示,用{Color,Type}或无棋子{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).