180 lines
5 KiB
C
180 lines
5 KiB
C
/*----------------------------------------------------------
|
|
* 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 <stdlib.h>
|
|
#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;
|
|
}
|
|
}
|