/*---------------------------------------------------------- * HTBLA-Leonding / Class: 2IHIF * --------------------------------------------------------- * Exercise Number: B1 * Title: Mine Sweeper Cell implementation * Author: Marc Tismonar * ---------------------------------------------------------- * Description: * Implementation of ms_cell.h. * ---------------------------------------------------------- */ #define CELL_COUNT MAX_BOARD_SIZE * MAX_BOARD_SIZE #include #include "ms_cell.h" /** Implementation of cell data */ struct MsCellData { CellIdx idx; bool covered; CellMarker marker; bool mine; Count dangerous_neighbor_count; }; /** Maximum amount of cell instances */ static MsCell cells[CELL_COUNT] = {0}; /** The number of produced cells */ static Count produced_cells = 0; /** * Provides another, yet unused instance, initialized Mine Sweeper cell * The provided cell is covered, carries no marker, no mine, and has 0 dangerous neighbors. * * Up to `MAX_BOARD_SIZE * MAX_BOARD_SIZE` cells can be produced by subsequent * calls of this function. * * @return The fresh cell instance or 0, if no more instance is available. */ MsCell msc_produce_cell() { if (produced_cells >= CELL_COUNT) { return 0; } if (cells[produced_cells] == 0) { cells[produced_cells] = (MsCell)calloc(1, sizeof(struct MsCellData)); } MsCell cell = cells[produced_cells]; cell->idx = produced_cells; cell->covered = true; cell->marker = NONE; cell->mine = false; cell->dangerous_neighbor_count = 0; produced_cells++; return cell; } /** * Resets the internal cell factory. Function `msc_produce_cell` is capable * to produce the full number of cell after this function is called. */ void msc_reset_cell_factory() { produced_cells = 0; } /** * Determines whether or not the given cell is valid. * A cell is NOT valid, if it is 0 or has a neighbor mine count * greater than 8. * * @param cell The cell instance in focus. * @return True if the given cell is valid, false otherwise. */ bool msc_is_valid(MsCell cell) { return cell != 0 && cell->dangerous_neighbor_count <= 8; } /** * Determines whether or not the given cell is currently covered. * * @param cell The cell instance in focus. * @return True if the given cell is covered, false otherwise. */ bool msc_is_covered(MsCell cell) { return cell != 0 && cell->covered; } /** * Uncovers the given cell. * If the cell carries a veritable marker (detected or suspected) * or is already uncovered, the request is ignored. Otherwise * function `msc_is_covered` returns `false` for this cell afterwards. * * Note: an uncovered cell cannot be covered again. * * @param cell The cell instance in focus. * @return True if the cell was successfully uncovered, false otherwise. */ bool msc_uncover(MsCell cell) { if (!msc_is_valid(cell) || !cell->covered || cell->marker != NONE) { return false; } cell->covered = false; return true; } /** * Determines whether or not the given cell carries a mine. * * @param cell The cell instance in focus. * @return True if the cell carries a mine, false otherwise. */ bool msc_has_mine(MsCell cell) { return cell != 0 && cell->mine; } /** * Specifies that the given cell carries a mine. * Invocations for invalid cells are ignored. * * @param cell The cell instance in focus. */ void msc_drop_mine(MsCell cell) { if (msc_is_valid(cell)) { cell->mine = true; } } /** * Provides the number of direct neighbor cells, which carries a mine. * * @param cell The cell instance in focus. * @return The number between 0 to 8 that encounters the neighbor cells * that carries a mine or 255 if the cell is not valid. */ Byte msc_get_dangerous_neighbor_count(MsCell cell) { return msc_is_valid(cell) ? cell->dangerous_neighbor_count : 0xFF; } /** * Increments (+1) the count of neighbor cells that carries a mine. * Invocations for invalid cells are ignored. * * @param cell The cell instance in focus. */ void msc_inc_dangerous_neighbor_count(MsCell cell) { if (msc_is_valid(cell)) { cell->dangerous_neighbor_count++; } } /** * Provides the given marker of the given cell. * * @param cell The cell instance in focus. * @return The marker carried by the cell * or `NONE`, if the cell is not valid. */ CellMarker msc_get_marker(MsCell cell) { return msc_is_valid(cell) ? cell->marker : NONE; } /** * Applies the given marker to the given cell. The marker is cleared * by applying a 'none' marker. * Invocations for invalid cells are ignored. * * @param cell The cell instance in focus. * @param marker The marker to apply. */ void msc_set_marker(MsCell cell, CellMarker marker) { if (msc_is_valid(cell)) { cell->marker = marker; } }