%DVOUMATICE - kooperativní konflikt - přenosná výhra
close all, clear all, clc
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Zadejte výplatní matice pro hráče 1 a 2 např. následovně:
% A=[-2 5 6; 3 1 -2; 1 4 2]
% B=[3 2 1; -1 4 -1; 5 4 2]

%Matice A a B musí nabývat stejných rozměrů.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Příklady vstupních parametrů:

% %Jeden rovnovážný bod => rovnovážné zaručené výhry, nepodstatná hra
% A=[4 6 2;9 7 3;7 5 6]
% B=[2 7 9;8 7 4;7 8 3]

% %Čtyři zaměnitelné rovnovážné body => rovnovážné zaručené výhry, nepodstatná hra
% A=[4 8 5;8 6 8;8 5 8]
% B=[4 3 9;8 7 8;8 5 8]

% %Čtyři rovnovážné body, jeden dominující => rovnovážné zaručené výhry, nepodstatná hra
% A=[9 3 4 2;1 2 3 10; 2 3 6 3; 2 4 3 1]
% B=[7 2 4 2;1 2 3 8; 2 3 5 3; 1 4 2 1]

% %Pět rovnovážných bodů, dva totožné a zaměnitelné ve sloupci => zaručené výhry podle maximinu, podstatná hra
% A=[9 3 4 2;1 2 3 10; 2 3 10 10; 2 4 3 1]
% B=[7 2 4 2;1 2 3 8; 2 3 9 9; 1 40 2 1]

% %Dva rovnovážné body, které se nedominují => zaručené výhry podle maximinu, podstatná hra
% A=[4 7 5;5 1 9;6 7 1]
% B=[9 5 3;2 0.97 5;4 8 1]

% %Jeden rovnovážný bod => zaručené rovnovážné výhry, podstatná hra
% A=[15 5;6 4;4 7]
% B=[10 16;11 5;7 12]

%Příklad z [9]:
% A=[3 -3;4 1]
% B=[5 -1;1 4]

%Příklad z diplomové práce:
% A=[60 100 90; 100 55 90; 90 105 60]
% B=[60 120 120; 95 65 115; 120 85 60]
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Zadejte vstupní parametry:




%kód algoritmu:
size_check=0;
[m,n]=size(A);
[m_2,n_2]=size(B);
if (m>=2 && n>=2) && (m==m_2 && n==n_2)
    size_check=1;
end

if (size_check==1)
    %radkova maxima v B
    for i=1:m
        Bi=B(i,:);
        mx_B=max(Bi);
        [~,p{i}]=find(Bi==mx_B); %[m,n]=find(max) <--zajima me jen index sloupce n
        k1(i)=numel(p{i}); %pocitani, kolikrat je maximum na radku
    end
    
    %sloupcova maxima v A
    for i=1:n
        Ai=A(:,i);
        mx_A=max(Ai);
        [q{i},~]=find(Ai==mx_A); %[m,n]=find(max) <--zajima me jen index radku m
        k2(i)=numel(q{i}); %pocitani, kolikrat je maximum ve sloupci
        
    end
    
    %indexovani radkovych maxim v B
    X= [0,0];
    for i=1:numel(k1)
        for j=1:k1(i)
            C1(j,:)=[i,p{i}(j)]; %v ramci i-teho p-cka najdi j-tou hodnotu C1(1,1)=[]
        end
        X=[X;C1];
        C1=[];
    end
    
    %indexovani sloupcovych maxim v A
    Y=[0,0];
    for i=1:numel(k2)
        for j=1:k2(i)
            C2(j,:)=[i,q{i}(j)]; %v ramci iteho q-cka najdi jtou hodnotu
        end
        Y=[Y;C2];
        C2=[];
    end
    
    %odstraneni prvnich nul
    X=X(2:end,:);
    Y=Y(2:end,:);
    
    %prohozeni indexu ve sloupcovych maximech v A
    swap = [1 2];
    Y(:, swap) = Y(:, flip(swap));
    
    %nalezeni spolecnych oznacenych strategii
    C = intersect(X,Y,'rows');
    
    disp('Nalezená sloupcová maxima v matici A:')
    [length_U,~] = size(Y); %kolik ma matice sloupcovych maxim radku(tzn, zaznamu)
    for i=1:length_U
        fprintf('a(i=%g,j=%g)=%g\n',Y(i,1),Y(i,2),A(Y(i,1),Y(i,2)));
    end
    disp('............................')
    
    disp('Nalezená řádková maxima v matici B:')
    [length_Z,~] = size(X); %kolik ma matice radkovych maxim radku(tzn, zaznamu)
    for i=1:length_Z
        fprintf('b(i=%g,j=%g)=%g\n',X(i,1),X(i,2),B(X(i,1),X(i,2)));
    end
    
    [length_C,~] = size(C);
    v1_v2_check=0;
    if (length_C>0)
        disp('............................');
        
        if(length_C>1)
            disp('Nalezené rovnovážné body:')
        else
            disp('Nalezený rovnovážný bod:')
        end
        for i=1:length_C
            fprintf('a(i=%g,j=%g)=%g \n',C(i,1),C(i,2),A(C(i,1),C(i,2)));
            fprintf('b(i=%g,j=%g)=%g \n',C(i,1),C(i,2),B(C(i,1),C(i,2)));
            disp('...');
        end
        disp('............................');
        disp('Hledání a odstranění dominovaných rovnovážných bodů:');
        [length_C,~] = size(C);
        D=[0 0];
        for j=1:length_C
            for i=1:length_C
                if (A(C(j,1),C(j,2)) > A(C(i,1),C(i,2))) && (B(C(j,1),C(j,2)) > B(C(i,1),C(i,2)))
                    fprintf('a(i=%g,j=%g)=%g > a(i=%g,j=%g)=%g , b(i=%g,j=%g)=%g > b(i=%g,j=%g)=%g \n',C(j,1),C(j,2),A(C(j,1),C(j,2)),C(i,1),C(i,2),A(C(i,1),C(i,2)),C(j,1),C(j,2),B(C(j,1),C(j,2)),C(i,1),C(i,2),B(C(i,1),C(i,2)));
                    disp('...');
                    D(i,:)=[C(i,1),C(i,2)]; %radkove indexy dominovanych strategii
                end
                
            end
        end
        C=setdiff(C,D,'rows');
        %odstraneni nulovych radku
        C(C(:,1)==0,:) = [] ;
        disp('............................');
        [length_C,~] = size(C);
        %jediny rovnovazny bod
        if length_C==1
            disp('Nalezen jediný nedominovaný rovnovážný bod:');
            fprintf('a(i=%g,j=%g)=%g \n',C(1,1),C(1,2),A(C(1,1),C(1,2)));
            fprintf('b(i=%g,j=%g)=%g \n',C(1,1),C(1,2),B(C(1,1),C(1,2)));
            v1_v2_check=1;
        else
            %eq_check overuje rovnost funkcnich hodnot rovnovaznych bodu
            eq_check=1;
            disp('Kontrola rovnosti funkčních hodnot nedominovaných rovnovážných bodů:');
            for j=1:length_C
                for i=1:length_C
                    if (A(C(j,1),C(j,2)) ~= A(C(i,1),C(i,2))) || (B(C(j,1),C(j,2)) ~= B(C(i,1),C(i,2)))
                        fprintf('a(i=%g,j=%g)=%g ~= a(i=%g,j=%g)=%g nebo b(i=%g,j=%g)=%g ~= b(i=%g,j=%g)=%g \n',C(j,1),C(j,2),A(C(j,1),C(j,2)),C(i,1),C(i,2),A(C(i,1),C(i,2)),C(j,1),C(j,2),B(C(j,1),C(j,2)),C(i,1),C(i,2),B(C(i,1),C(i,2)));
                        disp('...');
                        eq_check=0;
                    end
                end
            end
            %exchangable_check_count>0 znamena, ze nektery z rovnovaznych bodu je nezamenitelny
            exchangable_check_count=0;
            disp('............................');
            %rovnovazne body jsou si rovny, kontrola zamenitelnosti - resitelny pripad
            if eq_check==1
                disp('Kontrola zaměnitelnosti nedominovaných rovnovážných bodů:');
                member_check=inf;
                for j=1:length_C
                    for i=1:length_C
                        exchangable=intersect(C,[C(j,1) C(i,2)],'rows');
                        [member_check,~]=size(exchangable);
                        if (member_check==0)
                            exchangable_check_count=exchangable_check_count+1;
                        end
                    end
                end
            end
            % rovnovazne body jsou stejne (a zamenitelne)
            if (exchangable_check_count==0 && eq_check==1)
                disp('Nalezené nedominované rovnovážné body mají stejnou funkční hodnotu a jsou zaměnitelné.');
                disp('............................');
                v1_v2_check=1;
            else
                %rovnovazne body nejsou stejne nebo nejsou zamenitelne
                disp('Nalezené nedominované rovnovážné body nemají stejnou funkční hodnotu, nebo nejsou zaměnitelné.');
                disp('............................');
                disp('Hledání zaručených výher podle maximinu:');
            end
        end
    else
        
        disp('............................');
        disp('Matice nemá žádný rovnovážný bod.');
        disp('Hledání zaručených výher podle maximinu:');
        
    end
    %zarucene vyhry:
    %jestlize je v matici nedominovany rovnovazny bod, pak je znama zarucena vyhra obou hracu
    if (v1_v2_check==1)
        v_1=A(C(1,1),C(1,2));
        v_2=B(C(1,1),C(1,2));
        disp('............................')
        disp('Zaručené výhry dle rovnovážného bodu jsou:');
        fprintf('Rovnovážná zaručená výhra prvního hráče v(1)=%g \n',v_1);
        fprintf('Rovnovážná zaručená výhra druhého hráče v(2)=%g \n',v_2);
    else
        %jestlize v matici nedominovany rovnovazny bod neni, pak se zjisti
        %zarucena vyhra podle maximiminu v radcich A, a sloupcich B
        disp('Nalezená řádková minima v matici A:');
        v1_min=min(A,[],2);
        for i=1:m
            fprintf('řádek %g: %g \n',i,v1_min(i));
        end
        
        disp('Nalezená sloupcová minima v matici B:');
        v2_min=min(B);
        for i=1:n
            fprintf('sloupec %g: %g \n',i,v2_min(i));
        end
        v_1=max(v1_min);
        v_2=max(v2_min);
        disp('Zaručené výhry dle maximinu jsou:');
        fprintf('Zaručená výhra prvního hráče v(1)=%g \n',v_1);
        fprintf('Zaručená výhra druhého hráče v(2)=%g \n',v_2);
    end
    disp('............................')
    disp('Matice společných výher A+B je:')
    % matice A+B spolecnych vyher, najit v ni maxima a porovnat, jestli v(1,2)>v(1)+v(2)
    AB=A+B
    v_1_2=max(max(AB));
    fprintf('Maximální společná výhra v matici A+B je: v(1,2)=%g \n',v_1_2);
    
    %zjisteni superaditivni hodnoty v(1,2)-v(1)-v(2)
    superadditive=v_1_2-v_1-v_2;
    fprintf('Přebytek společné výhry v(1,2)-v(1)-v(2)=%g \n',superadditive);
    
    %test, jestli je hra podstatna
    if (v_1_2 > v_1+v_2)
        disp('............................')
        disp('Hra je podstatná a hráči budou spolu kooperovat, jelikož platí, že v(1,2)>v(1)+v(2).');
        disp('Přerozdělení podle teorie „spravedlivého“ rozdělení maximální společné výhry:')
        a_1=v_1+(1/2*superadditive);
        a_2=v_2+(1/2*superadditive);
        fprintf('Výhra prvního hráče a1=%g \n',a_1);
        fprintf('Výhra druhého hráče a2=%g \n',a_2);
        
        disp('............................')
        disp('Rozdělení maximální společné výhry s respektováním velikosti zaručených výher:')
        ratio=(v_1_2-v_2)+(v_1_2-v_1);
        a_1_a_2_ratio=superadditive/ratio;
        a_1_ratio=(v_1_2-v_2)*a_1_a_2_ratio;
        a_2_ratio=(v_1_2-v_1)*a_1_a_2_ratio;
        a_1=v_1+a_1_ratio;
        a_2=v_2+a_2_ratio;
        fprintf('Výhra prvního hráče a1=%g \n',a_1);
        fprintf('Výhra druhého hráče a2=%g \n',a_2);
        
        %pokud existuje pouze jedna maximalni vyhra:
        [max_m,max_n]=find(AB==v_1_2); % stejnych maxim muze byt v matici vic, pak nelze urcit hodnoty a(i,j), b(i,j)
        m_check=size(max_m);
        n_check=size(max_n);
        if (m_check(1,1)==1 && n_check(1,1)==1)
            disp('............................')
            disp('Rozdělení maximální společné výhry s respektováním příspěvků obou hráčů ke společné výhře:')
            ratio=(v_1_2-B(max_m,max_n))+(v_1_2-A(max_m,max_n));
            a_1_a_2_ratio=superadditive/ratio;
            a_1_ratio=(v_1_2-A(max_m,max_n))*a_1_a_2_ratio;
            a_2_ratio=(v_1_2-B(max_m,max_n))*a_1_a_2_ratio;
            a_1=v_1+a_1_ratio;
            a_2=v_2+a_2_ratio;
            fprintf('Výhra prvního hráče a1=%g \n',a_1);
            fprintf('Výhra druhého hráče a2=%g \n',a_2);
        end
        
        disp('............................')
        disp('Rozdělení maximální společné výhry na poloviny:')
        a_1=v_1_2/2;
        a_2=v_1_2/2;
        fprintf('Výhra prvního hráče a1=%g \n',a_1);
        fprintf('Výhra druhého hráče a2=%g \n',a_2);
        
        %jinak =>hra je nepodstatna
    else
        disp('Hra je nepodstatná, neboť neplatí: v(1,2)>v(1)+v(2):');
        fprintf('%g=%g+%g \n',v_1_2,v_1,v_2);
        disp('Hráči nemají důvod kooperovat. K nalezení řešení hry je třeba užít metod nekooperativní teorie her.');
    end
    
    
else
    disp('Chyba: Obě matice A, B musí mít tototžné rozměry o rozměrech alespoň 2x2.');
end



