Game with two cards 1 and 2 and two players P1 and P2. Rules:

- Each player sets 1.
- P1 passes or sets 1.
- Then P2 passes or sets 1.
- Player with higher card takes stock.
- Stock is shared with equal cards.

First we make a function, which computes the outcome of the game for specific cards and tactics.

>function play (c1,c2,t1,t2) ... ## compute outcome of game. ## c1,c2 - card of first and second player (1,2) ## t1,t2 - tactic of first and second player ## (e.g. [0,1] means pass with 1, set with 2) ## result: gain as seen from first player if t1[c1]==0 then return -1 elseif t2[c2]==0 then return 1 else if c1>c2 then return 2 elseif c1<c2 then return -2 else return 0 endif endif endfunction

Example: If P1 gets card 2, P2 gets card 1, both have the tactic to pass with card 1 and hold with card 2, then P1 will win 1.

>play(2,1,[0,1],[0,1])

1

We need the matrix of possible tactics.

>T=[0,0;0,1;1,0;1,1]

0 0 0 1 1 0 1 1

It is obvious that not all of these tactics are wise. E.g., it is easy to see that passing with card 2 is always inferior to bidding with card 2. For the time being, we simply ignore such considerations.

Now we loop over all tactics for both players and determine the expected result of the game in a matrix. The column index belongs to the first player. It is the row of T he selects for his tactic.

Example: Both players have the unreasonable tactic [1,0]. Then

- P1 looses -1 with card 2, no matter what card P2 has.
- P2 looses 1 with card 1 and equals with card 0.

On average, P1 looses -1/4.

>function makeR (T) ... ## make matrix of results k=rows(T); R=zeros(k,k); // loop over all tactics: for i1=1 to k for i2=1 to k v=0; // loop over all cards: for c1=1 to 2 for c2=1 to 2 v=v+play(c1,c2,T[i1],T[i2]); end; end; R[i2,i1]=v/4; // columns refer to first player! end; end; return R endfunction

>R=makeR(T);

Here is the matrix of game results.

>fraction R

-1 0 0 1 -1 -1/4 -3/4 0 -1 1/4 -1/4 1 -1 0 -1 0

An example is the tactic [1,0] for both players with an average loss of 1/4 for the first player.

The problem now is determine probabilities p[i] for each tactic, such that the minimal expected win is maximized. This amounts to

Let us make the matrix for this linear problem. Variables are the p[i] and the game result G.

>A=R|-1; ... A=A_ones(1,4)

-1 0 0 1 -1 -1 -0.25 -0.75 0 -1 -1 0.25 -0.25 1 -1 -1 0 -1 0 -1 1 1 1 1 0

We have >= in first 4 rows, and = in the last.

>eq=ones(4,1)_0

1 1 1 1 0

Thus we reformulate

>b=zeros(4,1)_1

0 0 0 0 1

We maximize G.

>c=zeros(1,4)|1

[0, 0, 0, 0, 1]

There is no restriction for G.

>restr=ones(1,4)|0

[1, 1, 1, 1, 0]

The result is boring. Each player should always set (tactic [1,1]).

>res=simplex(A,b,c,eq,restr,>max); res'

[0, 0, 0, 1, 0]

The game is fair.

>c.res

0

The strategy for the other player is the same.

>simplex(-A',b,c,eq,restr,>max)'

[0, 0, 0, 1, 0]

Let us make a function of the matrix manipulations.

>function game (R) ... ## compute best strategy for column player. ## return: {p,G} m=rows(R); n=cols(R); M=R|-1_ones(1,n); b=zeros(m,1)_1; eq=ones(m,1)_0; c=zeros(1,m)|1; restr=ones(1,m)|0; res=simplex(M,b,c,eq,restr,>max); return {res[1:n]',res[-1]}; endfunction

Here is our example so far.

>{p,G}=game(R); G, p

0 [0, 0, 0, 1]

Assume, we change the rules.

- Each player sets A.
- P1 passes or sets B.
- Then P2 passes or sets B.
- Player with higher card takes stock.
- Stock is shared with equal cards.

The game depends on the values of A and B.

>A=1; B=2;

We have to modify the function play(). For the moment, we refer to the global values of A and B.

>function play (c1,c2,t1,t2) ... global A,B; if t1[c1]==0 then return -A elseif t2[c2]==0 then return A else if c1>c2 then return A+B elseif c1<c2 then return -(A+B) else return 0 endif endif endfunction

Suddenly, the first player is in a disadvantage.

>{p,G}=game(makeR(T)); G, p,

-0.25 [0, 1, 0, 0]

Both players have to pass with 1 and hold with 2 (tactic [0,1]).

>{p,G}=game(-makeR(T)'); G, p,

0.25 [0, 1, 0, 0]

>T[2]

[0, 1]

To get a function for G depending on B, we define G(x). In the function we set the global variable B to x.

>function G(x) ... global B,T; B=x; {p,G}=game(makeR(T)); return G; endfunction

The result is that for B/A<1 the game is fair, and for B/A>1 the first player is in a disadvantage losing A/4 on average. For B/A>2 his loss is -0.25.

>plot2d("G",0,3,xl="B",yl="G"):

Up to B/A=2, the first player has to set always.

>B=1.9; {p,G}=game(makeR(T)); G, p,

-0.225 [0, 0, 0, 1]

From the matrix, it is clear that any other tactics is inferior.

>makeR(T)

-1 0 0 1 -1 -0.25 -0.975 -0.225 -1 0.475 -0.25 1.225 -1 0.225 -1.225 0

For B/A>2, the tactics must change, and the first player takes a more conservative approach, passing with 1.

>B=3; {p,G}=game(makeR(T)); G, p,

-0.25 [0, 1, 0, 0]

For three card values, we can use the same algorithm with minor changes.

First, we take all possible tactics into consideration, even though some of them are clearly inferior. To compute the tactics, the following recursive function will do.

>function makeT (n) ... if n==1 then return (0:1)'; else TL = makeT(n-1); return (0|TL)_(1|TL); endif; endfunction

>T=makeT(3)

0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 0 1 1 1 0 1 1 1

We have to modify makeR() to take the value of m into consideration.

>function makeR (T,m) ... ## make matrix of results k=rows(T); R=zeros(k,k); for i1=1 to k for i2=1 to k v=0; for c1=1 to m for c2=1 to m v=v+play(c1,c2,T[i1],T[i2]); end; end; R[i2,i1]=v/m^2; // column belongs to first player! end; end; return R endfunction

For A=B=1, the result is to always hold with a card value of 2,3.

>A=1; B=1; {p,G}=game(makeR(T,3)); p, G,

[0, 0, 0, 1, 0, 0, 0, 0] -0.111111111111

For A=1, B=2, things change.

>A=1; B=2; {p,G}=game(makeR(T,3)); p, G,

[0, 0, 0, 0.75, 0, 0, 0, 0.25] -0.166666666667

The optimal strategy for B/A=2 is

- with p=3/4 set with a card values 2,3.
- with p=1/4 set with any card value (1,2,3).

Setting with a card value of 2 can be considered a moderate form of a bluff.

>T[4], T[8]

[0, 1, 1] [1, 1, 1]

>function G(x) ... global T,B; B=x; {p,G}=game(makeR(T,3)); return G endfunction

Surprisingly, the expected win G for the optimal tactics is a quadratic function from B/A=1 to B/A=4.

>plot2d("G",0,5,n=20):

For more card values, we restrict to the promising tactics. We consider only the tactics "set with a card value greater or equal c".

We have to modify our play() function once more.

>function play (c1,c2,t1,t2,A,B) ... ## compute outcome of game. ## c1,c2 - card of first and second player (1,...,n) ## t1,t2 - tactic of first and second player ## e.g. t1=c means to set with card values c,c+1,...,n ## result: gain as seen from first player if c1<t1 then return -A elseif c2<t2 then return A else if c1>c2 then return (A+B) elseif c1<c2 then return -(A+B) else return 0 endif endif endfunction

The matrix of game results now has to use all possible tactics 1 to n, and simulate all possible card values 1 to n for both players.

>function makeR (n,A,B) ... ## make matrix of results R=zeros(n,n); for t1=1 to n for t2=1 to n v=0; for c1=1 to n for c2=1 to n v=v+play(c1,c2,t1,t2,A,B); end; end; R[t2,t1]=v/n^2; // column belongs to first player! end; end; return R endfunction

Let us test with the example above. We have 3 card values, A=1 and B=2.

>{p,G}=game(makeR(3,1,2)); p, G,

[0.25, 0.75, 0] -0.166666666667

The result gets more complicated with more card values, even if A=B=1.

>{p,G}=game(makeR(10,1,1)); p, G,

[0.555556, 0, 0, 0.444444, 0, 0, 0, 0, 0, 0] -0.106666666667

With B/A=10, we have to be more careful.

>{p,G}=game(makeR(10,1,10)); p, G,

[0, 0, 0, 0, 0, 0, 0, 0.75, 0.25, 0] -0.67

And with B/A=100, we have to be very careful.

>{p,G}=game(makeR(10,1,100)); p, G,

[0, 0, 0, 0, 0, 0, 0, 0, 0, 1] -0.81

>function G(x,n) ... {p,G}=game(makeR(n,1,x)); return G; endfunction

The game is no longer fair, even if B/A<1.

>plot2d("G(x,10)",0,1,n=40):

But the loss is limited for large B/A.

>plot2d("G(x,10)",0,20,n=40):

Let us determine the value for high B/A. In that case, it is optimal for both players to hold only with their largest card. Then the first player

- loses -A in (n-1)/n of all cases
- sets in 1/n of cases, but wins A only in (n-1)/n of these cases.

>function r(n) &= ratsimp((n-1)/n^2-(n-1)/n)

2 - n + 2 n - 1 -------------- 2 n

For n=10.

>r(10)

-0.81

That is exactly the value of the result matrix for these tactics.

>makeR(10,1,1)[10,10]

-0.81