import numpy as np
from itertools import product  # To generate all binary combinations

# Initialisierung der Schwellenwerte
lower_threshold = 0.8
upper_threshold = 1.2

# Lernrate
learning_rate = 0.1

# Trainingsdaten (Inputs für das XOR-Problem und andere)
inputs = [[0, 0], [0, 1], [1, 0], [1, 1]]

# Alle möglichen Zieltabellen (16 Kombinationen)
all_possible_targets = list(product([0, 1], repeat=4))

# Trainingsloop für jede mögliche Zieltabelle
for table_index, targets in enumerate(all_possible_targets, start=1):
    print(f"\n=== Wahrheitstabelle {table_index}: Targets = {targets} ===")
    
    # Initialisieren der Startwerte
    max_iterations = 2000  # Maximal 2000 Iterationen für jedes Bias
    epoch = 0
    network_trained = False
    start_weights = None
    final_weights = None
    bias_list = [0.0, 0.7, 0.9]  # Bias nur mit den Werten 0.0, 0.7, 0.9
    reset_count = 0  # Counter to track the number of weight resets

    # Iterate over bias values 0.0, 0.7, and 0.9
    for bias in bias_list:
        print(f"Versuch mit Bias {bias}:")
        
        epoch = 0
        network_trained = False  # Netzwerk muss erneut trainiert werden
        start_weights = np.random.uniform(0, 3, 2)  # Zufällige Startgewichte für die Trainingsrunde (von 0 bis 3)

        while epoch < max_iterations:
            epoch += 1
            all_correct = True
            current_weights = np.random.uniform(0, 3, 2)  # Zufällige Startgewichte im Bereich [0, 3]

            for input_vector, target in zip(inputs, targets):
                # Berechnung der gewichteten Summe inkl. Bias
                weighted_sum = np.dot(input_vector, current_weights) + bias

                # Aktivierungsfunktion (Schwellenwertfunktion mit zwei Schwellenwerten)
                output = 1 if lower_threshold < weighted_sum < upper_threshold else 0

                # Fehlerberechnung
                error = target - output

                # Wenn ein Fehler vorliegt, dann weise die Gewichte an
                if error != 0:
                    all_correct = False
                    current_weights += learning_rate * error * np.array(input_vector)

            # Überprüfe, ob alle Ausgaben korrekt sind
            if all_correct:
                network_trained = True
                final_weights = current_weights  # Speichere die finalen Gewichte
                break  # Stoppe, wenn alle Ausgaben korrekt sind

        if network_trained:
            print(f"Das Netzwerk hat Wahrheitstabelle {table_index} erfolgreich nach {epoch} Iterationen gelernt.")
            print(f"Startgewichte: {start_weights}")
            print(f"Endgewichte: {final_weights}")
            print(f"Endgültiger Bias: {bias}")
            break  # Wenn es mit diesem Bias erfolgreich war, gehe zum nächsten Wahrheitstabelle
        else:
            print(f"Das Netzwerk konnte mit Bias {bias} die Wahrheitstabelle {table_index} nicht lernen.")
            print("Versuche es mit dem nächsten Bias.")

    if not network_trained:
        print(f"Das Netzwerk hat Wahrheitstabelle {table_index} auch nach dem Testen aller Bias-Werte nicht korrekt gelernt.")
        print("Kein Erfolg mit diesem Ziel.")
