dsdfile *dsd_open(const char *name) { guchar header_id[4]; dsdfile *file = malloc(sizeof(dsdfile)); if (name == NULL) { file->stream = stdin; file->canseek = FALSE; } else { if ((file->stream = fopen(name, "r")) == NULL) { free(file); return NULL; } file->canseek = TRUE; } file->eof = FALSE; file->offset = 0; file->sample_offset = 0; file->channel_num = 0; file->sampling_frequency = 0; dsd_read_raw(header_id, sizeof(header_id), file); if (DSD_MATCH(header_id, "DSD ")) { file->type = DSF; if (!dsf_init(file)) { free(file); return NULL; } } else if (DSD_MATCH(header_id, "FRM8")) { file->type = DSDIFF; if (!dsdiff_init(file)) { free(file); return NULL; } } else { free(file); return NULL; } // Finalize buffer file->buffer.num_channels = file->channel_num; file->buffer.bytes_per_channel = 0; file->buffer.data = (guchar *)malloc(sizeof(guchar) * file->buffer.max_bytes_per_ch * file->channel_num); return file; }
static int *make_dsf(int *dsf, int *board, const int w, const int h) { const int sz = w * h; int i; if (!dsf) dsf = snew_dsf(w * h); else dsf_init(dsf, w * h); for (i = 0; i < sz; ++i) { int j; for (j = 0; j < 4; ++j) { const int x = (i % w) + dx[j]; const int y = (i / w) + dy[j]; const int k = w*y + x; if (x < 0 || x >= w || y < 0 || y >= h) continue; if (board[i] == board[k]) dsf_merge(dsf, i, k); } } return dsf; }
/* generate a random valid board; uses validate_board. */ static void make_board(int *board, int w, int h, random_state *rs) { int *dsf; const unsigned int sz = w * h; /* w=h=2 is a special case which requires a number > max(w, h) */ /* TODO prove that this is the case ONLY for w=h=2. */ const int maxsize = min(max(max(w, h), 3), 9); /* Note that if 1 in {w, h} then it's impossible to have a region * of size > w*h, so the special case only affects w=h=2. */ int nboards = 0; int i; assert(w >= 1); assert(h >= 1); assert(board); dsf = snew_dsf(sz); /* implicit dsf_init */ /* I abuse the board variable: when generating the puzzle, it * contains a shuffled list of numbers {0, ..., nsq-1}. */ for (i = 0; i < (int)sz; ++i) board[i] = i; while (1) { int change; ++nboards; shuffle(board, sz, sizeof (int), rs); /* while the board can in principle be fixed */ do { #ifdef ANDROID if (android_cancelled()) { sfree(dsf); return; } #endif change = FALSE; for (i = 0; i < (int)sz; ++i) { int a = SENTINEL; int b = SENTINEL; int c = SENTINEL; const int aa = dsf_canonify(dsf, board[i]); int cc = sz; int j; for (j = 0; j < 4; ++j) { const int x = (board[i] % w) + dx[j]; const int y = (board[i] / w) + dy[j]; int bb; if (x < 0 || x >= w || y < 0 || y >= h) continue; bb = dsf_canonify(dsf, w*y + x); if (aa == bb) continue; else if (dsf_size(dsf, aa) == dsf_size(dsf, bb)) { a = aa; b = bb; c = cc; } else if (cc == sz) c = cc = bb; } if (a != SENTINEL) { a = dsf_canonify(dsf, a); assert(a != dsf_canonify(dsf, b)); if (c != sz) assert(a != dsf_canonify(dsf, c)); dsf_merge(dsf, a, c == sz? b: c); /* if repair impossible; make a new board */ if (dsf_size(dsf, a) > maxsize) goto retry; change = TRUE; } } } while (change); for (i = 0; i < (int)sz; ++i) board[i] = dsf_size(dsf, i); sfree(dsf); printv("returning board number %d\n", nboards); return; retry: dsf_init(dsf, sz); } assert(FALSE); /* unreachable */ }