//! 入玉宣言勝ちのルール設定
//!
//! 入玉宣言勝ちとは、自玉が相手陣（敵陣 3 段目以内）に入った状態で
//! 一定の条件を満たすとき、勝ちを宣言できるルールです。
//!
//! # 点数計算
//!
//! 宣言側の持ち駒と、敵陣にある宣言側の駒（玉を除く）を点数化します。
//!
//! - 大駒（飛車・角・馬・龍）: 5 点
//! - 小駒（それ以外）: 1 点
//! - 玉は計算に含めない
//!
//! # ルールの種類
//!
//! | ルール | 先手の宣言条件 | 後手の宣言条件 |
//! |--------|---------------|---------------|
//! | `Point24` | 31 点以上 + 敵陣に自駒 10 枚以上 | 同左 |
//! | `Point27` | 28 点以上 + 敵陣に自駒 10 枚以上 | 27 点以上 + 同左 |
//! | `TryRule` | 自玉が相手の玉の初期位置に到達 | 同左 |
//!
//! `Handicap` 付きのバリアントは駒落ち対局用で、欠けている駒点ぶん後手側の必要点が調整されます。
//! いずれのルールでも、宣言時に自玉が王手されていないことが条件です。
use std::str::FromStr;

/// 入玉ルール文字列
pub const ENTERING_KING_RULE_NAMES: [&str; 6] =
    ["NoEnteringKing", "CSARule24", "CSARule24H", "CSARule27", "CSARule27H", "TryRule"];

/// 入玉ルール
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
pub enum EnteringKingRule {
    /// 入玉ルールなし
    None,
    /// 24点法（31点以上で宣言勝ち）
    Point24,
    /// 24点法（駒落ち対応）
    Point24Handicap,
    /// 27点法（CSAルール）
    Point27,
    /// 27点法（駒落ち対応）
    Point27Handicap,
    /// トライルール
    TryRule,
    /// 未設定
    #[default]
    Unset,
}

impl EnteringKingRule {
    /// YaneuraOu互換の文字列に変換
    #[must_use]
    pub const fn as_str(self) -> &'static str {
        match self {
            Self::None => ENTERING_KING_RULE_NAMES[0],
            Self::Point24 => ENTERING_KING_RULE_NAMES[1],
            Self::Point24Handicap => ENTERING_KING_RULE_NAMES[2],
            Self::Point27 => ENTERING_KING_RULE_NAMES[3],
            Self::Point27Handicap => ENTERING_KING_RULE_NAMES[4],
            Self::TryRule => ENTERING_KING_RULE_NAMES[5],
            Self::Unset => "EKR_NULL",
        }
    }
}

impl FromStr for EnteringKingRule {
    type Err = ();

    fn from_str(rule: &str) -> Result<Self, Self::Err> {
        for (idx, &name) in ENTERING_KING_RULE_NAMES.iter().enumerate() {
            if rule == name {
                return Ok(match idx {
                    0 => Self::None,
                    1 => Self::Point24,
                    2 => Self::Point24Handicap,
                    3 => Self::Point27,
                    4 => Self::Point27Handicap,
                    5 => Self::TryRule,
                    _ => return Err(()),
                });
            }
        }
        Err(())
    }
}
