簡單Elixir遊戲服設計-使table測試經過

error_msg.ex  使用了點宏git

(廢了點時間,一致在嘗試抹初那段for,想直接定義個工具宏, 因爲生疏了沒能很快成功,服務器

好在for的代碼也很簡短,而實際上從csv生成的話,也是要作循環工做,算是安慰)ide

defmodule ErrorMsg do
    @msgs %{
        player_not_enough: "player_not_enough",
        can_not_start_when_playing: "can_not_start_when_playing",
        can_not_dismiss_when_playing: "can_not_dismiss_when_playing",
        just_creator_can_start: "just_creator_can_start",
        just_creator_can_dismiss: "just_creator_can_dismiss",
        can_not_join_when_playing: "can_not_join_when_playing",
        repeated_join: "repeated_join",
        can_not_quit_when_playing: "can_not_quit_when_playing",
        can_not_quit_when_creator: "can_not_quit_when_creator",
        can_not_make_up_when_not_playing: "can_not_makeup_when_not_playing",
        can_not_make_up_when_open: "can_not_make_up_when_open",
        can_not_make_up_when_full: "can_not_make_up_when_full",
        just_tian_gong_can_open: "just_tian_gong_can_open",
        repeated_open: "repeated_open"
    }

    for {tag, text} <- @msgs do
        def unquote(tag)() do
            unquote text
        end
    end


end
error_msg.ex

錯誤消息也能夠從外部文件生成,只是系列自己主要演示基礎服務器開發,所以就不進一步了。工具

我曾經在博客裏有寫過方案從excel直接生成測試

(不過如今不建議了,該方案依賴的excel處理庫不夠好, 建議轉成csv,再從csv生成更好)ui

simple_table.ex 新增的使測試經過的代碼spa

defmodule SimpleTable do
    @state_ready  :ready
    @state_playing :playing
    @state_dismiss :dismiss
    def init() do
        %{
            id: 0,
            cards: nil,
            creator: nil,
            seat_map: %{},
            seat_order: [],
            state: @state_ready
        }
    end

    def is_playing?(table), do: table.state == @state_playing
    def is_dismiss?(table), do: table.state == @state_dismiss
    def is_ready?(table), do: table.state == @state_ready

    def set_playing(table), do: put_in(table.state, @state_playing)
    def set_ready(table), do: put_in(table.state, @state_ready)
    def set_dismiss(table), do: put_in(table.state, @state_dismiss)


    def set_cards(table, cards), do: put_in(table.cards, cards)
    def get_cards(table), do: table.cards

    def init_deal(table) do
        table.seat_order
        |> Enum.map(&(find_seat(table, &1)))
        |> Enum.reduce(table, 
            fn seat, new_table ->
                new_table |> init_deal_one(seat)
            end)
    end

    def init_deal_one(table, seat) do
        {:ok, cards, left} = SimplePoker.init_deal(table.cards)
        seat = seat |> Seat.add_cards(cards)
        table |> update_seat(seat)
              |> set_cards(left)
    end

    def set_id(table, id), do: put_in(table.id, id)
    def get_id(table), do: table.id

    def set_creator(table, player), do: put_in(table.creator, player)
    def get_creator(table), do: table.creator
    
    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 = table |> update_seat(seat)
        add_to_order(table, seat_id)
    end

    def update_seat(table, seat), do: put_in(table.seat_map[seat |> Seat.get_id], seat)

    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

    def start(table, player) do
        cond do
            is_playing?(table) -> {:error, ErrorMsg.can_not_start_when_playing}
            seat_count(table) < 2 -> {:error, ErrorMsg.player_not_enough}
            not is_creator?(table, player) -> {:error, ErrorMsg.just_creator_can_start}
            true ->
                table = table |> set_playing
                {:ok, table}
        end
    end

    def quit(table, player) do
        cond do
            is_playing?(table) -> {:error, ErrorMsg.can_not_quit_when_playing}
            is_creator?(table, player) -> {:error, ErrorMsg.can_not_quit_when_creator}
        end
    end
    
    def dismiss(table, player) do
        cond do
            is_playing?(table) -> {:error, ErrorMsg.can_not_dismiss_when_playing}
            not is_creator?(table, player) -> {:error, ErrorMsg.just_creator_can_dismiss}
            true ->
                table = table |> set_dismiss
                {:ok, table}
        end
    end

    def make_up(table, player) do
        cond do
            is_ready?(table) -> {:error, ErrorMsg.can_not_make_up_when_not_playing}
            find_seat(table, player) |> Seat.is_open? -> {:error, ErrorMsg.can_not_make_up_when_open}
            find_seat(table, player) |> Seat.is_full? -> {:error, ErrorMsg.can_not_make_up_when_full}
        end
    end

    def join(table, player) do
        cond do
            is_playing?(table) -> {:error, ErrorMsg.can_not_join_when_playing}
            find_seat(table, player) -> {:error, ErrorMsg.repeated_join}
            true -> 
                table = table |> add_seat(player)
                {:ok, table}
        end
    end

    def open(table, player) do
        cond do
            find_seat(table, player) |> Seat.is_open? -> {:error, ErrorMsg.repeated_open}
            not (find_seat(table, player) |> Seat.get_cards |> SimplePoker.can_be_tian_gong?) -> {:error, ErrorMsg.just_tian_gong_can_open}
        end
    end


    def is_creator?(table, player), do: table.creator |> Player.get_id == player |> Player.get_id

end
simple_table.ex

測試果真發現須要調整,分解測試仍是須要當心。3d

好在有測試的話,很容易就發現問題。這大概是測試的好處了吧。excel

還有其餘的小改動, seat.ex  simple_poker.excode

具體看git吧

果真,寫代碼比寫測試快得多, 看着測試一個一個經過,仍是挺享受的。

另外,看代碼 join 和 quit 的cond 語句少了true, 顯然說明咱們的測試還沒覆蓋到!!!!

測試使代碼更容易編寫,代碼又輔助發現測試不足。相輔相成。

相關文章
相關標籤/搜索