4f65659af0ef1f4590e4d91a14210dc297d6490f
2 * =====================================================================================
6 * Description: Handle the othello board content
9 * Created: 25/04/2017 15:16:08
13 * Author: Jerome Benoit (fraggle), jerome.benoit@piment-noir.org
14 * Organization: Piment Noir
16 * =====================================================================================
27 * Get current round player integer
28 * @param round_count current round integer
29 * @return current round player
31 unsigned int current_player(unsigned int round_count
) {
33 if (round_count
% 2 != 0) {
41 * Get current round opponent integer
42 * @param current_player current round player
43 * @return current round opponent integer
45 unsigned int current_opponent(unsigned int current_player
) {
47 if (current_player
== player_one
) {
54 /* for consistency with ncurses, the board coordinates are in the following order:
60 * The origin O has (1, 1) coordinates */
63 * Get pawn value at coordinates (x,y)
64 * @param y y coordinate
65 * @param x x coordinate
66 * @param pawn_array array of played pawns
67 * @return pawn integer type
69 unsigned int get_box_value(int y
, int x
, unsigned int pawn_array
[board_size
][board_size
]) {
71 return pawn_array
[y
-1][x
-1];
74 bool is_box_type(int y
, int x
, unsigned int pawn_array
[board_size
][board_size
], unsigned int type
) {
79 if (get_box_value(y
, x
, pawn_array
) == type
) {
86 static bool is_valid_coordinates(int y
, int x
) {
88 if ((y
> 0 && y
< board_size
+ 1) && \
89 (x
> 0 && x
< board_size
+ 1)) {
96 /* helper function to set a correct value at the (y, x) coordinates in the pawns array */
97 void set_pawn(int y
, int x
, unsigned int type
, unsigned int pawn_array
[board_size
][board_size
]) {
99 if (type
> 0 && type
< 3 && \
100 is_valid_coordinates(y
, x
)) {
101 pawn_array
[y
-1][x
-1] = type
;
102 } //FIXME: else case should set invalid values to permit to catch errors
105 /* reverse the pawn at (y, x) coordinates if it exists */
106 static void reverse_pawn(int y
, int x
, unsigned int pawn_array
[board_size
][board_size
]) {
108 if (is_box_type(y
, x
, pawn_array
, black
)) {
109 set_pawn(y
, x
, white
, pawn_array
);
110 } else if (is_box_type(y
, x
, pawn_array
, white
)) {
111 set_pawn(y
, x
, black
, pawn_array
);
115 void zero_pawns(unsigned int pawn_array
[board_size
][board_size
]) {
117 for (int i
= 1; i
<= board_size
; i
++) {
118 for (int j
= 1; j
<= board_size
; j
++) {
119 set_pawn(i
, j
, empty
, pawn_array
);
124 /* set the pawns in the start position */
125 void init_pawns(unsigned int pawn_array
[board_size
][board_size
]) {
127 /* the 2D array zeroing is not necessary if it is properly initialized to zero */
128 zero_pawns(pawn_array
);
129 set_pawn(5, 4, black
, pawn_array
);
130 set_pawn(4, 5, black
, pawn_array
);
131 set_pawn(4, 4, white
, pawn_array
);
132 set_pawn(5, 5, white
, pawn_array
);
135 unsigned int count_pawns_type(unsigned int pawn_array
[board_size
][board_size
], unsigned int type
) {
136 unsigned int count
= 0;
141 for (int i
= 1; i
<= board_size
; i
++) {
142 for (int j
= 1; j
<= board_size
; j
++) {
143 if (is_box_type(i
, j
, pawn_array
, type
)) {
151 static void direction_to_coordinates(unsigned int direction
, int* start_y
, int* start_x
) {
153 if (direction
== north
) {
154 *start_y
= *start_y
- 1;
155 } else if (direction
== north_east
) {
156 *start_y
= *start_y
- 1;
157 *start_x
= *start_x
+ 1;
158 } else if (direction
== east
) {
159 *start_x
= *start_x
+ 1;
160 } else if (direction
== south_east
) {
161 *start_y
= *start_y
+ 1;
162 *start_x
= *start_x
+ 1;
163 } else if (direction
== south
) {
164 *start_y
= *start_y
+ 1;
165 } else if (direction
== south_west
) {
166 *start_y
= *start_y
+ 1;
167 *start_x
= *start_x
- 1;
168 } else if (direction
== west
) {
169 *start_x
= *start_x
- 1;
170 } else if (direction
== north_west
) {
171 *start_y
= *start_y
- 1;
172 *start_x
= *start_x
- 1;
176 bool is_board_full(unsigned int pawn_array
[board_size
][board_size
]) {
178 /* an alternate method is to test the round count vs. 60 */
179 for (int i
= 1; i
<= board_size
; i
++) {
180 for (int j
= 1; j
<= board_size
; j
++) {
181 if (is_box_type(i
, j
, pawn_array
, empty
)) {
189 unsigned int eval_winner(unsigned int nb_white
, unsigned int nb_black
) {
191 if (nb_white
> nb_black
) {
193 } else if (nb_white
< nb_black
) {
200 static unsigned int count_pawn_to_reverse_one_direction(int y
, int x
, int direction
, unsigned int current_player
, unsigned int pawn_array
[board_size
][board_size
]) {
201 unsigned int nb_pawns_reversed
= 0;
202 int moving_y
= y
, moving_x
= x
;
204 /* count the pawns to reverse in the chosen direction */
205 direction_to_coordinates(direction
, &moving_y
, &moving_x
);
207 if (!is_valid_coordinates(moving_y
, moving_x
) || is_box_type(moving_y
, moving_x
, pawn_array
, empty
)) {
210 if (is_box_type(moving_y
, moving_x
, pawn_array
, current_player
)) {
214 direction_to_coordinates(direction
, &moving_y
, &moving_x
);
216 return nb_pawns_reversed
;
219 /* revert the pawns if needed in one direction */
220 static unsigned int reverse_one_direction(int y
, int x
, int direction
, unsigned int current_player
, unsigned int pawn_array
[board_size
][board_size
], bool dry_run
) {
221 unsigned int nb_pawns_reversed
= 0;
222 int moving_y
= y
, moving_x
= x
;
224 nb_pawns_reversed
= count_pawn_to_reverse_one_direction(moving_y
, moving_x
, direction
, current_player
, pawn_array
);
226 /* now reverse the needed pawns */
227 if (nb_pawns_reversed
> 0 && !dry_run
) {
228 moving_y
= y
, moving_x
= x
;
229 direction_to_coordinates(direction
, &moving_y
, &moving_x
);
230 while (!is_box_type(moving_y
, moving_x
, pawn_array
, current_player
)) {
231 reverse_pawn(moving_y
, moving_x
, pawn_array
);
232 direction_to_coordinates(direction
, &moving_y
, &moving_x
);
235 return nb_pawns_reversed
;
238 /* loop optimized version of valid_shot function changing nothing to the pawns 2D array */
239 bool is_legal_shot(int y
, int x
, unsigned int current_player
, unsigned int pawn_array
[board_size
][board_size
]) {
240 unsigned int nb_pawns_reversed
= 0;
242 if (!is_valid_coordinates(y
, x
) || !is_box_type(y
, x
, pawn_array
, empty
)) {
246 for (unsigned int direction
= north
; direction
<= north_west
; direction
++) {
247 nb_pawns_reversed
+= reverse_one_direction(y
, x
, direction
, current_player
, pawn_array
, true);
248 if (nb_pawns_reversed
> 0) {
255 /* play the shot if legal and flip or reverse the necessary pawns */
256 unsigned int valid_shot(int y
, int x
, unsigned int current_player
, unsigned int pawn_array
[board_size
][board_size
]) {
257 unsigned int nb_pawns_reversed
= 0;
259 if (!is_valid_coordinates(y
, x
) || !is_box_type(y
, x
, pawn_array
, empty
)) {
263 for (unsigned int direction
= north
; direction
<= north_west
; direction
++) {
264 nb_pawns_reversed
+= reverse_one_direction(y
, x
, direction
, current_player
, pawn_array
, false);
267 if (nb_pawns_reversed
== 0) {
268 return nb_pawns_reversed
;
271 set_pawn(y
, x
, current_player
, pawn_array
);
272 return nb_pawns_reversed
;
275 static void add_shots_list_cell(int y
, int x
, unsigned int type
, struct shots_list_s
* shots_list
) {
276 struct shots_list_s
* list_cell
= (struct shots_list_s
*)malloc(sizeof(struct shots_list_s
));
281 if (type
> 0 && type
< 5 && is_valid_coordinates(y
, x
)) {
284 list_cell
->type
= type
;
285 list_add_tail(&(list_cell
->list
), &(shots_list
->list
));
289 void free_shots_list(struct shots_list_s
* shots_list
) {
290 struct shots_list_s
* list_counter
;
292 while (!list_empty(&shots_list
->list
)) {
293 list_counter
= list_entry(shots_list
->list
.next
, struct shots_list_s
, list
);
294 list_del(&(list_counter
->list
));
300 void build_playable_shots_list(unsigned int current_player
, struct shots_list_s
* shots_list
, unsigned int pawn_array
[board_size
][board_size
]) {
302 for (unsigned int i
= 0; i
<= board_size
; i
++) {
303 for (unsigned int j
= 0; j
<= board_size
; j
++) {
304 if (is_legal_shot(i
, j
, current_player
, pawn_array
)) {
305 add_shots_list_cell(i
, j
, hint_allowed
, shots_list
);
306 /* FIXME: a neighbourhood detection is needed
307 } else if (is_box_type(i, j, pawn_array, empty)){
308 add_shots_list_cell(i, j, hint_forbidden, shots_list);