37typedef enum : uint32_t {
83 int32_t end_r = r + (dir.
delta_row * span);
84 int32_t end_c = c + (dir.
delta_col * span);
88 if ((end_r < 0) || (end_r >= rows) || (end_c < 0) || (end_c >= cols)) {
92 for (int32_t k = 0; k <= span; ++k) {
95 if (grid->
cells[cur_r][cur_c] != key[k]) {
134 uint32_t* out_end_row,
135 uint32_t* out_end_col)
139 {.delta_row = 0, .delta_col = 1},
140 {.delta_row = 1, .delta_col = 1},
141 {.delta_row = 1, .delta_col = 0},
142 {.delta_row = 1, .delta_col = -1},
143 {.delta_row = 0, .delta_col = -1},
144 {.delta_row = -1, .delta_col = -1},
145 {.delta_row = -1, .delta_col = 0},
146 {.delta_row = -1, .delta_col = 1},
152 const int32_t end_row = r + (dir.
delta_row * span);
153 const int32_t end_col = c + (dir.
delta_col * span);
154 *out_end_row = (uint32_t)end_row;
155 *out_end_col = (uint32_t)end_col;
163 const char* search_key,
165 uint32_t* out_start_row,
166 uint32_t* out_start_col,
167 uint32_t* out_end_row,
168 uint32_t* out_end_col)
170 if ((grid ==
nullptr) || (search_key ==
nullptr) || (out_start_row ==
nullptr) ||
171 (out_start_col ==
nullptr) || (out_end_row ==
nullptr) || (out_end_col ==
nullptr) ||
180 int32_t span = (int32_t)key_len - 1;
181 char lead = search_key[0];
183 for (int32_t r = 0; r < rows; ++r) {
184 for (int32_t c = 0; c < cols; ++c) {
185 if (grid->
cells[r][c] != lead) {
189 *out_start_row = (uint32_t)r;
190 *out_start_col = (uint32_t)c;
225 const char* ptr = *text_ptr;
230 if ((ptr >= text_end) || (*ptr <
'0') || (*ptr >
'9')) {
233 uint32_t digit = (uint32_t)(*ptr -
'0');
276 const char* text_end,
287 const char* ptr = *text_ptr;
288 if ((ptr >= text_end) || ((*ptr !=
'x') && (*ptr !=
'X'))) {
301 if ((ptr >= text_end) || ((*ptr !=
'\r') && (*ptr !=
'\n'))) {
342 const char* text_end,
344 uint32_t expected_cols)
346 const char* ptr = *text_ptr;
350 if ((ptr >= text_end) || (*ptr ==
'\0') || (*ptr ==
'\n') || (*ptr ==
'\r')) {
353 if ((*ptr !=
' ') && (*ptr !=
'\t')) {
354 if (c >= expected_cols) {
363 if (c != expected_cols) {
368 if ((ptr >= text_end) || ((*ptr !=
'\r') && (*ptr !=
'\n'))) {
403 for (uint32_t r = 0U; r < grid->
row_count; ++r) {
475 const char* text_end,
480 uint32_t* out_search_len)
482 const char* ptr = *text_ptr;
483 uint32_t word_len = 0U;
484 uint32_t search_len = 0U;
487 if ((ptr >= text_end) || (*ptr ==
'\0') || (*ptr ==
'\r') || (*ptr ==
'\n')) {
490 if ((word_len + 1U) < word_cap) {
491 word[word_len] = *ptr;
494 if ((*ptr !=
' ') && (*ptr !=
'\t')) {
495 if ((search_len + 1U) < key_cap) {
496 search_key[search_len] = *ptr;
504 if ((ptr >= text_end) || ((*ptr !=
'\r') && (*ptr !=
'\n'))) {
510 *out_search_len = search_len;
539 const char* text_end,
543 if ((ptr >= text_end) || (*ptr ==
'\0')) {
549 uint32_t search_len = 0U;
559 if (search_len == 0U) {
563 uint32_t start_row = 0U;
564 uint32_t start_col = 0U;
565 uint32_t end_row = 0U;
566 uint32_t end_col = 0U;
584 if ((ctx ==
nullptr) || (text ==
nullptr) || (out_stream ==
nullptr)) {
596 const char* ptr = text;
597 const char* text_end = &text[text_len];
static ra8_err_t internal_parse_dimensions(const char **text_ptr, const char *text_end, uint32_t *out_rows, uint32_t *out_cols)
Parse board header dimensions and validate against capacity limits.
static ra8_err_t internal_parse_grid(const char **text_ptr, const char *text_end, soup_grid_t *grid)
Parse complete grid character matrix from text stream.
ra8_err_t soup_init(soup_context_t *ctx)
Initialize a caller-owned puzzle solver context.
static void internal_emit_match(ra8_io_stream_t *out_stream, const char *word, uint32_t start_row, uint32_t start_col, uint32_t end_row, uint32_t end_col)
Emit single solved word result line to the stream.
static ra8_err_t internal_solve_words(soup_context_t *ctx, const char *ptr, const char *text_end, ra8_io_stream_t *out_stream)
Solve all words following the grid in the text buffer.
soup_numeric_constants_t
Numeric constants for parsing and search navigation.
@ k_decimal_overflow_cap
(UINT32_MAX - 9) / 10 threshold.
bool soup_find_word(const soup_grid_t *grid, const char *search_key, uint32_t key_len, uint32_t *out_start_row, uint32_t *out_start_col, uint32_t *out_end_row, uint32_t *out_end_col)
Search a grid for a normalized word along all 8 compass directions.
static ra8_err_t internal_parse_uint32(const char **text_ptr, const char *text_end, uint32_t *out_val)
Parse a positive decimal integer with overflow detection.
static void internal_parse_word_entry(const char **text_ptr, const char *text_end, char *word, size_t word_cap, char *search_key, size_t key_cap, uint32_t *out_search_len)
Parse one target word line into word and search key buffers.
static ra8_err_t internal_parse_single_row(const char **text_ptr, const char *text_end, char *row_cells, uint32_t expected_cols)
Parse a single grid row into grid cells with eager validation.
ra8_err_t soup_solve(soup_context_t *ctx, const char *text, uint32_t text_len, ra8_io_stream_t *out_stream)
Parse board and words from puzzle text and emit solutions to the output stream.
static bool internal_check_cell(const soup_grid_t *grid, const char *key, int32_t span, int32_t r, int32_t c, uint32_t *out_end_row, uint32_t *out_end_col)
Check all directions starting at a specific cell.
static bool internal_match_ray(const soup_grid_t *grid, const char *key, int32_t span, int32_t r, int32_t c, soup_dir_t dir)
Match word characters along a single directional ray.
Word search puzzle solver API and bounded workspace definitions.
@ k_soup_max_line_steps
Upper bound on line parse iterations.
@ k_soup_max_grid_rows
Maximum board row dimension.
@ k_soup_max_parse_steps
Upper bound on file parse iterations.
@ k_soup_max_dim_digits
Maximum digits in dimension specifier.
@ k_soup_max_word_chars
Maximum characters per target word.
@ k_soup_max_grid_cols
Maximum board column dimension.
@ k_soup_max_file_capacity
Maximum supported puzzle file size.
@ k_soup_direction_count
8-way directional navigation rays.
@ k_decimal_base
Decimal conversion radix.
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_invalid_arg
Invalid function argument.
@ k_ra8_err_range_check_failed
Value outside range enforced by RA8_CHECK_RANGE / RA8_CHECK_RANGE_TAG.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
void * memset(void *dst, int value, size_t n)
Fill memory with a constant byte value.
ra8_io targetable byte-stream facade – one writer, many destinations.
ra8_err_t ra8_io_stream_puts(ra8_io_stream_t *s, const char *str)
Write a NUL-terminated string (without the NUL) to the bound sink.
ra8_err_t ra8_io_stream_put_u32(ra8_io_stream_t *s, uint32_t value)
Write value as unsigned decimal ASCII (no leading zeros).
ra8_err_t ra8_io_stream_flush(ra8_io_stream_t *s)
Flush any sink-side buffering to its destination.
ra8_err_t ra8_io_stream_putc(ra8_io_stream_t *s, char c)
Write a single byte to the bound sink.
Caller-allocated byte-stream handle binding a sink to its context.
Caller-owned bounded workspace for puzzle solving (zero-heap).
soup_grid_t grid
Board grid storage.
char word_buffer[k_soup_max_word_chars]
Current word buffer.
char search_key_buffer[k_soup_max_word_chars]
Normalized key buffer.
Direction vector for 2D grid navigation.
int32_t delta_col
Column offset step.
int32_t delta_row
Row offset step.
In-memory word search board matrix.
char cells[k_soup_max_grid_rows][k_soup_max_grid_cols]
Character grid storage.
uint32_t row_count
Active row dimension.
uint32_t col_count
Active column dimension.