src/utilities.c
Functions
Name | |
---|---|
void | print_play(play_t * play)prints the content of a play for debugging purposes |
bool | is_duplicate(play_t * play1, play_t * play2)tests if two plays are identical |
bool | validity_play(play_t * play, bool player)tests if a play is valid |
void | free_tree(tree_t * tree)frees a tree |
tree_t * | create_tree(play_t * play, int value, int depth)creats a tree |
void | append_tree(tree_t * tree, play_t * play, int value, int depth)adds a node to the linked list tree |
void | fill_play_buffer(play_t * play)fills the buffer of a play |
void | cell_belongs_to_player(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player)part of the traversal_rec function, case where the following cell of a play belongs to the player |
void | cell_does_not_belongs_to_player(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player)part of the traversal_rec function, case where the following cell of a play does not belong to the player |
void | traversal_rec(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player)recursively generates plays |
tree_t * | gen_plays(board_t * board, int depth, bool player)generates all valid plays available given a board and a player |
Functions Documentation
function print_play
void print_play(
play_t * play
)
prints the content of a play for debugging purposes
function is_duplicate
bool is_duplicate(
play_t * play1,
play_t * play2
)
tests if two plays are identical
function validity_play
bool validity_play(
play_t * play,
bool player
)
tests if a play is valid
function free_tree
void free_tree(
tree_t * tree
)
frees a tree
function create_tree
tree_t * create_tree(
play_t * play,
int value,
int depth
)
creats a tree
function append_tree
void append_tree(
tree_t * tree,
play_t * play,
int value,
int depth
)
adds a node to the linked list tree
function fill_play_buffer
void fill_play_buffer(
play_t * play
)
fills the buffer of a play
function cell_belongs_to_player
void cell_belongs_to_player(
board_t * board,
tree_t * tree,
play_t * play,
cell_t * cell,
bool * visited,
bool player
)
part of the traversal_rec function, case where the following cell of a play belongs to the player
function cell_does_not_belongs_to_player
void cell_does_not_belongs_to_player(
board_t * board,
tree_t * tree,
play_t * play,
cell_t * cell,
bool * visited,
bool player
)
part of the traversal_rec function, case where the following cell of a play does not belong to the player
function traversal_rec
void traversal_rec(
board_t * board,
tree_t * tree,
play_t * play,
cell_t * cell,
bool * visited,
bool player
)
recursively generates plays
function gen_plays
tree_t * gen_plays(
board_t * board,
int depth,
bool player
)
generates all valid plays available given a board and a player
Source code
/* name : main.h
* authors : eloi petit, matheo thomas, domitille vale
* date : 18-06-24
*/
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "algos.h"
#include "init.h"
#include "utilities.h"
void print_play(play_t *play) {
if(validity_play(play, 1)) {
printf("ids: ");
for(int i = 0; i < play->cell_tab_length; i++) {
printf("%d ", play->cell_tab[i]->id);
}
printf("\n buffer : ");
for(int i = 0; i < play->cell_tab_length; i++) {
printf("%d ", play->buffer[i]);
}
printf("\ncell_tab_length : %d\n movement_direction : %d\n cell_direction %d\n",
play->cell_tab_length,
play->movement_direction,
play->cell_direction);
printf("validity : %d\n", validity_play(play, 1));
}
printf("\n buffer : ");
for(int i = 0; i < play->cell_tab_length; i++) {
printf("%d ", play->buffer[i]);
}
printf("\ncell_tab_length : %d\n movement_direction : %d\n cell_direction %d\n", play->cell_tab_length, play->movement_direction, play->cell_direction);
printf("validity : %d\n", validity_play(play, 1));
}
bool is_duplicate(play_t * play1, play_t * play2) {
// printf("is_duplicate\n");
if (play1 != NULL && play2 != NULL) {
// Can be a duplicate only if both have the same number of cells
// and movement_direction are equal
if (play1 -> cell_tab_length == play2 -> cell_tab_length &&
play1 -> movement_direction == play2 -> movement_direction) {
int length = play1 -> cell_tab_length;
// If cell_direction and movement_direction are not colinear
if (play1 -> cell_direction != play1 -> movement_direction &&
play1 -> cell_direction != (play1 -> movement_direction + 3) % 6) {
// Can be a duplicate only if extremums of cell_tabs are equals (invered or not)
if ((play1 -> cell_tab[0] -> id == play2 -> cell_tab[length - 1] -> id &&
play2 -> cell_tab[0] -> id == play1 -> cell_tab[length - 1] -> id) ||
(play1 -> cell_tab[0] -> id == play2 -> cell_tab[0] -> id &&
play2 -> cell_tab[length - 1] -> id == play1 -> cell_tab[length - 1] -> id))
return true;
}
else {
// We only need to check the buffer and ids in that case
// (both cell_directions are positively colinear)
for (int i = 0; i < length; i++) {
if (play1 -> cell_tab[i] -> id != play2 -> cell_tab[i] -> id)
return false;
if (play1 -> buffer[i] != play2 -> buffer[i])
return false;
}
return true;
}
}
}
return false;
}
bool validity_play(play_t * play, bool player) {
// printf("validity_play\n");
if (play == NULL) {
return false;
}
// cell_direction is meaningless when play is of size 1
// and creates a lot of duplicates that we can remove early
if (play -> cell_tab_length == 1 && play -> cell_direction != play -> movement_direction) {
return false;
}
state_e switch_player_color[2] = {BLACK, WHITE};
// Check if the play line is well ordered
bool changed_to_non_player_color = false;
cell_t * cell = play -> cell_tab[0];
int i = 0;
while (cell != NULL && i++ < 6 && cell -> state != EMPTY) {
if (cell -> state == switch_player_color[!player]) {
changed_to_non_player_color = true;
}
// If we find a cell belonging to player after a non player cell then the play is invalid
else if (cell -> state == switch_player_color[player] && changed_to_non_player_color) {
// puts("a");
return false;
}
cell = cell -> neighbor[play -> cell_direction];
}
// Check if movemement is valid when movement_direction and cell_direction are positively colinear
if (play -> cell_direction == play -> movement_direction) {
cell_t * cours = play -> cell_tab[0];
int player_cells = 0;
int total_cells = 0;
// We go further than the play length because of case 3 player cells
// then 3 non player cells -> last non player cell is possibly not accounted for in cell_tab
while (cours != NULL && total_cells < 6 && cours -> state != EMPTY) {
player_cells += (switch_player_color[player] == cours -> state) ? 1 : 0;
total_cells++;
cours = cours -> neighbor[play -> cell_direction];
}
//printf("player_cells : %d total_cells : %d\n", player_cells, total_cells);
if (2 * player_cells <= total_cells) {
//printf("player_cells false\n");
// puts("b");
return false;
}
// Handle cells being thrown off board
for (int j = 0; j < play -> cell_tab_length; j++) {
if (play -> cell_tab[j] -> neighbor[play -> movement_direction] == NULL) {
if(play -> cell_tab[j] -> state == switch_player_color[player]) {
// puts("c");
return false;
}
}
}
if (play -> cell_tab[play -> cell_tab_length - 1] -> neighbor[play -> movement_direction] != NULL &&
play -> cell_tab[play -> cell_tab_length - 1] -> neighbor[play -> movement_direction]->state ==
switch_player_color[player]) {
// puts("la mort");
return false;
}
}
// Check if movement is valid otherwise
else {
for (int k = 0; k < play -> cell_tab_length; k++) {
if (play -> cell_tab[k] -> neighbor[play -> movement_direction] == NULL) {
// puts("d");
return false;
}
if (play -> cell_tab[k] -> neighbor[play -> movement_direction] -> state != EMPTY) {
//printf("c\n");
// puts("e");
return false;
}
}
}
if (play->cell_tab_length > 1 &&
play->cell_tab[0]->neighbor[play->cell_direction] != play->cell_tab[1]) {
// puts("f");
return false;
}
return true;
}
void free_tree(tree_t * tree) {
while (tree != NULL) {
tree_t * previous = tree;
tree = tree -> next_tree;
free(previous -> play);
free(previous);
}
}
tree_t * create_tree(play_t * play, int value, int depth) {
// printf("create_tree\n");
tree_t * tree = malloc(sizeof(tree_t));
tree -> play = play;
tree -> value = value;
tree -> depth = depth;
tree -> next_tree = NULL;
return tree;
}
void append_tree(tree_t * tree, play_t * play, int value, int depth) {
// printf("append_tree\n");
if(validity_play(play, 1)) {
tree_t *new_tree = create_tree(play, value, depth);
tree_t * cours = tree;
while (cours -> next_tree != NULL) {
if (is_duplicate(play, cours -> play)) {
return;
}
cours = cours -> next_tree;
}
if (!is_duplicate(cours -> play, play)) {
cours -> next_tree = new_tree;
}
}
}
void fill_play_buffer(play_t * play) {
// printf("fill_play_buffer\n");
if (play -> cell_tab_length < 5) {
play -> cell_tab[play -> cell_tab_length] = NULL;
}
int i = 0;
while (i < play -> cell_tab_length) {
play -> buffer[i] = play -> cell_tab[i] -> state;
i++;
}
}
void cell_belongs_to_player(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player) {
// printf("cell_belongs_to_player\n");
if (play == NULL && visited[cell -> id] == true) {
return;
}
else if (visited[cell -> id] == false) {
visited[cell -> id] = true;
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
play_t * new_play = malloc(sizeof(play_t));
new_play -> cell_tab_length = 1;
new_play -> movement_direction = j;
new_play -> cell_direction = i;
new_play -> cell_tab[0] = cell;
new_play -> cell_tab[1] = NULL;
//printf("direction %d\n", new_play -> movement_direction);
traversal_rec(board, tree, new_play, cell -> neighbor[i], visited, player);
}
}
}
else if (play -> cell_tab_length < 3) {
play -> cell_tab[play -> cell_tab_length] = cell;
play -> cell_tab_length ++;
if (validity_play(play, player)) {
fill_play_buffer(play);
if(play->cell_tab[0]->id == 5) {
// printf("oulala %d\n", play->cell_tab_length);
}
append_tree(tree, play, 0, tree -> depth);
}
traversal_rec(board, tree, play, cell -> neighbor[play -> cell_direction], visited, player);
}
}
void cell_does_not_belongs_to_player(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player) {
// printf("cell_does_not_belongs_to_player\n");
if (play != NULL && play -> cell_tab_length < 5) {
// If movement direction is not colinear to cell direction then we should
// not add the cell of the other player
if (play -> cell_direction == play -> movement_direction ||
play -> cell_direction == (play -> movement_direction + 3) % 6) {
play -> cell_tab[play -> cell_tab_length] = cell;
play -> cell_tab_length ++;
if (validity_play(play, player)) {
fill_play_buffer(play);
if(play->cell_tab[0]->id == 5) {
// printf("putput\n");
}
append_tree(tree, play, 0, tree -> depth);
}
traversal_rec(board, tree, play, cell -> neighbor[play -> cell_direction], visited, player);
}
}
}
void traversal_rec(board_t * board, tree_t * tree, play_t * play, cell_t * cell, bool * visited, bool player) {
// printf("traversal_rec\n");
if (cell == NULL) { return; }
switch (cell -> state) {
case EMPTY:
if (!visited[cell -> id]) {
visited[cell -> id] = true;
if (play == NULL) {
for (int i = 0; i < 6; i++) {
traversal_rec(board, tree, NULL, cell -> neighbor[i], visited, player);
}
}
else {
if (validity_play(play, player)) {
fill_play_buffer(play);
if(play->cell_tab[0]->id == 5) {
// printf("putputput\n");
}
append_tree(tree, play, 0, tree -> depth);
for (int i = 0; i < 6; i++) {
traversal_rec(board, tree, NULL, cell -> neighbor[i], visited, player);
}
}
}
}
else {
if (validity_play(play, player)) {
fill_play_buffer(play);
if(play->cell_tab[0]->id == 5) {
// printf("putputput\n");
}
append_tree(tree, play, 0, tree -> depth);
}
}
break;
case WHITE:
(player) ?
cell_belongs_to_player(board, tree, play, cell, visited, player) :
cell_does_not_belongs_to_player(board, tree, play, cell, visited, player);
break;
case BLACK:
(!player) ?
cell_belongs_to_player(board, tree, play, cell, visited, player) :
cell_does_not_belongs_to_player(board, tree, play, cell, visited, player);
break;
}
}
tree_t * gen_plays(board_t * board, int depth, bool player) {
// printf("gen_plays\n");
// Player = 1 if bot is the player else 0
bool visited[CELL_NUMBER] = {false};
tree_t * tree = create_tree(NULL, 0, depth); //tête de liste
traversal_rec(board, tree, NULL, board -> cell, visited, player);
return tree -> next_tree;
}