comments
This commit is contained in:
1 parent
d3ffeb8eff
commit
88f92e8f2d
1 file changed
+106
-9
+106
-9
@@ -94,6 +94,13 @@ void game_save(cgame g, char* filename) {
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test if there is any error on the entire game
|
||||
*
|
||||
* @param g the game to analyze
|
||||
* @return true if there is 1 or more error on the game g
|
||||
* @return false if there is no one error on the game g
|
||||
*/
|
||||
bool game_has_error_general(cgame g) {
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
@@ -104,6 +111,22 @@ bool game_has_error_general(cgame g) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Change the array diagToTest who must containt coordinate i,j of a case else -1 if the cases are not on the same row / column take the cross point of
|
||||
* the two points
|
||||
* // clang off
|
||||
* 0 1 2
|
||||
* 0 a - b
|
||||
* 1 x 2 y
|
||||
* 2 c z d
|
||||
* // clang on
|
||||
* in this case the diagToTest must containt (zi,zj,xi,xj,yi,yj,?,?) (order doesn't matter) coordinates [2,1,0,1,1,0,-1,-1] and the function change this
|
||||
* coordinate of the points in the array to the cross points of these points in this case the array should look like this : [2,0,2,2,?,?,?,?]
|
||||
* ([ci,cj,di,dj,?,?,?,?]) and return the number of changed elements on diagToTest
|
||||
* @param diagToTest the tab to test and change
|
||||
* @param size the size of diagToTest
|
||||
* @return uint the number of element on the changed diagToTest
|
||||
*/
|
||||
uint coordinateCrossPointMaker(int* diagToTest, uint size) {
|
||||
int tab[size];
|
||||
uint cpt = 0;
|
||||
@@ -122,6 +145,20 @@ uint coordinateCrossPointMaker(int* diagToTest, uint size) {
|
||||
return cpt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief try to add a s square on blank cases in the directions of the array dir (who must have be fill with coef (-1 ; 0 ; 1) of directions like this :
|
||||
* [i,j,i,j,i,j,i,j]) to the i,j case in a 1 to max_gap distance from the i,j case if force is set to true place the square on lighted blank too (if there is an
|
||||
* error undo all moves and return 0)
|
||||
*
|
||||
* @param g the game to change
|
||||
* @param i the i coordinate of the case to add around
|
||||
* @param j the j coordinate of the case to add around
|
||||
* @param s the square to add around the i j case
|
||||
* @param max_gap the max distance to add the s square around the i j case
|
||||
* @param dir the array containing coef of directions
|
||||
* @param force true => place the s square on lighted blank too else only on blank
|
||||
* @return uint - the number of placed square (if there is an error undo all moves and return 0)
|
||||
*/
|
||||
uint addAround(game g, uint i, uint j, square s, uint max_gap, int* dir, bool force) {
|
||||
uint move_played = 0;
|
||||
for (uint gap_position = 1; gap_position <= max_gap; gap_position++) {
|
||||
@@ -153,6 +190,21 @@ uint addAround(game g, uint i, uint j, square s, uint max_gap, int* dir, bool fo
|
||||
return move_played;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief look the cases around the i j case of the game g from 1 case distance to max_gap distance and fill not_empty, lightbulb, mark, blank_not_lighted
|
||||
* variables with the number of occurence found. dirDiagoToEdit is an optional param who contain the coordinates of the blank squares
|
||||
*
|
||||
* @param g the game
|
||||
* @param i the i coordinate of the case to check around
|
||||
* @param j the j coordinate of the case to check around
|
||||
* @param max_gap the max distance to check around the i j coordinate
|
||||
* @param not_empty the variable to edit with the number of not empty case around i j
|
||||
* @param lightbulb the variable to edit with the number of lightbulb around i j
|
||||
* @param mark the variable to edit with the number of mark around i j
|
||||
* @param blank_not_lighted the variable to edit with the number of blank_not_lighted around i j
|
||||
* @param dirDiagoToEdit (optional) must be allocated with the maximum possible coordinate (4*2*gap_distance) will be edit with the coordinate of all blank
|
||||
* squares around i j
|
||||
*/
|
||||
void checkAround(cgame g, uint i, uint j, uint max_gap, int* not_empty, int* lightbulb, int* mark, int* blank_not_lighted, int* dirDiagoToEdit) {
|
||||
int dir[] = {1, 0, -1, 0, 0, 1, 0, -1};
|
||||
for (uint gap_position = 1; gap_position <= max_gap; gap_position++) {
|
||||
@@ -185,7 +237,8 @@ void checkAround(cgame g, uint i, uint j, uint max_gap, int* not_empty, int* lig
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief analyze the game and return the number of move played / special number
|
||||
* @brief analyze the game and play moves that are logical / mandatory. It stops only when it don't play any move and return the number of move played / special
|
||||
* number
|
||||
*
|
||||
* @param g the game to analyze
|
||||
* @return -1 if game_is_over ; -2 if the game has no sol ; else the number of move played
|
||||
@@ -199,6 +252,11 @@ int game_analyze(game g) {
|
||||
int dirLine[] = {1, 0, -1, 0, 0, 1, 0, -1};
|
||||
int dirDiago[8] = {-1, -1, -1, -1, -1, -1, -1, -1};
|
||||
uint tmp = 0;
|
||||
/**
|
||||
* @brief if the case is a blank (not lighted) test if there is only one blank square (itself) in all the directions if yes set a lightbulb (if
|
||||
* the lightbulb create an error the game is unsolvable => undo all moves and return -2)
|
||||
*
|
||||
*/
|
||||
if (game_get_square(g, i, j) == S_BLANK) {
|
||||
int lb = 0, not_empty = 0, mark = 0, blank = 0;
|
||||
checkAround(g, i, j, max(game_nb_cols(g), game_nb_rows(g)), ¬_empty, &lb, &mark, &blank, NULL);
|
||||
@@ -215,6 +273,12 @@ int game_analyze(game g) {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @brief if the square is a wall between 1 and 4 test if there is the number of lightbulb already placed => place marks on all the blanks
|
||||
* (if there is an error the game is unsolvable) square around the wall, else test if there is the number of blank (not lighted) needed by
|
||||
* the wall around it => set lightbulb around the wall (if there is an error the game is unsolvable)
|
||||
*
|
||||
*/
|
||||
} else if (game_get_state(g, i, j) >= S_BLACK1 && game_get_state(g, i, j) < S_BLACKU) {
|
||||
int lb = 0, not_empty = 0, mark = 0, blank = 0;
|
||||
checkAround(g, i, j, 1, ¬_empty, &lb, &mark, &blank, dirDiago);
|
||||
@@ -232,7 +296,12 @@ int game_analyze(game g) {
|
||||
move_played += tmp;
|
||||
if (game_is_over(g))
|
||||
return -1;
|
||||
} else if (blank == game_get_black_number(g, i, j) - lb + 1) {
|
||||
}
|
||||
/**
|
||||
* @brief if this statement is true that means a single lightbulb (set on diagonals of the wall) can obfuscate two blanks around the wall
|
||||
* and produce an error so we can place mark on these cases
|
||||
*/
|
||||
else if (blank == game_get_black_number(g, i, j) - lb + 1) {
|
||||
uint cpt = coordinateCrossPointMaker(dirDiago, 8);
|
||||
for (uint cpt_index = 0; cpt_index < cpt; cpt_index += 2) {
|
||||
if (game_get_square(g, dirDiago[cpt_index], dirDiago[cpt_index + 1]) == S_BLANK) {
|
||||
@@ -241,12 +310,17 @@ int game_analyze(game g) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (game_get_state(g, i, j) == S_BLACK0) {
|
||||
} // we can set marks all around a wall0 because it must not have lightbulb right next to it
|
||||
else if (game_get_state(g, i, j) == S_BLACK0) {
|
||||
move_played += addAround(g, i, j, S_MARK, 1, dirLine, true);
|
||||
if (game_is_over(g))
|
||||
return -1;
|
||||
|
||||
} else if (game_get_state(g, i, j) == S_MARK && !game_is_lighted(g, i, j)) {
|
||||
} /**
|
||||
* @brief if the mark is not lighted and there is only one blank in all the directions we can place a lightbulb (if there is an error the game
|
||||
* is unsolvable)
|
||||
*
|
||||
*/
|
||||
else if (game_get_state(g, i, j) == S_MARK && !game_is_lighted(g, i, j)) {
|
||||
int lb = 0, not_empty = 0, mark = 0, blank = 0;
|
||||
checkAround(g, i, j, max(game_nb_cols(g), game_nb_rows(g)), ¬_empty, &lb, &mark, &blank, NULL);
|
||||
if (blank == 1)
|
||||
@@ -269,6 +343,17 @@ int game_analyze(game g) {
|
||||
return total_move_played;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief the brutforce fonction set a lightbulb on each case (recursive call while deep > 1) if the lightbulb produce an error undo it and go to the next
|
||||
* coordinate on each new lightbulb who isn't producing error call game_analyze to see if it can help / say if the game is unsolvable (and set a mark on this
|
||||
* case)
|
||||
*
|
||||
* @param g the game to brutforce
|
||||
* @param deep the deepness of the brutforce
|
||||
* @param move_played the number of moves played (to undo in case of unsolvable game)
|
||||
* @return true if the game is solved
|
||||
* @return false if the game is unsolvable
|
||||
*/
|
||||
bool aux_game_solve(game g, uint deep, int* move_played) {
|
||||
for (uint i = 0; i < game_nb_rows(g); i++) {
|
||||
for (uint j = 0; j < game_nb_cols(g); j++) {
|
||||
@@ -306,17 +391,29 @@ bool aux_game_solve(game g, uint deep, int* move_played) {
|
||||
return false;
|
||||
}
|
||||
|
||||
uint total_number_of_blank_cases(game g) {
|
||||
uint cpt = 0;
|
||||
for (uint i = 0; i < game_nb_cols(g); i++) {
|
||||
for (uint j = 0; j < game_nb_rows(g); j++) {
|
||||
if (game_get_state(g, i, j) == S_BLANK)
|
||||
cpt++;
|
||||
}
|
||||
}
|
||||
return cpt;
|
||||
}
|
||||
|
||||
bool game_solve(game g) {
|
||||
// TODELETE
|
||||
// game_print(g);
|
||||
// first analyze of the game to reduce the number of brutforce needed
|
||||
int total_move_played = game_analyze(g);
|
||||
// to keep the first analyze
|
||||
// give move_played and not total_move_played to keep the first analyze
|
||||
int move_played = 0;
|
||||
if (total_move_played == -1)
|
||||
return true;
|
||||
// if the game is unsolvalbe at the first analyze it's unsolvable even with brutforce
|
||||
if (total_move_played == -2)
|
||||
return false;
|
||||
for (uint deep = 1; deep < game_nb_cols(g) * game_nb_rows(g); deep++) {
|
||||
// else try brutforce with deepness going from 1 to the total number of blank cases on the game
|
||||
for (uint deep = 1; deep < total_number_of_blank_cases(g); deep++) {
|
||||
total_move_played += move_played;
|
||||
if (aux_game_solve(g, deep, &move_played)) {
|
||||
return true;
|
||||
|
||||
Reference in new issue
Block a user