게임 리팩토링

우리의 게임은 거의 완성되었습니다(적어도 일부는). 하지만 모듈 게임을 개선하고 함께 할 수 있습니다.

시작하자...

나는 우리 게임의 논리를 풀기 위해 수학적 접근 방식으로 무언가를 찾고 있는 모듈식 산술을 찾았습니다(주제에 관심이 있다면 살펴보십시오here ).

이제 모듈식 산술을 사용하여 코드에 몇 가지 수학을 추가합니다. 그리고 코드를 더 밝고 깔끔하게 만드십시오.

수학적 접근



mod 함수는 한 정수를 다른 정수로 나눈 나머지를 제공합니다. 그리고 가위바위보의 세 가지 선택 사이의 순환 관계에 도움이 될 것입니다.

r = a mod b
r is the remainder when a is divided by b


따라서 코드, 특히 모듈 특성에 대해 살펴보겠습니다.

  @stone 1
  @paper 2
  @scissor 3


미적분을 보다 효율적으로 만드는 데 도움이 되는 팁을 보았습니다.

(first_player_choice - second_player_choice) % 3


게임 리팩토링



게임 결과를 계산하는 기능 추가game_calc :

defmodule Game do
  @moduledoc """
  Documentation for `Game`.
  """

  @stone 1
  @paper 2
  @scissor 3

  def play(first_player_choice, second_player_choice) do
    result(first_player_choice, second_player_choice)
  end

  defp result(first_player_choice, second_player_choice) do
    cond do
      first_player_choice == second_player_choice ->
        {:ok, "Draw!"}

      first_player_choice == @scissor && second_player_choice == @paper ->
        {:ok, "First player win!!!"}

      first_player_choice == @paper && second_player_choice == @stone ->
        {:ok, "First player win!!!"}

      first_player_choice == @stone && second_player_choice == @scissor ->
        {:ok, "First player win!!!"}

      first_player_choice == @paper && second_player_choice == @scissor ->
        {:ok, "Second player win!!!"}

      first_player_choice == @stone && second_player_choice == @paper ->
        {:ok, "Second player win!!!"}

      first_player_choice == @scissor && second_player_choice == @stone ->
        {:ok, "Second player win!!!"}
    end
  end

  defp game_calc(first_player_item, second_player_item) do
    rem(first_player_item - second_player_item, 3)
  end
end


이제 함수 결과를 단순화할 수 있습니다.

defmodule Game do
  @moduledoc """
  Documentation for `Game`.
  """

  @stone 1
  @paper 2
  @scissor 3

  def play(first_player_choice, second_player_choice) do
    result(first_player_choice, second_player_choice)
  end

  defp result(first_player_choice, second_player_choice) do
    game_calc_result = game_calc(first_player_choice, second_player_choice)

    case game_calc_result do
      0 -> {:ok, "Draw!"}
      1 -> {:ok, "First player win!!!"}
      _ -> {:ok, "Second player win!!!"}
    end
  end

  defp game_calc(first_player_item, second_player_item) do
    rem(first_player_item - second_player_item, 3)
  end
end


테스트 실행:




mix test


뭔가 잘못되었다. 테스트를 실행했을 때 3개의 경고와 1개의 실패 메시지를 받았습니다.

Compiling 1 file (.ex)
warning: module attribute @scissor was set but never used
  lib/game.ex:8

warning: module attribute @paper was set but never used
  lib/game.ex:7

warning: module attribute @stone was set but never used
  lib/game.ex:6

..

  1) test Game.play/2 when first player wins when first player chooses stone and second player chooses scissors (GameTest)
     test/game_test.exs:55
     Assertion with == failed
     code:  assert match == "First player win!!!"
     left:  "Second player win!!!"
     right: "First player win!!!"
     stacktrace:
       test/game_test.exs:61: (test)

......

Finished in 0.05 seconds (0.00s async, 0.05s sync)
9 tests, 1 failure

Randomized with seed 811857


경고 메시지를 해결하려면 모듈 속성을 제거해야 합니다.

defmodule Game do
  @moduledoc """
  Documentation for `Game`.
  """

  def play(first_player_choice, second_player_choice) do
    result(first_player_choice, second_player_choice)
  end

  defp result(first_player_choice, second_player_choice) do
    game_calc_result = game_calc(first_player_choice, second_player_choice)

    case game_calc_result do
      0 -> {:ok, "Draw!"}
      1 -> {:ok, "First player win!!!"}
      _ -> {:ok, "Second player win!!!"}
    end
  end

  defp game_calc(first_player_item, second_player_item) do
    rem(first_player_item - second_player_item, 3)
  end
end


이제 테스트를 다시 실행하면 다음과 같습니다.

mix test


테스트 실패만 표시됩니다.

Compiling 1 file (.ex)
....

  1) test Game.play/2 when first player wins when first player chooses stone and second player chooses scissors (GameTest)
     test/game_test.exs:55
     Assertion with == failed
     code:  assert match == "First player win!!!"
     left:  "Second player win!!!"
     right: "First player win!!!"
     stacktrace:
       test/game_test.exs:61: (test)

....

Finished in 0.04 seconds (0.00s async, 0.04s sync)
9 tests, 1 failure

Randomized with seed 730068


실패 메시지 이해



실패는 커널 함수 rem/2에 공식에서 음수 배당을 전달하기 때문입니다. 그리고 문서에 따르면 이 커널 함수는 잘린 나눗셈을 사용하는데, 이는 결과가 항상 피제수의 부호를 갖는다는 것을 의미합니다.

첫 번째 플레이어가 돌을 선택하고 두 번째 플레이어가 가위를 선택했을 때 첫 번째 플레이어가 이기면 결과는 -2입니다.

# stone = 1
# paper = 2
# scissor = 3

# R = (first_player_choice - second_player_choice) % 3
# R = (stone - scissors) % 3
# R = (1 - 3) % 3

# In elixir using rem/2

rem(1-3, 3)
> -2


실패 메시지 해결



설명서에 따르면 함수Integer.mod/2는 정수 나누기의 모듈로 나머지를 계산합니다.

알아두어야 할 사항: Integer.mod/2는 바닥 분할을 사용합니다. 즉, 결과는 항상 제수의 부호를 가집니다.

따라서 첫 번째 플레이어가 돌을 선택하고 두 번째 플레이어가 가위를 선택했을 때 첫 번째 플레이어가 이겼을 때 결과는 1입니다.

# stone = 1
# paper = 2
# scissor = 3

# R = (first_player_choice - second_player_choice) % 3
# R = (stone - scissors) % 3
# R = (1 - 3) % 3

# In elixir using rem/2

Integer.mod(1-3, 3)
> 1


따라서 실패 메시지를 해결하려면 rem/2 함수를 제거하고 Integer.mod/2를 추가해야 합니다.

defmodule Game do
  @moduledoc """
  Documentation for `Game`.
  """

  def play(first_player_choice, second_player_choice) do
    result(first_player_choice, second_player_choice)
  end

  defp result(first_player_choice, second_player_choice) do
    game_calc_result = game_calc(first_player_choice, second_player_choice)

    case game_calc_result do
      0 -> {:ok, "Draw!"}
      1 -> {:ok, "First player win!!!"}
      _ -> {:ok, "Second player win!!!"}
    end
  end

  defp game_calc(first_player_item, second_player_item) do
    Integer.mod(first_player_item - second_player_item, 3)
  end
end


이제 마지막으로 테스트를 다시 실행하면 다음과 같습니다.

mix test


모든 테스트는 성공적으로 통과했습니다\o/:

Compiling 1 file (.ex)
.........

Finished in 0.04 seconds (0.00s async, 0.04s sync)
9 tests, 0 failures

Randomized with seed 992719


이제 축하할 시간입니다. 가위바위보 게임이 "완료"되었습니다!

프로젝트 저장소: https://github.com/dnovais/rock_paper_scissor_elixir

곧 봐요!

콘택트 렌즈



이메일: [email protected]
링크드인:
트위터:


출처 및 참조


  • https://hexdocs.pm/elixir/1.12/Integer.html#mod/2
  • https://www.cs.drexel.edu/~jpopyack/Courses/CSP/Fa18/notes/CS150_RockPaperScissors_Revisited.pdf
  • https://www.cin.ufpe.br/~gdcc/matdis/aulas/aritmeticaModular.pdf
  • https://www.khanacademy.org/computing/computer-science/cryptography/modarithmetic/a/what-is-modular-arithmetic
  • 좋은 웹페이지 즐겨찾기