% Simulationsumgebung für den Wabenbau sozialer Insekten
global DX;
global DY;
global Wabengitter;
global Knotenzahl;
global zeit;
global Grenzen;
global MittelPunkte;
global MittelWabe;
global raumplot;
global bebautezellen;
global wespenanzahl;
global numberofruns;
global numberofgaruns;
global gadurchlauf;
global animation;
global ring;

DX = 41; % Breite des Gitters
DY = 41; % Höhe des Gitters
wespenanzahl = uint8(1); % Zahl der aktiven Agenten pro einzelner Wabe
MaxSteps = uint16(200); % Zahl der Schritte pro Simulationslauf
MaxSteps2 = uint16(1000); % Zahl der Schritte für zweite Hierarchie
numberofruns = uint8(4); % Größe der GA-Population
numberofgaruns = uint8(4); % Zahl der Durchläufe des GA
rulesetanzahl = uint8(1); % Zahl der unterschiedlichen Regelsätze
animation = true;

for ring=uint8(1):rulesetanzahl
    
    for gadurchlauf=uint8(1):numberofgaruns
        % close all; % schließt alle vorherigen Fenster
        
        for run=uint8(1):numberofruns
            
            Wabengitter = hextop(DX,DY); 
            % Erzeugen des hexagonalen Gitters
            % Struktur der Matrix:
            % Zeile 1: X-Koordinate des Knotenpunkts
            % Zeile 2: Y-Koordinate des Knotenpunkts
            % Zeile 3: Markierung, ob Knotenpunkt Wabenmittelpunkt ist (1/0)
            % Zeile 4: Belegung des Feldes (0 = leer, 1 = Baustein Typ 1, ...)
            
            Knotenzahl = size(Wabengitter,2);
            
            Position = DX + 2; % Initialisierung - erster Wabenmittelpunkt
            
            
            % Algorithmus zur Markierung der Wabenmittelpunkte
            % - legt eine dritte Zeile in der Matrix Wabengitter an und markiert jeden
            % Knotenpunkt, der einem Wabenmittelpunkt entspricht, mit einer 1
            
            for Position=DX+2:3:2*DX-1
                % die zweite Reihe vom zweiten bis zum vorletzten Element
                % mit horizontalem Abstand 3
                Position2 = Position;
                while Position2 < (Knotenzahl - DX) % oberste Zeile ausschließen
                    Wabengitter(3,Position2) = 1; % Setze Markierung für Mittelpunkt
                    Position2 = Position2 + 2 * DX;
                end
                Position2 = Position + DX + 2;
                if (mod(Position2,DX) > 1) && (mod(Position2,DX) < DX)
                    while Position2 < Knotenzahl - DX
                        Wabengitter(3,Position2) = 1;
                        Position2 = Position2 + 2*DX;
                    end
                end
            end
            
            MittelPunkte = find(Wabengitter(3,:));
            % erzeugt einen Vektor mit Indizes der Wabenmittelpunkte
            Grenzen = max(Wabengitter,[],2);
            % ereugt einen Vektor, der die Endkoordinaten des Gitters enthält
            MittelWabe = MittelPunkte(ceil(length(MittelPunkte) / 2));
            % Index der annähernd mittleren Wabe (Ausgangspunkt für die Simulation)
            mittelnachbarn = nachbarn(MittelWabe);
            Wabengitter(4,MittelWabe) = 1; % Baustein vom Typ 1 an Mittelpunkt gesetzt
            % Wird als Anfangspunkt benötigt
            for nachbarindex=1:6
                Wabengitter(4,mittelnachbarn(nachbarindex)) = 1;
            end % die sechs direkten Nachbarn des Mittelpunkts werden als bebaut markiert
            
            % if (gadurchlauf == numberofgaruns) % nur beim letzten Durchlauf grafisch anzeigen
                
                % close all; % schließt alle Fenster - Fix um Absturz zu verhindern
                
                scrsz = get(0,'ScreenSize');
                % erzeuge figure für die graphische Anzeige
                visual = figure('Name',['GA ' num2str(gadurchlauf) ' RS ' num2str(run)], ...
                    'Position',[1 scrsz(4) scrsz(3) scrsz(4)], ...
                    'NumberTitle','off');
                raumplot = gca;
                hold on; % verhindern, dass gezeichnetes wieder gelöscht wird
                
                
                
                view(3); % Betrachtungswinkel einstellen
                axis(raumplot,'manual');
                set(raumplot, 'DataAspectRatio', [1 1 1] ); % , ...
                % 'PlotBoxAspectRatio', [1 1 1] );
                axis(raumplot,[-2 (Grenzen(1)+2) -2 (Grenzen(2)+2)]);
                camlight('right');
                camproj('perspective');
                lighting gouraud;
                
                % leeres Gitter anzeigen
                plotgitter(Wabengitter, raumplot);
                plotwabe(MittelWabe, raumplot, 8); % die Anfangswabe wird markiert
                for nachbarindex=1:6
                    plotwabe(mittelnachbarn(nachbarindex), raumplot, 8);
                end % die sechs unmittelbaren Nachbarzellen der Mittelwabe werden auch gesetzt
                % verhindert die Notwendigkeit einer Einserregel
            % end
            
            
            
            % wespe(numberofruns,wespenanzahl) = bauagent([1.0 1.0], 1); % array preallocation
            if (ring == 1) % nur für den ersten Regelsatz
                
                if (gadurchlauf == 1) % nur im ersten Durchlauf des GA
                    
                    for nummer=uint8(1):wespenanzahl
                        wespe(run,nummer) = bauagent(Wabengitter(1:2, MittelWabe)', nummer);
                        % erzeugt ein Objekt der Klasse Bauagent auf den Koordinaten
                        % der mittleren Wabe
                    end
                    % erzeugt die durch wespenanzahl festgelegte Menge von Objekten der
                    % Klasse 'agent'
                    global wespe;
                else
                    for nummer=uint8(1):wespenanzahl
                        wespe(run,nummer).BuildCounter = 0;
                        wespe(run,nummer).Position = Wabengitter(1:2, MittelWabe)';
                    end
                end
                
            else
                % für den zweiten Durchlauf in der Hierarchie mit zwei
                % hintereinander zu benutzenden Regelsätzen
                for nummer=uint8(1):wespenanzahl
                    wespe(run,nummer).classifierset = bestclassifierset1;
                    wespe(run,nummer).numberofclassifiers = length(wespe(run,nummer).classifierset);
                    wespe(run,nummer).classifierfitnessstring = strcat(wespe(run,nummer).classifierset.fitnessstring);
                    wespe(run,nummer).BuildCounter = 0;
                    wespe(run,nummer).Position = Wabengitter(1:2, MittelWabe)';
                end
            end
            
            
            
            % Simulationsstart
            bebautezellen = find(Wabengitter(4,:)); % Update der Liste der Indizes aller bebauten Zellen
            
            grafik = gcf;
            % moviefile = avifile('simulation_04.avi');
            % moviefile.Quality = 100;
            % moviefile.fps = 5;
            
            
            for zeit=uint16(1):MaxSteps % aktuelle Simulationszeit als Integerwert - wird in jedem Zeitschritt um 1 erhöht
                for wespennummer=uint8(1):wespenanzahl
                    wespe(run,wespennummer).movebuild();
                end
                % plotwaben(Wabengitter);
                % drawnow;
                
                
                % film = getframe(grafik); % videoaufzeichnung
                % moviefile = addframe(moviefile,film);
                
                % displayString = ['Zeit: ' num2str(Zeit) ];
                % text(5,5,displayString);
            end
            
            
            if ( ring == 2 ) % zweiter hierarchischer Schritt
                
                for wespennummer=uint8(1):wespenanzahl
                    wespe(run,wespennummer).updateclassifierset(wespe(run,wespennummer).RuleSet2);
                    % zweites regelwerk benutzen
                end
                
                for zeit=MaxSteps+1:MaxSteps2 % zweite Zeitschleife für zweite Hierarchieebene
                    for wespennummer=uint8(1):wespenanzahl
                        wespe(run,wespennummer).movebuild();
                    end
                end
            end
            
            % Screenshot abspeichern
            figfilestring = ['./bilder/staticrs1_vergleich_' num2str(run)];
%            saveas(grafik,figfilestring, 'fig' );
            
            [fitnesswert, idealwert, aussenlaenge, wabenanzahl, quotient] = fitness(Wabengitter);
            outp = sprintf('run %u \n fitness %f \n idealwert %f \n aussenlaenge %d \n wabenzahl %d \n quotient %f', ...
                run, fitnesswert, idealwert, aussenlaenge, wabenanzahl, quotient)
            
            overallfitness(run) = quotient; % legt einen Vektor overallfitness an
            % hier wird für den Phänotyp (strukturelles Simulationsergebnis)
            % jedes Regelsatzes seine Overall-Fitness abgespeichert
            % Dient als Basis für den GA
        end
        
         strengthga(overallfitness); % Aufruf des GA zur Erzeugung neuer Regelsätze
        % mit anderen Fitnesswerten
        
        numberofruns = size(wespe,1);
        % Update der Anzahl der Durchläufe
        % - wenn neue Individuen (Regelsätze)
        % dazukommen, müssen die auch berücksichtigt
        % werden
        
        [maxwert, maxindex] = max(overallfitness);
        [minwert, minindex] = min(overallfitness);
        % ermittelt den Regelsatz mit bester bzw. niedrigster Fitness
        
        maxvektor(gadurchlauf,1) = maxwert;
        maxvektor(gadurchlauf,2) = maxindex;
        maxvektor(gadurchlauf,3) = minwert;
        maxvektor(gadurchlauf,4) = minindex;
        maxvektor(gadurchlauf,5) = mean(overallfitness);
    end
    
    % close(grafik);
    % moviefile = close(moviefile);
    
    outp = sprintf(['maximaler Fitnesswert / Index / minimaler' ...
                    ' Fitnesswert / Index / Durchschnittsfitness'])
    maxvektor
    
    if (ring == 1)
        bestclassifierset1 = wespe(uint16(maxvektor(gadurchlauf,2))).classifierset;
        % besten Regelsatz zur Wiederverwendung kopieren
        
        bestwespe1 = wespe(uint16(maxvektor(gadurchlauf,2)));
        bestwespe1.BuildCounter = 0;
        bestwespe1.Position = Wabengitter(1:2, MittelWabe)';
    end
end





