# frozen-string-literal: true

module Bioshogi
  module Explain
    class TechniqueMatcherInfo
      include ApplicationMemoryRecord
      memory_record [
        {
          key: "金底の歩",
          logic_desc: "打った歩が一番下の段でその上に自分の金がある",
          verify_process: proc {
            if false
              p executor.drop_hand
              soldier = executor.hand.soldier
              p soldier.piece.key
              p soldier.bottom_spaces
              p soldier.place
              p Place.lookup([soldier.place.x.value, soldier.place.y.value - soldier.location.value_sign])
            end

            # # 「打」でないとだめ
            # unless executor.drop_hand
            #   throw :skip
            # end

            soldier = executor.hand.soldier

            # 「最下段」でないとだめ
            if soldier.bottom_spaces != 0
              throw :skip
            end

            # # 「歩」でないとだめ
            # if soldier.piece.key != :pawn
            #   throw :skip
            # end

            # 1つ上の位置
            place = soldier.place
            v = Place.lookup([place.x.value, place.y.value - soldier.location.value_sign])

            # 1つ上の位置になにかないとだめ
            s = surface[v]
            unless s
              throw :skip
            end

            # 1つ上の駒が「自分」の「金」でないとだめ
            unless s.piece.key == :gold && s.location == soldier.location
              throw :skip
            end
          },
        },

        {
          key: "パンツを脱ぐ",
          logic_desc: "開戦前かつ、跳んだ桂が下から3つ目かつ、(近い方の)端から3つ目かつ、移動元の隣(端に近い方)に自分の玉がある",
          verify_process: proc {
            if false
              p executor.move_hand
              soldier = executor.move_hand.soldier
              p soldier.piece.key
              p soldier.bottom_spaces
              p soldier.place
              p Place.lookup([soldier.place.x.value, soldier.place.y.value - soldier.location.value_sign])
            end

            soldier = executor.move_hand.soldier

            # 「3段目」でないとだめ
            if soldier.bottom_spaces != 2
              throw :skip
            end

            # 「端から3つ目」でなければだめ
            if soldier.smaller_one_of_side_spaces != 2
              throw :skip
            end

            # 移動元は「端から2つ目」でなければだめ(△61から飛んだ場合を除外する)
            if executor.move_hand.origin_soldier.smaller_one_of_side_spaces != 1
              throw :skip
            end

            # FIXME: origin_soldier
            # 下に2つ、壁の方に2つ
            place = soldier.place
            v = Place.lookup([place.x.value + soldier.sign_to_goto_closer_side * 2, place.y.value + soldier.location.value_sign * 2])

            # そこに何かないとだめ
            s = surface[v]
            unless s
              throw :skip
            end

            # その駒が「自分」の「玉」でないとだめ
            unless s.piece.key == :king && s.location == soldier.location
              throw :skip
            end
          },
        },

        {
          key: "腹銀",
          logic_desc: "銀を打ったり移動したとき左右どちらかに相手の玉がある",
          verify_process: proc {
            soldier = executor.hand.soldier

            # 左右に相手の玉がいるか?
            place = soldier.place
            retv = [-1, +1].any? do |x|
              v = Place.lookup([place.x.value + x, place.y.value])
              if s = surface[v]
                s.piece.key == :king && s.location != soldier.location
              end
            end
            unless retv
              throw :skip
            end
          },
        },

        {
          key: "垂れ歩",
          logic_desc: "打った歩の前が空で次に成れる余地がある場合",
          verify_process: proc {
            soldier = executor.hand.soldier

            # 2, 3, 4段目でなければだめ(1段目は反則)
            v = soldier.top_spaces
            unless 1 <= v && v <= Dimension::PlaceY.promotable_depth
              throw :skip
            end

            # 一歩先が空
            place = soldier.place
            v = Place.lookup([place.x.value, place.y.value - soldier.location.value_sign])
            if surface[v]
              throw :skip
            end
          },
        },

        {
          key: "遠見の角",
          logic_desc: "打った角の位置が下から2番目かつ近い方の端から1番目(つまり自分の香の上の位置)",
          verify_process: proc {
            soldier = executor.hand.soldier

            # 8段目でなければだめ
            if soldier.bottom_spaces != 1
              throw :skip
            end

            # 端でなければだめ
            if soldier.smaller_one_of_side_spaces != 0
              throw :skip
            end
          },
        },

        {
          key: "割り打ちの銀",
          logic_desc: "打った銀の後ろの左右両方に相手の飛か金がある",
          verify_process: proc {
            soldier = executor.hand.soldier
            place = soldier.place
            retv = [-1, +1].all? do |x|
              v = Place.lookup([place.x.value + x, place.y.value + soldier.location.value_sign])
              if s = surface[v]
                if s.location != soldier.location
                  (s.piece.key == :rook && !s.promoted) || s.piece.key == :gold
                end
              end
            end
            unless retv
              throw :skip
            end
          },
        },

        {
          key: "桂頭の銀",
          logic_desc: "打った銀の上に相手の桂がある",
          verify_process: proc {
            soldier = executor.hand.soldier
            place = soldier.place
            v = Place.lookup([place.x.value, place.y.value - soldier.location.value_sign])
            unless s = surface[v]
              throw :skip
            end
            unless s.piece.key == :knight && !s.promoted && s.location != soldier.location
              throw :skip
            end
          },
        },

        {
          key: "ロケット",
          logic_desc: "打った香の下に自分の香か飛か龍がある",
          verify_process: proc {
            soldier = executor.hand.soldier
            place = soldier.place
            v = Place.lookup([place.x.value, place.y.value + soldier.location.value_sign])
            unless s = surface[v]
              throw :skip
            end
            if s.location != soldier.location
              throw :skip
            end
            unless (s.piece.key == :lance && !s.promoted) || s.piece.key == :rook
              throw :skip
            end
          },
        },

        {
          key: "ふんどしの桂",
          logic_desc: "打った桂の2つ前の左右に自分より価値の高い相手の駒がある",
          verify_process: proc {
            soldier = executor.hand.soldier
            place = soldier.place
            retv = [-1, +1].all? do |x|
              v = Place.lookup([place.x.value + x, place.y.value - soldier.location.value_sign * 2])
              if s = surface[v]
                if s.location != soldier.location
                  s.abs_weight > soldier.abs_weight
                end
              end
            end
            unless retv
              throw :skip
            end
          },
        },

        {
          key: "継ぎ桂",
          logic_desc: "打った桂の2つ後ろの左右のどちらかに自分の桂がある",
          verify_process: proc {
            soldier = executor.hand.soldier
            place = soldier.place
            retv = [-1, +1].any? do |x|
              v = Place.lookup([place.x.value + x, place.y.value + soldier.location.value_sign * 2])
              if s = surface[v]
                s.piece.key == :knight && !s.promoted && s.location == soldier.location
              end
            end
            unless retv
              throw :skip
            end
          },
        },

        {
          key: "入玉",
          logic_desc: "玉が移動して上のスペースが3つの状態から2つの状態になった",
          verify_process: proc {
            soldier = executor.hand.soldier
            if soldier.top_spaces != Dimension::PlaceY.promotable_depth - 1
              throw :skip
            end

            origin_soldier = executor.hand.origin_soldier
            if origin_soldier.top_spaces != Dimension::PlaceY.promotable_depth
              throw :skip
            end

            # ここで相手を見て、相手も入玉していたら、次のように相入玉とする方法もあるが
            # player.skill_set.note_infos << Explain::NoteInfo["相入玉"]
            # それでなくてもここは処理が重いのでやらない
            # formatter.container_run_once の方で、最後にチェックしている
          },
        },

        {
          key: "角不成",
          logic_desc: "相手陣地に入るときと出るときの両方チェックする",
          verify_process: proc {
            unless executor.hand.origin_soldier.next_promotable?(executor.soldier.place)
              throw :skip
            end
          },
        },

        {
          key: "飛車不成",
          logic_desc: "角不成と同じ方法でよい",
          verify_process: proc {
            unless executor.hand.origin_soldier.next_promotable?(executor.soldier.place)
              throw :skip
            end
          },
        },
      ]
    end
  end
end