葡京游戏网址简单Elixir游戏服设计-桌子进程走起

譬如Player进程那样多TableServer代表桌子进程

建模桌子和坐席

长TableSupervisor监控TableServer。使用及一个Registry,因此名字吧改成化LocalRegistry了。

代码比较短缺小,直接贴吧。

于是Registry的启航代码,以及原来PlayerServer的register_name要召开小修改。

model 里新建simple_table.ex 和 seat.ex, 项目里新增对应的test.

自你为堪采取2个例外之Registry,但也许即使假设加进一个RegstrySupervisor 去start_child了,

席有

而且或者手动启动2单(更加不建议)。

新的game_server.ex

defmodule Seat do
    def init(player) do
        %{
            id: player |> Player.get_id,
            player: player,
            score: 0,
        }
    end

    def get_id(seat), do: seat.id

    def update_player(seat, player), do: put_in(seat.player, player)
    def get_player(seat), do: seat.player
    def get_player_id(seat), do: seat.player |> Player.get_id

    def add_score(seat, num) when num >=0 , do: update_in(seat.score, &(&1 + num))
    def sub_score(seat, num) when num >= 0 , do: update_in(seat.score, &(&1 - num))
    def get_score(seat), do: seat.score

end

seat.ex

defmodule GameServer do
  use Application
  def start(_type, _args) do
    children = [
      {Registry, keys: :unique, name: LocalRegistry},
      PlayerSupervisor,
      TableSupervisor
    ]
    Supervisor.start_link(children, strategy: :one_for_one)
  end
end

game_server.ex

defmodule SeatTest do
  use ExUnit.Case
  doctest Seat

  setup do

    %{seat: Seat.init(Player.init)}
  end

  test "init", %{seat: seat} do
    assert 0 == seat |> Seat.get_score
  end

  test "add_and_remove_score", %{seat: seat} do
    num = 10
    old_score = seat |> Seat.get_score
    add_score_seat = seat |> Seat.add_score(num) 
    assert old_score + num == add_score_seat |> Seat.get_score
    sub_score_seat = seat |> Seat.sub_score(num)
    assert old_score - num == sub_score_seat |> Seat.get_score
  end

end

PlayerServer 的register_name 应该按table_server 那样修改,这样明晰,并且也未会见冲。

seat_test.exs

案子部分

defmodule TableServer do
    use GenServer, restart: :temporary, start: {__MODULE__, :start_link, []}

    def start_link(table) do
        GenServer.start_link(__MODULE__, table, name: register_name(table))
      end

    def init(table) do
        {:ok, table}
    end

    def register_name(%{} = table), do: register_name(table |> SimpleTable.get_id)
    def register_name(id), do: {:via, Registry, {LocalRegistry, {Table, id}}}

    def exist?(table) do
        key = {Table, table |> SimpleTable.get_id}
        case Registry.lookup(LocalRegistry, key) do
            [{_pid, _}] -> true
            [] -> false
        end
    end

end

table_server.ex

defmodule SimpleTable do

    def init() do
        %{
            cards: SimplePoker.init_cards,
            creator: nil,
            seat_map: %{},
            seat_order: []
        }
    end

    def seat_count(table), do: table.seat_order |> Enum.count
    def seat_order(table), do: table.seat_order

    def find_seat(table, %{} = player), do: find_seat(table, player |> Player.get_id)
    def find_seat(table, player_id), do: table.seat_map[player_id]

    def add_seat(table, player) do
        seat = Seat.init(player)
        seat_id = seat |> Seat.get_id
        table = put_in(table.seat_map[seat_id], seat)
        add_to_order(table, seat_id)
    end

    def add_to_order(table, seat_id), do: update_in(table.seat_order, &(&1 ++ [seat_id]))

    def remove_seat(table, %{} = player), do: remove_seat(table, player |> Player.get_id)
    def remove_seat(table, player_id) do
        table = update_in(table.seat_map, fn m -> Map.delete(m, player_id) end)
        update_in(table.seat_order, fn o -> List.delete(o, player_id) end)
    end


end

增产了exist? 判断函数,以后会发因此吧。

simple_table.ex

基准上当玩家创建了一个牌局后,没解散之前未允再次创(当然你得变更,我只是简化了)

table_supervisor 测试

defmodule SimpleTableTest do
  use ExUnit.Case
  doctest SimpleTable

  def create_player(id), do: Player.init |> Player.set_id(id)

  setup do
    %{
        table: SimpleTable.init,
          player1: create_player(1),
          player2: create_player(2),
          player3: create_player(3),
          player4: create_player(4)
    }
  end

  test "init", %{table: table} do
      assert 0 = table |> SimpleTable.seat_count
  end

  test "add_and_remove_seat", %{table: table, player1: player1, player2: player2, player3: player3, player4: player4} do
        table = table |> SimpleTable.add_seat(player1) 
                        |> SimpleTable.add_seat(player2)
                        |> SimpleTable.add_seat(player3)
                        |> SimpleTable.add_seat(player4)

        assert 4 == SimpleTable.seat_count(table)
        expect_seat_order = [player1 |> Player.get_id,
                player2 |> Player.get_id,
                  player3 |> Player.get_id,
                  player4 |> Player.get_id]
        assert ^expect_seat_order = SimpleTable.seat_order(table)

        new_expect_seat_order = [
                player2 |> Player.get_id,
                  player3 |> Player.get_id,
                  player4 |> Player.get_id
                ]

        table = table |> SimpleTable.remove_seat(player1)
      assert 3 == SimpleTable.seat_count(table)
      assert ^new_expect_seat_order = SimpleTable.seat_order(table)
  end 


end
defmodule TableSupervisorTest do
    use ExUnit.Case
    doctest PlayerSupervisor

    setup do
        Application.stop(GameServer)
        Application.start(GameServer)
        %{}
    end

    test "测试TableSupervisor启动TableServer" do
        table1 = SimpleTable.init |> SimpleTable.set_id(1)
        table2 = SimpleTable.init |> SimpleTable.set_id(2)
        assert {:ok, _p1} = TableSupervisor.start_table(table1)
        assert {:ok, _p2} = TableSupervisor.start_table(table2)
        assert TableServer.exist?(table1)
        assert TableServer.exist?(table2)
    end
end

simple_table_test.exs

反使用exist? 了

临时是任编写了,后续要重新调整。

player_supervisor_test.exs 也照在修改。

他日该从游戏过程了。

编译测试ok。

代码变迁参看git吧。

他日我们由玩家创建牌局,一步步开展吧。

XXXX,想了下
上句话不针对,创建那些和玩法吧从没干,先放正,直接打牌局玩才对。

XXXXX,上句看似也尴尬,本质上server进程只是转调用数据结构的操作,因此牌局玩法完全好是数据结构的操作先。

据此下回我们直接操作数据,进行牌局。