---
title: "Smart Warehouse Inventory Simulation"
Name: Shaikh Muskan M.
Student ID: 2513085
output: word_document
date: "23rd October 2026"
Assessment:  CW1 - Data Manipulation (Smart Warehouse Inventory)
Date: "18 October 2026"

---
```{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
```

Purpose:     Simulate 28 days of warehouse activity and summarise it
              using loops only (no apply family, aggregate, dplyr or
              user-defined functions, as required by the brief).
# This makes my tables reproducible and lets a marker check my output.
set.seed(2026)
```{r}
# Constants taken from the brief
n_days        <- 28
n_zones       <- 5
n_categories  <- 6
base_units    <- 100
time_per_unit <- 0.85
total_rows    <- n_days * n_zones * n_categories   # 28 * 5 * 6 = 840

# TASK A: Generate the warehouse data
warehouse_data <- data.frame(
  Day             = integer(total_rows),
  Zone            = integer(total_rows),
  Category        = integer(total_rows),
  UnitsProcessed  = numeric(total_rows),
  ProcessingTime  = numeric(total_rows)
)

row_counter <- 1   # points at the next empty row

# Three nested loops: one pass for every Day x Zone x Category combination
for (day in 1:n_days) {
  for (zone in 1:n_zones) {
    for (category in 1:n_categories) {

      # Random integer from -12 to +12 inclusive (25 possible values)
      random_variation <- sample(-12:12, 1)

      # Formula given in the brief
      units <- base_units + (zone * 8) + (category * 5) + random_variation

      warehouse_data$Day[row_counter]            <- day
      warehouse_data$Zone[row_counter]           <- zone
      warehouse_data$Category[row_counter]       <- category
      warehouse_data$UnitsProcessed[row_counter] <- units
      warehouse_data$ProcessingTime[row_counter] <- units * time_per_unit

      row_counter <- row_counter + 1
    }
  }
}

cat("---- TASK A: warehouse_data ----\n")
print(head(warehouse_data, 10))
cat("Number of rows:   ", nrow(warehouse_data), "\n")
cat("Number of columns:", ncol(warehouse_data), "\n\n")


```
```{r}
# TASK B: Total units processed per zone
zone_totals <- data.frame(
  Zone       = 1:n_zones,
  TotalUnits = numeric(n_zones)
)

# Outer loop picks a zone; inner loop scans every record and adds the
# units to a running total whenever the record belongs to that zone.
for (z in 1:n_zones) {
  running_total <- 0
  for (r in 1:total_rows) {
    if (warehouse_data$Zone[r] == z) {
      running_total <- running_total + warehouse_data$UnitsProcessed[r]
    }
  }
  zone_totals$TotalUnits[z] <- running_total
}

cat("---- TASK B: zone_totals ----\n")
print(zone_totals)
cat("\n")

```
```{r}
# TASK C: Average processing time per product category
category_average_time <- data.frame(
  Category              = 1:n_categories,
  AverageProcessingTime = numeric(n_categories)
)

# The brief asks for BOTH the total time and the record count to be
# built with loops, so I keep two separate counters per category.
for (cat_id in 1:n_categories) {
  time_total   <- 0
  record_count <- 0
  for (r in 1:total_rows) {
    if (warehouse_data$Category[r] == cat_id) {
      time_total   <- time_total + warehouse_data$ProcessingTime[r]
      record_count <- record_count + 1
    }
  }
  category_average_time$AverageProcessingTime[cat_id] <-
    round(time_total / record_count, 2)
}

cat("---- TASK C: category_average_time ----\n")
print(category_average_time)
cat("\n")

```
```{r}

# TASK D: Identify stock processing anomalies
# Step 1 - build a Day x Zone table of average units.
daily_zone_avg <- matrix(0, nrow = n_days, ncol = n_zones)

for (d in 1:n_days) {
  for (z in 1:n_zones) {
    unit_sum   <- 0
    unit_count <- 0
    for (r in 1:total_rows) {
      if (warehouse_data$Day[r] == d && warehouse_data$Zone[r] == z) {
        unit_sum   <- unit_sum + warehouse_data$UnitsProcessed[r]
        unit_count <- unit_count + 1
      }
    }
    daily_zone_avg[d, z] <- unit_sum / unit_count
  }
}

# Step 2 - compare every record with the average for its own day/zone
processing_anomalies <- data.frame(
  Day              = integer(total_rows),
  Zone             = integer(total_rows),
  Category         = integer(total_rows),
  UnitsProcessed   = numeric(total_rows),
  DailyZoneAverage = numeric(total_rows),
  Anomaly          = logical(total_rows)
)

for (r in 1:total_rows) {
  this_day  <- warehouse_data$Day[r]
  this_zone <- warehouse_data$Zone[r]
  this_avg  <- daily_zone_avg[this_day, this_zone]
  this_units <- warehouse_data$UnitsProcessed[r]

  processing_anomalies$Day[r]              <- this_day
  processing_anomalies$Zone[r]             <- this_zone
  processing_anomalies$Category[r]         <- warehouse_data$Category[r]
  processing_anomalies$UnitsProcessed[r]   <- this_units
  processing_anomalies$DailyZoneAverage[r] <- round(this_avg, 2)

  # Anomaly rule from the brief: more than 15% above or below average.
    if (this_units > this_avg * 1.15 || this_units < this_avg * 0.85) {
    processing_anomalies$Anomaly[r] <- TRUE
  } else {
    processing_anomalies$Anomaly[r] <- FALSE
  }
}

# Collect the first 10 anomalous rows with a loop (no subsetting helpers)
first_anomalies <- processing_anomalies[0, ]
anomalies_found <- 0
r <- 1
while (r <= total_rows && anomalies_found < 10) {
  if (processing_anomalies$Anomaly[r] == TRUE) {
    anomalies_found <- anomalies_found + 1
    first_anomalies[anomalies_found, ] <- processing_anomalies[r, ]
  }
  r <- r + 1
}

# Total anomaly count (used later in the report)
anomaly_total <- 0
for (r in 1:total_rows) {
  if (processing_anomalies$Anomaly[r]) {
    anomaly_total <- anomaly_total + 1
  }
}

cat("---- TASK D: first 10 anomalies ----\n")
print(first_anomalies)
cat("Total anomalies:", anomaly_total, "out of", total_rows,
    "records\n\n")

```
```{r}
# TASK E: Most productive day for each zone
peak_zone_days <- data.frame(
  Zone       = 1:n_zones,
  Day        = integer(n_zones),
  TotalUnits = numeric(n_zones)
)

for (z in 1:n_zones) {
  best_day   <- 0
  best_total <- -1     # lower than any possible total, so day 1 always wins first

  for (d in 1:n_days) {
    day_total <- 0
    for (r in 1:total_rows) {
      if (warehouse_data$Zone[r] == z && warehouse_data$Day[r] == d) {
        day_total <- day_total + warehouse_data$UnitsProcessed[r]
      }
    }
    # Strict ">" means that if two days tie, the earlier day is kept
    if (day_total > best_total) {
      best_total <- day_total
      best_day   <- d
    }
  }

  peak_zone_days$Day[z]        <- best_day
  peak_zone_days$TotalUnits[z] <- best_total
}

cat("---- TASK E: peak_zone_days ----\n")
print(peak_zone_days)

```


