11 发动回转卡!

再加入 回转功能卡 进入胜利判断之前
我想整理一下判断胜利相关的方法

每天都发现昨天写的很恶

目前是否执行 结束回合是由 maybe_end_round 方法的 guard 判断当下 turn 是否大於 3 来决定的
我想与其把判断胜利放在 maybe_end_round 里面,不如我放在 maybe_end_round 前面,也由 turn 是否大於 3 来决定
看看有没有比较好用。

把原本从 compare_score/3 开头的方法改成下面

  defp maybe_add_wins(%{turn: turn} = game) when turn > 3 do
    scores = calculate_score(game)

    if scores.host > scores.guest do
      assign_to_player(game, :host, :wins, game.host.wins + 1)
    else
      assign_to_player(game, :guest, :wins, game.guest.wins + 1)
    end
  end

  defp maybe_add_wins(game), do: game

  defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
    [host_score, guest_score] =
      [host_desk, guest_desk]
      |> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
      |> Enum.map(&Enum.sum(&1))

    %{host: host_score, guest: guest_score}
  end

现在 handle_cast :play_card 方法多了拉到这个层级的 maybe_add_wins 方法

  def handle_cast({:play_card, player, card}, game) do
    game =
      game
      |> play_card_for(player, card)
      |> maybe_end_turn()
      |> maybe_add_wins()
      |> maybe_end_round()

    {:noreply, game}
  end

每个都 maybe 好像有点瞎,都拿掉好了

  def handle_cast({:play_card, player, card}, game) do
    game =
      game
      |> play_card_for(player, card)
      |> end_turn()
      |> add_wins()
      |> end_round()

    {:noreply, game}
  end

加入 回转卡

我现在才发现我在 struct 把回转卡叫 :turn ,跟回合的 turn 好像有点撞到,
改成 :reverse 又很长,不过为了避免各种误会还是改一下好了

initial_hand = [1, 1, 2, 2, 3, 3, 4, 5, 6, :reverse, :reverse]

因为我们在计算分数是用加的
所以要再计算前把 reverse 拿掉

应该是放在这个计算方法

  defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
    [host_score, guest_score] =
      [host_desk, guest_desk]
      |> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
      |> Enum.map(&挡掉(:reverse))
      |> Enum.map(&Enum.sum(&1))

    %{host: host_score, guest: guest_score}
  end

我们可以用 Enum.reject(enumerable, fun) 方法

Enum.reject([1, 2, :reverse], fn card -> card == :reverse end)

就变成

  defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
    [host_score, guest_score] =
      [host_desk, guest_desk]
      |> Enum.map(&Enum.slice(&1, (round - 1)..(round * 3 - 1)))
      |> Enum.map(&Enum.reject(&1, fn card -> card == :reverse end))
      |> Enum.map(&Enum.sum(&1))

    %{host: host_score, guest: guest_score}
  end

再来是 :reverse 的效果是可以叠加的
我出一张 :reverse 你出一张 :reverse 的效果会抵销 依此类推

我猜可能要先数 :reverse 有几张,偶数就用没事,
奇数就在比较分数的时候用一下 not 方法

not(true) #=> false
not(host_score > guest_score)

於是判断是不是 host 赢的地方被我加了一个 apply_reverse/2 来决定要不要套用 not

  defp add_wins(%{turn: turn} = game) when turn > 3 do
    scores = calculate_score(game)

    if apply_reverse((scores.host > scores.guest), scores.reverse) do
      assign_to_player(game, :host, :wins, game.host.wins + 1)
    else
      assign_to_player(game, :guest, :wins, game.guest.wins + 1)
    end
  end

  defp apply_reverse(compare, true), do: not(compare)
  defp apply_reverse(compare, false), do: compare

至於这局要不要 套用我目前把做法放进 calculate_score 他有我们这次所需要的数值们,
很显然的,这又让calculate_socre这个方法做太多事了,没关系我们先把作法变出来

  defp calculate_score(%{host: %{desk: host_desk}, guest: %{desk: guest_desk}, round: round}) do
    [host_cards, guest_cards] =
      Enum.map([host_desk, guest_desk], &Enum.slice(&1, (round - 1)..(round * 3 - 1)))

    [host_score, guest_score] =
      [host_cards, guest_cards]
      |> Enum.map(&Enum.reject(&1, fn card -> card == :reverse end))
      |> Enum.map(&Enum.sum(&1))

    reverse =
      [host_desk, guest_desk]
      |> Enum.map(&Enum.filter(&1, fn card -> card == :reverse end))
      |> List.flatten()
      |> length()
      |> rem(2) == 1

    %{host: host_score, guest: guest_score, reverse: reverse}
  end

在利用 slice 取得当前这局双方的卡後,除了使用 reject 去掉 :reverse 继续算分数外
还有用他们套进 filter 取出所有的 :reverse,用 flatten 把它们混再一起後
算长度除 2 在比比看 是不是 1,就可以得到这局要不要 reverse

最後在 iex 试玩一下
现在试玩的步骤变得超长到我想要写个脚本...

iex(1)> import Game
Game
iex(2)> {:ok, pid} = start
{:ok, #PID<0.113.0>}
iex(3)> play_card pid, :host, 1
:ok
iex(4)> play_card pid, :guest, 2
:ok
iex(5)> play_card pid, :host, :reverse
:ok
iex(6)> play_card pid, :guest, :reverse
:ok
iex(7)> play_card pid, :host, :reverse 
:ok
iex(8)> play_card pid, :guest, 3       
:ok
iex(9)> status pid
%Game{
  guest: %{
    desk: [2, :reverse, 3],
    hand: [1, 1, 2, 3, 4, 5, 6, :reverse],
    wins: 0
  },
  host: %{
    desk: [1, :reverse, :reverse],
    hand: [1, 2, 2, 3, 3, 4, 5, 6],
    wins: 1
  },
  round: 2,
  turn: 1
}

<<:  DAY 13- 《公钥密码》-RSA(1)

>>:  Day 0x18 UVa10415 Eb Alto Saxophone Player

30天程序语言研究

今天是30天程序语言研究的第十八天,由於深度学习老师多让我们上了python的进阶课程里面包括之前没...

Day 7:AWS是什麽?30天从动漫/影视作品看AWS服务应用 -《PSYCHO-PASS心灵判官》part1

提到健康监控系统,就不可不提鼎鼎大名的《PSYCHO-PASS心灵判官》中的希必拉系统Sibyl S...

Day-5 谁是最棒的狗勾

谁是最棒的狗勾 tags: IT铁人 效能的定义 生活中很常对各种东西做出比较,哪本书比较好看、哪个...

Day_06 无线转有线

了解完套件更新的地方後,再回来玩其他的网路架构。依照day04的架构,严格说来树梅派wifi连上的其...

[Day 26] Edge Impulse + BLE Sense也能感受彩色的人生

在 [Day 20],[Day 21],[Day 22] 介绍了「Edge Impulse + BL...