elixir

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

不打扰是莪最后的温柔 提交于 2019-12-09 22:37:33
原文 学习一门新的语言或框架,最好的方法就是做一些小项目。Elixir和Phoenix很适合用来做扑克应用。 洗牌 我们要做的是德州扑克,首先,需要牌组: defmodule Poker.Deck do defmodule Card do defstruct [:rank, :suit] end def new do for rank <- ranks, suit <- suits do %Card{rank: rank, suit: suit} end |> Enum.shuffle end defp ranks, do: Enum.to_list(2..14) defp suits, do: [:spades, :clubs, :hearts, :diamonds] end 我们定义了一个能够给出一套洗好了的52张牌的new函数。for结构非常适合做这种数值与花色的组合。 有趣的模式匹配 defmodule Poker.Ranking do def evaluate(cards) do cards |> Enum.map(&to_tuple/1) |> Enum.sort |> eval end defp to_tuple( %Poker.Deck.Card{rank: rank, suit: suit} ), do: {rank, suit} defp eval( [{10,

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

半腔热情 提交于 2019-12-09 22:37:23
原文 现在我们已经做好了牌面大小的比较,游戏的流程,但还没有做玩家登陆,人数限制,甚至没有将奖金发送给赢家。接下来,让我们来完成它们。 玩家需要兑换游戏中的筹码才能开始游戏,在当不在游戏过程时,可以兑换筹码。 我们引入了两个新的进程。 银行 首先我们将建立一个银行,玩家可以在这里进行现金和筹码的相互转换。 银行GenServer会有两个API, deposit/2 和withdraw/2: defmodule Poker.Bank do use GenServer def start_link do GenServer.start_link(__MODULE__, [], name: __MODULE__) end def deposit(player, amount) do GenServer.cast(__MODULE__, {:deposit, player, amount}) end def withdraw(player, amount) do GenServer.call(__MODULE__, {:withdraw, player, amount}) end end 我们用模块名注册了这个进程,这样我们就不需要知道它的pid,就能进行访问了: def init(_) do {:ok, %{}} end def handle_cast({:deposit, player

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

扶醉桌前 提交于 2019-12-09 22:18:38
今天我们将为德州扑克游戏添加故障恢复能力。 OTP为我们准备好了构建容错程序所需要的工具。我们只需要定义正确的behavior 行为。 Supervisor 有了Supervisor,我们就只需要关心当进程崩溃时如何反应。首先,我们使用顶层的Supervisor——Application: defmodule GenPoker do use Application def start(_type, _args) do import Supervisor.Spec children = [ worker(Poker.Bank, []) ] opts = [strategy: :one_for_one, name: GenPoker.Supervisor] Supervisor.start_link(children, opts) end end 在mix.exs中注册我们的应用模块: def application do [mod: {GenPoker, []}] end 当工作中的进程崩溃后,会新建一个新的进程,打开 iex -S mix 测试一下: iex(1)> Process.whereis(Poker.Bank) #PID<0.93.0> iex(2)> Process.whereis(Poker.Bank) |> Process.exit(:kill) true iex

Lazy list comprehension in Elixir?

那年仲夏 提交于 2019-12-09 17:37:08
问题 Is there a way to make list comprehension lazy in Elixir? If not, is there a way to turn this into a Stream ? my_list = for i <- (1..1000000), j <- (1..1000000), do: {i, j} This code snippet blows my program by taking too much memory. I want to apply a filter, map and reduce on my_list. 回答1: A comprehension is a flat map. So your code is equivalent to: Stream.flat_map 1..1000000, fn i -> Stream.flat_map 1..1000000, fn j -> [{i, j}] end end I have proposed a "stream for" and "parallel for" for

How to create a Global Variable in elixir Module

半世苍凉 提交于 2019-12-09 16:35:51
问题 I have the following code in elixir: def get_trackerid(imei) do client = get_new_client() {:ok, result} = :cqerl.run_query(client, "SELECT * FROM trackers_by_imei where imei = \'#{imei}\';") row = :cqerl.all_rows(result) end Now, now many functions are calling get_trackerid function and everytime the function is called, a call to database is made. Is there a way to write a function in elixir such the result is stored in a local variable. So, when the next time trackerid for the same imei is

Can Go spawn and communicate with external processes without starting one OS-thread per external process?

北战南征 提交于 2019-12-09 15:41:44
问题 Short version: Is it possible in Golang to spawn a number of external processes (shell commands) in parallel , such that it does not start one operating system thread per external process ... and still be able to receive its output when it is finished? Longer version: In Elixir, if you use ports, you can spawn thousands of external processes without really increasing the number of threads in the Erlang virtual machine. E.g. the following code snippet, which starts 2500 external sleep

Making a field unique in ecto

天大地大妈咪最大 提交于 2019-12-09 14:00:35
问题 How to make a field unique in ecto? I thought it's the same as the active record in Ruby, but it seems it isn't 回答1: You want to use unique_constraint/3. This is not like Active Record because it is using the database to ensure uniqueness. Active Record would do a query for records with the same value and if any were returned then it would fail. This has a race condition where, if a value is inserted between fetching to check uniqueness and inserting your record, you will either end up with

Elixir macros and bind_quoted

时光总嘲笑我的痴心妄想 提交于 2019-12-09 11:30:02
问题 I have a macro that defines a module like so. defmodule Bar do def bar do IO.puts "I am #{inspect __MODULE__}" end end defmodule MacroFun do defmacro define_module(name) do quote do defmodule unquote(name) do import Bar def foo do bar IO.puts "I am #{inspect __MODULE__}" end end end end end defmodule Runner do require MacroFun def run do MacroFun.define_module Foo Foo.foo end end Runner.run The output of running this is: I am Bar I am Runner.Foo Which makes sense; MacroFun.define_module was

Proper way to use different Layouts for Templates in Phoenix

人走茶凉 提交于 2019-12-09 11:12:31
问题 Is the proper/simplest way to change the Layout of a Template to use the put_layout method within each Controller action? A simple example of wanting a different Layout for different Controllers seems to become very repetitive (below) so it feels like I'm missing something within the framework. defmodule MyPhoenix.AController do use MyPhoenix.Web, :controller def pageOne(conn, _params) do conn |> put_layout("LayoutA.html") |> render "page1.html" end def pageTwo(conn, _params) do conn |> put

Ecto association with a condition

白昼怎懂夜的黑 提交于 2019-12-09 08:54:08
问题 Let's say I have two models, Post and Comment and the comment model can be 1 out of 2 types, normal and fancy which is defined by the column type in the comments table. Now I want to add 2 associations on my Post model, where one refers to fancy comments and one to normal ones, how would I do it? So I want something like this: has_many :fancy_comments, MyApp.Comment, where: [type: 0] has_many :normal_comments, MyApp.Comment, where: [type: 1] 回答1: This is not available in Ecto, there is a