文档章节

(整理)用Elixir做一个多人扑克游戏 4

ljzn
 ljzn
发布于 2016/10/06 21:59
字数 435
阅读 80
收藏 0

sockets 和 channels 是Phoenix中用来实现实时效果的两大工具。

Sockets

socket是用来连接客户端与服务器的,它使用endpoint来声明:

defmodule GenPoker.Endpoint do
  use Phoenix.Endpoint, otp_app: :gen_poker

  socket "/socket", GenPoker.PlayerSocket
end

Channels

客户端只有加入了channel之后才能发送消息。

defmodule GenPoker.PlayerSocket do
  use Phoenix.Socket

  channel "tables:*", GenPoker.TableChannel
end

创建socket

defmodule GenPoker.PlayerSocket do
  use Phoenix.Socket

  transport :websocket, Phoenix.Transports.WebSocket

  def connect(%{"playerId" => player_id}, socket) do
    {:ok, assign(socket, :player_id, player_id)}
  end

  def id(socket) do 
    "players_socket:#{socket.assigns.player_id}"
  end
end

注册进程

defmodule Poker.Table do
  use GenServer

  def start_link(table_name, sup, storage, num_seats) do
    GenServer.start_link(
      __MODULE__, 
      [table_name, sup, storage, num_seats], 
      name: via_tuple(table_name)
    )
  end

  defp via_tuple(table) do 
    {:via, :gproc, {:n, :l, {:table, table}}}
  end

  def whereis(table) do
    :gproc.whereis_name({:n, :l, {:table, table}})
  end
end

我们使用了gproc库来注册进程,这样就可以使用一个term而不仅仅是atom作为名字。让我们来定义Channel:

module GenPoker.TableChannel do
  use GenPoker.Web, :channel
  alias Poker.Table

  def join("tables:" <> table, _payload, socket) do
    {:ok, assign(socket, :table, table)}
  end

  def handle_in(command, payload, socket) 
    when command in ~w(sit leave buy_in cash_out deal) 
  do
    table = Table.whereis(socket.assigns.table)
    arguments = [table, socket.assigns.player_id] ++ payload
    result = apply(Table, String.to_atom(command), arguments)
    if result == :ok do
      broadcast! socket, "update", Table.get_state(table)
    end
    {:reply, result, socket}
  end
end

对于客户端的join请求,我们有不同的回复。在JavaScript中可以这样写:

channel.push("message", arguments)
  .receive("ok", (msg) => console.log("Got OK!"))
  .receive("error", (msg) => console.log("Oops!"))

发送初始的state

def join("tables:" <> table, _payload, socket) do
  state = table |> Table.whereis |> Table.get_state
  push socket, "update", state
  {:ok, assign(socket, :table, table)}
end

使用handle_info

def join("tables:" <> table, _payload, socket) do
  send self, :after_join
  {:ok, assign(socket, :table, table)}
end

def handle_info(:after_join, socket) do
  state = socket.assigns.table |> Table.whereis |> Table.get_state
  push socket, "update", state
  {:noreply, socket}
end

def handle_info(_, socket) do
  {:noreply, socket}
end

拦截消息

def handle_out("update", state, socket) do
  push socket, "update", hide_other_hands(state, socket)
  {:noreply, socket}
end

defp hide_other_hands(state, socket) do
  player_id = socket.assigns.player_id
  hide_hand_if_current_player = fn
    %{id: ^player_id} = player -> player
    player -> Map.delete(player, :hand)
  end

  update_in(state.players, fn players ->
    Enum.map(players, hide_hand_if_current_player)
  end)
end

完整代码

© 著作权归作者所有

共有 人打赏支持
ljzn
粉丝 29
博文 69
码字总数 96245
作品 0
南平
程序员
(整理)用Elixir做一个多人扑克游戏 2

原文 现在我们已经做好了牌面大小的比较,游戏的流程,但还没有做玩家登陆,人数限制,甚至没有将奖金发送给赢家。接下来,让我们来完成它们。 玩家需要兑换游戏中的筹码才能开始游戏,在当不...

ljzn
2016/10/04
22
0
(整理)用Elixir做一个多人扑克游戏 1

原文 学习一门新的语言或框架,最好的方法就是做一些小项目。Elixir和Phoenix很适合用来做扑克应用。 洗牌 我们要做的是德州扑克,首先,需要牌组: 我们定义了一个能够给出一套洗好了的52张...

ljzn
2016/10/03
524
2
(整理)用Elixir做一个多人扑克游戏 3

今天我们将为德州扑克游戏添加故障恢复能力。 OTP为我们准备好了构建容错程序所需要的工具。我们只需要定义正确的behavior 行为。 Supervisor 有了Supervisor,我们就只需要关心当进程崩溃时...

ljzn
2016/10/05
38
0
独家首发 | NIPS 最佳论文视频解读!德州扑克背后的不完全信息博弈

美国时间, 2017 年 12 月 4 日 8:00。 全球机器学习顶级会议 NIPS 在美国长滩开幕了。 本年度 NIPS 将持续一周,你现在才想参加肯定来不及,因为票早就卖光了。 为了让你隔着太平洋都能跟上...

雷锋字幕组
2017/12/05
0
0
17年的人工智能承包了我们所有的游戏?!

  【IT168 资讯】在20世纪的大部分时间里,国际象棋博弈都是人工智能研究人员的基准。约翰・麦卡锡(John McCarthy)在20世纪50年代早期创造了“人工智能”一词,曾经把国际象棋称为“人工智...

it168网站
01/05
0
0

没有更多内容

加载失败,请刷新页面

加载更多

一切都靠大数据:滴滴已封禁4.3万人员、车辆

这段时间以来,滴滴出行相继出炉了各种整改措施,包括自身安全建设和外部社会共建,昨日就刚刚宣布正在筹备建立安全监督顾问委员会。 据媒体最新报道,9月30日,上海市交通委员会执法总队、上...

linuxCool
36分钟前
2
0
awk命令用法介绍

10月18日任务 9.6/9.7 awk 1.awk(上)(下) 1.awk 分段操作功能 指定分隔符,并把第一段打印出来,不会改动文件内容 将所有内容打印出来 awk 没有指定分隔符号,则会默认用空格或者空白字符...

hhpuppy
今天
4
0
Spring Cloud Eureka Server高可用之:在线扩容

本文共 1591字,阅读大约需要 6分钟 ! 概述 业务微服务化以后,我们要求服务高可用,于是我们可以部署多个相同的服务实例,并引入负载均衡机制。而微服务注册中心作为微服务化系统的重要单元...

CodeSheep
今天
2
0
内网esxi主机上安装CoreOS虚拟机

CoreOS是一个为专门运行容器而设计的轻量级linux发行版,旨在通过轻量的系统架构和灵活的应用程序部署能力简化数据中心的维护成本和复杂度。它没有包管理工具,运行容器化应用以提供服务;默...

hiwill
今天
1
0
20181018 上课截图

![](https://oscimg.oschina.net/oscnet/49f66c08ab8c59a21a3b98889d961672f30.jpg) ![](https://oscimg.oschina.net/oscnet/a61bc2d618b403650dbd4bf68a671fabecb.jpg)......

小丑鱼00
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部