|
|
- -module(game_core).
- -export([start_game/3, play_cards/3, get_game_state/1, is_valid_play/2]).
- -export([init_deck/0, deal_cards/1, get_card_type/1, compare_cards/2]).
-
- -record(game_state, {
- players = [], % [{Pid, Cards, Role}]
- current_player, % Pid
- last_play = [], % {Pid, Cards}
- played_cards = [], % [{Pid, Cards}]
- stage = waiting, % waiting | playing | finished
- landlord_cards = [] % 地主牌
- }).
-
- %% 初始化扑克牌
- init_deck() ->
- Colors = ["♠", "♥", "♣", "♦"],
- Numbers = ["3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K", "A", "2"],
- Cards = [{Color, Number} || Color <- Colors, Number <- Numbers],
- Jokers = [{"", "小王"}, {"", "大王"}],
- shuffle(Cards ++ Jokers).
-
- %% 发牌
- deal_cards(Deck) ->
- {Players, Landlord} = lists:split(51, Deck),
- {lists:sublist(Players, 1, 17),
- lists:sublist(Players, 18, 17),
- lists:sublist(Players, 35, 17),
- Landlord}.
-
- %% 开始游戏
- start_game(Player1, Player2, Player3) ->
- Deck = init_deck(),
- {Cards1, Cards2, Cards3, LandlordCards} = deal_cards(Deck),
- % 随机选择地主
- LandlordIdx = rand:uniform(3),
- Players = assign_roles([{Player1, Cards1}, {Player2, Cards2}, {Player3, Cards3}], LandlordIdx),
- #game_state{
- players = Players,
- current_player = element(1, lists:nth(LandlordIdx, Players)),
- landlord_cards = LandlordCards
- }.
-
- %% 出牌
- play_cards(GameState, PlayerPid, Cards) ->
- case validate_play(GameState, PlayerPid, Cards) of
- true ->
- NewState = update_game_state(GameState, PlayerPid, Cards),
- check_game_end(NewState);
- false ->
- {error, invalid_play}
- end.
-
- %% 验证出牌
- validate_play(GameState, PlayerPid, Cards) ->
- case get_player_cards(GameState, PlayerPid) of
- {ok, PlayerCards} ->
- has_cards(PlayerCards, Cards) andalso
- is_valid_play(Cards, GameState#game_state.last_play);
- _ ->
- false
- end.
-
- %% 判断牌型
- get_card_type(Cards) ->
- Sorted = sort_cards(Cards),
- case analyze_pattern(Sorted) of
- {Type, Value} -> {ok, Type, Value};
- invalid -> {error, invalid_pattern}
- end.
-
- %% 内部函数
-
- shuffle(List) ->
- [X || {_, X} <- lists:sort([{rand:uniform(), N} || N <- List])].
-
- analyze_pattern(Cards) ->
- case length(Cards) of
- 1 -> {single, card_value(hd(Cards))};
- 2 -> analyze_pair(Cards);
- 3 -> analyze_triple(Cards);
- 4 -> analyze_four_cards(Cards);
- _ -> analyze_complex_pattern(Cards)
- end.
-
- analyze_pair([{_, N}, {_, N}]) -> {pair, card_value({any, N})};
- analyze_pair(_) -> invalid.
-
- analyze_triple([{_, N}, {_, N}, {_, N}]) -> {triple, card_value({any, N})};
- analyze_triple(_) -> invalid.
-
- analyze_four_cards(Cards) ->
- case group_cards(Cards) of
- #{4 := [Value]} -> {bomb, card_value({any, Value})};
- _ -> analyze_four_with_two(Cards)
- end.
-
- analyze_complex_pattern(Cards) ->
- case is_straight(Cards) of
- true -> {straight, highest_card_value(Cards)};
- false -> analyze_other_patterns(Cards)
- end.
-
- %% 获取游戏状态
- get_game_state(GameId) ->
- % 简单实现,实际应该从某种存储中获取
- {ok, #game_state{}}.
- %% 初始化游戏状态
- init_game_state() ->
- % 创建一个空的游戏状态
- #game_state{
- players = [],
- current_player = undefined,
- last_play = [],
- played_cards = [],
- stage = waiting,
- landlord_cards = []
- }.
-
- %% 判断出牌是否有效
- is_valid_play(Cards, LastPlay) ->
- % 如果是第一手牌,任何合法牌型都可以
- case LastPlay of
- [] -> is_valid_card_type(Cards);
- {_, LastCards} ->
- % 检查牌型是否相同且大小是否更大
- {ok, Type1, Value1} = get_card_type(Cards),
- {ok, Type2, Value2} = get_card_type(LastCards),
- (Type1 =:= Type2 andalso Value1 > Value2) orelse
- (Type1 =:= bomb andalso Type2 =/= bomb)
- end.
-
- %% 判断牌型是否合法
- is_valid_card_type(Cards) ->
- case get_card_type(Cards) of
- {ok, _, _} -> true;
- _ -> false
- end.
-
- %% 比较两手牌的大小
- compare_cards(Cards1, Cards2) ->
- {ok, Type1, Value1} = get_card_type(Cards1),
- {ok, Type2, Value2} = get_card_type(Cards2),
- if
- Type1 =:= bomb andalso Type2 =/= bomb -> greater;
- Type2 =:= bomb andalso Type1 =/= bomb -> lesser;
- Type1 =:= Type2 andalso Value1 > Value2 -> greater;
- Type1 =:= Type2 andalso Value1 < Value2 -> lesser;
- true -> incomparable
- end.
-
- %% 分配角色
- assign_roles(PlayerCards, LandlordIdx) ->
- lists:map(
- fun({Idx, {Pid, Cards}}) ->
- Role = case Idx of
- LandlordIdx -> landlord;
- _ -> farmer
- end,
- {Pid, Cards, Role}
- end,
- lists:zip(lists:seq(1, length(PlayerCards)), PlayerCards)
- ).
-
- %% 更新游戏状态
- update_game_state(GameState, PlayerPid, Cards) ->
- % 更新玩家手牌
- UpdatedPlayers = lists:map(
- fun({Pid, PlayerCards, Role}) when Pid =:= PlayerPid ->
- {Pid, PlayerCards -- Cards, Role};
- (Player) -> Player
- end,
- GameState#game_state.players
- ),
-
- % 更新出牌记录和当前玩家
- NextPlayer = get_next_player(GameState, PlayerPid),
- GameState#game_state{
- players = UpdatedPlayers,
- current_player = NextPlayer,
- last_play = {PlayerPid, Cards},
- played_cards = [{PlayerPid, Cards} | GameState#game_state.played_cards]
- }.
-
- %% 获取下一个玩家
- get_next_player(GameState, CurrentPid) ->
- Players = GameState#game_state.players,
- PlayerPids = [Pid || {Pid, _, _} <- Players],
- CurrentIdx = get_player_index(PlayerPids, CurrentPid),
- lists:nth(1 + (CurrentIdx rem length(PlayerPids)), PlayerPids).
-
- %% 获取玩家索引
- get_player_index(PlayerPids, TargetPid) ->
- {Idx, _} = lists:foldl(
- fun(Pid, {Idx, Found}) ->
- case Pid =:= TargetPid of
- true -> {Idx, Idx};
- false -> {Idx + 1, Found}
- end
- end,
- {1, not_found},
- PlayerPids
- ),
- Idx.
-
- %% 检查游戏是否结束
- check_game_end(GameState) ->
- case lists:any(
- fun({_, Cards, _}) -> length(Cards) =:= 0 end,
- GameState#game_state.players
- ) of
- true ->
- Winner = lists:keyfind(0, 2, GameState#game_state.players),
- {game_over, Winner, GameState#game_state{stage = finished}};
- false ->
- {continue, GameState}
- end.
-
- %% 获取玩家手牌
- get_player_cards(GameState, PlayerPid) ->
- case lists:keyfind(PlayerPid, 1, GameState#game_state.players) of
- {_, Cards, _} -> {ok, Cards};
- false -> {error, player_not_found}
- end.
-
- %% 检查玩家是否有这些牌
- has_cards(PlayerCards, CardsToPlay) ->
- lists:all(
- fun(Card) ->
- Count = count_card(PlayerCards, Card),
- CountToPlay = count_card(CardsToPlay, Card),
- Count >= CountToPlay
- end,
- lists:usort(CardsToPlay)
- ).
-
- %% 计算特定牌的数量
- count_card(Cards, TargetCard) ->
- length([Card || Card <- Cards, Card =:= TargetCard]).
-
- %% 分析四带二
- analyze_four_with_two(Cards) ->
- Grouped = group_cards(Cards),
- case maps:get(4, Grouped, []) of
- [Value] ->
- case length(Cards) of
- 6 -> {four_with_two, card_value({any, Value})};
- _ -> invalid
- end;
- _ -> invalid
- end.
-
- %% 分组牌
- group_cards(Cards) ->
- lists:foldl(
- fun({_, Number}, Acc) ->
- Count = maps:get(Number, Acc, 0) + 1,
- Acc#{Number => Count}
- end,
- #{},
- Cards
- ).
-
- %% 获取最高牌值
- highest_card_value(Cards) ->
- lists:max([card_value(Card) || Card <- Cards]).
-
- %% 牌值转换
- card_value({_, "3"}) -> 3;
- card_value({_, "4"}) -> 4;
- card_value({_, "5"}) -> 5;
- card_value({_, "6"}) -> 6;
- card_value({_, "7"}) -> 7;
- card_value({_, "8"}) -> 8;
- card_value({_, "9"}) -> 9;
- card_value({_, "10"}) -> 10;
- card_value({_, "J"}) -> 11;
- card_value({_, "Q"}) -> 12;
- card_value({_, "K"}) -> 13;
- card_value({_, "A"}) -> 14;
- card_value({_, "2"}) -> 15;
- card_value({_, "小王"}) -> 16;
- card_value({_, "大王"}) -> 17;
- card_value({any, Value}) -> card_value({"♠", Value}).
-
- %% 检查是否为顺子
- is_straight(Cards) ->
- Values = [card_value(Card) || Card <- Cards],
- SortedValues = lists:sort(Values),
- length(SortedValues) >= 5 andalso
- lists:max(SortedValues) =< 14 andalso % A以下的牌才能组成顺子
- SortedValues =:= lists:seq(hd(SortedValues), lists:last(SortedValues)).
-
- %% 分析其他牌型
- analyze_other_patterns(Cards) ->
- % 实现其他复杂牌型的分析,如飞机、连对等
- % 简单实现,实际应该有更复杂的逻辑
- invalid.
-
- %% 排序牌
- sort_cards(Cards) ->
- lists:sort(fun(A, B) -> card_value(A) =< card_value(B) end, Cards).
|