changed memory allocation to calloc instead of GC_MALLOC and finsihed ms_ui_utils
This commit is contained in:
parent
655af3fcf4
commit
9727928404
4 changed files with 321 additions and 10 deletions
|
|
@ -13,6 +13,7 @@
|
||||||
#include "ms_board.h"
|
#include "ms_board.h"
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct MsBoardData {
|
struct MsBoardData {
|
||||||
Count column_count;
|
Count column_count;
|
||||||
|
|
@ -31,7 +32,7 @@ static MsBoard the_board = 0;
|
||||||
*/
|
*/
|
||||||
MsBoard msb_get_board() {
|
MsBoard msb_get_board() {
|
||||||
if (the_board == 0) {
|
if (the_board == 0) {
|
||||||
the_board = (MsBoard)GC_MALLOC(sizeof(struct MsBoardData));
|
the_board = (MsBoard)calloc(1, sizeof(struct MsBoardData));
|
||||||
}
|
}
|
||||||
return the_board;
|
return the_board;
|
||||||
}
|
}
|
||||||
|
|
@ -54,6 +55,8 @@ void msb_init_board(MsBoard board, Count column_count, Count row_count) {
|
||||||
board->column_count = column_count > MAX_BOARD_SIZE ? MAX_BOARD_SIZE : column_count;
|
board->column_count = column_count > MAX_BOARD_SIZE ? MAX_BOARD_SIZE : column_count;
|
||||||
board->row_count = row_count > MAX_BOARD_SIZE ? MAX_BOARD_SIZE : row_count;
|
board->row_count = row_count > MAX_BOARD_SIZE ? MAX_BOARD_SIZE : row_count;
|
||||||
|
|
||||||
|
msc_reset_cell_factory();
|
||||||
|
|
||||||
for (int row = 0; row < board->row_count; row++) {
|
for (int row = 0; row < board->row_count; row++) {
|
||||||
for (int col = 0; col < board->column_count; col++) {
|
for (int col = 0; col < board->column_count; col++) {
|
||||||
board->cells[col][row] = msc_produce_cell();
|
board->cells[col][row] = msc_produce_cell();
|
||||||
|
|
|
||||||
161
ms_cell.c
161
ms_cell.c
|
|
@ -12,8 +12,169 @@
|
||||||
|
|
||||||
#define CELL_COUNT MAX_BOARD_SIZE * MAX_BOARD_SIZE
|
#define CELL_COUNT MAX_BOARD_SIZE * MAX_BOARD_SIZE
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ms_cell.h"
|
||||||
|
|
||||||
/** Implementation of cell data */
|
/** Implementation of cell data */
|
||||||
|
struct MsCellData {
|
||||||
|
CellIdx idx;
|
||||||
|
bool covered;
|
||||||
|
CellMarker marker;
|
||||||
|
bool mine;
|
||||||
|
Count dangerous_neighbor_count;
|
||||||
|
};
|
||||||
|
|
||||||
/** Maximum amount of cell instances */
|
/** Maximum amount of cell instances */
|
||||||
|
static MsCell cells[CELL_COUNT] = {0};
|
||||||
|
|
||||||
/** The number of produced cells */
|
/** 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
155
ms_ui_utils.c
155
ms_ui_utils.c
|
|
@ -23,5 +23,160 @@ CellIdx msu_get_random_index(Count upper_limit) {
|
||||||
return (upper_limit == 0 ? 0 : rand() % (upper_limit));
|
return (upper_limit == 0 ? 0 : rand() % (upper_limit));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given cell index to the corresponding column address.
|
||||||
|
*
|
||||||
|
* @param idx The index to map.
|
||||||
|
* @return ColAddr The corresponding column address or a '0' value,
|
||||||
|
* if the index cannot be mapped.
|
||||||
|
*/
|
||||||
|
ColAddr msu_idx_to_col_address(CellIdx idx) {
|
||||||
|
if (idx > 0 && idx <= MAX_BOARD_SIZE) {
|
||||||
|
return (ColAddr)idx;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given cell index to the corresponding row address.
|
||||||
|
*
|
||||||
|
* @param idx The index to map.
|
||||||
|
* @return RowAddr The corresponding row address or a '0' value,
|
||||||
|
* if the index cannot be mapped.
|
||||||
|
*/
|
||||||
|
RowAddr msu_idx_to_row_address(CellIdx idx) {
|
||||||
|
if (idx > 0 && idx <= MAX_BOARD_SIZE) {
|
||||||
|
return (RowAddr)idx;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given column address to the corresponding cell index.
|
||||||
|
*
|
||||||
|
* @param addr The column address to map.
|
||||||
|
* @return CellIdx The corresponding cell index or 0,
|
||||||
|
* if the address cannot be mapped.
|
||||||
|
*/
|
||||||
|
CellIdx msu_col_address_to_index(ColAddr addr) {
|
||||||
|
if (addr > 0 && addr < MAX_BOARD_SIZE) {
|
||||||
|
return (CellIdx)addr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given row address to the corresponding cell index.
|
||||||
|
*
|
||||||
|
* @param addr The row address to map.
|
||||||
|
* @return CellIdx The corresponding cell index or 0,
|
||||||
|
* if the address cannot be mapped.
|
||||||
|
*/
|
||||||
|
CellIdx msu_row_address_to_index(RowAddr addr) {
|
||||||
|
if (addr > 0 && addr < MAX_BOARD_SIZE) {
|
||||||
|
return (CellIdx)addr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the character a user may type to perform the given action.
|
||||||
|
* The key must be unique for each action.
|
||||||
|
*
|
||||||
|
* @param action The action for which the corresponding 'key' is requested.
|
||||||
|
* @return char The corresponding 'key' character or '\0',
|
||||||
|
* if the action cannot reasonably be mapped.
|
||||||
|
*/
|
||||||
|
char msu_get_action_char(Action action) {
|
||||||
|
switch (action) {
|
||||||
|
case MARK_MINE:
|
||||||
|
return 'm';
|
||||||
|
case MARK_SUSPECT:
|
||||||
|
return 's';
|
||||||
|
case CLEAR_MARKER:
|
||||||
|
return 'c';
|
||||||
|
case UNCOVER:
|
||||||
|
return 'u';
|
||||||
|
case QUIT_GAME:
|
||||||
|
return 'q';
|
||||||
|
default:
|
||||||
|
return '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the action for the given 'key' character (the counterpart of ´msu_get_action_char´).
|
||||||
|
*
|
||||||
|
* @param key The key for the action.
|
||||||
|
* @return Action The action corresponding to the given 'key'
|
||||||
|
* or 'INVALID',if the key cannot be mapped.
|
||||||
|
*/
|
||||||
|
Action msu_get_action(char key) {
|
||||||
|
switch (key) {
|
||||||
|
case 'm':
|
||||||
|
return MARK_MINE;
|
||||||
|
case 's':
|
||||||
|
return MARK_SUSPECT;
|
||||||
|
case 'c':
|
||||||
|
return CLEAR_MARKER;
|
||||||
|
case 'u':
|
||||||
|
return UNCOVER;
|
||||||
|
case 'q':
|
||||||
|
return QUIT_GAME;
|
||||||
|
default:
|
||||||
|
return UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given cell marker to its presentation symbol
|
||||||
|
* (the character shown in the game visualization).
|
||||||
|
*
|
||||||
|
* @param marker The marker.
|
||||||
|
* @return char The corresponding character or '#', if
|
||||||
|
* the marker cannot be mapped.
|
||||||
|
*/
|
||||||
|
char msu_get_marker_symbol(CellMarker marker) {
|
||||||
|
switch (marker) {
|
||||||
|
case NONE:
|
||||||
|
return ' ';
|
||||||
|
case MINE_DETECTED:
|
||||||
|
return 'X';
|
||||||
|
case MINE_SUSPECTED:
|
||||||
|
return '?';
|
||||||
|
default:
|
||||||
|
return '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides the symbol that represents a mine
|
||||||
|
* (the character shown in the game visualization).
|
||||||
|
*
|
||||||
|
* @return char The symbol of a mine.
|
||||||
|
*/
|
||||||
|
char msu_get_mine_symbol() {
|
||||||
|
return '*';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps the given game status to a user presentable label.
|
||||||
|
*
|
||||||
|
* @param status The status to map.
|
||||||
|
* @return char* The text for the status or 0, if
|
||||||
|
* the status cannot be mapped.
|
||||||
|
*/
|
||||||
|
char* msu_get_status_label(GameState status) {
|
||||||
|
switch (status) {
|
||||||
|
case IN_PROGRESS:
|
||||||
|
return "In Progress";
|
||||||
|
case SOLVED:
|
||||||
|
return "Solved";
|
||||||
|
case FAILED:
|
||||||
|
return "Failed";
|
||||||
|
case INVALID:
|
||||||
|
default:
|
||||||
|
return "Invalid";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#define ___MS_UI_UTILS_H
|
#define ___MS_UI_UTILS_H
|
||||||
|
|
||||||
#include "general.h"
|
#include "general.h"
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes the random number generator. It must be invoked
|
* Initializes the random number generator. It must be invoked
|
||||||
|
|
@ -67,15 +68,6 @@ CellIdx msu_col_address_to_index(ColAddr addr);
|
||||||
*/
|
*/
|
||||||
CellIdx msu_row_address_to_index(RowAddr addr);
|
CellIdx msu_row_address_to_index(RowAddr addr);
|
||||||
|
|
||||||
/**
|
|
||||||
* Maps the given column address to the corresponding cell index.
|
|
||||||
*
|
|
||||||
* @param addr The column address to map.
|
|
||||||
* @return CellIdx The corresponding cell index or 0,
|
|
||||||
* if the address cannot be mapped.
|
|
||||||
*/
|
|
||||||
CellIdx msu_col_address_to_index(ColAddr addr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides the character a user may type to perform the given action.
|
* Provides the character a user may type to perform the given action.
|
||||||
* The key must be unique for each action.
|
* The key must be unique for each action.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue