goban/rules/
mod.rs

1//! Module for ruling in the game of go.
2
3use std::str::FromStr;
4
5use crate::pieces::stones::Color;
6use crate::pieces::util::coord::{Coord, Size};
7use crate::pieces::Nat;
8
9#[cfg(feature = "deadstones")]
10mod dead_stones;
11pub mod game;
12pub mod game_builder;
13mod sgf_bridge;
14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16pub enum GobanSizes {
17    Nineteen,
18    Nine,
19    Thirteen,
20    Custom(usize, usize),
21}
22
23impl From<GobanSizes> for Size {
24    fn from(goban_sizes: GobanSizes) -> Size {
25        match goban_sizes {
26            GobanSizes::Nine => (9, 9),
27            GobanSizes::Thirteen => (13, 13),
28            GobanSizes::Nineteen => (19, 19),
29            GobanSizes::Custom(height, width) => (height as u8, width as u8),
30        }
31    }
32}
33
34impl From<usize> for GobanSizes {
35    fn from(x: usize) -> Self {
36        match x {
37            9 => GobanSizes::Nine,
38            13 => GobanSizes::Thirteen,
39            19 => GobanSizes::Nineteen,
40            _ => panic!("Not implemented for others size than 9,13,19"),
41        }
42    }
43}
44
45/// Enum for playing in the Goban.
46#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
47pub enum Move {
48    Pass,
49    Resign(Color),
50    Play(Nat, Nat),
51}
52
53impl From<Coord> for Move {
54    fn from((x0, x1): Coord) -> Self {
55        Move::Play(x0, x1)
56    }
57}
58
59#[derive(Debug, Clone, PartialEq, Copy)]
60pub enum EndGame {
61    WinnerByScore(Color, f32),
62    WinnerByResign(Color),
63    WinnerByTime(Color),
64    WinnerByForfeit(Color),
65    Draw,
66}
67
68impl EndGame {
69    /// Return the winner of the game, if none the game is draw.
70    #[inline]
71    pub const fn get_winner(self) -> Option<Color> {
72        match self {
73            EndGame::WinnerByScore(p, _)
74            | EndGame::WinnerByResign(p)
75            | EndGame::WinnerByTime(p)
76            | EndGame::WinnerByForfeit(p) => Some(p),
77            EndGame::Draw => None,
78        }
79    }
80}
81
82#[derive(Clone, Eq, PartialEq, Debug, Copy)]
83pub enum PlayError {
84    Ko,
85    Suicide,
86    GamePaused,
87    FillEye,
88    PointNotEmpty,
89}
90
91type FlagUInt = u32;
92bitflags! {
93    /// Behaviours not permitted, if the flag is up then the move is not legal.
94    pub struct IllegalRules: FlagUInt{
95        /// Rule that filters normal Ko move
96        const KO = 1;
97        /// Rule that filters SUPER KO moves
98        const SUPERKO = 1 << 1;
99        /// Rule that filters suicides moves
100        const SUICIDE = 1 << 2;
101        /// Rule that filters eyes from the legals
102        const FILLEYE = 1 << 3;
103    }
104}
105bitflags! {
106    /// Types of scoring rules. the territory score is always added to the rules
107    pub struct ScoreRules : FlagUInt {
108        /// Stones needs to ben counted to the final score.
109        const STONES = 1;
110        /// The komi needs to be added.
111        const KOMI = 1 << 1;
112        /// The prisoners need to be added to the score.
113        const PRISONNERS = 1 << 2;
114    }
115}
116
117#[derive(Copy, Clone, Debug, PartialEq)]
118pub struct Rule {
119    pub komi: f32,
120    pub flag_illegal: IllegalRules,
121    pub flag_score: ScoreRules,
122}
123
124pub static JAPANESE: Rule = Rule {
125    komi: 6.5,
126    flag_illegal: IllegalRules::from_bits_truncate(
127        IllegalRules::KO.bits() | IllegalRules::SUICIDE.bits(),
128    ),
129    flag_score: ScoreRules::from_bits_truncate(
130        ScoreRules::KOMI.bits() | ScoreRules::PRISONNERS.bits(),
131    ),
132};
133
134pub static CHINESE: Rule = Rule {
135    komi: 7.5,
136    flag_illegal: IllegalRules::from_bits_truncate(
137        IllegalRules::KO.bits() | IllegalRules::SUPERKO.bits() | IllegalRules::SUICIDE.bits(),
138    ),
139    flag_score: ScoreRules::from_bits_truncate(ScoreRules::KOMI.bits() | ScoreRules::STONES.bits()),
140};
141
142impl FromStr for Rule {
143    type Err = String;
144
145    fn from_str(s: &str) -> Result<Self, Self::Err> {
146        match s {
147            "JAP" => Ok(JAPANESE),
148            "CHI" => Ok(CHINESE),
149            _ => Err(format!("The rule {s} is not implemented yet.")),
150        }
151    }
152}