[WIP] Elixir로 Blackjack CLI 게임 만들기

100일의 코드 중 6일차



오늘 나는 엘릭서로 쓴 내 Blackjack CLI 작업을 할 수 있었습니다. 모양이 갖춰지기 시작했지만 아직은 약간 부족한 느낌입니다. 간단한 데모는 다음과 같습니다.



사용자 경험 업데이트



먼저 주어진 카드의 값을 계산하는 함수 세트를 만들기 위해 함수에서 엘릭서의 패턴 매칭을 활용했습니다.

defmodule Card do
  ...
  def value(%{value: "J"}), do: 10
  def value(%{value: "Q"}), do: 10
  def value(%{value: "K"}), do: 10
  def value(%{value: "A"}), do: 11
  def value(%{value: value}), do: value
  ...
end


다음으로 흰색 배경을 추가하고 슈트에 따라 카드를 칠하여 카드 표시에 플래시를 추가했습니다.

defmodule Card do
  ...
  def display(%{suit: suit, value: value}) do
    IO.ANSI.color_background(15) <> IO.ANSI.color(color_code(suit)) <> "#{suit}#{value}" <> IO.ANSI.reset()
  end

  defp color_code("♥"), do: 9
  defp color_code("♦"), do: 9
  defp color_code("♣"), do: 0
  defp color_code("♠"), do: 0
end


내가 추가한 또 다른 플레어는 Deck @suits 상수를 각 수트에 대한 유니코드 아이콘으로 바꾸는 것이었습니다. 당신이 아는 작은 것들입니까?

이제 게임 모듈의 변경 사항을 살펴보겠습니다.

defmodule Game do
  # Added the "finished_players" attribute to the %Game struct. When a user
  # finishes their turn, they will be removed from the players list and placed
  # into the finished_players list.
  defstruct players: [%Player{name: "player_one"}, %Player{name: "dealer"}], cards: Deck.generate(), finished_players: []

  # After all users are removed from the players list, we can pattern match on
  # an empty players attr and finish the game.
  def play(%{players: []} = game) do
    game |> inspect_table()
  end

  # If there are still players, the play function logic will be a little
  # different, but with the pipe operator its pretty easy to follow.
  def play(game) do
    game
    |> deal()
    |> inspect_table()
    |> turn()
    |> play
  end

  # To handle a players turn, we just ask them if they want to Hit or Stay, and
  # build a new game struct accordingly.
  def turn(%{players: [current | players]} = game) do
    IO.puts "\n#{current.name} your move."
    case IO.gets("(H)it or (S)tay\n") |> String.downcase |> String.trim do
      "hit" -> deal_card(game, current)
      "h" -> deal_card(game, current)
      "stay" -> %{game | players: players, finished_players: [current | game.finished_players]}
      "s" -> %{game | players: players, finished_players: [current | game.finished_players]}
      _ -> game
    end
  end

  # Inspecting the table clears out the terminal, then displays info about for
  # the current state of the game
  defp inspect_table(%{players: players, finished_players: f_players} = game) do
    IO.write IO.ANSI.reset() <> IO.ANSI.clear() <> IO.ANSI.home()
    if length(players) == 0 do
      IO.puts "Game Over."
    end
    for player <- f_players ++ players do
      IO.puts "#{player.name}'s\n  hand: #{Player.display_hand(player)} |  #{player.total}"
    end
    game
  end
end


딜러 로직 구현



일반 블랙잭에서는 17개 미만이면 거래가 성사되어야 합니다. %Player{name: "dealer"}%Dealer 구조체로 교체하기로 결정했습니다. 이를 통해 다음과 같이 보이는 Game.turn/1 함수에 패턴 일치를 다시 사용할 수 있습니다.

  def turn(%{players: [%Dealer{} = dealer | players]} = game) do
    cond do
      dealer.total >= 17 -> %{game | players: players, finished_players: [dealer | game.finished_players]}
      true -> deal_card(game, dealer)
    end
    |> inspect_table()
    |> (fn (game) ->
      IO.gets("Press enter to continue.")
      game
    end).()
  end


무엇 향후 계획?



Blackjack CLI를 끝내려면 Ace를 처리해야 합니다. 에이스는 1 또는 11의 값을 가질 수 있습니다. 어렵지는 않지만 시간이 좀 걸릴 수 있습니다. 그 외에 플레이할 수 있는 데크 수를 선택하고, 게임을 재생성하기 전에 데크의 일정 비율로 플레이하는 것이 좋을 것입니다.

나는 아마도 elixirschool.com의 고급 섹션으로 이동하고 나중에 이 저장소로 돌아올 것입니다.

나를 따라 @



|

좋은 웹페이지 즐겨찾기