hive/engine/
game.rs

1use crate::engine::{
2  game::{action::Action, player::Player},
3  grid::{
4    coordinate::hex::Hex,
5    piece::{Piece, PieceColor, PieceType},
6    Grid,
7  },
8  moves::{available_actions_for_piece_color, available_moves},
9  rules,
10};
11use serde::{Deserialize, Serialize};
12use uuid::Uuid;
13
14pub mod action;
15pub mod player;
16
17#[derive(Debug, Serialize, Deserialize, Clone)]
18pub struct Game {
19  pub id: Uuid,
20  pub grid: Grid,
21  pub players: Vec<Player>,
22  pub actions_history: Vec<Action>,
23  pub turn: u64,
24  pub is_tournement_rule: bool,
25  pub current_player_index: usize,
26}
27
28impl Game {
29  pub fn tournament() -> Game {
30    Game {
31      id: Uuid::new_v4(),
32      grid: Grid::new(),
33      players: vec![Player::white(), Player::black()],
34      actions_history: Vec::new(),
35      turn: 0,
36      is_tournement_rule: true,
37      current_player_index: 0,
38    }
39  }
40
41  pub fn list_actions_for_player(&self, player: &Player) -> Vec<Action> {
42    let mut actions: Vec<Action> = Vec::new();
43
44    if player.is_queen_played {
45      for from in self.grid.grid.keys() {
46        let piece = self.grid.find_top_piece(from);
47
48        if let Some(piece) = piece {
49          if piece.p_color == player.color {
50            for to in available_moves(&self.grid, from) {
51              actions.push(Action {
52                piece: *piece,
53                from: *from,
54                to,
55                in_hand: false,
56              })
57            }
58          }
59        }
60      }
61    }
62
63    for to in available_actions_for_piece_color(&self.grid, &player.color) {
64      for piece in &player.pieces {
65        if self.can_play_piece(piece) {
66          actions.push(Action {
67            piece: *piece,
68            from: Hex::zero(),
69            to,
70            in_hand: true,
71          })
72        }
73      }
74    }
75
76    actions
77  }
78
79  fn can_play_piece(&self, piece: &Piece) -> bool {
80    let current_player = &self.players[self.current_player_index];
81
82    !(self.is_tournement_rule
83      && piece.p_type == PieceType::QUEENBEE
84      && (self.turn == 0 || self.turn == 1))
85      && !(piece.p_type != PieceType::QUEENBEE
86        && !current_player.is_queen_played
87        && (self.turn >= 6))
88  }
89
90  pub fn play_action(&mut self, action: Action) {
91    if self
92      .list_actions_for_player(&self.players[self.current_player_index])
93      .contains(&action)
94    {
95      if action.in_hand {
96        self.grid.place_piece_to_hex(action.piece, action.to);
97        let index = self.players[self.current_player_index]
98          .pieces
99          .iter()
100          .position(|p| p.p_type == action.piece.p_type && p.p_color == action.piece.p_color)
101          .unwrap();
102        self.players[self.current_player_index].pieces.remove(index);
103      } else {
104        self.grid.move_piece_from_to(action.from, action.to)
105      }
106
107      if action.piece.p_type == PieceType::QUEENBEE {
108        self.players[self.current_player_index].is_queen_played = true
109      }
110
111      self.actions_history.push(action);
112
113      self.next_turn()
114    }
115  }
116
117  pub fn winner(&self) -> Option<PieceColor> {
118    let mut winner: Option<PieceColor> = None;
119
120    if rules::queen_surrounded_rule(&self.grid, PieceColor::WHITE) {
121      winner = Option::from(PieceColor::BLACK)
122    } else if rules::queen_surrounded_rule(&self.grid, PieceColor::BLACK) {
123      winner = Option::from(PieceColor::WHITE)
124    }
125
126    winner
127  }
128
129  fn next_turn(&mut self) {
130    self.turn += 1;
131    self.current_player_index = Game::current_player_index(self.turn);
132  }
133
134  fn current_player_index(turn: u64) -> usize {
135    if turn % 2 == 0 {
136      0
137    } else {
138      1
139    }
140  }
141}