Quelle API RESTful utiliseriez-vous pour un serveur de jeu au tour par tour?

StackOverflow https://stackoverflow.com/questions/405588

  •  03-07-2019
  •  | 
  •  

Question

Comment modéliseriez-vous un serveur de jeu tour par tour en tant qu'API RESTful? Par exemple, un serveur d'échecs, où vous pouvez jouer à un jeu d'échecs contre un autre client de la même API. Vous auriez besoin d’un moyen de demander et de négocier un jeu avec l’autre client, et de jouer les mouvements individuels du jeu.

Est-ce un bon candidat pour une API REST (RESTful)? Ou devrait-il être modélisé différemment?

Était-ce utile?

La solution

Quelles sont les ressources que vous essayez de modéliser? Il semblerait que j'en ai quatre: vous, votre adversaire, le jeu particulier (session, instance) et l'état du plateau. Donc, cela commencerait par quelque chose comme

/game
/game/gameID/gamer/gamerID
/game/gameID/board

nous avons une bonne introduction / vue d'ensemble sur InfoQ .

Autres conseils

Je pense à quelque chose comme:

/game/<gameID>/move/<moveID>

en ce qui concerne les ressources de base. Je ne suis pas sûr de savoir comment gérer le " l'autre joueur a-t-il encore bougé? " idée, cependant. J'ai pensé simplement à avoir le bloc de requête GET jusqu'à ce que le coup soit joué - c'est-à-dire. mon client indiquerait les coordonnées de mon déménagement vers

/game/13/move/1

et puis obtenir

/game/13/move/2

Le serveur ne répondra pas immédiatement, mais gardez la connexion ouverte jusqu'à ce que l'autre joueur soit déplacé (c'est-à-dire PUT à cet emplacement). Nakajima parle-t-il de "comet-esque"?

Charlie, je ne suis pas tout à fait sûr de ce que vous entendez par le "jeton". à qui cela revient-il de résoudre le même problème sans recourir à une consultation ou à une connexion bloquante?

Pour les identifiants de lecteur, est-il judicieux de les modéliser en tant que ressource dans une partie de l'URL? Je prévoyais simplement d'utiliser l'authentification d'utilisateur HTTP (où l'utilisateur / le mot de passe est envoyé dans le cadre de chaque demande). Vous pouvez toujours obtenir la plupart des ressources sans authentification, mais si vous essayez, par exemple,

PUT /game/13/move/2

vous obtiendrez une erreur d'autorisation refusée si vous ne disposez pas des informations d'identification correctes pour ce jeu.

D'accord, l'idée de base de REST est que vous transférez l'état. vous voulez avoir peu ou pas de " état de session " sur le serveur. Donc, vous ne voudriez pas utiliser l’état de session et une keepalive, ce que fait Comet. Mais prenons l'exemple d'un jeu de type «jeu par courrier»: vous avez tous les deux une copie du tableau et vous échangez des coups. La Poste ne connaît pas le jeu.

Maintenant, je dois admettre que je pense de plus en plus à cette idée. En fait, je pourrais écrire un article basé sur cette question, mais voici l’idée, comme certaines histoires:

  1. Vous voulez jouer à un jeu d'échecs ligne, de sorte que vous allez à un URI connu à prends en un. Vous récupérez une page montrer qui, si quelqu'un, attend pour commencer une partie.
  2. Vous choisissez l'une des personnes en attente pour jouer et cliquez sur le bouton approprié lien. Vous obtenez un nouvel affichage (ajax magie ici si vous voulez) avec le conseil mis en place. L'un de vous est blanc, le blanc se déplace en premier.
  3. Celui qui a le droit de bouger entre un mouvement, et commet (comme prendre votre main de la pièce dans un jeu.) Le conseil met à jour et le droit de déplacer va à l'autre joueur.

Vous n'avez pas besoin de beaucoup en termes d'état du serveur - bien que vous souhaitiez peut-être l'étendre en gardant une trace des mouvements, par exemple pour le classement - et la question de savoir qui a le droit de déplacer peut être calculée entièrement de la page du conseil: si vous avez le droit, vous avez un formulaire pour entrer un mouvement; lorsque vous renvoyez le formulaire, la réponse vous renvoie une page sans emplacement pour saisir un coup.

Par "le jeton" Je veux juste dire une représentation arbitraire de ce bit d'état "Mon mouvement" / "votre mouvement".

On dirait que les ressources dont vous avez besoin sont

  • A "rechercher un jeu" page d'accueil
  • Une page utilisateur si vous suivez les statistiques et tel
  • un URI unique pour chaque jeu actif.

Merci, Charlie. Je ne comprends toujours pas comment vous êtes informé du mouvement de votre adversaire dans votre stratagème. Bien sûr, la question de savoir qui a le droit de bouger peut être calculée simplement - soit à partir de la ressource du tableau, soit en utilisant une ressource séparée qui indique explicitement à qui il appartient de déplacer. Mais comment un client peut-il savoir que cette ressource a changé? Doit-il simplement interroger continuellement, en se souvenant de l'état antérieur, jusqu'à ce qu'il remarque que quelque chose a changé? Dans le modèle de bureau de poste, le bureau de poste "pousse". un message au client (votre boîte aux lettres), ce qui n'est pas possible en HTTP.

Je suppose que cela fait partie d'une question plus générale: s'il y a une ressource REST que je souhaite surveiller pour des modifications ou des modifications, quel est le meilleur moyen de le faire? Et y at-il quelque chose que le serveur peut faire pour rendre cela plus facile pour le client?

Je pense que je vais en fait poser cette question séparément car je pense que c'est intéressant en soi.

Modifié pour ajouter: Quoi est un moyen RESTful de surveiller les modifications d'une ressource REST?

Je ne pense pas que REST soit un bon choix pour une telle application. Les transformations et les opérations que vous devez effectuer (déplacer, afficher l'historique, annuler, obtenir une suggestion, activer la notification) ne correspondent pas parfaitement au concept de ressources de REST. (Les difficultés sont peut-être plus évidentes si l’on considère l’apparence d’une API RESTful pour des jeux plus complexes au tour par tour tels que Scrabble ou Monopoly.)

Je pense qu'une API REST raisonnable finira probablement par encapsuler quelque chose de non-RESTful, comme un protocole avec état qui envoie notation de jeu portable dans les deux sens.

Je pense que vous pourriez modéliser le reste. La mise en œuvre sera plus difficile, car vous aurez besoin d'un comet ) ou une solution similaire ou vous devrez interroger le serveur à un intervalle relativement court via AJAX.

Pour ce qui est de la manière dont vous exposeriez une interface RESTful, je dirais que vous avez besoin d’un plateau de jeu avec des coordonnées, des pièces pouvant occuper ces coordonnées et des actions modifiant ces coordonnées.

Lorsqu'un joueur effectue un coup, une nouvelle action est créée. Après avoir validé pour vous assurer que cela est autorisé, vous devez mettre à jour le statut du jeu, puis restituer la réponse nécessaire pour mettre à jour l'interface utilisateur.

Donc, c'est fondamentalement comme ça que je le modéliserais. La mise en œuvre est ce que j’aimerais considérer comme la plus grande difficulté ici.

Je ne pense pas que ce soit compliqué, Nakajima. Vous transmettriez des données, par exemple en JSON, pour le poste sur le tableau, pour les déplacements et avec un jeton pour identifier le prochain déplacement. Ce serait exactement comme si vous jouiez par courrier.

Vous commencez par aller au jeu et à la recherche d'un partenaire, donc

/game/

vous donne une liste des personnes en attente. quand vous entrez, s'il n'y a personne en attente, vous obtenez un identifiant de jeu; sinon, vous choisissez quelqu'un qui attend et récupérez son identifiant de jeu.

/game/gameID

vous montre le tableau. Vous avez besoin de quelque chose pour définir qui joue le blanc, je le laisse comme exercice. L’opération GET vous donne le tableau, donc un POST envoie un coup; si vous n'avez pas le déménagement, vous obtenez une erreur. Vous trouvez le résultat par le prochain GET.

Bon sang, dans ce modèle, je n’utilise même pas l’identité du joueur, bien que ce soit une bonne idée pour que personne ne puisse entrer dans le jeu en tant que kibitzer.

Donc, vous pensez qu'au lieu de faire des actions un objet de première classe, chaque coup serait considéré comme une mise à jour du jeu lui-même? C'est certainement une façon différente de le faire, même si je préférerais scinder l'objet d'action en une entité de première classe pour plusieurs raisons. La principale raison est que je pense que c'est plus testable. Qu'un mouvement soit valide ou non peut dépendre de l'objet action, au lieu de craindre que le tableau ne soit dans un état valide à tout moment. Certes, je ne sais pas ce que l’une ou l’autre approche impliquerait, mais cela me convient mieux.

L'autre raison, que vous pouvez totalement réfuter via YAGNI, est qu'un objet action de première classe fournirait un historique des déplacements. Intéressant peut-être, mais à moins d’une exigence, c’est un point discutable.

L'un des développeurs de planet.jabber est impliqué dans Chesspark , une communauté d'échecs en ligne. Ils utilisent beaucoup Jabber / XMPP; Si je ne me trompe pas, ces messages sont ceux-ci .

XMPP est un protocole de messagerie instantanée, basé en gros sur un échange de messages XML réduit. Il existe des bibliothèques pour la plupart des langues, y compris Javascript. Je ne suis toutefois pas sûr que cela convienne à votre problème.

Pour un jeu simple comme les échecs, il s’agit vraiment de définir le type de média.

Voici un exemple de ce qui est probablement un médiatype trop simpliste pour modéliser un jeu d'échecs.

Je vais ignorer la gestion de plusieurs jeux pouvant être exécutés sur le même serveur et modéliser simplement un jeu en cours d'exécution.

La première étape consiste généralement à définir un index pour l'application.

index

Le point d’entrée du jeu. Récupérez-le pour découvrir des informations sur le jeu.

La charge utile peut ressembler à ceci:

{
    "links": {
        "self": "http://my-chess-game.host/games/123",
        "player": "http://my-chess-game.host/players/1",
        "player": "http://my-chess-game.host/players/2",
        "me": "http://my-chess-game.host/players/1",
         ...
    }
    "board": [
        {
           "x": 0,
           "y": 1,
           "piece": null,
           "rel": "space",
           "href": "http://my-chess-game/.../boards/123/0/1/something-random-to-discourage-uri-construction"
        },
        {
           "x": 1,
           "y": 2,
           "rel": "space",
           "href": "...",
           "piece": {
               "player": "http://my-chess-game/.../players/1",
               "type": "http://my-chess-game/pieces/Bishop",
               "rel": "piece",
               "href": "http://my-chess-game/games/123/pieces/player1/Bishop/1",
               "links": [
                    { "rel": "move": "href": "http://my-chess-game/.../boards/123/..." },
                    ...
                ]
            }
        },

        ...
    ]
}

move

POST une charge JSON aux liens marqués d'un rel de move pour déplacer un élément. Les champs suivants DOIVENT être inclus:

  • location: l'URI de l'espace vers lequel se déplacer

Les réponses retenues ont un code de statut de 200 et contiendront une entité identique à la charge index avec l’état du jeu mis à jour.

400 si l'utilisateur n'est pas autorisé à y déplacer sa pièce ou si ce n'est pas son tour.

lecteur

Obtenir la description d'un joueur.

Les champs suivants DOIVENT être dans la réponse:

  • nom d'utilisateur: nom d'utilisateur du joueur
  • href: URI identifiant le joueur de ce jeu.

pièce

Les pièces

sont incorporées dans la charge index , mais PEUVENT exister par elles-mêmes. Chaque pièce DOIT avoir les champs suivants:

  • type: un URI identifiant le type de la pièce. PAR EXEMPLE. Bishop, Rook, King. OBTENIR cet URI PEUT fournir des informations sur le fonctionnement de cette pièce dans le jeu d’échecs.
  • href: un URI identifiant la pièce réelle sur ce forum. Les requêtes GET adressées à cet URI PEUVENT fournir des informations sur cet élément particulier.

Chaque élément DOIT avoir un lien move .

Une autre décision de conception que j’aurais pu prendre ici était de fournir un lien individuel pour chaque déménagement valide. Il y a peut-être de bonnes raisons de le faire, mais je voulais démontrer que ce n'était pas obligatoire. Il y a probablement une poignée d'autres ressources que vous voudriez inclure pour gérer des choses telles que d'aider le client à déterminer à qui le tour appartient et le reste.

Pour des jeux plus compliqués, comme Civilization, RTS, FPS ou MMOG et autres, l’OMI n’est peut-être pas si pratique.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top