#include "puzzle_common.h" #include "puzzle_p.h" #include "puzzle.h" #include "globals.h" static int puzzle_median_cmp(const void * const a_, const void * const b_) { const double a = * (const double *) a_; const double b = * (const double *) b_; if (a < b) { return -1; } else if (a > b) { return 1; } return 0; } static double puzzle_median(double * const vec, size_t size) { size_t n; size_t o; double avg; if (size <= (size_t) 0U) { return 0.0; } qsort((void *) vec, size, sizeof *vec, puzzle_median_cmp); if ((n = size / (size_t) 2U) == (size_t) 0U) { if (size > (size_t) 1U) { o = (size_t) 1U; } else { o = (size_t) 0U; } } else { o = n + (size_t) 1U; } if (o < n) { puzzle_err_bug(__FILE__, __LINE__); } avg = (vec[n] + vec[o]) / 2.0; if (avg < vec[n] || avg > vec[o]) { avg = vec[n]; } return avg; } int puzzle_fill_cvec_from_dvec(PuzzleContext * const context, PuzzleCvec * const cvec, const PuzzleDvec * const dvec) { size_t s; const double *dvecptr; signed char *cvecptr; double *lights = NULL, *darks = NULL; size_t pos_lights = (size_t) 0U, pos_darks = (size_t) 0U; size_t sizeof_lights, sizeof_darks; double lighter_cutoff, darker_cutoff; int err = 0; double dv; if ((cvec->sizeof_vec = dvec->sizeof_compressed_vec) <= (size_t) 0U) { puzzle_err_bug(__FILE__, __LINE__); } if ((cvec->vec = calloc(cvec->sizeof_vec, sizeof *cvec->vec)) == NULL) { return -1; } sizeof_lights = sizeof_darks = cvec->sizeof_vec; if ((lights = calloc(sizeof_lights, sizeof *lights)) == NULL || (darks = calloc(sizeof_darks, sizeof *darks)) == NULL) { err = -1; goto out; } dvecptr = dvec->vec; s = cvec->sizeof_vec; do { dv = *dvecptr++; if (dv >= - context->puzzle_noise_cutoff && dv <= context->puzzle_noise_cutoff) { continue; } if (dv < context->puzzle_noise_cutoff) { darks[pos_darks++] = dv; if (pos_darks > sizeof_darks) { puzzle_err_bug(__FILE__, __LINE__); } } else if (dv > context->puzzle_noise_cutoff) { lights[pos_lights++] = dv; if (pos_lights > sizeof_lights) { puzzle_err_bug(__FILE__, __LINE__); } } } while (--s != (size_t) 0U); lighter_cutoff = puzzle_median(lights, pos_lights); darker_cutoff = puzzle_median(darks, pos_darks); free(lights); lights = NULL; free(darks); darks = NULL; dvecptr = dvec->vec; cvecptr = cvec->vec; s = cvec->sizeof_vec; do { dv = *dvecptr++; if (dv >= - context->puzzle_noise_cutoff && dv <= context->puzzle_noise_cutoff) { *cvecptr++ = 0; } else if (dv < 0.0) { *cvecptr++ = dv < darker_cutoff ? -2 : -1; } else { *cvecptr++ = dv > lighter_cutoff ? +2 : +1; } } while (--s != (size_t) 0U); if ((size_t) (cvecptr - cvec->vec) != cvec->sizeof_vec) { puzzle_err_bug(__FILE__, __LINE__); } out: free(lights); free(darks); return err; } void puzzle_init_cvec(PuzzleContext * const context, PuzzleCvec * const cvec) { (void) context; cvec->sizeof_vec = (size_t) 0U; cvec->vec = NULL; } void puzzle_free_cvec(PuzzleContext * const context, PuzzleCvec * const cvec) { (void) context; free(cvec->vec); cvec->vec = NULL; } int puzzle_dump_cvec(PuzzleContext * const context, const PuzzleCvec * const cvec) { size_t s = cvec->sizeof_vec; const signed char *vecptr = cvec->vec; (void) context; if (s <= (size_t) 0U) { puzzle_err_bug(__FILE__, __LINE__); } do { printf("%d\n", *vecptr++); } while (--s != (size_t) 0U); return 0; } int puzzle_cvec_cksum(PuzzleContext * const context, const PuzzleCvec * const cvec, unsigned int * const sum) { size_t s = cvec->sizeof_vec; const signed char *vecptr = cvec->vec; (void) context; *sum = 5381; do { *sum += *sum << 5; *sum ^= (unsigned int) *vecptr++; } while (--s != (size_t) 0U); return 0; } int puzzle_fill_cvec_from_file(PuzzleContext * const context, PuzzleCvec * const cvec, const char * const file) { PuzzleDvec dvec; int ret; puzzle_init_dvec(context, &dvec); if ((ret = puzzle_fill_dvec_from_file(context, &dvec, file)) == 0) { ret = puzzle_fill_cvec_from_dvec(context, cvec, &dvec); } puzzle_free_dvec(context, &dvec); return ret; } int puzzle_fill_cvec_from_mem(PuzzleContext * const context, PuzzleCvec * const cvec, const void * const mem, const size_t size) { PuzzleDvec dvec; int ret; puzzle_init_dvec(context, &dvec); if ((ret = puzzle_fill_dvec_from_mem(context, &dvec, mem, size)) == 0) { ret = puzzle_fill_cvec_from_dvec(context, cvec, &dvec); } puzzle_free_dvec(context, &dvec); return ret; }