#include <stdio.h>
#include <pthread.h>

#define THREAD_COUNT 4
#define N 12
#define STEPS 3

double current[N];
double next[N];
pthread_barrier_t phase_barrier;

void *average(void *argument) {
    long id = *(long *)argument;
    for (int step = 0; step < STEPS; step++) {
        /* Phase 1: read current; write distinct elements of next. */
        for (int i = (int)id; i < N; i += THREAD_COUNT) {
            if (i == 0 || i == N - 1) {
                next[i] = current[i];
            } else {
                next[i] = (current[i - 1] + current[i] + current[i + 1]) / 3.0;
            }
        }
        pthread_barrier_wait(&phase_barrier);

        /* Phase 2: copy the completed next array into current. */
        for (int i = (int)id; i < N; i += THREAD_COUNT) {
            current[i] = next[i];
        }
        pthread_barrier_wait(&phase_barrier);
    }
    return NULL;
}

int main(void) {
    pthread_t workers[THREAD_COUNT];
    long ids[THREAD_COUNT];
    current[N / 2 - 1] = 12.0;

    printf("Before:");
    for (int i = 0; i < N; i++) printf(" %.3f", current[i]);
    printf("\n");

    pthread_barrier_init(&phase_barrier, NULL, THREAD_COUNT);
    for (long t = 0; t < THREAD_COUNT; t++) {
        ids[t] = t;
        pthread_create(&workers[t], NULL, average, &ids[t]);
    }
    for (int t = 0; t < THREAD_COUNT; t++) {
        pthread_join(workers[t], NULL);
    }
    pthread_barrier_destroy(&phase_barrier);

    printf("After %d steps:", STEPS);
    for (int i = 0; i < N; i++) printf(" %.3f", current[i]);
    printf("\n");
    return 0;
}
