今天我们可能可以来做一下回合,毕竟要算分数还是干嘛都是建立在回和上面。
目前我们的 game struct 长这样,已经有预留 round 跟 turn
%Game{
guest: %{desk: [], hand: [1, 1, 2, 2, 3, 3, 4, 5, 6, :turn, :turn], wins: 0},
host: %{desk: [1], hand: [1, 2, 2, 3, 3, 4, 5, 6, :turn, :turn], wins: 0},
round: 1,
turn: 1
}
这次要做的事情有
感觉这件事情是要放在出牌的方法里面
双方都出牌这个条件,应该是出完牌检查两个人的 desk 长度是不是一样
defp maybe_end_turn(%{guest: guest, host: host} = game) do
if length(guest.desk) == length(host.desk) do
Map.merge(game, %{turn: game.turn + 1})
else
game
end
end
elixir 在 module 定义 private 方法,就是只有在这个 module 里面才可以呼叫的方法,是用 defp
我们在这个 maybe_end_turn 方法的变数收 game struct
方法的结果也是回传 game struct
所以我们在 handle :play_card 方法里面可以这样子接
def handle_cast({:play_card, :host, card}, %{host: host} = game) do
game =
game
|> Map.replace(:host, play_card_helper(host, card))
|> maybe_end_turn()
{:noreply, game}
end
这里有一个新符号 |>
这个像三角形的东西叫 pipe operator ,可能要直接用范例比较好解释
defmodule MyMath do
def add_one(number) do
number + 1
end
end
今天我们有一个 add_one/1 方法,他收一个变数,并回传变数加一为结果
假如我要用 3 次
MyMath.add_one(MyMath.add_one(MyMath.add_one(1)))
或是
first_add = MyMath.add_one(1)
second_add = MyMath.add_one(first_add)
result = MyMath.add_one(second_add)
这两个写法都让人很烦躁,於是我们用 pipe operator 看看
1
|> MyMath.add_one()
|> MyMath.add_one()
|> MyMath.add_one()
在 |>
之後的方法的第一个变数,会自动填入 |>
左边的结果
所以如果原本有两个变数,串在 |>
里面的时候,只需要填第二个。
因为这样子写的时候配合适当的方法名称,读起来会像句子
水饺皮
|> 加馅(水饺馅)
|> 包起来
懂 pipe 之後我们再回来看
def handle_cast({:play_card, :host, card}, %{host: host} = game) do
game =
game
|> Map.replace(:host, play_card_helper(host, card))
|> maybe_end_turn()
{:noreply, game}
end
新的game =
旧的game
|> 出卡方法
|> 回合方法
感觉出卡方法应该可以在变得更清楚一些,像是
def handle_cast({:play_card, player, card}, game) do
game =
game
|> play_card_for(player, card)
|> maybe_end_turn()
{:noreply, game}
end
defp play_card_for(game, player, card) do
data =
game
|> Map.get(player)
|> then(&Map.merge(&1, %{hand: &1.hand -- [card], desk: &1.desk ++ [card]}))
Map.replace(game, player, data)
end
defp maybe_end_turn(%{guest: guest, host: host} = game) do
if length(guest.desk) == length(host.desk) do
Map.merge(game, %{turn: game.turn + 1})
else
game
end
end
整理完之後,在 handle_cast 里面只留下比较好读的方法名称,
细部的做法都丢进 private 方法中。
也顺便把两个 handle_cast :play_card 合成一个。
最後来 iex 试试看
我们这次进 iex 之後先 import Game
这样我们就可以直接呼叫 Game module 里面的方法
$ iex game.ex
iex(1)> import Game
Game
iex(2)> {:ok, pid} = start
{:ok, #PID<0.113.0>}
iex(3)> play_card pid, :host, 3
:ok
iex(4)> play_card pid, :guest, 4
:ok
iex(5)> status pid
%Game{
guest: %{desk: [4], hand: [1, 1, 2, 2, 3, 3, 5, 6, :turn, :turn], wins: 0},
host: %{desk: [3], hand: [1, 1, 2, 2, 3, 4, 5, 6, :turn, :turn], wins: 0},
round: 1,
turn: 2
}
成功了,双方都出牌之後,turn 就 + 1 了
round 留到明天好了哈哈,掰掰
<<: RISC V::中断与异常处理 -- PLIC 介绍
接下来的几篇文章,我们将要几乎可以说是软件架构模式始祖 ( 大概 ) 的这本书 : 企业应用架构模式...
ㄧ、资料前处理 1. 补值、删值 前面我们透过视觉化的方式找到资料有缺值,因此我们要将资料进行补值。...
随着新的科技环境变化, 资讯安全也会变得更多面向。 根据NIST(美国国家标准暨技术研究院)定义的电...
第一次出书新手上路,请多多指教 谢谢第十届我们的Diablo, the rest of the li...
django 基础篇 主要说明如何创建一个基本的 django 服务。 基本工具 env虚拟机 - ...