import numpy as np
import matplotlib.pyplot as plt
m, L = 4, 15
s = [0, 0, 1, 0]
B = [[], [], [], []]
for _ in range(L):
    for i in range(4):
        B[i].append(s[i])
    f = s[0] ^ s[1]
    s = [s[1], s[2], s[3], f]
print("b3 | b2 | b1 | b0")
print("-" * 25)
for i in range(L):
    print(f"{B[3][i]}  | {B[2][i]}  | {B[1][i]}  | {B[0][i]}")
x = B[0]
def get_runs(x):
    n = len(x)
    start = next(i for i in range(n) if x[i] != x[i-1])
    y = x[start:] + x[:start]
    runs = []
    bit = y[0]
    count = 1
    for v in y[1:]:
        if v == bit:
            count += 1
        else:
            runs.append((bit, count))
            bit = v
            count = 1
    runs.append((bit, count))
    return runs
R = get_runs(x)
print("\nPROPERTIES")
P1 = sum(x) == 8
P2 = x.count(0) == 7
P3 = (1, 4) in R
P4 = not any(bit == 0 and n >= 4 for bit, n in R)
P5 = not any(bit == 1 and n > 4 for bit, n in R)
P6 = (0, 3) in R
expected = [
    (1, 4), (0, 3), (1, 2), (0, 2),
    (1, 1), (0, 1), (1, 1), (0, 1)
]
P7 = sorted(R) == sorted(expected)
print(f"P1 Number of 1s              : {'PASS' if P1 else 'FAIL'}")
print(f"P2 Number of 0s              : {'PASS' if P2 else 'FAIL'}")
print(f"P3 Run of four 1s            : {'PASS' if P3 else 'FAIL'}")
print(f"P4 No run of four 0s         : {'PASS' if P4 else 'FAIL'}")
print(f"P5 Maximum run of 1s = 4     : {'PASS' if P5 else 'FAIL'}")
print(f"P6 Run of three 0s           : {'PASS' if P6 else 'FAIL'}")
print(f"P7 Run distribution         : {'PASS' if P7 else 'FAIL'}")
a = np.array([1 if v == 1 else -1 for v in x])
shifts = np.arange(-14, 15)
C = np.array([
    np.sum(a * np.roll(a, k))
    for k in shifts
])
P8 = (
    C[14] == 15 and
    np.all(np.delete(C, 14) == -1)
)
print(f"P8 Autocorrelation           : {'PASS' if P8 else 'FAIL'}")
plt.figure(figsize=(8, 4))
plt.plot(shifts, C, 'o-', color='blue')
plt.xlim(-15, 15)
plt.ylim(-1, 15)
plt.axhline(0, color='black', linewidth=0.7)
plt.axvline(0, color='red', linestyle='--', linewidth=0.8)
plt.xlabel("Shift")
plt.ylabel("Autocorrelation")
plt.title("PN Sequence Autocorrelation")
plt.grid(True)
plt.show()
