接上章,我新建了个app做包含Table模型, TableServer等。Table桌子的代码暂时如下, 有一些状态还没用上

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.exs

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,然后让它跑起来。

Elixir游戏服设计六的更多相关文章

  1. Elixir游戏服设计五

    在<Elixir游戏服设计一>里提到,按照系统功能划分成app要保证原子性很难, 现在想想也没那么难.保证原子性,无非就是需要某个单点去完成操作.那么选择玩家进程去做原子性工作就可以了. ...

  2. Elixir游戏服设计一

    在Erlang游戏服设计总结http://www.cnblogs.com/rubyist/p/5530575.html里, 我提到我想要的游戏服设计方法,希望以应用做为基础构建块.最近我在学习elix ...

  3. 简单Elixir游戏服设计- 游戏玩法介绍

    抄以前的,做了点修改. 到目前为止,我们完成了玩家的数据和进程建模,现在介绍游戏玩法. 为什么我们还不做客户端接入.协议指定呢?为什么还没有网关和数据存储呢.在我接手的游戏, 这些通常已经定下来了,我 ...

  4. Elixir游戏服设计三

    玩家进程用gen_server来建模,我不直接使用 use GenServer, 而是使用exactor,该库可以去掉反锁的接口定义. 我们新建一个 player_server_manager app ...

  5. 简单Elixir游戏服设计-玩家进程跑起来

    有了玩家模型,我们试试让玩家进程跑起来. 需要搞个PlayerSupervisor来负责启动和监控玩家进程. defmodule PlayerSupervisor do use Supervisor ...

  6. 关于Elixir游戏服设计系列

    写着写着就废球了,感觉空对空,实在没什么意思. 另外很快就要搞新项目,决定新项目就直接上elixir了.目前该做的准备工作已经探索了一些了. 以下的东西是写给同事参考的,感兴趣的可以看看,提建议更好. ...

  7. 简单Elixir游戏服设计-玩家进程注册

    上回说用Registry 做本地注册(跨服可以用syn,只是稍微麻烦点,需要模拟global注册机制,写个封装模块). 修改game_server 项目的mix.exs, 增加应用启动 def app ...

  8. Elixir游戏服设计四

    上章说到我们要引入syn https://github.com/ostinelli/syn/ 看过文档,它并没有直接提供{via, Module, Name} 相关的方法.我们需要封装一下. Name ...

  9. Elixir游戏服设计二

    搞一个例子,而没有实际的目标,做起来真是烦人.几次三番都想放弃. 后来想想,即使最后完成不了完整的服务器,把需要的知识点搞搞,摸熟悉也是好的. 这里没有完整的项目目录,主要是对需要的指点进行整理.要完 ...

随机推荐

  1. Apache2 httpd.conf 配置详解(一)

    常用配置指令说明 ServerRoot:服务器的基础目录,一般来说它将包含conf/和logs/子目录,其它配置文件的相对路径即基于此目录.默认为安装目录,不需更改. 语法:ServerRoot di ...

  2. 向GitHub 提交你的源代码

    之前的这篇文章「Git入门篇」相信大家都已经对 Git 的基本操作熟悉了,但是这篇文章只介绍了对本地 Git 仓库的基本操作,今天我就来介绍下如何跟远程仓库一起协作,教你们向 GitHub 上提交你们 ...

  3. 最近见到的JS返回函数的一些题

    JS返回值题一直都是考察重点,面试和笔试之中也经常涉及到,说一说我最近遇到的一些有意思的JS返回函数问题. 之前见到过一道有意思的问题,说有一个sum函数,用户可以通过sum(2,3)来取到2+3 = ...

  4. tween.js的使用

    前面的话 TweenJS提供了一个简单但强大的渐变界面.它支持渐变的数字对象属性&CSS样式属性,并允许链接补间动画和行动结合起来,创造出复杂的序列.本文将详细介绍tween.js的使用 概述 ...

  5. 编程零基础应当如何开始学习 Python?

    提前说一下,这篇福利多多,别的不说,直接让你玩回最有手感的怀旧游戏,参数贴图很方便自己可以根据喜好修改哦. 本篇通过以下四块展开,提供大量资源对应. 选一个好版本 有没有看过<在下坂本,有何贵干 ...

  6. Color.js增强你对颜色的控制

    往逝之因 不要低头,皇冠会掉...  可你又没有皇冠 Color.js 增强你对颜色的控制 阅读目录 轻松管理颜色--color.js库 使用color.js Accessor Methods 你该知 ...

  7. 对eigrp默认网络的理解!

    EIGRP 默认网络设置的个人总结 (了解即可) //该机制同rip和ospf的default-informationoriginate,原理相同,只是配置格式不同. //!!(唯一作用)该命令起到减 ...

  8. 软工+C(2017第5期) 工具和结构化

    // 上一篇:Alpha/Beta换人 // 下一篇:最近发展区/脚手架 工具/轮子 软件工程/计算机相关专业的一个特点是会使用到众多的工具,工具的使用是从程序猿进化到程序员的一个关键要素.软件工程师 ...

  9. 软工+C(2017第9期) 助教指南

    //上一篇:提问与回复 [备注]:请优先阅读 Handshake/点评/评分 三部分. 0x00 Handshake 了解<构建之法>作者参与软件工程改革的一些背景: http://www ...

  10. Swing-JPopupMenu弹出菜单用法-入门

    弹出菜单是GUI程序中非常常见的一种控件.它通常由鼠标右击事件触发,比如在windows系统桌面上右击时,会弹出一个包含“刷新”.“属性”等菜单的弹出菜单.Swing中的弹出菜单是JPopupMenu ...