Skip to content

Instantly share code, notes, and snippets.

@BSN4
Created November 26, 2024 20:05
Show Gist options
  • Save BSN4/b2acac15113d80e6edcb93f53f2ddd6f to your computer and use it in GitHub Desktop.
Save BSN4/b2acac15113d80e6edcb93f53f2ddd6f to your computer and use it in GitHub Desktop.
rock_paper_scissors_context.ex
defmodule RPS do
defmodule Score, do: defstruct player: 0, computer: 0
defmodule Context do
defstruct [
score: %Score{},
rounds_to_play: 3,
valid_moves: [:rock, :paper, :scissors],
win_conditions: %{rock: :scissors, paper: :rock, scissors: :paper},
io: IO
]
end
def play(rounds \\ 3) do
%Context{rounds_to_play: rounds}
|> Stream.iterate(&play_round/1)
|> Enum.at(rounds)
|> announce_winner()
|> maybe_play_again()
end
defp play_round(ctx) do
with {:ok, player} <- get_move(ctx),
computer = get_computer_move(ctx) do
ctx.io.puts("Computer chose: #{computer}")
winner = determine_winner(ctx, player, computer)
ctx.io.puts(format_result(winner, player, computer))
update_score(ctx, winner)
else
{:error, msg} ->
ctx.io.puts(msg)
play_round(ctx)
end
end
defp get_move(ctx) do
case ctx.io.gets("Enter move (rock/paper/scissors): ") |> String.trim() |> String.downcase() do
"rock" -> {:ok, :rock}
"paper" -> {:ok, :paper}
"scissors" -> {:ok, :scissors}
_ -> {:error, "Invalid move"}
end
end
defp get_computer_move(ctx) do
Enum.random(ctx.valid_moves)
end
defp determine_winner(ctx, player, computer) do
cond do
player == computer -> :draw
ctx.win_conditions[player] == computer -> :player
true -> :computer
end
end
defp format_result(:draw, move, _), do: "Draw! Both threw #{move}"
defp format_result(:player, player_move, computer_move), do: "You won with #{player_move} against #{computer_move}"
defp format_result(:computer, player_move, computer_move), do: "Computer won with #{computer_move} against #{player_move}"
defp update_score(ctx, :player) do
%{ctx | score: %{ctx.score | player: ctx.score.player + 1}}
end
defp update_score(ctx, :computer) do
%{ctx | score: %{ctx.score | computer: ctx.score.computer + 1}}
end
defp update_score(ctx, :draw), do: ctx
defp announce_winner(ctx) do
%Score{player: p, computer: c} = ctx.score
ctx.io.puts("\nFinal Score - You: #{p}, Computer: #{c}")
ctx.io.puts(if p > c, do: "You win!", else: if(p < c, do: "Computer wins!", else: "Draw!"))
ctx
end
defp maybe_play_again(ctx) do
if String.starts_with?(ctx.io.gets("\nPlay again? (y/n): ") |> String.downcase(), "y") do
play(ctx.rounds_to_play)
else
ctx.io.puts("Thanks for playing!")
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment