summaryrefslogtreecommitdiff
path: root/lib/chessh/schema/game.ex
blob: 87774729428dae667951a0f19b32daae50e5abcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
defmodule Chessh.Game do
  alias Chessh.{Bot, Player, Game}
  use Ecto.Schema
  import Ecto.Changeset

  @default_fen "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"

  schema "games" do
    field(:fen, :string)
    field(:moves, :integer, default: 0)
    field(:last_move, :string)

    field(:turn, Ecto.Enum, values: [:light, :dark], default: :light)
    field(:winner, Ecto.Enum, values: [:light, :dark, :none], default: :none)
    field(:status, Ecto.Enum, values: [:continue, :draw, :winner], default: :continue)

    field(:game_moves, :string)

    belongs_to(:light_player, Player, foreign_key: :light_player_id)
    belongs_to(:dark_player, Player, foreign_key: :dark_player_id)

    belongs_to(:bot, Bot, foreign_key: :bot_id)

    field(:discord_thread_id, :string)

    timestamps()
  end

  def changeset(game, attrs) do
    game
    |> cast(attrs, [
      :fen,
      :moves,
      :turn,
      :winner,
      :status,
      :last_move,
      :light_player_id,
      :dark_player_id,
      :discord_thread_id,
      :bot_id,
      :game_moves
    ])
  end

  def new_game(initial_player_color, player_id, fen \\ @default_fen) do
    Game.changeset(
      %Game{
        fen: fen
      },
      if(initial_player_color == :light,
        do: %{light_player_id: player_id},
        else: %{dark_player_id: player_id}
      )
    )
  end

  def update_with_status(%Game{} = game, move, fen, status) do
    Game.changeset(
      game,
      %{
        fen: fen,
        moves: game.moves + 1,
        turn: if(game.turn == :dark, do: :light, else: :dark),
        last_move: move,
        game_moves:
          if(!is_nil(game) && game.game_moves != "", do: "#{game.game_moves} ", else: "") <> move
      }
      |> Map.merge(changeset_from_status(status))
    )
  end

  def changeset_from_status(game_status) do
    case game_status do
      :continue ->
        %{}

      {:draw, _} ->
        %{status: :draw}

      {:checkmate, :white_wins} ->
        %{status: :winner, winner: :light}

      {:checkmate, :black_wins} ->
        %{status: :winner, winner: :dark}
    end
  end
end