接上章,我新建了個app作包含Table模型, TableServer等。Table桌子的代碼暫時以下, 有一些狀態還沒用上app
defmodule Table do @state_accept 0 #準備接入玩家 @state_ready 1 #開局準備? defdelegate [fetch(t, key), get_and_update(t, key, list)], to: Map defstruct [:config, :seats, :state] def new(config) do %Table{ config: config, seats: %{}, state: @state_accept } end def is_full?(table) do cur_count = Enum.count(table.seats) cur_count >= table.config.allow_count end def has_player?(table, player_id) do table.seats[player_id] end def check_in(table, player) do update_in(table.seats, &(Map.put(&1, player.base_info.id, player))) end def check_out(table, player_id) do update_in(table.seats, &(Map.delete(&1, player_id))) end end
咱們須要相關的配置table_config.txt函數
id, allow_count, base_gold, need_gold, desc int, int, int, int, string 1, 4, 10, 480, 新手場 2, 4, 100, 4800, 中級場 3, 4, 1000, 48000, 高級場
這個txt能夠由excel經過xslx2csv工具生成。而後咱們利用table_config.txt 生成代碼配置table_config.ex.工具
咱們固然能夠在TableConfig裏經由excel文件直接生成,那樣會更方便。測試
defmodule TableConfig do Module.register_attribute __MODULE__, :column_names, [] Module.register_attribute __MODULE__, :column_types, [] Module.register_attribute __MODULE__, :config, [] line_with_index = File.stream!(Path.join([__DIR__, "table_config.txt"]) , [], :line) |> Stream.with_index for {line, index} <- line_with_index do items = line |> String.split(",") |> Stream.map(&String.strip(&1)) case index do 0 -> @column_names items |> Enum.map(&String.to_atom(&1)) 1 -> @column_types items |> Stream.with_index |> Enum.map(fn {v, i} -> {i, String.to_atom(v)} end) |> IO.inspect |> Enum.into(%{}) _ -> new_items = items |> Stream.with_index |> Stream.map( &( TypeConverter.convert(&1, @column_types) ) ) zip = Enum.zip(@column_names, new_items) @config Enum.into(zip, %{}) IO.inspect @config
# 如下函數花了我點時間,最後不得不經過模塊屬性完成,我不知道有沒有其餘方法
# 早期的版本是者這樣的
# config = Enum.into(zip, %{})
# def get(unquote(config.id)) do
# unquote(config) # 這裏會報錯,百思不得其解,在ErrorMsg裏我是這樣用的,沒有問題。不知2者區別在哪
# end
def get(unquote(@config.id)) do @config end end end end
最後上點測試代碼table_test.exsfetch
defmodule TabelTest do use ExUnit.Case # import PipeHere setup do config = TableConfig.get(1) table = Table.new(config) {:ok, table: table} end test "table is full ", %{table: table} do new_table = 1..table.config.allow_count |> Stream.map(&Player.new/1) |> Enum.reduce(table, fn p, acc -> Table.check_in(acc, p) end) assert new_table |> Table.is_full? end test "table has player", %{table: table} do p1 = Player.new(1) p2 = Player.new(2) new_table = Table.check_in(table, p1) assert Table.has_player?(new_table, p1.base_info.id) refute Table.has_player?(table, p2.base_info.id) end test "table check_in_and_out", %{table: table} do p1 = Player.new(1) new_table = Table.check_in(table, p1) check_out_table = Table.check_out(new_table, p1.base_info.id) refute Table.has_player?(check_out_table, p1.base_info.id) end end
下一小節會從牌局開始吧,而後TableServer,而後讓它跑起來。atom