#include <stdlib.h>

#include "backtrack.h"
#include "queens.h"

// El estado del problema. columns[fila] es la columna de la reina de esa fila, o -1.
typedef struct {
    int n;
    int *columns;
    long solutions;
    int stop_at_first;  // 1 si se busca solo la primera solución
    int *first;         // adónde copiar la primera solución, o NULL
} Queens;

// --- Por escribir. El paso es la fila, y la opción es la columna. Usen coloring.c de modelo. ---

// Hay una opción por cada columna.
static int queens_options(void *context, int step) {
    (void) context;
    (void) step;
    return 0;
}

// Revisa la misma columna y las dos diagonales, contra las reinas de las filas anteriores.
static int queens_is_valid(void *context, int step, int option) {
    (void) context;
    (void) step;
    (void) option;
    return 0;
}

static void queens_place(void *context, int step, int option) {
    (void) context;
    (void) step;
    (void) option;
}

static void queens_undo(void *context, int step, int option) {
    (void) context;
    (void) step;
    (void) option;
}

// Cuenta la solución. Si es la primera y first no es NULL, la copia ahí.
// Devuelve 1 si hay que detenerse, según stop_at_first.
static int queens_on_solution(void *context) {
    (void) context;
    return 1;
}

// --- De aquí para abajo ya está hecho. Es igual para las dos funciones públicas. ---

static long run_search(Queens *state, long *nodes) {
    state->columns = malloc((size_t) state->n * sizeof(state->columns[0]));
    if (state->columns == NULL) {
        return -1;
    }
    for (int row = 0; row < state->n; row++) {
        state->columns[row] = -1;
    }
    state->solutions = 0;

    Problem problem = {
        .steps = state->n,
        .options = queens_options,
        .is_valid = queens_is_valid,
        .place = queens_place,
        .undo = queens_undo,
        .on_solution = queens_on_solution,
    };
    *nodes = backtrack(&problem, state);

    free(state->columns);
    return state->solutions;
}

long queens_count(int n, long *nodes) {
    Queens state = {.n = n, .stop_at_first = 0, .first = NULL};
    return run_search(&state, nodes);
}

int queens_first(int n, int *columns, long *nodes) {
    Queens state = {.n = n, .stop_at_first = 1, .first = columns};
    long found = run_search(&state, nodes);
    if (found < 0) {
        return -1;
    }
    return found > 0;
}
