diff --git a/chapter_1/demo.erl b/chapter_1/demo.erl index 5b703dc..25f92c8 100644 --- a/chapter_1/demo.erl +++ b/chapter_1/demo.erl @@ -1,7 +1,9 @@ -module(demo). -export([double/1, area/1]). -double(Value) -> times(Value, 2). +double(Value) -> + times(Value, 2). + times(X, Y) -> X * Y. area(sharp) -> {sharp, 1}; diff --git a/chapter_12/gensrv.erl b/chapter_12/gensrv.erl index f94d9ae..3f8c92f 100644 --- a/chapter_12/gensrv.erl +++ b/chapter_12/gensrv.erl @@ -1,4 +1,4 @@ --module(sample_gensrv). +-module(gensrv). -export([start/0, stop/0]). -export([init/1, handle_cast/2, handle_call/3, terminate/2]). -export([say_hello/1]). @@ -7,7 +7,7 @@ start() -> Name = "Jack", - gen_server:start({local, ?MODULE}, ?MODULE, Name, []). + gen_server:start({global, {test, ?MODULE}}, ?MODULE, Name, []). init(Name) -> io:format("Init OPT ~p~n", [Name]), diff --git a/chapter_12/usr-1.0/ebin/usr.app b/chapter_12/usr-1.0/ebin/usr.app deleted file mode 100644 index 5fadc61..0000000 --- a/chapter_12/usr-1.0/ebin/usr.app +++ /dev/null @@ -1,9 +0,0 @@ -{application, usr, [ - {description, "Mobile Services Database"}, - {vsn, "1.0"}, - {modules, [usr, usr_db, usr_sup, usr_app]}, - {registered, [usr, usr_sup]}, - {applications, [kernel, stdlib]}, - {env, [{dets_name, "usrDb.db"}]}, - {mod, {usr_app, []}}]}. - diff --git a/chapter_15/tcp_server.erl b/chapter_15/tcp_server.erl new file mode 100644 index 0000000..0a83db1 --- /dev/null +++ b/chapter_15/tcp_server.erl @@ -0,0 +1,16 @@ +-module(tcp_server). +-export([start/0, send/2]). + +-define(log(Message), + fun() -> + io:foramt("<~p> LOGGER: ~p~n", [self(), Message]) + end()). + +start() -> + {ok, ListenSocket} = gen_tcp:listen(5000, [binary, {active, false}]), + wait_connect(ListenSocket, 0). + +wait_connect(ListenSocket, Count) -> + ?log("Begin Wait Connection ..."). + {ok, Socket} = gen_tcp:accept(ListenSocket), + ?log("Receive a TCP request ..."). diff --git a/chapter_15/udp_server.erl b/chapter_15/udp_server.erl new file mode 100644 index 0000000..549731b --- /dev/null +++ b/chapter_15/udp_server.erl @@ -0,0 +1,44 @@ +-module(udp_server). +-export([start_link/0, stop/0]). +-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]). +-export([send/1]). + +-behaviour(gen_server). + +-define(SERVER_PORT, 18000). +-define(CLIENT_PORT, 18001). + +start_link() -> + gen_server:start_link({local, ?MODULE}, ?MODULE, null, []). + +stop() -> + gen_server:cast(?MODULE, stop). + +init(_Params) -> + {ok, Sock} = gen_udp:open(?SERVER_PORT), + io:format("Init Sock ~p~n", [Sock]), + {ok, {server, Sock}}. + +terminate(Reason, {server, Sock}) -> + gen_udp:close(Sock). + +handle_cast(stop, {server, Sock}) -> + {stop, normal, {server, Sock}}. + +handle_info({udp, Client, _Ip, _Port, Msg}, LoopData) -> + io:format("receive udp data ~p from ~p~n", [Msg, Client]), + {noreply, LoopData}; + +handle_info(Msg, LoopData) -> + io:format("receive info ~p~n", [Msg]), + {noreply, LoopData}. + +send(Msg) -> + gen_server:call(?MODULE, {message, Msg}). + +handle_call({message, Msg}, _From, {server, Sock}) -> + {ok, Client} = gen_udp:open(?CLIENT_PORT), + io:format("Sock ~p Client ~p~n", [Sock, Client]), + gen_udp:send(Client, {127,0,0,1}, ?SERVER_PORT, Msg), + gen_udp:close(Client), + {reply, ok, {server, Sock}}. diff --git a/chapter_2/example.erl b/chapter_2/example.erl index f6eceae..58354ff 100644 --- a/chapter_2/example.erl +++ b/chapter_2/example.erl @@ -7,4 +7,3 @@ even(Int) when Int rem 2 == 1 -> false. number(Num) when is_integer(Num) -> interger; number(Num) when is_float(Num) -> float; number(_Other) -> false. - diff --git a/dbg/ping.erl b/dbg/ping.erl new file mode 100644 index 0000000..44ee0d2 --- /dev/null +++ b/dbg/ping.erl @@ -0,0 +1,16 @@ +-module(ping). +-export([start/0, send/1, loop/0]). + +start() -> spawn_link(ping, loop, []). + +send(Pid) -> + Pid ! {self(), ping}, + receive pong -> pong end. + +loop() -> + receive + {Pid, ping} -> + spawn(crash, do_not_exist, []), + Pid ! pong, + loop() + end. diff --git a/gen_fsm/code_lock.erl b/gen_fsm/code_lock.erl new file mode 100644 index 0000000..4b6b3d4 --- /dev/null +++ b/gen_fsm/code_lock.erl @@ -0,0 +1,37 @@ +-module(code_lock). +-behaviour(gen_fsm). + +-export([start_link/1]). +-export([button/1]). +-export([init/1, locked/2, open/2]). + +% client function +% +start_link(Code) -> + gen_fsm:start({local, ?MODULE}, code_lock, Code, []). + +button(Digit) -> + gen_fsm:send_event(?MODULE, {button, Digit}). + +% callback function +% +init(Code) -> + io:format("new code lock ~p ~n", [Code]), + {ok, locked, {[], Code}}. + +locked({button, Digit}, {SoFar, Code}) -> + case [Digit|SoFar] of + Code -> + % do_unlock(), + io:format("do unlock"), + {next_state, open, {[], Code}, 3000}; + Incomplete when length(Incomplete) + {next_state, locked, {Incomplete, Code}}; + _Wrong -> + {next_state, locked, {[], Code}} + end. + +open(timeout, State) -> + io:format("do lock"), + % do_lock(), + {next_state, locked, State}. diff --git a/gen_fsm/door.erl b/gen_fsm/door.erl new file mode 100644 index 0000000..d1c629c --- /dev/null +++ b/gen_fsm/door.erl @@ -0,0 +1,24 @@ +-module(door). +-export([start/1, init/1]). + +start(Codes) -> + spawn(fun() -> door:init(Codes) end). + +init(Codes) -> + init_lock(Codes), + loop(). + +init_lock([]) -> + ok; + +init_lock([Code|Codes]) -> + Res = code_lock:start_link(Code), + io:format("Result is ~p~n", [Res]), + init_lock(Codes). + +loop() -> + receive + ok -> + {ok}, + loop() + end. diff --git a/openpoker-server/README b/openpoker-server/README index aa6cee7..7e6d694 100644 --- a/openpoker-server/README +++ b/openpoker-server/README @@ -2,6 +2,45 @@ OpenPoker is released under a dual GPL/commercial license. Please see doc/install.txt for installation instructions and visit http://groups.google.com/group/openpoker if you have questions. +src/betting 赌注状态机(cardgame) +src/bits +src/blinds 盲注状态机(cardgame) +src/bot 机器人 +src/cardgame 纸牌游戏状态机宿主(gen_fsm) +src/common.hrl 公共Header定义(header) +src/counter 累加器(lib) +src/db 数据库相关(gen_server) +src/deal_cards 发牌状态机(cardgame) +src/deck 扑克牌(gen_server) +src/delayed_start 延迟游戏启动状态机(cardgame) +src/fixed_limit +src/game +src/gateway +src/hand 手牌(gen_server) +src/id +src/ircdb 聊天室 +src/ircdb.hrl 聊天室定义 +src/lang 语言文字定义(lib) +src/lang.hrl +src/login 登陆(lib) +src/monitor +src/multibot +src/observer +src/player 玩家(gen_server) +src/pot +src/proto 协议(lib) +src/proto.hrl 协议定义(header) +src/schema 数据库结构(lib) +src/schema.hrl 结构定义(header) +src/server 游戏服务器(gen_server) +src/showdown 游戏结束状态机(cardgame) +src/tcp_server 网络通信服务器(gen_server) +src/test +src/test +src/texas 德州扑克 +src/util +src/visitor 访问者(gen_server) + More information can also be found at http://wagerlabs.com. Thanks, Joel Reymont diff --git a/openpoker-server/src/betting.erl b/openpoker-server/src/betting.erl index 31b4227..64d843c 100644 --- a/openpoker-server/src/betting.erl +++ b/openpoker-server/src/betting.erl @@ -26,7 +26,7 @@ -export([init/1, terminate/3]). -export([handle_event/3, handle_info/3, - handle_sync_event/4, code_change/4]). + handle_sync_event/4, code_change/4]). -export([betting/2]). @@ -36,261 +36,261 @@ -include("proto.hrl"). -record(data, { - game, - context, - have_blinds, - max_raises, - stage, - expected, % {Player, Min, Max} - call, - raise_count, - timer - }). + game, + context, + have_blinds, + max_raises, + stage, + expected, % {Player, Min, Max} + call, + raise_count, + timer + }). init([Game, MaxRaises, Stage]) -> - init([Game, MaxRaises, Stage, false]); + init([Game, MaxRaises, Stage, false]); init([Game, MaxRaises, Stage, HaveBlinds]) -> - Data = #data { - game = Game, - have_blinds = HaveBlinds, - max_raises = MaxRaises, - stage = Stage - }, - {ok, betting, Data}. + Data = #data { + game = Game, + have_blinds = HaveBlinds, + max_raises = MaxRaises, + stage = Stage + }, + {ok, betting, Data}. stop(Ref) -> - cardgame:send_all_state_event(Ref, stop). + cardgame:send_all_state_event(Ref, stop). betting({'START', Context}, Data) -> - Game = Data#data.game, - %% assume that we are given a record - Button = element(2, Context), - Call = element(3, Context), - %%io:format("betting/start: call = ~.2. f~n", [Call * 1.0]), - Active = gen_server:call(Game, {'SEATS', Button, ?PS_PLAY}), - PlayerCount = length(Active), - if - PlayerCount < 2 -> - {stop, {normal, Context}, Data}; - true -> - _Total = gen_server:call(Game, 'POT TOTAL'), - gen_server:cast(Game, {'BROADCAST', - {?PP_GAME_STAGE, Data#data.stage}}), - if - Data#data.have_blinds -> - %% start with the player after the big blind - BB = element(6, Context), - Temp = gen_server:call(Game, {'SEATS', BB, ?PS_PLAY}), - Player = hd(Temp); - true -> - %% start with the first player after the button - Player = hd(Active) - end, - Data1 = Data#data { - context = Context, - call = Call, - raise_count = 0 - }, - Data2 = ask_for_bet(Data1, Player), - {next_state, betting, Data2} - end; + Game = Data#data.game, + %% assume that we are given a record + Button = element(2, Context), + Call = element(3, Context), + %%io:format("betting/start: call = ~.2. f~n", [Call * 1.0]), + Active = gen_server:call(Game, {'SEATS', Button, ?PS_PLAY}), + PlayerCount = length(Active), + if + PlayerCount < 2 -> + {stop, {normal, Context}, Data}; + true -> + _Total = gen_server:call(Game, 'POT TOTAL'), + gen_server:cast(Game, {'BROADCAST', + {?PP_GAME_STAGE, Data#data.stage}}), + if + Data#data.have_blinds -> + %% start with the player after the big blind + BB = element(6, Context), + Temp = gen_server:call(Game, {'SEATS', BB, ?PS_PLAY}), + Player = hd(Temp); + true -> + %% start with the first player after the button + Player = hd(Active) + end, + Data1 = Data#data { + context = Context, + call = Call, + raise_count = 0 + }, + Data2 = ask_for_bet(Data1, Player), + {next_state, betting, Data2} + end; betting({?PP_CALL, Player, Amount}, Data) -> - Game = Data#data.game, - {Expected, Call, _Min, _Max} = Data#data.expected, - if - Expected /= Player -> - {next_state, betting, Data}; - true -> - %% it's us - cancel_timer(Data), - InPlay = gen_server:call(Player, 'INPLAY'), - if - Amount > InPlay -> - betting({?PP_FOLD, Player}, Data); - Amount > Call -> - betting({?PP_FOLD, Player}, Data); - Amount == InPlay -> - %% all-in - gen_server:cast(Game, {'ADD BET', Player, Amount}), - next_turn(Data, Player); - true -> - %% proper bet - gen_server:cast(Game, {'SET STATE', Player, ?PS_BET}), - gen_server:cast(Game, {'ADD BET', Player, Amount}), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CALL, - Player, Call}}), - next_turn(Data, Player) - end - end; + Game = Data#data.game, + {Expected, Call, _Min, _Max} = Data#data.expected, + if + Expected /= Player -> + {next_state, betting, Data}; + true -> + %% it's us + cancel_timer(Data), + InPlay = gen_server:call(Player, 'INPLAY'), + if + Amount > InPlay -> + betting({?PP_FOLD, Player}, Data); + Amount > Call -> + betting({?PP_FOLD, Player}, Data); + Amount == InPlay -> + %% all-in + gen_server:cast(Game, {'ADD BET', Player, Amount}), + next_turn(Data, Player); + true -> + %% proper bet + gen_server:cast(Game, {'SET STATE', Player, ?PS_BET}), + gen_server:cast(Game, {'ADD BET', Player, Amount}), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CALL, + Player, Call}}), + next_turn(Data, Player) + end + end; betting({?PP_RAISE, Player, Amount}, Data) -> - Game = Data#data.game, - RaiseCount = Data#data.raise_count, - {Expected, Call, Min, Max} = Data#data.expected, - if - Expected /= Player -> - {next_state, betting, Data}; - true -> - %% it's us - cancel_timer(Data), - InPlay = gen_server:call(Player, 'INPLAY'), - if - (Amount > InPlay) or - (Amount > Max) or - (Max == 0) or % should have sent CALL - ((Amount < Min) and ((Amount + Call) /= InPlay)) -> - betting({?PP_FOLD, Player}, Data); - true -> - %% proper raise - RaiseCount1 = if - Call /= 0 -> - RaiseCount + 1; - true -> - RaiseCount - end, - gen_server:cast(Game, {'ADD BET', Player, Amount + Call}), - gen_server:cast(Game, {'RESET STATE', ?PS_BET, ?PS_PLAY}), - if - Amount + Call == InPlay -> - ok; - true -> - gen_server:cast(Game, - {'SET STATE', Player, ?PS_BET}) - end, - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_RAISE, - Player, Amount}}), - Data1 = Data#data { - call = Data#data.call + Amount, - raise_count = RaiseCount1 - }, - next_turn(Data1, Player) - end - end; + Game = Data#data.game, + RaiseCount = Data#data.raise_count, + {Expected, Call, Min, Max} = Data#data.expected, + if + Expected /= Player -> + {next_state, betting, Data}; + true -> + %% it's us + cancel_timer(Data), + InPlay = gen_server:call(Player, 'INPLAY'), + if + (Amount > InPlay) or + (Amount > Max) or + (Max == 0) or % should have sent CALL + ((Amount < Min) and ((Amount + Call) /= InPlay)) -> + betting({?PP_FOLD, Player}, Data); + true -> + %% proper raise + RaiseCount1 = if + Call /= 0 -> + RaiseCount + 1; + true -> + RaiseCount + end, + gen_server:cast(Game, {'ADD BET', Player, Amount + Call}), + gen_server:cast(Game, {'RESET STATE', ?PS_BET, ?PS_PLAY}), + if + Amount + Call == InPlay -> + ok; + true -> + gen_server:cast(Game, + {'SET STATE', Player, ?PS_BET}) + end, + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_RAISE, + Player, Amount}}), + Data1 = Data#data { + call = Data#data.call + Amount, + raise_count = RaiseCount1 + }, + next_turn(Data1, Player) + end + end; betting({?PP_FOLD, Player}, Data) -> - {Expected, _Call, _Min, _Max} = Data#data.expected, - if - Expected /= Player -> - {next_state, betting, Data}; - true -> - cancel_timer(Data), - gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_FOLD}), - gen_server:cast(Data#data.game, {'BROADCAST', - {?PP_PLAYER_STATE, - Player, - ?PS_FOLD}}), - next_turn(Data, Player) - end; + {Expected, _Call, _Min, _Max} = Data#data.expected, + if + Expected /= Player -> + {next_state, betting, Data}; + true -> + cancel_timer(Data), + gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_FOLD}), + gen_server:cast(Data#data.game, {'BROADCAST', + {?PP_PLAYER_STATE, + Player, + ?PS_FOLD}}), + next_turn(Data, Player) + end; betting({timeout, _Timer, Player}, Data) -> - cancel_timer(Data), - Game = Data#data.game, - GID = gen_server:call(Game, 'ID'), - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - error_logger:warning_report([{message, "Player timeout!"}, - {module, ?MODULE}, - {player, Player}, - {game, GID}, - {seat, Seat}]), - %% - %%io:format("~w timed out, folding~n", [Player]), - betting({?PP_FOLD, Player}, Data); + cancel_timer(Data), + Game = Data#data.game, + GID = gen_server:call(Game, 'ID'), + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + error_logger:warning_report([{message, "Player timeout!"}, + {module, ?MODULE}, + {player, Player}, + {game, GID}, + {seat, Seat}]), + %% + %%io:format("~w timed out, folding~n", [Player]), + betting({?PP_FOLD, Player}, Data); betting(Event, Data) -> - handle_event(Event, betting, Data). + handle_event(Event, betting, Data). handle_event(stop, _State, Data) -> - {stop, normal, Data}; + {stop, normal, Data}; handle_event(Event, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {message, Event}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}]), - {next_state, State, Data}. - + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {message, Event}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}]), + {next_state, State, Data}. + handle_sync_event(Event, From, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {message, Event}, - {from, From}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}]), - {next_state, State, Data}. - + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {message, Event}, + {from, From}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}]), + {next_state, State, Data}. + handle_info(Info, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {message, Info}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}]), - {next_state, State, Data}. + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {message, Info}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}]), + {next_state, State, Data}. terminate(_Reason, _State, _Data) -> - ok. + ok. code_change(_OldVsn, State, Data, _Extra) -> - {ok, State, Data}. + {ok, State, Data}. %% %% Utility %% next_turn(Data, Player) -> - Game = Data#data.game, - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - Active = gen_server:call(Game, {'SEATS', Seat, ?PS_PLAY}), - Standing = gen_server:call(Game, {'SEATS', Seat, ?PS_STANDING}), - ActiveCount = length(Active), - StandingCount = length(Standing), - if - StandingCount < 2 -> - %% last man standing wins - {stop, {endgame, Data#data.context}, Data}; - ActiveCount == 0 -> - %% we are done with this stage - gen_server:cast(Game, {'RESET STATE', ?PS_BET, ?PS_PLAY}), - Ctx = setelement(3, Data#data.context, 0), % call = 0 - gen_server:cast(Game, 'NEW STAGE'), - {stop, {normal, Ctx}, Data}; - true -> - %% next player - Data1 = ask_for_bet(Data, hd(Active)), - {next_state, betting, Data1} - end. + Game = Data#data.game, + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + Active = gen_server:call(Game, {'SEATS', Seat, ?PS_PLAY}), + Standing = gen_server:call(Game, {'SEATS', Seat, ?PS_STANDING}), + ActiveCount = length(Active), + StandingCount = length(Standing), + if + StandingCount < 2 -> + %% last man standing wins + {stop, {endgame, Data#data.context}, Data}; + ActiveCount == 0 -> + %% we are done with this stage + gen_server:cast(Game, {'RESET STATE', ?PS_BET, ?PS_PLAY}), + Ctx = setelement(3, Data#data.context, 0), % call = 0 + gen_server:cast(Game, 'NEW STAGE'), + {stop, {normal, Ctx}, Data}; + true -> + %% next player + Data1 = ask_for_bet(Data, hd(Active)), + {next_state, betting, Data1} + end. ask_for_bet(Data, Seat) -> - Game = Data#data.game, - Stage = Data#data.stage, - Player = gen_server:call(Game, {'PLAYER AT', Seat}), - Bet = gen_server:call(Game, {'BET TOTAL', Player}), - Call = Data#data.call - Bet, - {Min, Max} = gen_server:call(Game, {'RAISE SIZE', Player, Stage}), - Parent = gen_server:call(Data#data.game, 'FSM'), - gen_server:cast(Player, {?PP_BET_REQ, Parent, Call, Min, Max}), - Data1 = restart_timer(Data, Player), - Data1#data { - expected = {Player, Call, Min, Max} - }. + Game = Data#data.game, + Stage = Data#data.stage, + Player = gen_server:call(Game, {'PLAYER AT', Seat}), + Bet = gen_server:call(Game, {'BET TOTAL', Player}), + Call = Data#data.call - Bet, + {Min, Max} = gen_server:call(Game, {'RAISE SIZE', Player, Stage}), + Parent = gen_server:call(Data#data.game, 'FSM'), + gen_server:cast(Player, {?PP_BET_REQ, Parent, Call, Min, Max}), + Data1 = restart_timer(Data, Player), + Data1#data { + expected = {Player, Call, Min, Max} + }. cancel_timer(Data) -> - catch cardgame:cancel_timer(Data#data.timer). + catch cardgame:cancel_timer(Data#data.timer). restart_timer(Data, Msg) -> - Timeout = gen_server:call(Data#data.game, 'TIMEOUT'), - Data#data { - timer = cardgame:start_timer(Timeout, Msg) - }. - + Timeout = gen_server:call(Data#data.game, 'TIMEOUT'), + Data#data { + timer = cardgame:start_timer(Timeout, Msg) + }. + %% %% Test suite %% test() -> - ok. + ok. diff --git a/openpoker-server/src/bits.erl b/openpoker-server/src/bits.erl index 1a45c10..5cfdd04 100644 --- a/openpoker-server/src/bits.erl +++ b/openpoker-server/src/bits.erl @@ -30,67 +30,67 @@ bits0(N) when N >= 0-> bits0(N, 0). bits0(0, C) -> C; bits0(N, C) -> - bits0((N band (N-1)), C+1). + bits0((N band (N-1)), C+1). clear_extra_bits(N, _) when N =:= 0 -> - N; + N; clear_extra_bits(N, X) -> - C = bits0(N), - if - X >= C -> - N; - true -> - clear_extra_bits(N, X, C) - end. + C = bits0(N), + if + X >= C -> + N; + true -> + clear_extra_bits(N, X, C) + end. clear_extra_bits(N, X, C) when N =:= 0; C =:= 0; X =:= C -> - N; +N; clear_extra_bits(N, X, C) -> - clear_extra_bits(N band (N - 1), X, C - 1). + clear_extra_bits(N band (N - 1), X, C - 1). bits1(0) -> 0; bits1(N) when N > 0, N < 16#100000000 -> - bits1(N, [1, 16#55555555, - 2, 16#33333333, - 4, 16#0F0F0F0F, - 8, 16#00FF00FF, - 16, 16#0000FFFF]). - -bits1(N, []) -> N; -bits1(N, [S, B|Magic]) -> - bits1(((N bsr S) band B) + (N band B), Magic). - - -%% log2, aka, position of the high bit - -log2(N) when N > 0, N < 16#100000000 -> - log2(N, 0, [16, 16#FFFF0000, 8, 16#FF00, 4, 16#F0, 2, 16#C, 1, 16#2]). - -log2(_, C, []) -> C; -log2(N, C, [S,B|Magic]) -> - if (N band B) == 0 -> log2(N, C, Magic); - true -> log2((N bsr S), (C bor S), Magic) - end. - -%% trailing zero bits, aka position of the lowest set bit. - -tzb0(N) when N > 0, N < 16#100000000 -> - tzb0(N, 32, [16, 16#0000FFFF, - 8, 16#00FF00FF, - 4, 16#0F0F0F0F, - 2, 16#33333333, - 1, 16#55555555]). - -tzb0(_, Z, []) -> Z-1; -tzb0(N, Z, [S, B|Magic]) -> - if (N band B) == 0 -> tzb0(N, Z, Magic); - true -> tzb0((N bsl S), (Z - S), Magic) - end. - -tzb1(N) when N > 0, N < 16#100000000 -> - Mod = {32,0,1,26,2,23,27,0,3,16,24,30, - 28,11,0,13,4,7,17,0,25,22,31,15, - 29,10,12,6,0,21,14,9,5,20,8,19,18}, - P = (-N band N) rem 37, - element(P+1, Mod). + bits1(N, [1, 16#55555555, + 2, 16#33333333, + 4, 16#0F0F0F0F, + 8, 16#00FF00FF, + 16, 16#0000FFFF]). + + bits1(N, []) -> N; + bits1(N, [S, B|Magic]) -> + bits1(((N bsr S) band B) + (N band B), Magic). + + + %% log2, aka, position of the high bit + + log2(N) when N > 0, N < 16#100000000 -> + log2(N, 0, [16, 16#FFFF0000, 8, 16#FF00, 4, 16#F0, 2, 16#C, 1, 16#2]). + + log2(_, C, []) -> C; + log2(N, C, [S,B|Magic]) -> + if (N band B) == 0 -> log2(N, C, Magic); + true -> log2((N bsr S), (C bor S), Magic) + end. + + %% trailing zero bits, aka position of the lowest set bit. + + tzb0(N) when N > 0, N < 16#100000000 -> + tzb0(N, 32, [16, 16#0000FFFF, + 8, 16#00FF00FF, + 4, 16#0F0F0F0F, + 2, 16#33333333, + 1, 16#55555555]). + + tzb0(_, Z, []) -> Z-1; + tzb0(N, Z, [S, B|Magic]) -> + if (N band B) == 0 -> tzb0(N, Z, Magic); + true -> tzb0((N bsl S), (Z - S), Magic) + end. + + tzb1(N) when N > 0, N < 16#100000000 -> + Mod = {32,0,1,26,2,23,27,0,3,16,24,30, + 28,11,0,13,4,7,17,0,25,22,31,15, + 29,10,12,6,0,21,14,9,5,20,8,19,18}, + P = (-N band N) rem 37, + element(P+1, Mod). diff --git a/openpoker-server/src/blinds.erl b/openpoker-server/src/blinds.erl index 67fad5c..ceabf55 100644 --- a/openpoker-server/src/blinds.erl +++ b/openpoker-server/src/blinds.erl @@ -26,7 +26,7 @@ -export([init/1, terminate/3]). -export([handle_event/3, handle_info/3, - handle_sync_event/4, code_change/4]). + handle_sync_event/4, code_change/4]). -export([small_blind/2, big_blind/2]). @@ -36,39 +36,39 @@ -include("proto.hrl"). -record(data, { - game, - context, - small_blind_seat, - big_blind_seat, - button_seat, - no_small_blind, - small_blind_amount, - small_blind_bet, - big_blind_amount, - timer, - expected, % {Player, Seat, Amount} - type - }). + game, + context, + small_blind_seat, + big_blind_seat, + button_seat, + no_small_blind, + small_blind_amount, + small_blind_bet, + big_blind_amount, + timer, + expected, % {Player, Seat, Amount} + type + }). init([Game]) -> - init([Game, normal]); + init([Game, normal]); init([Game, Type]) -> - {Small, Big} = gen_server:call(Game, 'BLINDS'), - Data = #data { - game = Game, - small_blind_amount = Small, - big_blind_amount = Big, - small_blind_bet = 0, - no_small_blind = false, - timer = none, - expected = {none, 0}, - type = Type - }, - {ok, small_blind, Data}. + {Small, Big} = gen_server:call(Game, 'BLINDS'), + Data = #data { + game = Game, + small_blind_amount = Small, + big_blind_amount = Big, + small_blind_bet = 0, + no_small_blind = false, + timer = none, + expected = {none, 0}, + type = Type + }, + {ok, small_blind, Data}. stop(Ref) -> - cardgame:send_all_state_event(Ref, stop). + cardgame:send_all_state_event(Ref, stop). %% Theory @@ -93,623 +93,623 @@ stop(Ref) -> %% are posted normally. small_blind({'START', Context}, Data) -> - if - Data#data.type /= irc -> - Data1 = Data#data { - context = Context, - small_blind_seat = Context#texas.small_blind_seat, - big_blind_seat = Context#texas.big_blind_seat, - button_seat = Context#texas.button_seat - }; - true -> - Data1 = Data#data { - context = Context, - small_blind_seat = none, - big_blind_seat = none, - button_seat = none - } - end, - Game = Data1#data.game, - %% advance button and broadcast position - {Button1, Bust} = advance_button(Data1), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_BUTTON, Button1}}), - %% collect blinds - SBPlayers = gen_server:call(Game, {'SEATS', Button1, ?PS_ACTIVE}), - BBPlayers = gen_server:call(Game, {'SEATS', Button1, ?PS_BB_ACTIVE}), - L1 = length(SBPlayers), - L2 = length(BBPlayers), - HeadsUp = ((L1 == 2) and (L2 == 2)) % two active, 0 waiting for bb - or ((L1 == 1) and (L2 == 2)), % one active, one waiting for bb - BB_N = length(BBPlayers), - if - BB_N < 2 -> - {stop, {normal, restart}, Data1}; - Bust and not HeadsUp -> - %% there's no small blind so the first player - %% after the button is the big blind - Data2 = Data1#data { - button_seat = Button1, - no_small_blind = true, - small_blind_seat = Data1#data.big_blind_seat - }, - Amount = Data2#data.big_blind_amount, - %% ask for big blind - Data3 = ask_for_blind(Data2, hd(BBPlayers), Amount), - {next_state, big_blind, Data3}; - Bust and HeadsUp -> - %% the first player after the button - %% is the big blind and the other player - %% is the small blind and button - Data2 = Data1#data { - button_seat = Button1 - }, - Amount = Data2#data.small_blind_amount, - Data3 = ask_for_blind(Data2, lists:last(SBPlayers), Amount), - {next_state, small_blind, Data3}; - true -> - Data2 = Data1#data { - button_seat = Button1 - }, - Amount = Data2#data.small_blind_amount, - Data3 = ask_for_blind(Data2, hd(SBPlayers), Amount), - {next_state, small_blind, Data3} - end; - + if + Data#data.type /= irc -> + Data1 = Data#data { + context = Context, + small_blind_seat = Context#texas.small_blind_seat, + big_blind_seat = Context#texas.big_blind_seat, + button_seat = Context#texas.button_seat + }; + true -> + Data1 = Data#data { + context = Context, + small_blind_seat = none, + big_blind_seat = none, + button_seat = none + } + end, + Game = Data1#data.game, + %% advance button and broadcast position + {Button1, Bust} = advance_button(Data1), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_BUTTON, Button1}}), + %% collect blinds + SBPlayers = gen_server:call(Game, {'SEATS', Button1, ?PS_ACTIVE}), + BBPlayers = gen_server:call(Game, {'SEATS', Button1, ?PS_BB_ACTIVE}), + L1 = length(SBPlayers), + L2 = length(BBPlayers), + HeadsUp = ((L1 == 2) and (L2 == 2)) % two active, 0 waiting for bb + or ((L1 == 1) and (L2 == 2)), % one active, one waiting for bb + BB_N = length(BBPlayers), + if + BB_N < 2 -> + {stop, {normal, restart}, Data1}; + Bust and not HeadsUp -> + %% there's no small blind so the first player + %% after the button is the big blind + Data2 = Data1#data { + button_seat = Button1, + no_small_blind = true, + small_blind_seat = Data1#data.big_blind_seat + }, + Amount = Data2#data.big_blind_amount, + %% ask for big blind + Data3 = ask_for_blind(Data2, hd(BBPlayers), Amount), + {next_state, big_blind, Data3}; + Bust and HeadsUp -> + %% the first player after the button + %% is the big blind and the other player + %% is the small blind and button + Data2 = Data1#data { + button_seat = Button1 + }, + Amount = Data2#data.small_blind_amount, + Data3 = ask_for_blind(Data2, lists:last(SBPlayers), Amount), + {next_state, small_blind, Data3}; + true -> + Data2 = Data1#data { + button_seat = Button1 + }, + Amount = Data2#data.small_blind_amount, + Data3 = ask_for_blind(Data2, hd(SBPlayers), Amount), + {next_state, small_blind, Data3} + end; + small_blind({?PP_CALL, Player, Amount}, Data) -> - Game = Data#data.game, - {ExpPlayer, Seat, ExpAmount} = Data#data.expected, - if - ExpPlayer /= Player -> - {next_state, small_blind, Data}; - true -> - %% it's us - cancel_timer(Data), - InPlay = gen_server:call(Player, 'INPLAY'), - if - (ExpAmount /= Amount) and - (InPlay /= Amount) -> - timeout(Data, Player, small_blind); - true -> - %% small blind posted - Data1 = Data#data { - small_blind_seat = Seat, - small_blind_bet = Amount - }, - BBPlayers = gen_server:call(Game, - {'SEATS', Seat, ?PS_BB_ACTIVE}), - Data2 = ask_for_blind(Data1, - hd(BBPlayers), - Data1#data.big_blind_amount), - {next_state, big_blind, Data2} - end - end; + Game = Data#data.game, + {ExpPlayer, Seat, ExpAmount} = Data#data.expected, + if + ExpPlayer /= Player -> + {next_state, small_blind, Data}; + true -> + %% it's us + cancel_timer(Data), + InPlay = gen_server:call(Player, 'INPLAY'), + if + (ExpAmount /= Amount) and + (InPlay /= Amount) -> + timeout(Data, Player, small_blind); + true -> + %% small blind posted + Data1 = Data#data { + small_blind_seat = Seat, + small_blind_bet = Amount + }, + BBPlayers = gen_server:call(Game, + {'SEATS', Seat, ?PS_BB_ACTIVE}), + Data2 = ask_for_blind(Data1, + hd(BBPlayers), + Data1#data.big_blind_amount), + {next_state, big_blind, Data2} + end + end; small_blind({?PP_FOLD, Player}, Data) -> - {ExpPlayer, _Seat, _ExpAmount} = Data#data.expected, - if - ExpPlayer /= Player -> - {next_state, small_blind, Data}; - true -> - timeout(Data, Player, small_blind) - end; + {ExpPlayer, _Seat, _ExpAmount} = Data#data.expected, + if + ExpPlayer /= Player -> + {next_state, small_blind, Data}; + true -> + timeout(Data, Player, small_blind) + end; small_blind({timeout, _Timer, Player}, Data) -> - cancel_timer(Data), - Game = Data#data.game, - GID = gen_server:call(Game, 'ID'), - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - error_logger:warning_report( - [{message, "Player timeout!"}, - {module, ?MODULE}, - {state, small_blind}, - {player, Player}, - {game, GID}, - {seat, Seat}, - {now, now()}]), - timeout(Data, Player, small_blind); + cancel_timer(Data), + Game = Data#data.game, + GID = gen_server:call(Game, 'ID'), + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + error_logger:warning_report( + [{message, "Player timeout!"}, + {module, ?MODULE}, + {state, small_blind}, + {player, Player}, + {game, GID}, + {seat, Seat}, + {now, now()}]), + timeout(Data, Player, small_blind); small_blind({?PP_JOIN, Player, SeatNum, BuyIn}, Data) -> - join(Data, Player, SeatNum, BuyIn, small_blind); + join(Data, Player, SeatNum, BuyIn, small_blind); small_blind({?PP_LEAVE, Player}, Data) -> - leave(Data, Player, small_blind); + leave(Data, Player, small_blind); small_blind({?PP_SIT_OUT, Player}, Data) -> - sit_out(Data, Player, small_blind); + sit_out(Data, Player, small_blind); small_blind({?PP_COME_BACK, Player}, Data) -> - come_back(Data, Player, small_blind); + come_back(Data, Player, small_blind); small_blind(Event, Data) -> - handle_event(Event, small_blind, Data). + handle_event(Event, small_blind, Data). big_blind({?PP_CALL, Player, Amount}, Data) -> - Game = Data#data.game, - {ExpPlayer, Seat, ExpAmount} = Data#data.expected, - if - ExpPlayer /= Player -> - {next_state, big_blind, Data}; - true -> - %% it's us - cancel_timer(Data), - InPlay = gen_server:call(Player, 'INPLAY'), - if - (ExpAmount /= Amount) and - (InPlay /= Amount) -> - timeout(Data, Player, big_blind); - true -> - %% big blind posted - SB = Data#data.small_blind_seat, - BB = Seat, - SBPlayer = gen_server:call(Game, {'PLAYER AT', SB}), - BBPlayer = Player, - gen_server:cast(Game, {'SET STATE', SBPlayer, ?PS_PLAY}), - gen_server:cast(Game, {'SET STATE', BBPlayer, ?PS_PLAY}), - %% record blind bets - Small = Data#data.small_blind_bet, - Big = Amount, - if - Data#data.no_small_blind -> - ok; - true -> - gen_server:cast(Game, {'ADD BET', SBPlayer, Small}) - end, - gen_server:cast(Game, {'ADD BET', BBPlayer, Big}), - %% adjust button if a heads-up game - Seats = gen_server:call(Game, {'SEATS', ?PS_ACTIVE}), - if - (length(Seats) == 2) and (Data#data.type /= irc) -> - Button = SB; - true -> - Button = Data#data.button_seat - end, - Data1 = Data#data { - big_blind_seat = BB, - button_seat = Button, - expected = {none, none, 0} - }, - %% notify players - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_SB, SB}}), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_BB, BB}}), - gen_server:cast(Game, {'BROADCAST', - {?PP_NOTIFY_BET, SBPlayer, Small}}), - gen_server:cast(Game, {'BROADCAST', - {?PP_NOTIFY_BET, BBPlayer, Big}}), - Ctx = Data#data.context, - Ctx1 = Ctx#texas { - call = Amount, - small_blind_seat = SB, - big_blind_seat = BB, - button_seat = Button - }, - {stop, {normal, Ctx1}, Data1} - end - end; + Game = Data#data.game, + {ExpPlayer, Seat, ExpAmount} = Data#data.expected, + if + ExpPlayer /= Player -> + {next_state, big_blind, Data}; + true -> + %% it's us + cancel_timer(Data), + InPlay = gen_server:call(Player, 'INPLAY'), + if + (ExpAmount /= Amount) and + (InPlay /= Amount) -> + timeout(Data, Player, big_blind); + true -> + %% big blind posted + SB = Data#data.small_blind_seat, + BB = Seat, + SBPlayer = gen_server:call(Game, {'PLAYER AT', SB}), + BBPlayer = Player, + gen_server:cast(Game, {'SET STATE', SBPlayer, ?PS_PLAY}), + gen_server:cast(Game, {'SET STATE', BBPlayer, ?PS_PLAY}), + %% record blind bets + Small = Data#data.small_blind_bet, + Big = Amount, + if + Data#data.no_small_blind -> + ok; + true -> + gen_server:cast(Game, {'ADD BET', SBPlayer, Small}) + end, + gen_server:cast(Game, {'ADD BET', BBPlayer, Big}), + %% adjust button if a heads-up game + Seats = gen_server:call(Game, {'SEATS', ?PS_ACTIVE}), + if + (length(Seats) == 2) and (Data#data.type /= irc) -> + Button = SB; + true -> + Button = Data#data.button_seat + end, + Data1 = Data#data { + big_blind_seat = BB, + button_seat = Button, + expected = {none, none, 0} + }, + %% notify players + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_SB, SB}}), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_BB, BB}}), + gen_server:cast(Game, {'BROADCAST', + {?PP_NOTIFY_BET, SBPlayer, Small}}), + gen_server:cast(Game, {'BROADCAST', + {?PP_NOTIFY_BET, BBPlayer, Big}}), + Ctx = Data#data.context, + Ctx1 = Ctx#texas { + call = Amount, + small_blind_seat = SB, + big_blind_seat = BB, + button_seat = Button + }, + {stop, {normal, Ctx1}, Data1} + end + end; big_blind({?PP_FOLD, Player}, Data) -> - {ExpPlayer, _Seat, _ExpAmount} = Data#data.expected, - if - ExpPlayer /= Player -> - {next_state, big_blind, Data}; - true -> - timeout(Data, Player, big_blind) - end; + {ExpPlayer, _Seat, _ExpAmount} = Data#data.expected, + if + ExpPlayer /= Player -> + {next_state, big_blind, Data}; + true -> + timeout(Data, Player, big_blind) + end; big_blind({timeout, _Timer, Player}, Data) -> - cancel_timer(Data), - Game = Data#data.game, - GID = gen_server:call(Game, 'ID'), - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - error_logger:warning_report( - [{message, "Player timeout!"}, - {module, ?MODULE}, - {state, big_blind}, - {player, Player}, - {game, GID}, - {seat, Seat}, - {now, now()}]), - timeout(Data, Player, big_blind); + cancel_timer(Data), + Game = Data#data.game, + GID = gen_server:call(Game, 'ID'), + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + error_logger:warning_report( + [{message, "Player timeout!"}, + {module, ?MODULE}, + {state, big_blind}, + {player, Player}, + {game, GID}, + {seat, Seat}, + {now, now()}]), + timeout(Data, Player, big_blind); big_blind({?PP_JOIN, Player, SeatNum, BuyIn}, Data) -> - join(Data, Player, SeatNum, BuyIn, big_blind); + join(Data, Player, SeatNum, BuyIn, big_blind); big_blind({?PP_LEAVE, Player}, Data) -> - leave(Data, Player, big_blind); + leave(Data, Player, big_blind); big_blind({?PP_SIT_OUT, Player}, Data) -> - sit_out(Data, Player, big_blind); + sit_out(Data, Player, big_blind); big_blind({?PP_COME_BACK, Player}, Data) -> - come_back(Data, Player, big_blind); + come_back(Data, Player, big_blind); big_blind(Event, Data) -> - handle_event(Event, big_blind, Data). + handle_event(Event, big_blind, Data). handle_event(stop, _State, Data) -> - {stop, normal, Data}; + {stop, normal, Data}; handle_event(Event, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {where, handle_event}, - {message, Event}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}, - {sb, Data#data.small_blind_seat}, - {bb, Data#data.big_blind_seat}, - {b, Data#data.button_seat}]), - {next_state, State, Data}. - + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {where, handle_event}, + {message, Event}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}, + {sb, Data#data.small_blind_seat}, + {bb, Data#data.big_blind_seat}, + {b, Data#data.button_seat}]), + {next_state, State, Data}. + handle_sync_event(Event, From, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {where, handle_sync_event}, - {message, Event}, - {from, From}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}, - {sb, Data#data.small_blind_seat}, - {bb, Data#data.big_blind_seat}, - {b, Data#data.button_seat}]), - {next_state, State, Data}. - + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {where, handle_sync_event}, + {message, Event}, + {from, From}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}, + {sb, Data#data.small_blind_seat}, + {bb, Data#data.big_blind_seat}, + {b, Data#data.button_seat}]), + {next_state, State, Data}. + handle_info(Info, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {where, handle_info}, - {message, Info}, - {self, self()}, - {game, Data#data.game}, - {expected, Data#data.expected}, - {sb, Data#data.small_blind_seat}, - {bb, Data#data.big_blind_seat}, - {b, Data#data.button_seat}]), - {next_state, State, Data}. + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {where, handle_info}, + {message, Info}, + {self, self()}, + {game, Data#data.game}, + {expected, Data#data.expected}, + {sb, Data#data.small_blind_seat}, + {bb, Data#data.big_blind_seat}, + {b, Data#data.button_seat}]), + {next_state, State, Data}. terminate(_Reason, _State, _Data) -> - ok. + ok. code_change(_OldVsn, State, Data, _Extra) -> - {ok, State, Data}. + {ok, State, Data}. %% %% Utility %% timeout(Data, Player, State) -> - cancel_timer(Data), - Game = Data#data.game, - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - case State of - small_blind -> - Players = gen_server:call(Game, {'SEATS', Seat, ?PS_ACTIVE}), - Amount = Data#data.small_blind_amount, - Expected = 2; - _ -> - Temp = gen_server:call(Game, {'SEATS', Seat, ?PS_BB_ACTIVE}), - %% remove small blind - Players = lists:delete(Data#data.small_blind_seat, Temp), - Amount = Data#data.big_blind_amount, - Expected = 1 - end, - Players1 = lists:delete(Seat, Players), - %%gen_server:cast(Game, {?PP_LEAVE, Player}), % kick player - gen_server:cast(Game, {'SET STATE', Player, ?PS_SIT_OUT}), - if - length(Players1) < Expected -> - {stop, {normal, restart}, Data}; - true -> - Data1 = ask_for_blind(Data, hd(Players1), Amount), - {next_state, State, Data1} - end. + cancel_timer(Data), + Game = Data#data.game, + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + case State of + small_blind -> + Players = gen_server:call(Game, {'SEATS', Seat, ?PS_ACTIVE}), + Amount = Data#data.small_blind_amount, + Expected = 2; + _ -> + Temp = gen_server:call(Game, {'SEATS', Seat, ?PS_BB_ACTIVE}), + %% remove small blind + Players = lists:delete(Data#data.small_blind_seat, Temp), + Amount = Data#data.big_blind_amount, + Expected = 1 + end, + Players1 = lists:delete(Seat, Players), + %%gen_server:cast(Game, {?PP_LEAVE, Player}), % kick player + gen_server:cast(Game, {'SET STATE', Player, ?PS_SIT_OUT}), + if + length(Players1) < Expected -> + {stop, {normal, restart}, Data}; + true -> + Data1 = ask_for_blind(Data, hd(Players1), Amount), + {next_state, State, Data1} + end. join(Data, Player, SeatNum, BuyIn, State) -> - Game = Data#data.game, - gen_server:cast(Game, {?PP_JOIN, Player, SeatNum, BuyIn, ?PS_MAKEUP_BB}), - {next_state, State, Data}. + Game = Data#data.game, + gen_server:cast(Game, {?PP_JOIN, Player, SeatNum, BuyIn, ?PS_MAKEUP_BB}), + {next_state, State, Data}. leave(Data, Player, State) -> - Game = Data#data.game, - Seat = gen_server:call(Game, {'WHAT SEAT', Player}), - if - %% small blind can't leave - %% while we are collecting - %% the big blind - (State == big_blind) and - (Seat == Data#data.small_blind_seat) -> - oops; - true -> - gen_server:cast(Game, {?PP_LEAVE, Player}) - end, - {next_state, State, Data}. + Game = Data#data.game, + Seat = gen_server:call(Game, {'WHAT SEAT', Player}), + if + %% small blind can't leave + %% while we are collecting + %% the big blind + (State == big_blind) and + (Seat == Data#data.small_blind_seat) -> + oops; + true -> + gen_server:cast(Game, {?PP_LEAVE, Player}) + end, + {next_state, State, Data}. sit_out(Data, Player, State) -> - gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_SIT_OUT}), - {next_state, State, Data}. + gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_SIT_OUT}), + {next_state, State, Data}. come_back(Data, Player, State) -> - gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_PLAY}), - {next_state, State, Data}. + gen_server:cast(Data#data.game, {'SET STATE', Player, ?PS_PLAY}), + {next_state, State, Data}. advance_button(Data) -> - Game = Data#data.game, - B = Data#data.button_seat, - if - B == none -> - %% first hand of the game - %% start with the first player - Players = gen_server:call(Game, {'SEATS', ?PS_ANY}), - Button = lists:last(Players), - Bust = false; - true -> - %% start with the first - %% player after the button - Players = gen_server:call(Game, {'SEATS', B, ?PS_ANY}), - Button = hd(Players), - %% big blind is bust - BB = Data#data.big_blind_seat, - BBPlayer = gen_server:call(Game, {'PLAYER AT', BB}), - State = gen_server:call(Game, {'STATE', BBPlayer}), - Bust = ?PS_FOLD == State - end, - {Button, Bust}. + Game = Data#data.game, + B = Data#data.button_seat, + if + B == none -> + %% first hand of the game + %% start with the first player + Players = gen_server:call(Game, {'SEATS', ?PS_ANY}), + Button = lists:last(Players), + Bust = false; + true -> + %% start with the first + %% player after the button + Players = gen_server:call(Game, {'SEATS', B, ?PS_ANY}), + Button = hd(Players), + %% big blind is bust + BB = Data#data.big_blind_seat, + BBPlayer = gen_server:call(Game, {'PLAYER AT', BB}), + State = gen_server:call(Game, {'STATE', BBPlayer}), + Bust = ?PS_FOLD == State + end, + {Button, Bust}. ask_for_blind(Data, Seat, Amount) -> - Game = Data#data.game, - FSM = gen_server:call(Game, 'FSM'), - Player = gen_server:call(Game, {'PLAYER AT', Seat}), - gen_server:cast(Player, {?PP_BET_REQ, FSM, Amount, 0, 0}), - Data1 = restart_timer(Data, Player), - Data1#data { - expected = {Player, Seat, Amount} - }. + Game = Data#data.game, + FSM = gen_server:call(Game, 'FSM'), + Player = gen_server:call(Game, {'PLAYER AT', Seat}), + gen_server:cast(Player, {?PP_BET_REQ, FSM, Amount, 0, 0}), + Data1 = restart_timer(Data, Player), + Data1#data { + expected = {Player, Seat, Amount} + }. cancel_timer(Data) -> - catch cardgame:cancel_timer(Data#data.timer). + catch cardgame:cancel_timer(Data#data.timer). restart_timer(Data, Msg) -> - Timeout = gen_server:call(Data#data.game, 'TIMEOUT'), - Data#data { - timer = cardgame:start_timer(Timeout, Msg) - }. + Timeout = gen_server:call(Data#data.game, 'TIMEOUT'), + Data#data { + timer = cardgame:start_timer(Timeout, Msg) + }. %%% %%% Test suite %%% modules() -> - %%[{delayed_start, [0]}, - %% {blinds, []}]. - [{blinds, []}]. + %%[{delayed_start, [0]}, + %% {blinds, []}]. + [{blinds, []}]. make_game_heads_up() -> - Players = test:make_players(2), - Ctx = #texas { - small_blind_seat = none, - big_blind_seat = none, - button_seat = none - }, - Game = test:make_test_game(Players, Ctx, modules()), - {Game, Players}. + Players = test:make_players(2), + Ctx = #texas { + small_blind_seat = none, + big_blind_seat = none, + button_seat = none + }, + Game = test:make_test_game(Players, Ctx, modules()), + {Game, Players}. make_game_3_bust() -> - Players = test:make_players(3), - Ctx = #texas { - small_blind_seat = element(2, lists:nth(2, Players)), - big_blind_seat = element(2, lists:nth(3, Players)), - button_seat = element(2, lists:nth(1, Players)) - }, - Game = test:make_test_game(Players, Ctx, modules()), - {Game, Players}. + Players = test:make_players(3), + Ctx = #texas { + small_blind_seat = element(2, lists:nth(2, Players)), + big_blind_seat = element(2, lists:nth(3, Players)), + button_seat = element(2, lists:nth(1, Players)) + }, + Game = test:make_test_game(Players, Ctx, modules()), + {Game, Players}. make_game_5_bust() -> - make_game_5_bust(1, 2, 3). + make_game_5_bust(1, 2, 3). make_game_5_bust(Button_N, SB_N, BB_N) -> - A = test:make_player('A'), - B = test:make_player('B'), - C = test:make_player('C'), - D = test:make_player('D'), - E = test:make_player('E'), - Players = [{A, 2}, {B, 4}, {C, 6}, {D, 8}, {E, 9}], - Ctx = #texas { - small_blind_seat = element(2, lists:nth(SB_N, Players)), - big_blind_seat = element(2, lists:nth(BB_N, Players)), - button_seat = element(2, lists:nth(Button_N, Players)) - }, - Game = test:make_test_game(10, Players, Ctx, modules()), - {Game, Players}. + A = test:make_player('A'), + B = test:make_player('B'), + C = test:make_player('C'), + D = test:make_player('D'), + E = test:make_player('E'), + Players = [{A, 2}, {B, 4}, {C, 6}, {D, 8}, {E, 9}], + Ctx = #texas { + small_blind_seat = element(2, lists:nth(SB_N, Players)), + big_blind_seat = element(2, lists:nth(BB_N, Players)), + button_seat = element(2, lists:nth(Button_N, Players)) + }, + Game = test:make_test_game(10, Players, Ctx, modules()), + {Game, Players}. test() -> - test3(), - test4(), - test5(), - test6(), - test7(), - test8(), - test9(), - test10(), - test11(), - test12(), - ok. + test3(), + test4(), + test5(), + test6(), + test7(), + test8(), + test9(), + test10(), + test11(), + test12(), + ok. %% Both blinds are posted post_blinds_trigger(Game, Event, Pid) -> - case Event of - {in, {'$gen_cast', {?PP_BET_REQ, Game, Amount, 0, 0}}} -> - %% post the blind - cardgame:send_event(Game, {?PP_CALL, Pid, Amount}); - _ -> - ok - end, - Game. + case Event of + {in, {'$gen_cast', {?PP_BET_REQ, Game, Amount, 0, 0}}} -> + %% post the blind + cardgame:send_event(Game, {?PP_CALL, Pid, Amount}); + _ -> + ok + end, + Game. test3() -> - {Game, Players} = make_game_heads_up(), - [A, B] = Players, - test:install_trigger(fun post_blinds_trigger/3, Game, [A, B]), - Ctx = #texas { - button_seat = element(2, A), - small_blind_seat = element(2, A), - big_blind_seat = element(2, B), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_heads_up(), + [A, B] = Players, + test:install_trigger(fun post_blinds_trigger/3, Game, [A, B]), + Ctx = #texas { + button_seat = element(2, A), + small_blind_seat = element(2, A), + big_blind_seat = element(2, B), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% http://www.homepokertourney.com/button.htm %%% 3 players, button is bust test4() -> - {Game, Players} = make_game_3_bust(), - [A, B, C] = Players, - cardgame:cast(Game, {'SET STATE', element(1, A), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), - Ctx = #texas { - button_seat = element(2, C), - small_blind_seat = element(2, C), - big_blind_seat = element(2, B), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_3_bust(), + [A, B, C] = Players, + cardgame:cast(Game, {'SET STATE', element(1, A), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), + Ctx = #texas { + button_seat = element(2, C), + small_blind_seat = element(2, C), + big_blind_seat = element(2, B), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% 3 players, small blind is bust test5() -> - {Game, Players} = make_game_3_bust(), - [A, B, C] = Players, - cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), - Ctx = #texas { - button_seat = element(2, C), - small_blind_seat = element(2, C), - big_blind_seat = element(2, A), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_3_bust(), + [A, B, C] = Players, + cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), + Ctx = #texas { + button_seat = element(2, C), + small_blind_seat = element(2, C), + big_blind_seat = element(2, A), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% 3 players, big blind is bust test6() -> - {Game, Players} = make_game_3_bust(), - [A, B, C] = Players, - cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), - Ctx = #texas { - button_seat = element(2, B), - small_blind_seat = element(2, B), - big_blind_seat = element(2, A), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_3_bust(), + [A, B, C] = Players, + cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [A, B, C]), + Ctx = #texas { + button_seat = element(2, B), + small_blind_seat = element(2, B), + big_blind_seat = element(2, A), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% 5 players, small blind is bust test7() -> - {Game, Players} = make_game_5_bust(), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, B), - small_blind_seat = element(2, C), - big_blind_seat = element(2, D), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, B), + small_blind_seat = element(2, C), + big_blind_seat = element(2, D), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). test8() -> - {Game, Players} = make_game_5_bust(2, 3, 4), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, C), - small_blind_seat = element(2, D), - big_blind_seat = element(2, E), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(2, 3, 4), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, C), + small_blind_seat = element(2, D), + big_blind_seat = element(2, E), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% 5 players, big blind is bust test9() -> - {Game, Players} = make_game_5_bust(), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, B), - small_blind_seat = element(2, C), - big_blind_seat = element(2, D), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, B), + small_blind_seat = element(2, C), + big_blind_seat = element(2, D), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). test10() -> - {Game, Players} = make_game_5_bust(2, 3, 4), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, C), - small_blind_seat = element(2, D), - big_blind_seat = element(2, E), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(2, 3, 4), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, C), + small_blind_seat = element(2, D), + big_blind_seat = element(2, E), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). %%% 5 players, both blinds are bust test11() -> - {Game, Players} = make_game_5_bust(), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), - cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, B), - small_blind_seat = element(2, C), - big_blind_seat = element(2, D), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), + cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, B), + small_blind_seat = element(2, C), + big_blind_seat = element(2, D), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). test12() -> - {Game, Players} = make_game_5_bust(2, 3, 4), - [_, B, C, D, E] = Players, - cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), - cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), - test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), - Ctx = #texas { - button_seat = element(2, C), - small_blind_seat = element(2, D), - big_blind_seat = element(2, E), - call = 10 - }, - ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), - cardgame:stop(Game), - test:kill_players(Players). + {Game, Players} = make_game_5_bust(2, 3, 4), + [_, B, C, D, E] = Players, + cardgame:cast(Game, {'SET STATE', element(1, B), ?PS_FOLD}), + cardgame:cast(Game, {'SET STATE', element(1, C), ?PS_FOLD}), + test:install_trigger(fun post_blinds_trigger/3, Game, [B, C, D, E]), + Ctx = #texas { + button_seat = element(2, C), + small_blind_seat = element(2, D), + big_blind_seat = element(2, E), + call = 10 + }, + ?match(success, ?waitmsg({'CARDGAME EXIT', Game, Ctx}, 1000)), + cardgame:stop(Game), + test:kill_players(Players). diff --git a/openpoker-server/src/deck.erl b/openpoker-server/src/deck.erl index f61f09a..f088b28 100644 --- a/openpoker-server/src/deck.erl +++ b/openpoker-server/src/deck.erl @@ -23,7 +23,7 @@ -behaviour(gen_server). -export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2, code_change/3]). + handle_info/2, terminate/2, code_change/3]). -export([start/0, start_link/0, stop/1, test/0]). @@ -31,139 +31,139 @@ -include("common.hrl"). -record(data, { - rigged, - cards - }). + rigged, + cards + }). new() -> - #data { - rigged = [], - cards = shuffle(make_deck()) - }. + #data { + rigged = [], + cards = shuffle(make_deck()) + }. start() -> - gen_server:start(deck, [], []). + gen_server:start(deck, [], []). start_link() -> - gen_server:start_link(deck, [], []). + gen_server:start_link(deck, [], []). init(_) -> - process_flag(trap_exit, true), - {ok, new()}. + process_flag(trap_exit, true), + {ok, new()}. stop(DeckRef) -> - gen_server:cast(DeckRef, stop). + gen_server:cast(DeckRef, stop). terminate(normal, _Data) -> - ok. + ok. handle_cast(stop, Data) -> - {stop, normal, Data}; + {stop, normal, Data}; handle_cast('RESET', Data) -> - Data1 = case Data#data.rigged of - [] -> - %%io:format("Deck is not rigged~n"), - new(); - Cards -> - %%io:format("Deck is rigged with ~w~n", [Cards]), - Data#data { - cards = Cards - } - end, - {noreply, Data1}; + Data1 = case Data#data.rigged of + [] -> + %%io:format("Deck is not rigged~n"), + new(); + Cards -> + %%io:format("Deck is rigged with ~w~n", [Cards]), + Data#data { + cards = Cards + } + end, + {noreply, Data1}; handle_cast({'RIG', Cards}, Data) -> - Data1 = Data#data { - rigged = Cards, - cards = Cards - }, - {noreply, Data1}; + Data1 = Data#data { + rigged = Cards, + cards = Cards + }, + {noreply, Data1}; handle_cast(Event, Data) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {deck, self()}, - {message, Event}]), - {noreply, Data}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {deck, self()}, + {message, Event}]), + {noreply, Data}. handle_call('DRAW', _From, Data) -> - if - length(Data#data.cards) > 0 -> - [Card|Rest] = Data#data.cards, - Data1 = Data#data { - cards = Rest - }, - {reply, Card, Data1}; - true -> - {reply, none, Data} - end; + if + length(Data#data.cards) > 0 -> + [Card|Rest] = Data#data.cards, + Data1 = Data#data { + cards = Rest + }, + {reply, Card, Data1}; + true -> + {reply, none, Data} + end; handle_call(Event, From, Data) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {deck, self()}, - {message, Event}, - {from, From}]), - {noreply, Data}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {deck, self()}, + {message, Event}, + {from, From}]), + {noreply, Data}. handle_info({'EXIT', _Pid, _Reason}, Data) -> - %% child exit? - {noreply, Data}; + %% child exit? + {noreply, Data}; handle_info(Info, Data) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {deck, self()}, - {message, Info}]), - {noreply, Data}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {deck, self()}, + {message, Info}]), + {noreply, Data}. code_change(_OldVsn, Deck, _Extra) -> - {ok, Deck}. + {ok, Deck}. make_deck() -> - Face = [ two, - three, - four, - five, - six, - seven, - eight, - nine, - ten, - jack, - queen, - king, - ace ], - Suit = [ clubs, - diamonds, - hearts, - spades ], - make_deck(Face, Suit, []). + Face = [ two, + three, + four, + five, + six, + seven, + eight, + nine, + ten, + jack, + queen, + king, + ace ], + Suit = [ clubs, + diamonds, + hearts, + spades ], + make_deck(Face, Suit, []). make_deck(Face, [Suit|Rest], Acc) when atom(Face) -> - make_deck(Face, Rest, [{ Face, Suit }|Acc]); + make_deck(Face, Rest, [{ Face, Suit }|Acc]); make_deck(_Face, [], Acc) -> - Acc; + Acc; make_deck([Face|Rest], Suit, Acc) -> - Acc1 = make_deck(Face, Suit, Acc), - make_deck(Rest, Suit, Acc1); + Acc1 = make_deck(Face, Suit, Acc), + make_deck(Rest, Suit, Acc1); make_deck([], _Suit, Acc) -> - Acc. + Acc. shuffle(Cards) -> - Temp = lists:map(fun(X) -> - {random:uniform(1 bsl 64), X} - end, - Cards), - Temp1 = lists:keysort(1, Temp), - lists:map(fun(X) -> - element(2, X) - end, - Temp1). + Temp = lists:map(fun(X) -> + {random:uniform(1 bsl 64), X} + end, + Cards), + Temp1 = lists:keysort(1, Temp), + lists:map(fun(X) -> + element(2, X) + end, + Temp1). test() -> - ok. + ok. diff --git a/openpoker-server/src/delayed_start.erl b/openpoker-server/src/delayed_start.erl index 439cca4..a792fa3 100644 --- a/openpoker-server/src/delayed_start.erl +++ b/openpoker-server/src/delayed_start.erl @@ -26,7 +26,7 @@ -export([init/1, terminate/3]). -export([handle_event/3, handle_info/3, - handle_sync_event/4, code_change/4]). + handle_sync_event/4, code_change/4]). -export([delayed_start/2]). @@ -36,112 +36,112 @@ -include("proto.hrl"). -record(data, { - game, - context, - delay - }). + game, + context, + delay + }). init([Game, Delay]) -> - Data = #data { - game = Game, - delay = Delay - }, - {ok, delayed_start, Data}. + Data = #data { + game = Game, + delay = Delay + }, + {ok, delayed_start, Data}. stop(Ref) -> - cardgame:send_all_state_event(Ref, stop). + cardgame:send_all_state_event(Ref, stop). delayed_start({'START', Context}, Data) -> - Delay = Data#data.delay, - cardgame:send_event_after(Delay, 'CHECK'), - %% reset call amount - Context1 = setelement(3, Context, 0), - Data1 = Data#data { - context = Context1 - }, - {next_state, delayed_start, Data1}; + Delay = Data#data.delay, + cardgame:send_event_after(Delay, 'CHECK'), + %% reset call amount + Context1 = setelement(3, Context, 0), + Data1 = Data#data { + context = Context1 + }, + {next_state, delayed_start, Data1}; delayed_start('CHECK', Data) -> - Game = Data#data.game, - Active = gen_server:call(Game, {'SEATS', ?PS_ACTIVE}), - BBActive = gen_server:call(Game, {'SEATS', ?PS_BB_ACTIVE}), - ReqCount = gen_server:call(Game, 'REQUIRED'), - L1 = length(Active), - L2 = length(BBActive), - Start = (L1 >= ReqCount) or ((L1 > 0) and (L2 > ReqCount)), - Empty = gen_server:call(Game, 'IS EMPTY'), - if - Start -> - gen_server:cast(Game, 'RESET'), - Msg = lang:msg(?GAME_STARTING), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CHAT, 0, Msg}}), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_START_GAME}}), - {stop, {normal, Data#data.context}, Data}; - Empty -> - {stop, {normal, restart}, Data}; - true -> - Msg = lang:msg(?GAME_CANCELLED), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CHAT, 0, Msg}}), - gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CANCEL_GAME}}), - {stop, {normal, restart}, Data} - end; - + Game = Data#data.game, + Active = gen_server:call(Game, {'SEATS', ?PS_ACTIVE}), + BBActive = gen_server:call(Game, {'SEATS', ?PS_BB_ACTIVE}), + ReqCount = gen_server:call(Game, 'REQUIRED'), + L1 = length(Active), + L2 = length(BBActive), + Start = (L1 >= ReqCount) or ((L1 > 0) and (L2 > ReqCount)), + Empty = gen_server:call(Game, 'IS EMPTY'), + if + Start -> + gen_server:cast(Game, 'RESET'), + Msg = lang:msg(?GAME_STARTING), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CHAT, 0, Msg}}), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_START_GAME}}), + {stop, {normal, Data#data.context}, Data}; + Empty -> + {stop, {normal, restart}, Data}; + true -> + Msg = lang:msg(?GAME_CANCELLED), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CHAT, 0, Msg}}), + gen_server:cast(Game, {'BROADCAST', {?PP_NOTIFY_CANCEL_GAME}}), + {stop, {normal, restart}, Data} + end; + delayed_start({?PP_JOIN, Player, SeatNum, BuyIn}, Data) -> - Game = Data#data.game, - gen_server:cast(Game, {?PP_JOIN, Player, SeatNum, BuyIn, ?PS_PLAY}), - {next_state, delayed_start, Data}; + Game = Data#data.game, + gen_server:cast(Game, {?PP_JOIN, Player, SeatNum, BuyIn, ?PS_PLAY}), + {next_state, delayed_start, Data}; delayed_start({?PP_LEAVE, Player}, Data) -> - Game = Data#data.game, - gen_server:cast(Game, {?PP_LEAVE, Player}), - {next_state, delayed_start, Data}; + Game = Data#data.game, + gen_server:cast(Game, {?PP_LEAVE, Player}), + {next_state, delayed_start, Data}; delayed_start({?PP_SIT_OUT, Player}, Data) -> - Game = Data#data.game, - gen_server:cast(Game, {'SET STATE', Player, ?PS_SIT_OUT}), - {next_state, delayed_start, Data}; + Game = Data#data.game, + gen_server:cast(Game, {'SET STATE', Player, ?PS_SIT_OUT}), + {next_state, delayed_start, Data}; delayed_start({?PP_COME_BACK, Player}, Data) -> - Game = Data#data.game, - gen_server:cast(Game, {'SET STATE', Player, ?PS_PLAY}), - {next_state, delayed_start, Data}; + Game = Data#data.game, + gen_server:cast(Game, {'SET STATE', Player, ?PS_PLAY}), + {next_state, delayed_start, Data}; delayed_start(Event, Data) -> - handle_event(Event, delayed_start, Data). + handle_event(Event, delayed_start, Data). handle_event(stop, _State, Data) -> - {stop, normal, Data}; + {stop, normal, Data}; handle_event(Event, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {message, Event}, - {self, self()}, - {game, Data#data.game}]), - {next_state, State, Data}. - + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {message, Event}, + {self, self()}, + {game, Data#data.game}]), + {next_state, State, Data}. + handle_sync_event(Event, From, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {from, From}, - {message, Event}, - {self, self()}, - {game, Data#data.game}]), - {next_state, State, Data}. + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {from, From}, + {message, Event}, + {self, self()}, + {game, Data#data.game}]), + {next_state, State, Data}. handle_info(Info, State, Data) -> - error_logger:error_report([{module, ?MODULE}, - {line, ?LINE}, - {message, Info}, - {self, self()}, - {game, Data#data.game}]), - {next_state, State, Data}. + error_logger:error_report([{module, ?MODULE}, + {line, ?LINE}, + {message, Info}, + {self, self()}, + {game, Data#data.game}]), + {next_state, State, Data}. terminate(_Reason, _State, _Data) -> - ok. + ok. code_change(_OldVsn, State, Data, _Extra) -> - {ok, State, Data}. + {ok, State, Data}. %% @@ -149,5 +149,5 @@ code_change(_OldVsn, State, Data, _Extra) -> %% test() -> - ok. + ok. diff --git a/openpoker-server/src/game.erl b/openpoker-server/src/game.erl index 23f91a0..52fb23f 100644 --- a/openpoker-server/src/game.erl +++ b/openpoker-server/src/game.erl @@ -540,7 +540,7 @@ create_seats(Seats, I) -> bet = 0, hand = Hand, state = ?PS_EMPTY - }, + }, NewSeats = setelement(I, Seats, Seat), create_seats(NewSeats, I - 1). diff --git a/openpoker-server/src/server.erl b/openpoker-server/src/server.erl index d4ba7b2..4906465 100644 --- a/openpoker-server/src/server.erl +++ b/openpoker-server/src/server.erl @@ -23,7 +23,7 @@ -behaviour(gen_server). -export([init/1, handle_call/3, handle_cast/2, - handle_info/2, terminate/2, code_change/3]). + handle_info/2, terminate/2, code_change/3]). -export([start/1, start/2, start/3, stop/1, test/0]). @@ -34,101 +34,101 @@ -include("test.hrl"). -record(server, { - port, - host, - avg, - games, - test_mode - }). + port, + host, + avg, + games, + test_mode + }). -record(client, { - server = none, - player = none - }). + server = none, + player = none + }). start([Port, Host]) - when is_atom(Port), - is_atom(Host) -> - Port1 = list_to_integer(atom_to_list(Port)), - Host1 = atom_to_list(Host), - start(Host1, Port1). +when is_atom(Port), +is_atom(Host) -> + Port1 = list_to_integer(atom_to_list(Port)), + Host1 = atom_to_list(Host), + start(Host1, Port1). start(Host, Port) -> - start(Host, Port, false). + start(Host, Port, false). start(Host, Port, TestMode) -> - mnesia:start(), - case mnesia:wait_for_tables([game_config, game_xref], 10000) of - ok -> - case gen_server:start(server, [Host, Port, TestMode], []) of - {ok, Pid} -> - %%io:format("server:start: pid ~w~n", [Pid]), - pg2:create(?GAME_SERVERS), - ok = pg2:join(?GAME_SERVERS, Pid), - {ok, Pid}; - Result -> - error_logger:error_report( - [{module, ?MODULE}, - {line, ?LINE}, - {message, "Unexpected result"}, - {call, 'gen_server:start(server)'}, - {result, Result}, - {port, Port}, - {now, now()}]), - Result - end; - Other -> - error_logger:error_report( - [{module, ?MODULE}, - {line, ?LINE}, - {message, "Unexpected result"}, - {result, Other}, - {call, 'mnesia:wait_for_tables'}, - {now, now()}]), - Other - end. + mnesia:start(), + case mnesia:wait_for_tables([game_config, game_xref], 10000) of + ok -> + case gen_server:start(server, [Host, Port, TestMode], []) of + {ok, Pid} -> + %%io:format("server:start: pid ~w~n", [Pid]), + pg2:create(?GAME_SERVERS), + ok = pg2:join(?GAME_SERVERS, Pid), + {ok, Pid}; + Result -> + error_logger:error_report( + [{module, ?MODULE}, + {line, ?LINE}, + {message, "Unexpected result"}, + {call, 'gen_server:start(server)'}, + {result, Result}, + {port, Port}, + {now, now()}]), + Result + end; + Other -> + error_logger:error_report( + [{module, ?MODULE}, + {line, ?LINE}, + {message, "Unexpected result"}, + {result, Other}, + {call, 'mnesia:wait_for_tables'}, + {now, now()}]), + Other + end. init([Host, Port, TestMode]) -> - process_flag(trap_exit, true), - %%error_logger:logfile({open, "/tmp/" - %% ++ atom_to_list(node()) - %% ++ ".log"}), - Client = #client { - server = self() - }, - F = fun(Sock) -> parse_packet(Sock, Client) end, - tcp_server:stop(Port), - {ok, _} = tcp_server:start_raw_server(Port, F, 10240, 2048), - Server = #server { - host = Host, - port = Port, - avg = 0, - games = start_games(), - test_mode = TestMode - }, - {ok, Server}. + process_flag(trap_exit, true), + %%error_logger:logfile({open, "/tmp/" + %% ++ atom_to_list(node()) + %% ++ ".log"}), + Client = #client { + server = self() + }, + F = fun(Sock) -> parse_packet(Sock, Client) end, + tcp_server:stop(Port), + {ok, _} = tcp_server:start_raw_server(Port, F, 10240, 2048), + Server = #server { + host = Host, + port = Port, + avg = 0, + games = start_games(), + test_mode = TestMode + }, + {ok, Server}. stop(Server) -> - gen_server:cast(Server, stop). + gen_server:cast(Server, stop). terminate(normal, Server) -> - kill_games(Server#server.games), - tcp_server:stop(Server#server.port), - ok. + kill_games(Server#server.games), + tcp_server:stop(Server#server.port), + ok. handle_cast(stop, Server) -> - {stop, normal, Server}; + {stop, normal, Server}; handle_cast(Event, Server) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {self, self()}, - {message, Event}]), - {noreply, Server}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {self, self()}, + {message, Event}]), + {noreply, Server}. handle_call('WHERE', _From, Server) -> - {reply, {Server#server.host, Server#server.port}, Server}; + {reply, {Server#server.host, Server#server.port}, Server}; %% {ok, [{X, _, _}|_]} = inet:getif(), %% io:format("Server address: ~w~n", [X]), %% Host = io_lib:format("~.B.~.B.~.B.~.B", @@ -139,191 +139,187 @@ handle_call('WHERE', _From, Server) -> %% {reply, {Host, Server#server.port}, Server}; handle_call('USER COUNT', _From, Server) -> - Children = tcp_server:children(Server#server.port), - {reply, length(Children), Server}; + Children = tcp_server:children(Server#server.port), + {reply, length(Children), Server}; handle_call('TEST MODE', _From, Server) -> - {reply, Server#server.test_mode, Server}; + {reply, Server#server.test_mode, Server}; handle_call(Event, From, Server) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {self, self()}, - {message, Event}, - {from, From}]), - {noreply, Server}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {self, self()}, + {message, Event}, + {from, From}]), + {noreply, Server}. handle_info({'EXIT', _Pid, _Reason}, Server) -> - %% child exit? - {noreply, Server}; + %% child exit? + {noreply, Server}; handle_info(Info, Server) -> - error_logger:info_report([{module, ?MODULE}, - {line, ?LINE}, - {self, self()}, - {message, Info}]), - {noreply, Server}. + error_logger:info_report([{module, ?MODULE}, + {line, ?LINE}, + {self, self()}, + {message, Info}]), + {noreply, Server}. code_change(_OldVsn, Server, _Extra) -> - {ok, Server}. + {ok, Server}. parse_packet(Socket, Client) -> - receive - {tcp, Socket, Bin} -> - %%io:format("--> ~w~n", [Bin]), - case proto:read(Bin) of - {?PP_LOGIN, Nick, Pass} -> - %%io:format("Logging in ~s~n", [Nick]), - case login:login(Nick, Pass, self()) of - {error, Error} -> - %%io:format("Login error: ~w~n", [Error]), - ok = ?tcpsend(Socket, {?PP_BAD, - ?PP_LOGIN, - Error}), - parse_packet(Socket, Client); - {ok, Player} -> - %% disconnect visitor - if - Client#client.player /= none -> - gen_server:cast(Client#client.player, - 'DISCONNECT'); - true -> - ok - end, - ID = gen_server:call(Player, 'ID'), - ok = ?tcpsend(Socket, {?PP_PID, ID}), - Client1 = Client#client { - player = Player - }, - parse_packet(Socket, Client1) - end; - ?PP_LOGOUT -> - gen_server:cast(Client#client.player, 'LOGOUT'), - ok = ?tcpsend(Socket, {?PP_GOOD, - ?PP_LOGOUT, - 0}), - %% Replace player process with a visitor - {ok, Visitor} = visitor:start(), - Client1 = Client#client { - player = Visitor - }, - gen_server:cast(Visitor, {'SOCKET', self()}), - parse_packet(Socket, Client1); - {?PP_GAME_QUERY, - GameType, LimitType, - ExpOp, Expected, - JoinOp, Joined, - WaitOp, Waiting} -> - _ST = now(), - find_games(Socket, - GameType, LimitType, - ExpOp, Expected, - JoinOp, Joined, - WaitOp, Waiting), - _ET = now(), - %%Elapsed = timer:now_diff(ET, ST) / 1000, - %%io:format("~wms to send games to ~w~n", - %% [Elapsed, Socket]), - parse_packet(Socket, Client); - {?PP_MAKE_TEST_GAME, Data} -> - case gen_server:call(Client#client.server, - 'TEST MODE') of - true -> - ok = ?tcpsend(Socket, start_test_game(Data)); - _ -> - ok - end, - parse_packet(Socket, Client); - ?PP_PING -> - ok = ?tcpsend(Socket, ?PP_PONG), - parse_packet(Socket, Client); - none -> - io:format("Unrecognized packet: ~w~n", [Bin]); - Event -> - Client1 = if - Client#client.player == none -> - %% start a proxy - {ok, Visitor} = visitor:start(), - gen_server:cast(Visitor, - {'SOCKET', self()}), - Client#client { - player = Visitor - }; - true -> - Client - end, - gen_server:cast(Client1#client.player, Event), - parse_packet(Socket, Client1) - end; - {tcp_closed, Socket} -> - gen_server:cast(Client#client.player, 'DISCONNECT'); - {packet, Packet} -> - %%io:format("<-- ~w~n", [Packet]), - ok = ?tcpsend(Socket, Packet), - parse_packet(Socket, Client) - end. - -find_games(Socket, - GameType, LimitType, - ExpOp, Expected, - JoinOp, Joined, - WaitOp, Waiting) -> - {atomic, L} = game:find(GameType, LimitType, - ExpOhowdown(Event, Data) -> - handle_event(Event, showdown, Data). -p, Expected, - JoinOp, Joined, - WaitOp, Waiting), - lists:foreach(fun(Packet) -> - ?tcpsend(Socket, Packet) - end, L). + receive + {tcp, Socket, Bin} -> + %%io:format("--> ~w~n", [Bin]), + case proto:read(Bin) of + {?PP_LOGIN, Nick, Pass} -> + %%io:format("Logging in ~s~n", [Nick]), + case login:login(Nick, Pass, self()) of + {error, Error} -> + %%io:format("Login error: ~w~n", [Error]), + ok = ?tcpsend(Socket, {?PP_BAD, + ?PP_LOGIN, + Error}), + parse_packet(Socket, Client); + {ok, Player} -> + %% disconnect visitor + if + Client#client.player /= none -> + gen_server:cast(Client#client.player, + 'DISCONNECT'); + true -> + ok + end, + ID = gen_server:call(Player, 'ID'), + ok = ?tcpsend(Socket, {?PP_PID, ID}), + Client1 = Client#client { + player = Player + }, + parse_packet(Socket, Client1) + end; + ?PP_LOGOUT -> + gen_server:cast(Client#client.player, 'LOGOUT'), + ok = ?tcpsend(Socket, {?PP_GOOD, + ?PP_LOGOUT, + 0}), + %% Replace player process with a visitor + {ok, Visitor} = visitor:start(), + Client1 = Client#client { + player = Visitor + }, + gen_server:cast(Visitor, {'SOCKET', self()}), + parse_packet(Socket, Client1); + {?PP_GAME_QUERY, + GameType, LimitType, + ExpOp, Expected, + JoinOp, Joined, + WaitOp, Waiting} -> + _ST = now(), + find_games(Socket, + GameType, LimitType, + ExpOp, Expected, + JoinOp, Joined, + WaitOp, Waiting), + _ET = now(), + %%Elapsed = timer:now_diff(ET, ST) / 1000, + %%io:format("~wms to send games to ~w~n", + %% [Elapsed, Socket]), + parse_packet(Socket, Client); + {?PP_MAKE_TEST_GAME, Data} -> + case gen_server:call(Client#client.server, + 'TEST MODE') of + true -> + ok = ?tcpsend(Socket, start_test_game(Data)); + _ -> + ok + end, + parse_packet(Socket, Client); + ?PP_PING -> + ok = ?tcpsend(Socket, ?PP_PONG), + parse_packet(Socket, Client); + none -> + io:format("Unrecognized packet: ~w~n", [Bin]); + Event -> + Client1 = if + Client#client.player == none -> + %% start a proxy + {ok, Visitor} = visitor:start(), + gen_server:cast(Visitor, + {'SOCKET', self()}), + Client#client { + player = Visitor + }; + true -> + Client + end, + gen_server:cast(Client1#client.player, Event), + parse_packet(Socket, Client1) + end; + {tcp_closed, Socket} -> + gen_server:cast(Client#client.player, 'DISCONNECT'); + {packet, Packet} -> + %%io:format("<-- ~w~n", [Packet]), + ok = ?tcpsend(Socket, Packet), + parse_packet(Socket, Client) + end. + +find_games(Socket, GameType, LimitType, ExpOp, Expected, JoinOp, Joined, WaitOp, Waiting) -> + {atomic, L} = game:find(GameType, LimitType, + %ExpOhowdown(Event, Data) -> + %handle_event(Event, showdown, Data). + ExpOp, Expected, + JoinOp, Joined, + WaitOp, Waiting), + lists:foreach(fun(Packet) -> + ?tcpsend(Socket, Packet) + end, L). start_games() -> - {atomic, Games} = db:find(game_config), - start_games(Games, []). + {atomic, Games} = db:find(game_config), + start_games(Games, []). start_games([Game|Rest], Acc) -> - Acc1 = start_games(Game, Game#game_config.max, Acc), - start_games(Rest, Acc1); + Acc1 = start_games(Game, Game#game_config.max, Acc), + start_games(Rest, Acc1); start_games([], Acc) -> - Acc. + Acc. start_games(_Game, 0, Acc) -> - Acc; + Acc; start_games(Game, N, Acc) -> - {ok, Pid} = cardgame:start(Game#game_config.type, - Game#game_config.seat_count, - Game#game_config.limit, - Game#game_config.start_delay, - Game#game_config.player_timeout), - start_games(Game, N - 1, [Pid|Acc]). + {ok, Pid} = cardgame:start(Game#game_config.type, + Game#game_config.seat_count, + Game#game_config.limit, + Game#game_config.start_delay, + Game#game_config.player_timeout), + start_games(Game, N - 1, [Pid|Acc]). kill_games([]) -> - ok; + ok; kill_games([Pid|Rest]) -> - cardgame:stop(Pid), - kill_games(Rest). + cardgame:stop(Pid), + kill_games(Rest). start_test_game(Bin) - when is_binary(Bin) -> - {GameType, Expected, Limit, Delay, Timeout, Cards} = - binary_to_term(Bin), - {ok, Pid} = cardgame:start(GameType, - Expected, - Limit, - Delay, - Timeout), - cardgame:cast(Pid, {'RIG', Cards}), - cardgame:cast(Pid, {'REQUIRED', Expected}), - GID = cardgame:call(Pid, 'ID'), - {?PP_GOOD, ?PP_MAKE_TEST_GAME, GID}. - +when is_binary(Bin) -> + {GameType, Expected, Limit, Delay, Timeout, Cards} = + binary_to_term(Bin), + {ok, Pid} = cardgame:start(GameType, + Expected, + Limit, + Delay, + Timeout), + cardgame:cast(Pid, {'RIG', Cards}), + cardgame:cast(Pid, {'REQUIRED', Expected}), + GID = cardgame:call(Pid, 'ID'), + {?PP_GOOD, ?PP_MAKE_TEST_GAME, GID}. + %% %% Test suite %% test() -> - ok. + ok. diff --git a/openpoker-server/src/tcp_server.erl b/openpoker-server/src/tcp_server.erl index 73854bb..0b4ead4 100644 --- a/openpoker-server/src/tcp_server.erl +++ b/openpoker-server/src/tcp_server.erl @@ -7,6 +7,7 @@ -module(tcp_server). -export([start_raw_server/4, start_client/3, stop/1, children/1]). +-export([port_name/1]). -define(KILL_DELAY, 1000). @@ -61,6 +62,9 @@ start_client(Host, Port, Length) -> %% Note when start_raw_server returns it should be ready to %% Immediately accept connections +% 开启对应端口号的进程 +% 通过port_name查找对应的进程名称 +% 启动进程后等待消息,指导启动进程返回{Pid, ok}的结果再注册进程 start_raw_server(Port, Fun, Max, Length) -> Name = port_name(Port), case whereis(Name) of @@ -80,7 +84,7 @@ start_raw_server(Port, Fun, Max, Length) -> {error, already_started} end. -stop(Port) when integer(Port) -> +stop(Port) when is_integer(Port) -> Name = port_name(Port), case whereis(Name) of undefined -> @@ -91,13 +95,13 @@ stop(Port) when integer(Port) -> stopped end. -children(Port) when integer(Port) -> +children(Port) when is_integer(Port) -> port_name(Port) ! {children, self()}, receive {session_server, Reply} -> Reply end. -port_name(Port) when integer(Port) -> +port_name(Port) when is_integer(Port) -> list_to_atom("portServer" ++ integer_to_list(Port)). cold_start(Master, Port, Fun, Max, Length) -> @@ -143,7 +147,7 @@ socket_loop(Listen, New, Active, Fun, Max) -> io:format("Here in loop:~p~n",[Other]) end. -possibly_start_another(New, Listen, Active, Fun, Max) when pid(New) -> +possibly_start_another(New, Listen, Active, Fun, Max) when is_pid(New) -> socket_loop(Listen, New, Active, Fun, Max); possibly_start_another(false, Listen, Active, Fun, Max) -> case length(Active) of @@ -176,5 +180,3 @@ start_child(Parent, Listen, Fun) -> _Other -> exit(oops) end. - - diff --git a/openpoker-server/src/test.hrl b/openpoker-server/src/test.hrl index 7465a14..7e48ab5 100644 --- a/openpoker-server/src/test.hrl +++ b/openpoker-server/src/test.hrl @@ -20,100 +20,98 @@ %%% at joelr@well.com for more information. -define(error1(Expr, Expected, Actual), - io:format("~s is ~w instead of ~w at ~w:~w~n", - [??Expr, Actual, Expected, ?MODULE, ?LINE])). + io:format("~s is ~w instead of ~w at ~w:~w~n", + [??Expr, Actual, Expected, ?MODULE, ?LINE])). -define(error2(Message), - io:format("~s at ~w:~w~n", - [Message, ?MODULE, ?LINE])). + io:format("~s at ~w:~w~n", + [Message, ?MODULE, ?LINE])). -define(match(Expected, Expr), - fun() -> - Actual = (catch (Expr)), - case Actual of - Expected -> - {success, Actual}; - _ -> - ?error1(Expr, Expected, Actual), - erlang:error("match failed", Actual) - end - end()). + fun() -> + Actual = (catch (Expr)), + case Actual of + Expected -> + {success, Actual}; + _ -> + ?error1(Expr, Expected, Actual), + erlang:error("match failed", Actual) + end + end()). -define(differ(Expected, Expr), - fun() -> - Actual = (catch (Expr)), - case Actual of - Expected -> - ?error1(Expr, Expected, Actual), - erlang:error("differ failed", Actual); - _ -> - {success, Actual} - end - end()). + fun() -> + Actual = (catch (Expr)), + case Actual of + Expected -> + ?error1(Expr, Expected, Actual), + erlang:error("differ failed", Actual); + _ -> + {success, Actual} + end + end()). -define(waitmsg(Message, Timeout), - fun() -> - receive - Message -> - success; - Other -> - {error, Other} - after Timeout -> - {error, timeout} - end - end()). + fun() -> + receive + Message -> + success; + Other -> + {error, Other} + after Timeout -> + {error, timeout} + end + end()). -define(waitexit(Pid, Timeout), - fun() -> - receive - {'CARDGAME EXIT', Pid, Data} -> - {success, Data}; - Other -> - {error, Other} - after Timeout -> - {error, timeout} - end - end()). + fun() -> + receive + {'CARDGAME EXIT', Pid, Data} -> + {success, Data}; + Other -> + {error, Other} + after Timeout -> + {error, timeout} + end + end()). -define(waittcp(Message, Timeout), - fun() -> - receive - {tcp, _, Bin} -> - case proto:read(Bin) of - Message -> - success; - Any -> - {error, Any} - end; - Other -> - {error, Other} - after Timeout -> - {error, timeout} - end - end()). + fun() -> + receive + {tcp, _, Bin} -> + case proto:read(Bin) of + Message -> + success; + Any -> + {error, Any} + end; + Other -> + {error, Other} + after Timeout -> + {error, timeout} + end + end()). -define(tcpsend(Socket, Data), - fun() -> - XXX = proto:write(Data), - case gen_tcp:send(Socket, XXX) of - ok -> - ok; - {error, closed} -> - ok; - {error,econnaborted} -> - ok; - Any -> - error_logger:error_report([ - {message, "gen_tcp:send error"}, - {module, ?MODULE}, - {line, ?LINE}, - {socket, Socket}, - {port_info, erlang:port_info(Socket, connected)}, - {data, Data}, - {bin, XXX}, - {error, Any}]) - end - end()). - - + fun() -> + XXX = proto:write(Data), + case gen_tcp:send(Socket, XXX) of + ok -> + ok; + {error, closed} -> + ok; + {error,econnaborted} -> + ok; + Any -> + error_logger:error_report([ + {message, "gen_tcp:send error"}, + {module, ?MODULE}, + {line, ?LINE}, + {socket, Socket}, + {port_info, erlang:port_info(Socket, connected)}, + {data, Data}, + {bin, XXX}, + {error, Any}]) + end + end()). diff --git a/openpoker-server/src/util.erl b/openpoker-server/src/util.erl index 6b79355..888d9f3 100644 --- a/openpoker-server/src/util.erl +++ b/openpoker-server/src/util.erl @@ -23,9 +23,5 @@ -export([is_process_alive/1]). -is_process_alive(Pid) - when is_pid(Pid) -> - rpc:call(node(Pid), erlang, is_process_alive, [Pid]). - - - +is_process_alive(Pid) when is_pid(Pid) -> + rpc:call(node(Pid), erlang, is_process_alive, [Pid]). diff --git a/supervisor/order_sup.erl b/supervisor/order_sup.erl new file mode 100644 index 0000000..2594d92 --- /dev/null +++ b/supervisor/order_sup.erl @@ -0,0 +1,14 @@ +-module(order_sup). +-behavior(supervisor). + +-export([start_link/0]). +-export([init/1]). + +start_link() -> + supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +init([]) -> + {ok, {{one_for_one, 1, 1}, [ + {make_ref(), {gen_server, start_link, [server, ["Srv1", 2000], []]}, permanent, 1000, worker, [server]}, + {make_ref(), {gen_server, start_link, [server, ["Srv2", 3000], []]}, permanent, 1000, worker, [server]} + ]}}. diff --git a/supervisor/server.erl b/supervisor/server.erl new file mode 100644 index 0000000..e36d168 --- /dev/null +++ b/supervisor/server.erl @@ -0,0 +1,32 @@ +-module(server). +-behavior(gen_server). + +-export([init/1, terminate/2, handle_call/3, handle_cast/2, code_change/3, handle_info/2]). + +%% +%% Callback Functions +%% + +init([Name, Time]) -> + io:format("~w server start after ~w ms ~n", [Name, Time]), + timer:sleep(Time), + io:format("~w server start successful ~n", [Name]), + {ok, nil}. + +terminate(_Reason, _LoopData) -> + ok. + +handle_info(_Info, LoopData) -> + {noreply, LoopData}. + +code_change(_OldVsn, LoopData, _Extra) -> + {ok, LoopData}. + +handle_call(_Msg, _From, LoopData) -> + {reply, ok, LoopData}. + +handle_cast(stop, LoopData) -> + {stop, normal, LoopData}; +handle_cast(_Msg, LoopData) -> + {noreply, LoopData}. +