L'IA du king a triché
Le king est disponible sur Whisthub depuis un bon moment déjà. Le 1er avril 2024, cela fera exactement deux ans qu'il a été lancé - et ce n'était pas une blague ! Depuis, le king est devenu l'un des jeux de cartes les plus appréciés sur Whisthub, aux côtés des grands classiques que sont le whist à la couleur et la manille.
Récemment cependant, j'ai reçu un e-mail de quelqu'un m'informant que l'IA trichait. « Impossible ! » ai-je pensé. J'ai écrit l'IA moi-même, et je ne l'ai vraiment pas programmée pour tricher. L'IA joue toujours avec la même information qu'un joueur humain : elle ne sait pas quelles cartes détiennent les autres joueurs. « L'utilisateur a dû se tromper, l'IA n'a pas changé depuis toutes ces années, donc ce serait étrange que personne ne l'ait jamais signalé ! » a été ma première réaction, tout à fait naturelle.
Malgré tout, ma curiosité a été piquée, alors j'ai essayé de reproduire le comportement de triche signalé par l'utilisateur. Et là, quelle surprise ! Il s'est avéré que l'IA du king trichait bel et bien, sans même que je le sache ! Est-ce que cela signifie que les ordinateurs sont enfin devenus conscients, à une époque où l'IA semble être partout ? Eh bien non, mais voyons ce qui s'est réellement passé !
La triche se produisait dans une situation de jeu qui ressemble à ceci
Bert a choisi de jouer un jeu à atout, a choisi ♦ comme couleur d'atout, et Chris a joué ♦10 sur le ♦2 de Rachel. Nous avons ♦K, ♦Q et ♦8, donc idéalement, on jouerait notre ♦8, car Bert détient probablement ♦A, puisque c'est lui qui a choisi ♦ comme atout. C'est par exemple ce que vous feriez normalement au whist à la couleur. Cependant, selon les règles du king, nous devons surcouper si possible, donc nous sommes obligés de jouer soit ♦K, soit ♦Q.
C'est là que ça coince avec l'IA. Si l'IA se retrouve dans cette situation, elle joue quand même ♦8, alors que ce n'est pas autorisé selon les règles ! Au début, j'étais plutôt surpris par ça. Après tout, comme vous pouvez le voir, ♦8 est correctement grisée, et vous ne pouvez pas la jouer en tant que joueur humain. D'où venait donc cette différence ?
Il faut d'abord comprendre que le serveur fait une distinction entre les coups joués par des humains et ceux joués par l'IA. Pour les coups humains, il ne suffit pas que les cartes illégales soient grisées dans l'interface. En effet, si vous avez des connaissances techniques, vous pourriez quand même envoyer un coup illégal au serveur, et rien ne peut vraiment empêcher cela. C'est pourquoi chaque coup humain qui arrive sur le serveur est d'abord vérifié pour s'assurer qu'il ne s'agit pas d'un coup illégal. Le code correspondant côté serveur ressemble à peu près à ceci
// Find the player and move from the incoming request.
let player = game.findPlayer(request.id);
let { move } = request.body;
// If the move is invalid, throw an error.
if (!game.isValidMove(move)) {
throw new Error(`Invalid move ${move}!`);
}
// No error? Cool, carry out the move.
player.move(move);Les coups de l'IA sont cependant différents. Nous avons un contrôle total sur la façon dont l'IA joue, donc nous pouvons simplement la programmer pour qu'elle suive les règles. Cela élimine le besoin de vérifier les coups joués par l'IA, ce qui la rend plus rapide.
Bien que ce ne soit pas vraiment intentionnel, ne pas vérifier les coups de l'IA a en fait un autre avantage : si l'IA a un bug et choisit une carte illégale, la partie ne plante pas, elle échoue simplement en silence. Si on y réfléchit, c'est en fait plutôt une bonne chose ! Imaginez que ça n'ait pas été le cas : la partie resterait bloquée si l'IA choisissait accidentellement une carte invalide, car on ne peut pas lui dire de simplement « réessayer » : l'IA joue de façon déterministe, donc elle choisirait toujours à nouveau la même carte - illégale !
Il s'avère aussi que le bug ne se produit pas toujours. Si la main avait été
autrement dit, avec seulement une carte qui surcoupe le ♦10 de Chris, alors l'IA joue bien ♦Q, comme il se doit. La raison, c'est que l'IA utilise un raccourci : s'il n'y a qu'une seule option valide, on choisit simplement cette option. Il n'est pas nécessaire de parcourir toute la logique de l'IA s'il n'y a qu'une seule option valide. Cela rend l'IA beaucoup plus rapide. Cela explique probablement aussi pourquoi le bug est resté inaperçu si longtemps, car il n'y a souvent qu'une seule carte qui surcoupe ce qui a été joué, et dans ce cas, l'IA suit bel et bien les règles grâce à ce raccourci.
Ce n'est que lorsqu'il y a plusieurs cartes permettant de surcouper que le bug se produit. La raison, c'est que la logique décidant quoi jouer dans ce genre de situation est largement basée sur l'IA du whist à la couleur. Au whist à la couleur, les règles sont beaucoup moins strictes, et la seule règle, en gros, est qu'il faut fournir la couleur demandée.
Cela signifie que la logique décidant quoi jouer dans ce cas ne tenait pas compte du fait qu'il pouvait y avoir des restrictions sur ce qui peut être joué, et le code évaluait simplement toutes les cartes de la couleur demandée. Quelque chose comme ceci :
// Rank the cards and then pick the "best" one to play.
function decide(player, trick) {
let { suit } = trick;
let cards = player.hand.suit(suit);
let sorted = cards.sort(rankCards);
return sorted[0];
}C'était une erreur de ma part, et j'aurais dû la détecter en testant l'IA. Heureusement, Whisthub a été mis à jour, et le bug a maintenant disparu. L'IA n'est plus autorisée à tricher !
Je sais déjà ce que certains d'entre vous vont dire :
Débarrassez-vous donc de cette règle idiote qui vous oblige à surcouper, et laissez-nous simplement jouer ♦8 ! Ça aurait évité ce bug.
Je comprends, et honnêtement, je préfère ça aussi, mais j'ai décidé d'utiliser exactement les mêmes règles que celles utilisées par IWWA, dans un souci de cohérence et d'uniformité. Vous pouvez les relire ici. S'ils décident un jour de changer cet aspect des règles, je suivrai bien sûr avec plaisir, mais d'ici là, il faudra vous en accommoder. Après tout, les règles sont les mêmes pour tout le monde, désormais IA comprise !
Alors, qu'ai-je retenu de tout ça ? Eh bien, la leçon la plus importante, c'est que lorsque je développe l'IA d'un nouveau jeu, je dois désormais m'assurer que les coups de l'IA sont vérifiés par rapport aux règles du jeu lors des simulations. J'écrirai probablement un autre article de blog à l'avenir sur la façon dont l'IA est développée, mais faire tourner des simulations - c'est-à-dire l'IA jouant contre elle-même - en est un élément fondamental. C'est d'ailleurs aussi comme ça que j'ai pu vérifier que le bug de triche n'est désormais plus présent : après avoir simulé 200 000 parties, tous les coups joués par l'IA respectaient les règles.
Humanité contre IA : les humains sont toujours en tête !