1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use crate::{Board, Color, Error, Hand, Square};

/// Represents actions that can be executed in the game.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum Action {
   Move { from: Square, to: Square },
   PlaceFromHand { index: usize, to: Square },
}

/// Represents the progress or result of the game.
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
pub enum Status {
   OnGoing,
   BlackWins,
   WhiteWins,
}

/// Manages board, hands, turn, and result of the game.
#[derive(Clone, Debug)]
pub struct Game {
   board: Board,
   hands: [Hand; Color::NUM],
   turn: Color,
   status: Status,
}

impl Game {
   pub fn new() -> Self {
      Self {
         board: Board::new(),
         hands: [Hand::new(Color::Black), Hand::new(Color::White)],
         turn: Color::Black,
         status: Status::OnGoing,
      }
   }

   /// Returns the board.
   pub fn board(&self) -> &Board {
      &self.board
   }

   /// Returns the hand of the given color.
   pub fn hand(&self, color: Color) -> &Hand {
      &self.hands[color as usize]
   }

   /// Returns the color of the current player's turn.
   pub fn turn(&self) -> Color {
      self.turn
   }

   /// Returns the status of the game.
   pub fn status(&self) -> Status {
      self.status
   }

   /// Executes the given action and returns result.
   pub fn execute(&mut self, action: Action) -> Result<Status, Error> {
      match self.status {
         Status::OnGoing => {}
         Status::BlackWins => {
            return Ok(Status::BlackWins);
         }
         Status::WhiteWins => {
            return Ok(Status::WhiteWins);
         }
      };

      let result;
      match action {
         Action::Move { from, to } => match self.board.r#move(from, to) {
            Ok(board) => {
               self.board = board;
            }
            Err(err) => {
               return Err(err);
            }
         },
         Action::PlaceFromHand { index, to } => {
            if let Some(&piece) = self.hands[self.turn as usize].peek(index) {
               match self.board.place(piece, to) {
                  Ok(board) => {
                     self.hands[self.turn as usize].pop(index);
                     self.board = board;
                  }
                  Err(err) => {
                     return Err(err);
                  }
               };
            }
         }
      };

      if self.board.has_won(Color::Black) {
         self.status = Status::BlackWins;
      }
      if self.board.has_won(Color::White) {
         self.status = Status::WhiteWins;
      }

      self.change_turn();

      result = Ok(self.status);
      result
   }

   fn change_turn(&mut self) {
      self.turn = self.turn.reverse();
   }
}