# frozen-string-literal: true

module Bioshogi
  module Container
    concern :PlayersMethods do
      class_methods do
        def start
          new.tap do |e|
            e.placement_from_preset("平手")
          end
        end
      end

      attr_reader :players

      def players
        @players ||= Location.collect do |e|
          Player.new(container: self, location: e)
        end
      end

      # player_at(-1) でも後手を取得できる
      def player_at(location)
        players[Location.fetch(location).code]
      end

      # 現在の手番のプレイヤー
      # 引数の数値だけ手番が入れ替わる
      def current_player(diff = 0)
        players[turn_info.current_location(diff).code]
      end

      # 現在の手番の相手プレイヤー
      def opponent_player
        current_player(1)
      end

      # 次のプレイヤー(つまり相手)
      def next_player
        opponent_player
      end

      # 対局が終わった時点での勝者
      def win_player
        opponent_player
      end

      # 対局が終わった時点での敗者
      def lose_player
        current_player
      end

      # 両方のプレイヤーの駒台をクリア
      def piece_box_clear
        players.each { |e| e.piece_box.clear }
      end

      # 両者の(別名を含む)スキル名のリストを合わせてユニークにしたもの
      # つまりその対局に関連するすべてのタグに相当する
      def normalized_names_with_alias
        players.flat_map { |e| e.skill_set.normalized_names_with_alias }.uniq
      end

      # def basic_score
      #   evaluator.basic_score
      # end

      # 互いに王手されている局面か? (ありえない)
      def position_invalid?
        players.all?(&:mate_advantage?)
      end

      concerning :OtherMethods do
        # 文字列で両者に駒を配る
        def pieces_set(str)
          Piece.s_to_h2(str).each do |location_key, counts|
            player_at(location_key).piece_box.set(counts)
          end
        end
      end

      concerning :TurnMethods do
        attr_writer :turn_info

        def turn_info
          @turn_info ||= TurnInfo.new
        end
      end

      concerning :PieceCountCheckMethods do
        # 両者の駒を一つに集める
        def to_piece_box
          piece_box = PieceBox.new
          piece_box = players.inject(piece_box) { |a, e| a.add(e.piece_box) }
          piece_box.add(board.to_piece_box)
        end

        # 足りない駒が入っている箱を返す
        def not_enough_piece_box
          all = PieceBox.real_box
          all.safe_sub(to_piece_box)
        end
      end
    end
  end
end