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;