BESNIER Benjamin MOLION Enzo

Q1 : Simulation sans mémoire

basicSize = 50000 ; # Number of games in classic case 
plotSize = 10000 ; # Number of games in case of ploting for all x and y in [0;1] by 0.1 steps

On construit une fonction buildBounds(probabiltyVector) qui crée une liste de vecteurs bounds de façon à ce que bounds[[i]] donne un intervalle de taille probabilityVector[i] et que pour tout i ≠ j, bounds[[i]] et bounds[[j]] n’ont aucun élément en commun en dehors, éventuellement, de leur bornes.
L’entrée doit être de la forme (a, b, c)a est la probabilité du premier évènement, b la probabilité du deuxième évènement et c la probabilité du troisième évènement. Nécessairement, a + b + c = 1.

buildBounds = function(probabilityVector){
  if (sum(probabilityVector) != 1){
    stop("Make sure that ProbabilityVector is really a probability vector (ie sum = 1)");
  }
  bounds = list();
  bounds[[1]] = c(0, probabilityVector[1]);
  bounds[[2]] = c(probabilityVector[1], probabilityVector[1] + probabilityVector[2]);
  bounds[[3]] = c(probabilityVector[1] + probabilityVector[2], 1); 
  return(bounds)
}

# Correct case
# buildBounds(c(1/4, 1/4, 1/2));
# sum < 1 case
# buildBounds(c(1/4, 1/4, 1/4));
# sum > 1 case 
# buildBounds(c(1/2, 1/2, 1/2));

On construit la fonction fromR01toPFC qui, à partir d’un réel appartenant à [0;1] et d’une liste de vecteurs bounds (créée avec buildBounds), donne le résultat correspondant Pierre, Feuille ou Ciseaux.
Exemple : bounds = [[0 ; 0.5], [0.5 ; 0.75], [0.75 ; 1]]
- x = 0.1 ⇒ fromR01toPFC(x, bounds) = P
- x = 0.63 ⇒ fromR01toPFC(x, bounds) = F
- x = 0.98 ⇒ fromR01toPFC(x, bounds) = C

inInterval = function(x, interval) {
  return(x >= interval[1] && x <= interval[2]);
}

fromR01toPFC = function(x, bounds){
  if(inInterval(x, bounds[[1]])){
    return("P");
  }
  else if (inInterval(x, bounds[[2]])){
    return("F");
  }
  else if (inInterval(x, bounds[[3]])){
    return("C");
  }
  else {
    stop("Decision number not in bounds");
  }
}

On construit la fonction buildPlaysVector qui construit,à partir d’une liste de vecteurs bounds construite avec buildBounds et d’un entier size donnés, le vecteur de taille size correspondant à size choix successifs de jeu.
Exemple buildPlaysVector(3, bounds) = [F, P, C] => le joueur fera 3 parties et jouera successivement Feuille, Pierre puis Ciseaux.
On peut se permettre d’avoir une fonction construisant à priori l’ensemble des choix successifs seulement parce que le choix se fait sans mémoire des choix précédents.

buildPlaysVector = function(size, bounds) {
  runifVector = runif(size);
  return(sapply(runifVector, fromR01toPFC, bounds = bounds));
}

# Test
# print(buildPlaysVector(10, buildBounds(c(1/3, 1/3, 1/3))));

On construit ensuite une fonction qui renvoie le résultat d’une partie :
L’entrée se fait sous la forme getWinner(A, B)A et B sont de la forme respectivement "P", "F" ou "C" si le joueur a joué respectivement Pierre, Feuille ou Ciseaux.
Le résultat est 0 si la partie est nulle, -1 si A a gagné la partie et 1 si B a gagné la partie.

getWinner = function(aChoice, bChoice) {
  if(aChoice == "P"){
    if(bChoice == "P"){return(0);}
    else if(bChoice == "F"){return(1);}
    else if(bChoice == "C"){return(-1);}
  }
  else if(aChoice == "F"){
    if(bChoice == "P"){return(-1);}
    else if(bChoice == "F"){return(0);}
    else if(bChoice == "C"){return(1);}
  }
  else if(aChoice == "C"){
    if(bChoice == "P"){return(1);}
    else if(bChoice == "F"){return(-1);}
    else if(bChoice == "C"){return(0);}
  }
}

# Tie case
# getWinner("C", "C");
# A winning case
# getWinner("F", "P");
# B winning case
# getWinner("C", "P");

On construit la fonction buildResultVector(n, Pa, Pb) qui à partir des vecteurs de probabilités Pa et Pb de deux joueurs, donne le vecteur indiquant les résultats de n parties.

# used https://stackoverflow.com/questions/35352647/r-apply-on-a-function-with-two-variables to know how to use mapply in addition to its documentation
buildResultVector = function(size, Pa, Pb){ 
  
  apv = buildPlaysVector(size, buildBounds(Pa));
  bpv = buildPlaysVector(size, buildBounds(Pb));

  return(mapply(getWinner, apv, bpv));
}

# Test
# Pa = c(1/4,1/4,1/2);
# Pb = c(1/4,1/4,1/2);
# cat("Result vector of size 10 given Pa and Pb : [", buildResultVector(10, Pa, Pb), "]");

On construit la fonction expectedValue(n, Pa, Pb) qui renvoie l’espérance de gain de B jouant n parties avec le vecteur de probabilité Pb contre A de vecteur de probabilité Pb.

expectedValue = function(size, Pa, Pb) {
  return(sum(buildResultVector(size, Pa, Pb))/size);
}

# Test
# Pa = c(1/4,1/4,1/2);
# Pb = c(1/4,1/4,1/2);
# print(expectedValue(basicSize, Pa, Pb));

On construit la fonction allPlotsForXYin01(size, Pa) qui affiche tous les graphes ayant pour ordonnée l’espérance de gain estimée sur size parties opposant deux joueurs ayant pour vecteurs de probabilité Pa et (x, y, 1 - x - y) et pour abscisse y, pour x fixé. Elle affiche également (x, y) tels que l’espérance correspondant soit maximale.

allPlotsForXYin01 = function(size, Pa, ymin = -1, ymax = 1){
  expectedValueVector = c();
  abscissa = c();
  
  maxExpectedValue = -Inf;
  maxExpectedValueX = -Inf;
  maxExpectedValueY = -Inf;
  
  for(x in 0.1 * (0:10)){
    
    yindex = 1 ;
    for(y in 0.1 * (0:10)){
      
      # Assert that (x, y, 1 - x - y) is a valid probability vector
      if(x + y <= 1){
        abscissa[yindex] = y ;
        expectedValueVector[yindex] = expectedValue(size, Pa, c(x, y, 1 - x - y));
        # Save x and y s.t. E(X) is maximal
        if(expectedValueVector[yindex] > maxExpectedValue){
          maxExpectedValue = expectedValueVector[yindex] ;
          maxExpectedValueY = y ;
          maxExpectedValueX = x ;
        }
      }
      else{
        expectedValueVector[yindex] = -Inf ;
      }
      yindex = yindex + 1 ;
    }

    plot(x = abscissa, y = expectedValueVector, ylim = c(ymin, ymax), xlab = "y", ylab = "Espérance", main = paste("Esperance en fonction de y pour x = ", x, sep = ""));
  }
  cat(paste("L'espérance est maximale pour (x = ", maxExpectedValueX, ", y = ", maxExpectedValueY, ") et vaut : ", maxExpectedValue, sep = ""));
}

Le joueur biaisé

1.

Pa = c(1/4,1/4,1/2);
Pb = c(1/4,1/4,1/2);
print(expectedValue(basicSize, Pa, Pb));
## [1] 0.00398

2.

Pa = c(1/4,1/4,1/2);
Pb = c(1/3,1/3,1/3);
print(expectedValue(basicSize, Pa, Pb));
## [1] 0.00254

3.

Pa = c(1/4, 1/4, 1/2);
allPlotsForXYin01(plotSize, Pa);

## L'espérance est maximale pour (x = 1, y = 0) et vaut : 0.245

4.

On en déduit que la meilleure stratégie pour le joueur B lorsque \(P^{(A)} = (\frac{1}{4}, \frac{1}{4}, \frac{1}{2})\) est d’adopter le vecteur probabilité \(P^{(A)} = (1, 0, 0)\), soit de jouer systématiquement Pierre.

5.

Soient \(x_i\) avec \(i \in [\![1 ; 3]\!]\) tels que
\(x_1\) l’évènement “B gagne la partie”,
\(x_2\) l’évènement “la partie se solde par une égalité”,
\(x_3\) l’évènement “B perd la partie”.

Soit \(C\) = {\(Pierre, Feuille, Ciseau\)} l’ensemble des choix possibles et \(J\) = {\(A, B\)} l’ensemble des joueurs. Alors on note “\(c_j\), \((c \in C, j \in J)\) le joueur \(j\) joue le choix \(c\)”.

On a alors pour \(P^{(B)} = (\frac{1}{4}, \frac{1}{4}, \frac{1}{2})\) :
\(P(X = x_1) = Pierre_{B} \times Ciseau_{A} + Feuille_{B} \times Pierre_{A} + Ciseau_{B} \times Feuille_{A} = \frac{1}{4} \times \frac{1}{2} + \frac{1}{4} \times \frac{1}{4} + \frac{1}{2} \times \frac{1}{4} = 0.3125\)
De même,
\(P(X = x_2) = \frac{1}{4} \times \frac{1}{4} + \frac{1}{4} \times \frac{1}{4} + \frac{1}{2} \times \frac{1}{2} = 0.375\)
\(P(X = x_3) = \frac{1}{4} \times \frac{1}{4} + \frac{1}{4} \times \frac{1}{2} + \frac{1}{2} \times \frac{1}{4} = 0.3125\)

Comme on joue en version à somme nulle, on a \(x_{1} = 1\), \(x_{2} = 0\), \(x_{3} = -1\).

On rappelle la formule de l’espérance : \[\mathbb{E}(X) = \sum\limits_{i=1}^3 x_{i} \times P(X=x_{i})\]

On obtient \(\mathbb{E}(X) = \sum\limits_{i=1}^3 x_{i} \times P(X=x_{i}) = 1 \times 0.3125 + 0 \times 0.375 + (-1) \times 0.3125 = 0\).

De même pour \(P^{(B)} = (\frac{1}{3}, \frac{1}{3}, \frac{1}{3})\), on obtient \(\mathbb{E}(X) = 0\).

Pour la formule générale \(P^{(B)} = (x, y, 1-x-y)\), on obtient \(\mathbb{E}(X) = 1 \times (x \times \frac{1}{2} + y \times \frac{1}{4} + (1 - x - y) \times \frac{1}{4}) - 1 \times (x \times \frac{1}{4} + y \times \frac{1}{2} + (1 - x -y) \times \frac{1}{4}) = \frac{1}{4} \times x - \frac{1}{4} \times y\).

Afin de maximiser l’espérance \(\mathbb{E}(X)\), il convient de maximiser \(x\) et de minimiser \(y\).
La valeur extrême pouvant être prise par \((x, y)\) est \((1, 0)\), ce qui correspond à \(P^{(B)} = (1, 0, 0)\).

On peut déduire que pour maximiser ses victoires, le joueur B doit systématiquement jouer Pierre (ce qui est assez intuitif car le joueur A joue la plupart du temps Ciseau, qui est battu par Pierre).

Le joueur non biaisé

1.

Pa = c(1/3,1/3,1/3);
Pb = c(1/4,1/4,1/2);
print(expectedValue(basicSize, Pa, Pb));
## [1] -0.0013

2.

Pa = c(1/3,1/3,1/3);
Pb = c(1/3,1/3,1/3);
print(expectedValue(basicSize, Pa, Pb));
## [1] -0.0021

3.

Pa = c(1/3, 1/3, 1/3);
allPlotsForXYin01(plotSize, Pa, ymin = -0.2, ymax = 0.2);