tp3
This commit is contained in:
84
R4.01_R4.A.10/td_tp/tp3/README.md
Normal file
84
R4.01_R4.A.10/td_tp/tp3/README.md
Normal file
@@ -0,0 +1,84 @@
|
||||
#### Ex1 : modele MVC et pattern strategy
|
||||
|
||||
> Stratégie est un patron de conception comportemental qui permet de définir une
|
||||
> famille d’algorithmes, de les mettre dans des classes séparées et de rendre
|
||||
> leurs objets interchangeables. (source wikipédia)
|
||||
|
||||
|
||||
|
||||
Le but est de réaliser ce pattern de conception dans le jeu très simple du chifoumi.
|
||||
|
||||
<div align="center">
|
||||
<img src="./img/chifoumi.png">
|
||||
</div>
|
||||
|
||||
Pour l'instant, le jeu utilise le pattern MVC. Le modèle, qui calcule le coup de l'ordinateur utilise
|
||||
un tirage aléatoire. On veut pouvoir utilisé d'autres méthodes, qui utilisent l'historique des coups
|
||||
joués par le joueur.
|
||||
|
||||
1. Modifiez le modèle et la vue pour que le jeu affiche le pourcentage de victoires, matchs nuls et défaites du joueur depuis le début
|
||||
de la partie.
|
||||
|
||||
|
||||
|
||||
On veut maintenant séparer la façon dont l'ordinateur choisit son coup de la logique du jeu. Le modèle utilisera
|
||||
une stratégie donnée.
|
||||
|
||||
2. Créez un sous-répétoires `stratégies` dans lequel on stokera les différentes stratégies disponibles.
|
||||
|
||||
Les différentes stratégies réaliseront l'interface
|
||||
|
||||
```js
|
||||
getChoice(playerHistory)
|
||||
```
|
||||
|
||||
qui calcule le coup de l'ordinateur, en fonction de l'historique des différents coups du joueur.
|
||||
|
||||
3. Ecrivez 3 stratégies simples `RandomStrategy.js` (stratégie initiale), `CopyPlayerStrategy.js`
|
||||
(joue le même coup que le joueur) `CounterMostUsedStrategy.js` (joue le coup le plus joué par le joueur) :
|
||||
|
||||
Chaque fichier implémente la stratégie correspondante sous la forme :
|
||||
```js
|
||||
export default class RandomStrategy {
|
||||
getChoice(playerHistory) {
|
||||
....
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. Mettez à jour le modèle pour qu'il puisse utiliser une stratégie donnée.
|
||||
5. testez dans le main.
|
||||
|
||||
#### Ajout d'une stratégie
|
||||
|
||||
On va ajouter une stratégie markovienne d'ordre 1. On fait
|
||||
l'hyptohése que le coup du joueur dépend de son coup précedent (ordre 1).
|
||||
On met à jour au fur et à mesure la matrice de transitions entre
|
||||
les coups joué par le joueur. Par exemple,
|
||||
|
||||
```js
|
||||
{
|
||||
rock: { rock: 2, paper: 5, scissors: 1 },
|
||||
paper: { rock: 1, paper: 3, scissors: 4 },
|
||||
scissors: { rock: 6, paper: 1, scissors: 2 }
|
||||
}
|
||||
```
|
||||
|
||||
signifie qu'après paper, le joueur a joué 1 fois rock, 3 fois paper, et 4 fois scissors.
|
||||
|
||||
On se sert de la matrice pour contrer la prédiction.
|
||||
|
||||
5. Écrivezz cette stratégie, et testez la.
|
||||
|
||||
#### Stratégie mixte
|
||||
Le but est d'implanter une stratégie mixte. On se donne une probabilité `p`.
|
||||
|
||||
- la stratégie markovienne est jouée avec la probabilité `p`.
|
||||
- la stratégie aléatoire est jouée avec la probabilité `1-p`
|
||||
|
||||
Écrivez la stratégie mixte, et testez.
|
||||
|
||||
#### Stratégie adaptative
|
||||
La probabilité `p` dépend du score. On l'adapte au fur et à mesure. Si on gagne beaucoup (trop),
|
||||
on joue au hasard, sinon avec Markov.
|
||||
|
||||
BIN
R4.01_R4.A.10/td_tp/tp3/img/chifoumi.png
Normal file
BIN
R4.01_R4.A.10/td_tp/tp3/img/chifoumi.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
41
R4.01_R4.A.10/td_tp/tp3/src/css/style.css
Normal file
41
R4.01_R4.A.10/td_tp/tp3/src/css/style.css
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
.game {
|
||||
}
|
||||
.choices{
|
||||
display : flex;
|
||||
align-items:stretch;
|
||||
height:8em;
|
||||
}
|
||||
.choices > span:nth-child(2) {
|
||||
margin-left:3em;
|
||||
}
|
||||
|
||||
.choices span i{
|
||||
font-size: 2em;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
margin-right:0.25em;
|
||||
transition: transform 0.2s, color 0.2s;
|
||||
}
|
||||
|
||||
#player,#computer{
|
||||
font-size: 3em;
|
||||
border: none;
|
||||
margin-right:0.25em;
|
||||
}
|
||||
|
||||
|
||||
.choices span i:hover {
|
||||
color:#398712
|
||||
}
|
||||
|
||||
#player {
|
||||
color:#398712
|
||||
}
|
||||
|
||||
#computer {
|
||||
color:#D93526;
|
||||
}
|
||||
|
||||
|
||||
|
||||
40
R4.01_R4.A.10/td_tp/tp3/src/index.html
Normal file
40
R4.01_R4.A.10/td_tp/tp3/src/index.html
Normal file
@@ -0,0 +1,40 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Pierre Feuille Ciseaux</title>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.min.css"
|
||||
>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.4/css/all.css">
|
||||
<link rel="stylesheet" href="css/style.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<main>
|
||||
<h1>
|
||||
Pierre - Feuille - Ciseaux
|
||||
</h1>
|
||||
<div class="choices">
|
||||
<span>
|
||||
<i data-choice="rock" class="far fa-hand-rock"></i>
|
||||
<i data-choice="paper" class="far fa-hand-paper"></i>
|
||||
<i data-choice="scissors" class="far fa-hand-scissors"></i>
|
||||
</span>
|
||||
<span>
|
||||
<span id="player"></span>
|
||||
<span id="computer"></span>
|
||||
</span>
|
||||
</div>
|
||||
<div class="game">
|
||||
<p id="score"></p>
|
||||
<p id="result"></p>
|
||||
</div>
|
||||
</main>
|
||||
<script type="module" src="js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
18
R4.01_R4.A.10/td_tp/tp3/src/js/controller.js
Normal file
18
R4.01_R4.A.10/td_tp/tp3/src/js/controller.js
Normal file
@@ -0,0 +1,18 @@
|
||||
export default class GameController {
|
||||
constructor(model, view) {
|
||||
this.model = model;
|
||||
this.view = view;
|
||||
|
||||
this.view.bindPlay(this.handlePlay);
|
||||
this.view.displayScore(this.model.getScore());
|
||||
}
|
||||
|
||||
handlePlay = (playerChoice) => {
|
||||
const computerChoice = this.model.getComputerChoice();
|
||||
const result = this.model.getResult(playerChoice, computerChoice);
|
||||
|
||||
this.view.displayResult(playerChoice, computerChoice, result);
|
||||
this.view.displayScore(this.model.getScore());
|
||||
}
|
||||
}
|
||||
|
||||
9
R4.01_R4.A.10/td_tp/tp3/src/js/main.js
Normal file
9
R4.01_R4.A.10/td_tp/tp3/src/js/main.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import GameModel from "./model.js";
|
||||
import GameView from "./view.js";
|
||||
import GameController from "./controller.js";
|
||||
|
||||
const app = new GameController(
|
||||
new GameModel(),
|
||||
new GameView()
|
||||
);
|
||||
|
||||
29
R4.01_R4.A.10/td_tp/tp3/src/js/model.js
Normal file
29
R4.01_R4.A.10/td_tp/tp3/src/js/model.js
Normal file
@@ -0,0 +1,29 @@
|
||||
export default class GameModel {
|
||||
constructor() {
|
||||
this.choices = ["rock", "paper", "scissors"];
|
||||
this.score = { player: 0, computer: 0};
|
||||
}
|
||||
|
||||
getComputerChoice() {
|
||||
const index = Math.floor(Math.random() * this.choices.length);
|
||||
return this.choices[index];
|
||||
}
|
||||
|
||||
getResult(player, computer) {
|
||||
if (player === computer) return "égalité";
|
||||
|
||||
if (
|
||||
(player === "rock" && computer === "scissors") ||
|
||||
(player === "paper" && computer === "rock") ||
|
||||
(player === "scissors" && computer === "paper")
|
||||
) {
|
||||
this.score.player++;
|
||||
return "gagné";
|
||||
}
|
||||
this.score.computer++;
|
||||
return "perdu";
|
||||
}
|
||||
getScore() {
|
||||
return this.score;
|
||||
}
|
||||
}
|
||||
50
R4.01_R4.A.10/td_tp/tp3/src/js/view.js
Normal file
50
R4.01_R4.A.10/td_tp/tp3/src/js/view.js
Normal file
@@ -0,0 +1,50 @@
|
||||
export default class GameView {
|
||||
#icons = {
|
||||
"rock" : "far fa-hand-rock",
|
||||
"paper" : "far fa-hand-paper",
|
||||
"scissors" : "far fa-hand-scissors"
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.resultEl = document.getElementById("result");
|
||||
this.scoreEl = document.getElementById("score");
|
||||
this.buttons = document.querySelectorAll(".choices span i");
|
||||
this.player = document.getElementById("player");
|
||||
this.computer = document.getElementById("computer");
|
||||
|
||||
}
|
||||
|
||||
bindPlay(handler) {
|
||||
this.buttons.forEach(button => {
|
||||
button.addEventListener("click", () => {
|
||||
handler(button.dataset.choice);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
displayResult(player, computer, result) {
|
||||
let i = document.createElement("i");
|
||||
i.classList.add(...this.#icons[player].split(' '))
|
||||
this.player.replaceChildren(i)
|
||||
|
||||
i = document.createElement("i");
|
||||
i.classList.add(...this.#icons[computer].split(' '))
|
||||
this.computer.replaceChildren(i)
|
||||
|
||||
|
||||
this.resultEl.innerHTML =
|
||||
`Joueur <i class="${this.#icons[player]}"></i>, ordinateur <i class="${this.#icons[computer]}"></i> → ${result}`;
|
||||
|
||||
}
|
||||
|
||||
displayScore(score) {
|
||||
|
||||
let winRate = ((score.player * 100 / score.count) || 0).toFixed(2)
|
||||
let lossRate = ((score.computer * 100 / score.count) ||0).toFixed(2)
|
||||
let drawRate = (100 - winRate - lossRate).toFixed(2)
|
||||
|
||||
this.scoreEl.textContent =
|
||||
`Score — Joueur: ${score.player} | Ordinateur: ${score.computer}`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user