|
|
- -module(game_logic).
- -export([validate_play/2, calculate_card_value/1, evaluate_hand_strength/1,
- find_all_possible_patterns/1, analyze_card_pattern/1]).
-
- -define(CARD_VALUES, #{
- "3" => 3, "4" => 4, "5" => 5, "6" => 6, "7" => 7, "8" => 8, "9" => 9,
- "10" => 10, "J" => 11, "Q" => 12, "K" => 13, "A" => 14, "2" => 15,
- "小王" => 16, "大王" => 17
- }).
-
- %% 牌型定义
- -record(card_pattern, {
- type, % single | pair | triple | triple_with_one | straight |
- % straight_pair | airplane | airplane_with_wings | four_with_two | bomb | rocket
- value, % 主牌值
- length = 1, % 顺子长度
- extra = [] % 附加牌
- }).
-
- %% 验证出牌是否合法
- validate_play(Cards, LastPlay) ->
- case analyze_card_pattern(Cards) of
- {invalid, _} ->
- false;
- {Pattern, Value} ->
- case analyze_card_pattern(LastPlay) of
- {Pattern, LastValue} when Value > LastValue ->
- true;
- {_, _} ->
- check_special_cases(Pattern, Value, LastPlay);
- _ ->
- false
- end
- end.
-
- %% 分析牌型
- analyze_card_pattern(Cards) ->
- Grouped = group_cards(Cards),
- case identify_pattern(Grouped) of
- {Type, Value} when Type =/= invalid ->
- {#card_pattern{type = Type, value = Value}, Value};
- _ ->
- {invalid, 0}
- end.
-
- %% 计算手牌价值
- calculate_card_value(Cards) ->
- {Pattern, BaseValue} = analyze_card_pattern(Cards),
- case Pattern#card_pattern.type of
- bomb -> BaseValue * 2;
- rocket -> 1000;
- _ -> BaseValue
- end.
-
- %% 评估手牌强度
- evaluate_hand_strength(Cards) ->
- Patterns = find_all_possible_patterns(Cards),
- BaseScore = lists:foldl(
- fun(Pattern, Acc) ->
- Acc + calculate_pattern_value(Pattern)
- end,
- 0,
- Patterns
- ),
- adjust_score_by_combination(BaseScore, Cards).
-
- %% 找出所有可能的牌型组合
- find_all_possible_patterns(Cards) ->
- Grouped = group_cards(Cards),
- Singles = find_singles(Grouped),
- Pairs = find_pairs(Grouped),
- Triples = find_triples(Grouped),
- Straights = find_straights(Cards),
- StraightPairs = find_straight_pairs(Grouped),
- Airplanes = find_airplanes(Grouped),
- Bombs = find_bombs(Grouped),
- Rockets = find_rockets(Cards),
- Singles ++ Pairs ++ Triples ++ Straights ++ StraightPairs ++
- Airplanes ++ Bombs ++ Rockets.
-
- %% 内部辅助函数
-
- group_cards(Cards) ->
- lists:foldl(
- fun({_, Number}, Acc) ->
- maps:update_with(
- Number,
- fun(Count) -> Count + 1 end,
- 1,
- Acc
- )
- end,
- #{},
- Cards
- ).
-
- identify_pattern(Grouped) ->
- case maps:size(Grouped) of
- 1 ->
- [{Number, Count}] = maps:to_list(Grouped),
- case Count of
- 1 -> {single, maps:get(Number, ?CARD_VALUES)};
- 2 -> {pair, maps:get(Number, ?CARD_VALUES)};
- 3 -> {triple, maps:get(Number, ?CARD_VALUES)};
- 4 -> {bomb, maps:get(Number, ?CARD_VALUES)};
- _ -> {invalid, 0}
- end;
- _ ->
- identify_complex_pattern(Grouped)
- end.
-
- identify_complex_pattern(Grouped) ->
- case find_straight_pattern(Grouped) of
- {ok, Pattern} -> Pattern;
- false ->
- case find_airplane_pattern(Grouped) of
- {ok, Pattern} -> Pattern;
- false ->
- case find_four_with_two(Grouped) of
- {ok, Pattern} -> Pattern;
- false -> {invalid, 0}
- end
- end
- end.
-
- find_straight_pattern(Grouped) ->
- Numbers = lists:sort(maps:keys(Grouped)),
- case is_consecutive(Numbers) of
- true when length(Numbers) >= 5 ->
- MaxValue = lists:max([maps:get(N, ?CARD_VALUES) || N <- Numbers]),
- {ok, {straight, MaxValue}};
- _ ->
- false
- end.
-
- is_consecutive(Numbers) ->
- case Numbers of
- [] -> true;
- [_] -> true;
- [First|Rest] ->
- lists:all(
- fun({A, B}) -> maps:get(B, ?CARD_VALUES) - maps:get(A, ?CARD_VALUES) =:= 1 end,
- lists:zip(Numbers, Rest)
- )
- end.
-
- calculate_pattern_value(Pattern) ->
- case Pattern of
- #card_pattern{type = single, value = V} -> V;
- #card_pattern{type = pair, value = V} -> V * 2;
- #card_pattern{type = triple, value = V} -> V * 3;
- #card_pattern{type = bomb, value = V} -> V * 4;
- #card_pattern{type = rocket} -> 1000;
- #card_pattern{type = straight, value = V, length = L} -> V * L;
- _ -> 0
- end.
-
- adjust_score_by_combination(BaseScore, Cards) ->
- CombinationBonus = case length(Cards) of
- N when N =< 5 -> BaseScore * 1.2;
- N when N =< 10 -> BaseScore * 1.1;
- _ -> BaseScore
- end,
- round(CombinationBonus).
-
- check_special_cases(Pattern, Value, LastPlay) ->
- case Pattern#card_pattern.type of
- bomb -> true;
- rocket -> true;
- _ -> false
- end.
|