void measurement_step(struct measurement *trace, float dt) { trace->accumulated_time += dt; if (trace->accumulated_time > trace->next_period) { // Generate new control point value float next = lerp(trace->min_intensity, trace->max_intensity, rng_next(), UINT16_MAX); // Weight heavily towards the previous point trace->points[trace->start] = (2 * trace->points[wrap(trace->start + 3)] + next) / 3; // Increment control point trace->start = wrap(trace->start + 1); trace->accumulated_time -= trace->next_period; trace->next_period = lerp(trace->min_period, trace->max_period, rng_next(), UINT16_MAX); } // Evaluate the catmull-rom spline float t = trace->accumulated_time / trace->next_period; float p0 = trace->points[wrap(trace->start + 0)]; float p1 = trace->points[wrap(trace->start + 1)]; float p2 = trace->points[wrap(trace->start + 2)]; float p3 = trace->points[wrap(trace->start + 3)]; trace->value = p1 + 0.5f*t*(p2 - p0 + t*((2*p0 - 5*p1 + 4*p2 - p3) + t*(3*p1 - 3*p2 + p3 - p0))); }
// Initialize first four parameters void measurement_init(struct measurement *trace, float range[2], float timescale[2]) { trace->min_period = timescale[0]; trace->max_period = timescale[1]; trace->min_intensity = range[0]; trace->max_intensity = range[1]; trace->value = lerp(range[0], range[1], rng_next(), UINT16_MAX); for (uint8_t i = 0; i < 4; i++) trace->points[i] = trace->value; }
// -- OCaml wrapper function returning a random permutation of n integers // -- in the range [0, n - 1]. CAMLprim value wrap_rng_perm(value vn) { CAMLparam1(vn); CAMLlocal2(ar, h); int j, k; // -- The OCaml - C - interface requires to use Store_field() macros // -- for block access even for integers. This is probably quite // -- inefficient. Therefore a working arrays is defined here static int work[NWORK]; // -- check constraints const int n = Int_val(vn); if (n < 0 || n >= NWORK) caml_invalid_argument("Rng.perm: n out of bounds"); // -- OCaml does not allow for heap allocated zero-sized arrays; // -- return atom instead if (n == 0) CAMLreturn(Atom(0)); // -- initialize work array for (j = 0; j < n; j++) work[j] = j; // -- perform permutation by successively drawing numbers from the RNG // -- and swapping values for (j = n - 1; j > 0; j--) { k = rng_next() % (j + 1); // -- positive int between 0 .. j h = work[k]; work[k] = work[j]; work[j] = h; } // -- allocate n-element array and initialize with work ar = caml_alloc(n, 0); for (j = 0; j < n; j++) Store_field(ar, j, Val_int(work[j])); CAMLreturn(ar); }
// -- Ocaml wrapper function returning an array of n double prec // -- random numbers in the open interval (0, 1). CAMLprim value wrap_rng_get_array(value vn) { CAMLparam1(vn); CAMLlocal1(ar); int j; // -- check constrains const int n = Int_val(vn); if ( n < 0 ) caml_invalid_argument("Rng.get_array: n must be positive or 0"); // -- OCaml does not allow for heap allocated zero-sized arrays; // -- return atom instead if (n == 0) CAMLreturn(Atom(0)); // -- allocate block and initialize ar = caml_alloc(n * NDBL, Double_array_tag); for (j = 0; j < n; j++) Store_double_field(ar, j, fac * rng_next()); CAMLreturn(ar); }
// -- OCaml wrapper function returning an 31 or 63 bit integer in the // -- closed interval [0, n - 1]. CAMLprim value wrap_rng_get_int(value n) { CAMLparam1(n); CAMLreturn(Val_long( (rng_next() - 1) % Long_val(n) )); }
// -- OCaml wrapper function returning a double value in the // -- open interval (0.0, 1.0). CAMLprim value wrap_rng_get() { CAMLparam0(); CAMLreturn(caml_copy_double(fac * rng_next())); }
int mahjong(unsigned seed) { Taku taku; rng_init(seed); init_taku(&taku); taku.chicha = rng_next() % N_PLAYER; while (taku.kyoku < 8) { taku_wo_miseru(&taku); shipai(&taku); taku_wo_miseru(&taku); kaimen(&taku); taku_wo_miseru(&taku); haipai(&taku); taku_wo_miseru(&taku); taku.teban = oya(&taku); while (rest_tsumo(&taku.yama)) { unsigned pai; unsigned info; unsigned action; unsigned nakite; Kawa *kawa; pai = tsumo_from_yama(&taku.yama); taku.current = taku.yama.narabi + taku.yama.tsumo_idx; after_tsumo: taku_wo_miseru(&taku); info = tsumo_select_action(&taku, pai); action = info_to_action(info); kawa = &taku.kawa[taku.teban]; switch (action) { case ACTION_KAKAN: pai = info_to_pai(info); info = chankan_select_action_all(&taku, pai); nakite = info_to_player(info); if (taku.teban != nakite) { taku.teban = nakite; goto after_hohra; } case ACTION_ANKAN: pai = tsumo_from_rinshan(&taku.yama); goto after_tsumo; case ACTION_RIICHI: taku.tenbo[taku.teban] -= 1000; taku.riichibo++; kawa->riichi_idx = kawa->sute_idx; case ACTION_SUTE: pai = info_to_pai(info); taku.current = kawa->narabi + kawa->sute_idx; kawa->narabi[kawa->sute_idx++] = pai; goto after_sute; case ACTION_TSUMO: goto after_hohra; } after_sute: taku_wo_miseru(&taku); if (is_sufurenda(&taku)) goto after_ryukyoku; info = furo_select_action_all(&taku, pai); nakite = info_to_player(info); action = info_to_action(info); if (action == ACTION_SANCHAHOH) goto after_ryukyoku; if (taku.teban != nakite) { taku.teban = nakite; kawa = &taku.kawa[taku.teban]; switch (action) { case ACTION_RON: goto after_hohra; case ACTION_CHI: case ACTION_PON: case ACTION_MINKAN: info = furo_sute_action(&taku, info); pai = info_to_pai(info); taku.current = kawa->narabi + kawa->sute_idx; kawa->narabi[kawa->sute_idx++] = pai; goto after_sute; case ACTION_THROUGH: break; } } if (is_suchariichi(&taku)) goto after_ryukyoku; if (is_sukaikan(&taku)) goto after_ryukyoku; taku.teban = (taku.teban + 1) % N_PLAYER; } after_ryukyoku: taku_wo_miseru(&taku); if (ryukyoku(&taku)) taku.kyoku++; else taku.tsumibo++; continue; after_hohra: taku_wo_miseru(&taku); if (hohra(&taku)) taku.kyoku++; else taku.tsumibo++; } return 0; }
void shuffle_narabi(uint8_t *narabi, unsigned n) { while (--n) swap_narabi(narabi, n, rng_next()%n); }