gameSolver
Solves zero-sum finite strategic games using the pivot method. Two players are playing a game where they each choose a move from a finite set of possibilities. For each combination of strategies, a (possibly negative) value is specified that player II must pay to player I. The game can then be represented as a matrix, and the game reduces to player I picking a row and player II picking a column. Solving the game is to find a probability vector for each player that guarantees I a minimal expected profit and II a maximal expected loss, and to find the value of the game. The value is the expected profit or loss, which are equal by von Neumann's minimax theorem.
function [p, q, V] = gameSolver(A)
% uses the pivot method to solve finite strategic games given in matrix form A.
[m, n] = size(A);
[sp] = pony(A);
if ~isempty(sp),
p = zeros(m, 1);
p(sp(1)) = 1;
q = zeros(1, n);
q(sp(2)) = 1;
V = a(sp(1), sp(2));
fprintf('Saddle point found.\n');
return;
end;
c = min(A(:));
if c < 0,
A = A + abs(c);
fprintf([num2str(abs(c)) ' added to A.\n']);
end;
T = initPivotTable(A);
T = pivotMethod(A);
V = 1 / T.A(m + 1, n + 1) - abs(c);
p = zeros(m, 1);
for c = 1:n,
swappedx = findstr(T.y{c}, 'x');
if isempty(swappedx),
continue;
end;
r = str2num(T.y{c}(2:end));
p(r) = T.A(c, n + 1) .* (1 / T.A(m + 1, n + 1));
end;
q = zeros(1, n);
for r = 1:m,
swappedy = findstr(T.x{r}, 'y');
if isempty(swappedy),
continue;
end;
c = str2num(T.x{r}(2:end));
q(c) = T.A(m + 1, r) .* (1 / T.A(m + 1, n + 1));
end;
function T = initPivotTable(A)
[m, n] = size(A);
for r = 1:m,
T.x{r} = ['x' num2str(r)];
end;
for c = 1:n,
T.y{c} = ['y' num2str(c)];
end;
T.A = [[A ones(m, 1)]; [-1 * ones(1, n) 0]];
function T = pivotMethod(A)
T = initPivotTable(A);
while length(find(T.A(end, :) < 0)) > 0,
c = find(T.A(end, :) < 0);
if ~isempty(find(c == 2)),
c0 = 2;
else,
c0 = c(1);
end;
fprintf(['Pivotting column ' num2str(c0) '.\n']);
T = pivot(T, c0);
end;
function T_new = pivot(T, c0)
%T.A is the game matrix with added column and row
%T.x
%T.y
T_new = [];
if T.A(end, c0) >= 0,
return;
end;
[m, n] = size(T.A);
% find row with smallest border-column / A(row, c0) ratio
minrat = [];
r0 = [];
for r = 1:m,
if T.A(r, c0) <= 0,
continue;
end;
rat0 = T.A(r, n) / T.A(r, c0);
if isempty(minrat),
minrat = rat0;
r0 = r;
elseif rat0 < minrat,
minrat = rat0;
r0 = r;
end;
end;
if isempty(r0),
return;
end;
T_new.x = T.x;
T_new.x(r0) = T.y(c0);
T_new.y = T.y;
T_new.y(c0) = T.x(r0);
T_new.A = [];
for r = 1:m,
for c = 1:n,
if r == r0 && c == c0,
T_new.A(r, c) = 1/T.A(r0, c0);
elseif r == r0,
T_new.A(r, c) = T.A(r, c) / T.A(r0, c0);
elseif c == c0,
T_new.A(r, c) = -T.A(r, c) / T.A(r0, c0);
else,
T_new.A(r, c) = T.A(r, c) - T.A(r, c0) * T.A(r0, c) / T.A(r0, c0);
end;
end;
end;
disp(T_new.y);
for r = 1:(m-1),
fprintf([T_new.x{r} ' ' num2str(T_new.A(r, :)) '\n']);
end;
fprintf([' ' num2str(T_new.A(m, :)) '\n']);
function sp = pony(A)
% finds saddle points
[m, n] = size(A);
maxPerColumn = max(A);
minPerRow = min(A, 2);
sp = [];
for r = 1:m,
for c = 1:n,
if A(r, c) == minPerRow(r) && A(r, c) == maxPerColumn(c),
sp = [r c];
return;
end;
end;
end;