zoukankan      html  css  js  c++  java
  • 简单Elixir游戏服设计-使table测试通过

    error_msg.ex  使用了点宏

    (废了点时间,一致在尝试抹初那段for,想直接定义个工具宏, 由于生疏了没能很快成功,

    好在for的代码也很简短,而实际上从csv生成的话,也是要做循环工作,算是安慰)

    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生成更好)

    simple_table.ex 新增的使测试通过的代码

    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

    测试果然发现需要调整,分解测试还是需要小心。

    好在有测试的话,很容易就发现问题。这大概是测试的好处了吧。

    还有其他的小改动, seat.ex  simple_poker.ex

    具体看git吧

    果然,写代码比写测试快得多, 看着测试一个一个通过,还是挺享受的。

    另外,看代码 join 和 quit 的cond 语句少了true, 显然说明我们的测试还没覆盖到!!!!

    测试使代码更容易编写,代码又辅助发现测试不足。相辅相成。

  • 相关阅读:
    缓存---缓存位置
    缓存---LRU算法实现
    缓存---缓存特征
    Redis---分片
    Redis---复制
    Redis---事件
    Redis---事务
    Redis---持久化
    javaSript 处理电脑和浏览器pc端缩放对页面的影响
    css设置不可复制
  • 原文地址:https://www.cnblogs.com/rubyist/p/7661250.html
Copyright © 2011-2022 走看看