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}