# Project Euler 298
# E[|L-R|] after 50 turns to 8 decimals.
extern {
function calloc(n: i64, size: i64) -> ptr<void>
function free(p: ptr<void>) -> void
function fopen(path: string, mode: string) -> ptr<void>
function fclose(f: ptr<void>) -> i32
function fgetc(f: ptr<void>) -> i32
}
function read_i32_list(path: string, arr: ptr<i32>, n: i64) -> void {
let f: ptr<void> = fopen(path, "r")
let mut i: i64 = 0
let mut c: i32 = fgetc(f)
while i < n {
while c == 32 || c == 10 || c == 13 || c == 9 {
c = fgetc(f)
}
let mut sign: i32 = 1
if c == 45 {
sign = -1
c = fgetc(f)
}
let mut v: i32 = 0
while c >= 48 && c <= 57 {
v = v * 10 + (c - 48)
c = fgetc(f)
}
arr[i] = v * sign
i = i + 1
}
fclose(f)
}
function main() -> i32 {
let NS: i64 = 439
let TURNS: i64 = 50
let NT: i64 = 2886
let NO: i64 = 440
let offs: ptr<i32> = calloc(NO, 4)
let tos: ptr<i32> = calloc(NT, 4)
let deltas: ptr<i32> = calloc(NT, 4)
let weights: ptr<i32> = calloc(NT, 4)
read_i32_list("data/p298_offs.txt", offs, NO)
read_i32_list("data/p298_tos.txt", tos, NT)
read_i32_list("data/p298_deltas.txt", deltas, NT)
read_i32_list("data/p298_weights.txt", weights, NT)
let MAXLEN: i64 = 2 * TURNS + 1
let cur: ptr<f64> = calloc(NS * MAXLEN, 8)
let nxt: ptr<f64> = calloc(NS * MAXLEN, 8)
let active: ptr<i8> = calloc(NS, 1)
let nactive: ptr<i8> = calloc(NS, 1)
cur[0 * MAXLEN + 0] = 1.0
active[0] = 1
let mut t: i64 = 0
while t < TURNS {
let new_len: i64 = 2 * (t + 1) + 1
let old_len: i64 = 2 * t + 1
let mut s: i64 = 0
while s < NS {
nactive[s] = 0
let mut i: i64 = 0
while i < new_len {
nxt[s * MAXLEN + i] = 0.0
i = i + 1
}
s = s + 1
}
s = 0
while s < NS {
if active[s] != 0 {
let a: i64 = offs[s] as i64
let b: i64 = offs[s + 1] as i64
let mut e: i64 = a
while e < b {
let ns: i64 = tos[e] as i64
let delta: i64 = deltas[e] as i64
let w: f64 = (weights[e] as f64) / 10.0
let shift: i64 = delta + 1
nactive[ns] = 1
let mut i: i64 = 0
while i < old_len {
let val: f64 = cur[s * MAXLEN + i]
if val != 0.0 {
nxt[ns * MAXLEN + i + shift] = nxt[ns * MAXLEN + i + shift] + val * w
}
i = i + 1
}
e = e + 1
}
}
s = s + 1
}
s = 0
while s < NS {
active[s] = nactive[s]
let mut i: i64 = 0
while i < new_len {
cur[s * MAXLEN + i] = nxt[s * MAXLEN + i]
i = i + 1
}
s = s + 1
}
t = t + 1
}
let mut expected: f64 = 0.0
let offset: i64 = TURNS
let mut s: i64 = 0
while s < NS {
if active[s] != 0 {
let mut i: i64 = 0
while i < MAXLEN {
let diff: i64 = i - offset
let mut ad: f64 = diff as f64
if ad < 0.0 { ad = 0.0 - ad }
expected = expected + ad * cur[s * MAXLEN + i]
i = i + 1
}
}
s = s + 1
}
printf("%.8f\n", expected)
free(offs); free(tos); free(deltas); free(weights); free(cur); free(nxt); free(active); free(nactive)
return 0
}
Generated C
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Flow runtime helpers */
typedef struct flow_temp_node { struct flow_temp_node* next; } flow_temp_node;
static flow_temp_node* flow_temp_head = NULL;
static int flow_temp_atexit_set = 0;
__attribute__((unused)) static void flow_temp_free_all(void) {
while (flow_temp_head) {
flow_temp_node* n = flow_temp_head;
flow_temp_head = n->next;
free(n);
}
}
__attribute__((unused)) static void* flow_temp_alloc(size_t nbytes) {
flow_temp_node* node = (flow_temp_node*)malloc(sizeof(flow_temp_node) + nbytes);
if (!node) return NULL;
node->next = flow_temp_head;
flow_temp_head = node;
if (!flow_temp_atexit_set) {
flow_temp_atexit_set = 1;
atexit(flow_temp_free_all);
}
return (void*)(node + 1);
}
#ifndef FLOW_DIAG
#define FLOW_DIAG(msg) fprintf(stderr, "%s", (msg))
#endif
#ifndef FLOW_LOG
#define FLOW_LOG(fmt, ...) printf(fmt, __VA_ARGS__)
#endif
#ifndef FLOW_LOG_EMPTY
#define FLOW_LOG_EMPTY(fmt) printf(fmt)
#endif
static char* flow_strcat(const char* a, const char* b) {
size_t la = strlen(a ? a : ""), lb = strlen(b ? b : "");
char* r = (char*)flow_temp_alloc(la + lb + 1);
if (!r) return NULL;
if (la) memcpy(r, a, la);
if (lb) memcpy(r + la, b, lb);
r[la + lb] = '\0';
return r;
}
#define __flow_in_arr(arr, val) __extension__ ({ \
int _found = 0; \
size_t _n = sizeof(arr)/sizeof((arr)[0]); \
for (size_t _i = 0; _i < _n; _i++) { \
if ((arr)[_i] == (val)) { _found = 1; break; } \
} _found; })
/* Unified fault handler (MISRA #279) — override with -DFLOW_FAULT_HANDLER=fn */
#ifndef FLOW_FAULT_HANDLER
__attribute__((unused)) static inline void flow_fault_handler(const char* msg) {
fprintf(stderr, "flow: %s\n", msg ? msg : "fault");
abort();
#if defined(__GNUC__) || defined(__clang__)
__builtin_unreachable();
#endif
}
#else
#define flow_fault_handler FLOW_FAULT_HANDLER
#endif
#define flow_div_by_zero_handler() flow_fault_handler("division by zero")
#define flow_shift_ub_handler() flow_fault_handler("invalid shift (amount out of range or left-shift of negative)")
#ifndef FLOW_CHECKED_DIV
#define FLOW_CHECKED_DIV(L, R) (((R) != 0) ? ((L) / (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_MOD
#define FLOW_CHECKED_MOD(L, R) (((R) != 0) ? ((L) % (R)) : (flow_div_by_zero_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHL
#define FLOW_CHECKED_SHL(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull)) && ((L) >= 0)) ? ((L) << (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#ifndef FLOW_CHECKED_SHR
#define FLOW_CHECKED_SHR(L, R) ((((R) >= 0) && ((unsigned long long)(R) < (sizeof(L) * 8ull))) ? ((L) >> (R)) : (flow_shift_ub_handler(), (L) * 0))
#endif
#include <math.h>
void* _ui_state = NULL;
static inline float i32_to_f32(int32_t v) { return (float)v; }
/* Host stub for @gpu kernels (device codegen replaces this). */
static inline int32_t gpu_thread_id(void) { return 0; }
void read_i32_list_string_ptr_i32_i64(char* path, int32_t* arr, int64_t n);
int32_t main(void);
void read_i32_list_string_ptr_i32_i64(char* path, int32_t* arr, int64_t n) {
void* f = (void*)(fopen(path, "r"));
int64_t i = 0;
int32_t c = fgetc(f);
while (i < n) {
while ((((c == 32 || c == 10) || c == 13) || c == 9)) {
c = fgetc(f);
}
int32_t sign = 1;
if (c == 45) {
sign = (-1);
c = fgetc(f);
}
int32_t v = 0;
while ((c >= 48 && c <= 57)) {
v = ((v * 10) + (c - 48));
c = fgetc(f);
}
arr[i] = (v * sign);
i = (i + 1);
}
fclose(f);
}
int32_t main(void) {
int64_t NS = 439;
int64_t TURNS = 50;
int64_t NT = 2886;
int64_t NO = 440;
int32_t* offs = (int32_t*)(calloc(NO, 4));
int32_t* tos = (int32_t*)(calloc(NT, 4));
int32_t* deltas = (int32_t*)(calloc(NT, 4));
int32_t* weights = (int32_t*)(calloc(NT, 4));
read_i32_list_string_ptr_i32_i64("data/p298_offs.txt", offs, NO);
read_i32_list_string_ptr_i32_i64("data/p298_tos.txt", tos, NT);
read_i32_list_string_ptr_i32_i64("data/p298_deltas.txt", deltas, NT);
read_i32_list_string_ptr_i32_i64("data/p298_weights.txt", weights, NT);
int64_t MAXLEN = ((2 * TURNS) + 1);
double* cur = (double*)(calloc((NS * MAXLEN), 8));
double* nxt = (double*)(calloc((NS * MAXLEN), 8));
int8_t* active = (int8_t*)(calloc(NS, 1));
int8_t* nactive = (int8_t*)(calloc(NS, 1));
cur[((0 * MAXLEN) + 0)] = 1.0;
active[0] = 1;
int64_t t = 0;
while (t < TURNS) {
int64_t new_len = ((2 * (t + 1)) + 1);
int64_t old_len = ((2 * t) + 1);
int64_t s = 0;
while (s < NS) {
nactive[s] = 0;
int64_t i = 0;
while (i < new_len) {
nxt[((s * MAXLEN) + i)] = 0.0;
i = (i + 1);
}
s = (s + 1);
}
s = 0;
while (s < NS) {
if (active[s] != 0) {
int64_t a = ((int64_t)(offs[s]));
int64_t b = ((int64_t)(offs[(s + 1)]));
int64_t e = a;
while (e < b) {
int64_t ns = ((int64_t)(tos[e]));
int64_t delta = ((int64_t)(deltas[e]));
double w = (((double)(weights[e])) / 10.0);
int64_t shift = (delta + 1);
nactive[ns] = 1;
int64_t i = 0;
while (i < old_len) {
double val = cur[((s * MAXLEN) + i)];
if (val != 0.0) {
nxt[(((ns * MAXLEN) + i) + shift)] = (nxt[(((ns * MAXLEN) + i) + shift)] + (val * w));
}
i = (i + 1);
}
e = (e + 1);
}
}
s = (s + 1);
}
s = 0;
while (s < NS) {
active[s] = nactive[s];
int64_t i = 0;
while (i < new_len) {
cur[((s * MAXLEN) + i)] = nxt[((s * MAXLEN) + i)];
i = (i + 1);
}
s = (s + 1);
}
t = (t + 1);
}
double expected = 0.0;
int64_t offset = TURNS;
int64_t s = 0;
while (s < NS) {
if (active[s] != 0) {
int64_t i = 0;
while (i < MAXLEN) {
int64_t diff = (i - offset);
double ad = ((double)(diff));
if (ad < 0.0) {
ad = (0.0 - ad);
}
expected = (expected + (ad * cur[((s * MAXLEN) + i)]));
i = (i + 1);
}
}
s = (s + 1);
}
printf("%.8f\n", expected);
free(offs);
free(tos);
free(deltas);
free(weights);
free(cur);
free(nxt);
free(active);
free(nactive);
return 0;
}