Skip to main content

katago_analysis/
rules.rs

1use serde::Serialize;
2
3/// Rules settings for KataGo.
4///
5/// See [KataGo's Supported Go Rules](https://lightvector.github.io/KataGo/rules.html) for more details.
6///
7/// ```
8/// # use katago_analysis::*;
9/// let japanese_rules = Rules::japanese();
10/// let bga_rules = Rules::Named("bga".to_string());
11/// let custom_rules = Rules::Explicit {
12///     ko: Ko::Positional,
13///     scoring: Scoring::Territory,
14///     tax: Tax::Seki,
15///     suicide: false,
16///     has_button: false,
17///     white_handicap_bonus: Bonus::Zero,
18///     friendly_pass_ok: true,
19/// };
20/// ```
21#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
22#[serde(untagged, rename_all_fields = "camelCase")]
23pub enum Rules {
24    /// A ruleset identified by name.
25    Named(String),
26
27    /// A ruleset defined by settings for each rule.
28    Explicit {
29        /// The ko rule.
30        ko: Ko,
31
32        /// The scoring method.
33        scoring: Scoring,
34
35        /// The group tax rule.
36        tax: Tax,
37
38        /// Whether multi-stone suicide is legal.
39        suicide: bool,
40
41        /// Whether the button rule is used.
42        has_button: bool,
43
44        /// The bonus points white receives in handicap games.
45        white_handicap_bonus: Bonus,
46
47        /// Whether it's allowed to pass before removing all dead stones.
48        friendly_pass_ok: bool,
49    },
50}
51
52macro_rules! rules {
53    ($(#[$meta:meta])* $name:ident, $value:expr) => {
54        $(#[$meta])*
55        pub fn $name() -> Self {
56            Rules::Named($value.to_string())
57        }
58    };
59}
60
61impl Rules {
62    rules!(
63        /// Japanese and Korean rules.
64        japanese, "japanese"
65    );
66    rules!(
67        /// Chinese rules as implemented over the board (no superko).
68        chinese, "chinese"
69    );
70    rules!(
71        /// Chinese rules as implemented online (positional superko).
72        chinese_ogs, "chinese-ogs"
73    );
74    rules!(
75        /// Stone scoring (area scoring with group tax).
76        stone_scoring, "stone-scoring"
77    );
78    rules!(
79        /// Territory scoring with group tax.
80        ancient_territory, "ancient-territory"
81    );
82    rules!(
83        /// AGA rules using the button.
84        aga_button, "aga-button"
85    );
86    rules!(
87        /// AGA, BGA, and French rules.
88        aga, "aga"
89    );
90    rules!(
91        /// New Zealand rules.
92        new_zealand, "new-zealand"
93    );
94    rules!(
95        /// Tromp-Taylor rules.
96        tromp_taylor, "tromp-taylor"
97    );
98    rules!(
99        /// Ing rules.
100        ing, "ing"
101    );
102}
103
104/// Ko rules.
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
106#[serde(rename_all = "UPPERCASE")]
107pub enum Ko {
108    /// The immediately previous position is forbidden.
109    Simple,
110
111    /// Any previous position is forbidden.
112    Positional,
113
114    /// Any previous position with the same player to move is forbidden.
115    Situational,
116}
117
118/// Scoring methods.
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
120#[serde(rename_all = "UPPERCASE")]
121pub enum Scoring {
122    /// Area scoring as used in Chinese rules.
123    Area,
124
125    /// Territory scoring as used in Japanese rules.
126    Territory,
127}
128
129/// Group tax rules.
130#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
131#[serde(rename_all = "UPPERCASE")]
132pub enum Tax {
133    /// All surrounded empty points count.
134    None,
135
136    /// Empty points surrounded by a group in seki don't count.
137    Seki,
138
139    /// All groups are taxed up to 2 of their surrounded empty points.
140    All,
141}
142
143/// Bonus points white receives in handicap games.
144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize)]
145pub enum Bonus {
146    /// White receives no bonus points.
147    #[serde(rename = "0")]
148    Zero,
149
150    /// White receives bonus points equal to one less than the number of handicap stones.
151    #[serde(rename = "N-1")]
152    NMinusOne,
153
154    /// White receives bonus points equal to the number of handicap stones.
155    N,
156}