14 实作出牌倒数 诶这是什麽放置游戏

实作出牌倒数计时

ok, 我们有两个地方需要开始计时
第一个是游戏开始的时候,
第二个是 turn 结束的时候。

  def init(game) do
    Process.send_after(self(), {:times_up, :host, 1, 1}, 3000) # 游戏开始的时候,开始倒数
    Process.send_after(self(), {:times_up, :guest, 1, 1}, 3000) # 一人一个
    {:ok, game}
  end

Process.send_after/3 的第一个变数是收 pid,
我们可以用 self() 来得到目前执行这个地方本身的 pid。
为了等一下好测试,我们先用 3 秒,而不是原本要的 30

再来是时间到了之後要执行的 handle_info :times_up

执行的时候要做的事情有

  1. 检查目前的游戏状态还是不是同个回合(turn):
    因为就算玩家出牌,这个超时自动出牌的要求也不会自动取消
    因此要在这边判断,如果回合已经换了,就是玩家有正常出牌,就不需要执行自动出牌
  2. 从玩家手牌中随机抽一张牌
  3. 代替玩家出牌,并执行正常的出牌程序
  4. 出牌後,为新回合执行出牌倒数

我直接按照列表直接做,变超长的,我把项目标示在下方注解里

  def handle_info(
        {:times_up, player, round, turn},
        %{round: current_round, turn: current_turn} = game
      )
      when round == current_round and turn == current_turn do
      # 这个 guard 用来实现 1.检查目前的游戏状态还是不是同个回合

      # 2.随机抽牌
    card =
      game
      |> Map.get(player)
      |> Map.get(:hand)
      |> Enum.random()

    # 我们暂时在这边用 IO.puts 来印出讯息,待会在 iex 跑的时候比较知道在跑啥
    IO.puts("time's up, play #{card} for #{player}")

    # 3.代替玩家出牌
    # 这个是直接从原本的出牌方法 handle_cast :play_card 复制过来的
    game =
      game
      |> play_card_for(player, card)
      |> end_turn()
      |> add_wins()
      |> end_round()
      |> end_game()

    # 4. 出牌後,为新回合执行出牌倒数
    # 这边判断如果 游戏还在进行,而且这次出牌有导致 换到新的 turn
    if game.status == :start && current_turn != game.turn do
      Process.send_after(self(), {:times_up, :host, game.round, game.turn}, 3000)
      Process.send_after(self(), {:times_up, :guest, game.round, game.turn}, 3000)
    end

    {:noreply, game}
  end

  # 如果玩家有出过牌了,就忽略
  def handle_info({:times_up, _player, _round, _turn}, game), do: {:noreply, game}

完成了,使用 GenServer 真的让这件事情简单很多

印出一些回馈来看游戏情况

除了上面在帮玩家出牌的时候有印出 帮谁出什麽牌之外
在 add_wins 方法,我也暂时用 IO.puts 显示谁赢一局,与目前比数

  defp add_wins(%{turn: turn, round: round, host: host, guest: guest} = game) when turn > 3 do
    range_start = (round - 1) * 3
    range = range_start..(range_start + 2)
    host_desk = Enum.slice(host.desk, range)
    guest_desk = Enum.slice(guest.desk, range)

    if apply_reverse(
         get_score(host_desk) > get_score(guest_desk),
         reverse?(host_desk ++ guest_desk)
       ) do
      IO.puts("? Host win this round, host: #{host.wins + 1}, guest: #{guest.wins}") # 显示该局结果
      assign_to_player(game, :host, :wins, game.host.wins + 1)
    else
      IO.puts("? Guest win this round, host: #{host.wins}, guest: #{guest.wins + 1}") # 显示该局结果
      assign_to_player(game, :guest, :wins, game.guest.wins + 1)
    end
  end

还有结束游戏的地方也加上通知

  defp end_game(%{guest: %{wins: 2}} = game) do
    IO.puts "? winner is Guest"
    Map.replace(game, :status, :guest_win)
  end
  defp end_game(%{host: %{wins: 2}} = game) do
    IO.puts "? winner is Host"
    Map.replace(game, :status, :host_win)
  end
  defp end_game(game), do: game

来跑跑看吧,这次只要打一行,因为我们暂时把出牌时间设定成 3 秒,就好像游戏自动玩一样

iex(1)> Game.start
{:ok, #PID<0.112.0>}
time's up, play 3 for host
time's up, play reverse for guest
time's up, play 6 for host
time's up, play 3 for guest
time's up, play reverse for host
time's up, play 3 for guest
? Host win this round, host: 1, guest: 0
time's up, play reverse for host
time's up, play 1 for guest
time's up, play 5 for host
time's up, play reverse for guest
time's up, play 1 for host
time's up, play 5 for guest
? Host win this round, host: 2, guest: 0
? winner is Host

执行动图
https://ppt.cc/fY35lx@.gif


<<:  Day-14 TableLayout

>>:  每日挑战,从Javascript面试题目了解一些你可能忽略的概念 - Day13

DAY24 - 利用 uptime 让你的 Heroku 永不休眠

上一篇成功将 Nestjs 部属到 heroku 上面,不过我们使用的是免费方案,免费方案有几个限制...

Day2 一切都从Shioaji API开始

Shioaji 是一个建构在永丰金证券上所开发的API,让原本是用人操作的App功能,独立出来让程...

JavaScript Day 26. API 串接:POST、GET、DELETE、PUT/PATCH

前面几篇我们提到过 DOM API 节点,但貌似没有讨论到什麽是 API;到了今天这个主题,好像确实...

Day 22 - Blocking & Non-blocking Mode

本篇重点 官方说明文件:https://sinotrade.github.io/tutor/adva...

Day21:【TypeScript 学起来】Generics 泛型

是说在社群到处都在爆雷的《鱿鱼游戏》,我进度第一集,好想弃赛来追剧(我就废 然後谢谢没看鱿鱼游戏,...