/*
 * Author: Iván Iglesias
 * Date: 23-11-2026
 * Description: PR2 - The goal of this exercise is to replace the parallel vector implementation 
 * with a design based on hierarchical data structures (tuples) 
 * and to break the code down into actions and functions.
 */

/* ------------------------------- */

/* System header files */
#include <stdio.h>
#include <stdbool.h>

/* Symbolic constants */
#define SENSORS_PER_WAGON 14
#define SENSORS_PER_AXLE 7
#define CRITICAL_TEMPERATURE 90.0
#define VIBRATION_ALERT_LEVEL 7.1
#define WEAR_CRITICAL_THRESHOLD 25.0
#define MIN_WORN_FOR_WARNING 3
#define COMPONENT_TYPES 4
#define MAX_FILENAME 101

/* Definition of types */
typedef enum
{
    BEARING = 1,
    WHEEL,
    BRAKE,
    AXLE
} tComponentType;

typedef struct
{
    tComponentType componentType;
    float temperature;
    float vibration;
    float residualLife;
} tSensor;

typedef tSensor tWagonSensors[SENSORS_PER_WAGON];
typedef int tAlertCounts[COMPONENT_TYPES];

typedef struct
{
    float avgTemp;
    float maxTemp;
    int peakPos;
    int alertCount;
    int wornCount;
    tAlertCounts alertCounts;
} tInspectionResult;

/* Function and action declarations */

/* Exercise 1 */
void loadWagonFromFile(char filename[], tWagonSensors sensors, bool *isRead);

/* Exercise 2 */
void inspectWagon(tWagonSensors sensors, tInspectionResult *result);

/* Exercise 2.1 */
bool isSensorWorn(tSensor sensor);

/* Exercise 2.2 */
bool isSensorInAlert(tSensor sensor);

/* Exercise 2.3 */
int getComponentTypeIndex(tComponentType compType);

/* Exercise 3 */
void displaySummary(tWagonSensors sensors, tInspectionResult result);

/* Exercise 3.1 */
char *getSensorAxleName(int position);

/* Exercise 3.2 */
char *getComponentName(tComponentType compType);

/* Main function */
int main(void)
{
    tWagonSensors sensors;
    char filename[MAX_FILENAME];
    tInspectionResult inspectionResult;
    bool isRead;

    printf("--- WAGON INSPECTION SYSTEM (PR2 - MODULAR) ---\n");
    printf("LOAD DATA FROM FILE. ENTER FILE NAME >> ");

    if (scanf("%100s", filename) != 1)
    {
        printf("Error: Could not open file\n");
        return 1;
    }

    loadWagonFromFile(filename, sensors, &isRead);

    if (isRead)
    {
        inspectWagon(sensors, &inspectionResult);
        displaySummary(sensors, inspectionResult);
    }
    else
    {
        printf("Error: Could not open file\n");
    }

    return 0;
}

/* Exercise 1 */
void loadWagonFromFile(char filename[], tWagonSensors sensors, bool *isRead)
{
    FILE *fileToRead;
    int i;
    int componentTypeValue;

    *isRead = false;
    fileToRead = fopen(filename, "r");

    if (fileToRead == NULL)
    {
        return;
    }

    for (i = 0; i < SENSORS_PER_WAGON; i++)
    {
        if (fscanf(fileToRead, "%d %f %f %f",
                   &componentTypeValue,
                   &sensors[i].temperature,
                   &sensors[i].vibration,
                   &sensors[i].residualLife) != 4)
        {
            fclose(fileToRead);
            return;
        }

        if (componentTypeValue < BEARING || componentTypeValue > AXLE)
        {
            fclose(fileToRead);
            return;
        }

        sensors[i].componentType = (tComponentType) componentTypeValue;
    }

    fclose(fileToRead);
    *isRead = true;
}

/* Exercise 2 */
void inspectWagon(tWagonSensors sensors, tInspectionResult *result)
{
    int i;
    int componentIndex;
    float sumTemperature;

    sumTemperature = 0.0f;
    result->maxTemp = sensors[0].temperature;
    result->peakPos = 1;
    result->alertCount = 0;
    result->wornCount = 0;

    for (i = 0; i < COMPONENT_TYPES; i++)
    {
        result->alertCounts[i] = 0;
    }

    for (i = 0; i < SENSORS_PER_WAGON; i++)
    {
        sumTemperature += sensors[i].temperature;

        if (sensors[i].temperature > result->maxTemp)
        {
            result->maxTemp = sensors[i].temperature;
            result->peakPos = i + 1;
        }

        if (isSensorWorn(sensors[i]))
        {
            result->wornCount++;
        }

        if (isSensorInAlert(sensors[i]))
        {
            result->alertCount++;
            componentIndex =
                getComponentTypeIndex(sensors[i].componentType);

            result->alertCounts[componentIndex - 1]++;
        }
    }

    result->avgTemp = sumTemperature / SENSORS_PER_WAGON;
}

/* Exercise 2.1 */
bool isSensorWorn(tSensor sensor)
{
    return sensor.residualLife < WEAR_CRITICAL_THRESHOLD;
}

/* Exercise 2.2 */
bool isSensorInAlert(tSensor sensor)
{
    return sensor.temperature > CRITICAL_TEMPERATURE ||
           sensor.vibration > VIBRATION_ALERT_LEVEL ||
           isSensorWorn(sensor);
}

/* Exercise 2.3 */
int getComponentTypeIndex(tComponentType compType)
{
    int index;

    switch (compType)
    {
        case BEARING:
            index = 1;
            break;

        case WHEEL:
            index = 2;
            break;

        case BRAKE:
            index = 3;
            break;

        case AXLE:
            index = 4;
            break;

        default:
            index = 0;
            break;
    }

    return index;
}

/* Exercise 3 */
void displaySummary(tWagonSensors sensors, tInspectionResult result)
{
    int i;

    printf("----------------------------------------\n");
    printf("INSPECTION SUMMARY\n");
    printf("----------------------------------------\n");
    printf("COMPONENT TYPES: 1-BEARING, 2-WHEEL, 3-BRAKE, 4-AXLE\n");

    printf("AVERAGE TEMPERATURE (CELSIUS): %.2f\n",
           result.avgTemp);

    printf("PEAK TEMPERATURE (CELSIUS): %.2f AT POSITION %d "
           "(AXLE: %s, TYPE: %s)\n",
           result.maxTemp,
           result.peakPos,
           getSensorAxleName(result.peakPos),
           getComponentName(sensors[result.peakPos - 1].componentType));

    if (result.alertCount > 0)
    {
        printf("COMPONENTS IN ALERT: %d\n", result.alertCount);

        for (i = 0; i < SENSORS_PER_WAGON; i++)
        {
            if (isSensorInAlert(sensors[i]))
            {
                printf("POSITION %d - TYPE: %s\n",
                       i + 1,
                       getComponentName(sensors[i].componentType));
            }
        }

        printf("ALERTS BY COMPONENT TYPE:\n");
        printf("- BEARING: %d\n",
               result.alertCounts[getComponentTypeIndex(BEARING) - 1]);
        printf("- WHEEL: %d\n",
               result.alertCounts[getComponentTypeIndex(WHEEL) - 1]);
        printf("- BRAKE: %d\n",
               result.alertCounts[getComponentTypeIndex(BRAKE) - 1]);
        printf("- AXLE: %d\n",
               result.alertCounts[getComponentTypeIndex(AXLE) - 1]);
    }
    else
    {
        printf("NO COMPONENTS IN ALERT\n");
    }

    printf("WORN COMPONENTS: %d\n", result.wornCount);

    if (result.wornCount >= MIN_WORN_FOR_WARNING)
    {
        printf("WAGON STATUS: NOT RELIABLE\n");
    }
    else
    {
        printf("WAGON STATUS: RELIABLE\n");
    }

    printf("----------------------------------------\n");
}

/* Exercise 3.1 */
char *getSensorAxleName(int position)
{
    char *axleName;

    if (position <= SENSORS_PER_AXLE)
    {
        axleName = "AXLE1";
    }
    else
    {
        axleName = "AXLE2";
    }

    return axleName;
}

/* Exercise 3.2 */
char *getComponentName(tComponentType compType)
{
    char *name;

    switch (compType)
    {
        case BEARING:
            name = "BEARING";
            break;

        case WHEEL:
            name = "WHEEL";
            break;

        case BRAKE:
            name = "BRAKE";
            break;

        case AXLE:
            name = "AXLE";
            break;

        default:
            name = "UNKNOWN";
            break;
    }

    return name;
}












Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: