Qual API RESTful você usaria para um servidor de jogo baseado em turnos?

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

  •  03-07-2019
  •  | 
  •  

Pergunta

Como você modelaria um servidor de jogo baseado em turnos como uma API RESTful?Por exemplo, um servidor de xadrez, onde você pode jogar xadrez contra outro cliente da mesma API.Você precisaria de alguma forma de solicitar e negociar um jogo com o outro cliente e de alguma forma de executar os movimentos individuais do jogo.

Este é um bom candidato para uma API REST (RESTful)?Ou isso deveria ser modelado de uma maneira diferente?

Foi útil?

Solução

Quais são os recursos que você está tentando modelar? Eu parece ter quatro: você, seu oponente, o jogo em particular (sessão, instância) e o estado do quadro de jogos. Então começaria com algo como

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

Temos uma boa introdução/visão geral em Infoq.

Outras dicas

Estou pensando em algo como:

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

No que diz respeito aos recursos básicos. Não tenho certeza de como lidar com o "outro jogador já se moveu?" ideia, no entanto. Eu pensei em simplesmente ter o bloco de solicitação de get até que a mudança seja jogada-meu cliente colocaria as coordenadas da minha mudança para

/game/13/move/1

E então seria

/game/13/move/2

O servidor não responderia imediatamente, mas mantenha a conexão aberta até que o outro jogador se mova (ou seja, colocar nesse local). É disso que Nakajima se refere como "Comet-esque"?

Charlie, não tenho muita certeza do que você quis dizer com o "token" por quem é-é isso, isso resolve o mesmo problema sem a necessidade de votação ou uma conexão de bloqueio?

Para IDs de jogador, faz sentido modelá -los como um recurso em parte do URL? Eu estava planejando simplesmente usar a autenticação do usuário HTTP (onde o usuário/passagem é enviado como parte de todas as solicitações). Você ainda pode obter a maioria dos recursos sem autenticação, mas se você tentou, digamos,

PUT /game/13/move/2

Isso lhe daria uma permissão negado erro se você não tivesse as credenciais corretas para esse jogo.

Ok, a idéia básica de descanso é que você está transferindo o estado; Você deseja ter pouco ou nenhum "estado de sessão" no servidor. Portanto, você não gostaria de usar o estado da sessão e um keepalive, que é o que o cometa faz. Mas pense no exemplo de um jogo de reprodução: vocês dois têm uma cópia do quadro e troca movimentos. Os correios não sabem sobre o jogo.

Agora, admito que isso está crescendo em minha mente enquanto penso sobre isso - na verdade, posso escrever um artigo com base nessa pergunta - mas aqui está a ideia, como algumas histórias:

  1. Você quer jogar um jogo de xadrez on -line, então você vai a um Uri conhecido para conseguir um. Você recebe uma página mostrando quem, se alguém está esperando para iniciar um jogo.
  2. Você escolhe uma das pessoas esperando para jogar e clica no link apropriado. Você recebe uma nova tela (Ajax Magic aqui, se quiser) com a placa configurada. Um de vocês é branco, os movimentos brancos primeiro.
  3. Quem tem o direito de se mudar e se compromete (como tirar a mão da peça em um jogo.) A placa atualiza e o direito de se mover vão para o outro jogador.

Você não precisa de nada em termos de estado do servidor-embora você queira estendê-lo, acompanhando movimentos etc., digamos para o ranking-e a questão de quem tem o direito de se mover pode ser calculada inteiramente a partir do Página da placa: Se você tiver o direito, você tem um formulário para entrar em um movimento; Quando você envia o retorno do formulário, a resposta retorna uma página para você sem slot para entrar em movimento.

Por "The Token", só quero dizer alguma representação arbitrária daquele pouco do estado "My Move"/"Your Move".

Parece que os recursos que você precisa são

  • Uma página inicial "Find A Game"
  • Uma página do usuário se você estiver rastreando estatísticas e tal
  • Um URI único para cada jogo ativo.

Obrigado, Charlie. Ainda não estou claro como você é notificado da jogada do oponente em seu esquema. É claro que a questão de quem tem o direito de mover pode ser calculada de maneira simples-a partir do recurso do conselho ou usando um recurso separado que afirma explicitamente cuja vez é mover-se. Mas como um cliente sabe que esse recurso mudou? Ele tem que simplesmente pesquisar continuamente, lembrando -se do estado anterior, até que perceba que algo mudou? No modelo dos correios, o correio "empurra" uma mensagem para o cliente (sua caixa de correio), o que não é possível no HTTP.

Suponho que isso faça parte de uma pergunta mais geral: se houver um recurso de repouso que eu queira monitorar para alterações ou modificações, qual é a melhor maneira de fazê -lo? E há algo que o servidor pode fazer para facilitar isso para o cliente?

Acho que vou postar isso como uma pergunta separada, já que acho interessante por si só.

Editado para adicionar: O que é uma maneira repousante de monitorar um recurso de descanso para alterações?

Não acho que o REST seja uma boa escolha para esse aplicativo. As transformações e operações que você precisa fazer (faça mover, ver o histórico de movimentos, desfazer, obter sugestões, notificar a notificação) não mapeiam ordenadamente para o conceito de recursos do REST. (As dificuldades talvez sejam mais óbvias se considerarmos como uma API RESTful para jogos mais complicados baseados em turnos, como Scrabble ou Monopoly, pode parecer.)

Eu acho que qualquer API de REST sensata provavelmente acabaria sendo um invólucro em torno de algo não restrito, como um protocolo com estado que enviou Notação de jogo portátil vai e volta.

Eu acho que você poderia modelo isso é repleto. Implementação Será mais difícil, porque você precisaria de um cometa) -Esque Solução ou você teria que pesquisar o servidor em um intervalo relativamente curto via Ajax.

Em termos de como você exporia uma interface repousante, eu diria que você precisa de uma prancha de coordenadas, peças que podem ocupar essas coordenadas e ações que alteram essas coordenadas.

Quando um jogador faz uma mudança, uma nova ação seria criada. Depois de validar para garantir que seja permitido, você atualizaria o status do jogo e, em seguida, renderizaria qualquer resposta necessária para atualizar a interface do usuário.

Então é assim que eu o modela. O lado da implementação é o que eu consideraria a maior dificuldade aqui.

Eu não acho que seja tudo isso complicado, Nakajima. Você passaria dados, digamos, no JSON, para a posição do conselho, para os movimentos e com um token para quem tem o próximo passo. Seria exatamente como jogar pelo correio.

Você começa indo ao jogo e procurando um parceiro, então

/game/

Dá a você uma lista de pessoas esperando. Quando você entra, se não houver ninguém esperando, você recebe um ID de jogo; Caso contrário, você escolhe alguém esperando e obtém o ID do jogo que eles têm.

/game/gameID

mostra o quadro. Você precisa de algo para configurar a decisão de quem joga branco, vou deixar isso como um exercício. A operação GE fornece a placa, então uma postagem envia uma mudança; Se você não tiver o movimento, recebe um erro. Você encontra o resultado no próximo Get.

Inferno, neste modelo, eu nem estou usando o ID do jogador, embora possa ser bom para que ninguém possa entrar no jogo como um Kibitzer.

Então, seu pensamento é que, em vez de tornar as ações um objeto de primeira classe, cada movimento seria tratado como uma atualização do próprio jogo? Certamente é uma maneira diferente de fazê -lo, embora eu pense que prefiro dividir o objeto de ação em sua própria entidade de primeira classe por alguns motivos. A maior razão é que acredito que é mais testável. Se um movimento é válido ou não, poderia ou não viver no objeto de ação, em vez de precisar se preocupar com o fato de a placa estar em um estado válido o tempo todo. É verdade que não sei o que qualquer uma abordagem implicaria, mas isso me parece melhor.

A outra razão, que você pode refutar totalmente via Yagni, é que um objeto de ação de primeira classe forneceria um histórico de movimentos. Interessante talvez, mas a menos que um requisito seja um ponto discutível.

Um dos desenvolvedores em Planet.jabber está envolvido em Chesspark, uma comunidade de xadrez online. Eles estão usando extensivamente o Jabber/XMPP; se não estou errado, Estas são as suas postagens sobre o assunto.

O XMPP é um protocolo de mensagem instantânea, com base aproximadamente na pequena troca de mensagens XML. Existem bibliotecas para a maioria dos idiomas, Incluindo JavaScript. Não tenho certeza se vai se encaixar no seu problema.

Para um jogo simples como o xadrez, trata-se apenas de definir o tipo de mídia.

Aqui está um exemplo do que provavelmente é um tipo de mídia simplificado para modelar um jogo de xadrez.

Vou pular o gerenciamento de vários jogos que podem estar rodando no mesmo servidor e apenas modelar um jogo já rodando.

A primeira etapa geralmente é definir um índice para o aplicativo.

index

O ponto de entrada do jogo.Busque isso para descobrir informações sobre o jogo.

A carga útil pode ser semelhante a esta:

{
    "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 uma carga JSON em links marcados com um rel de move para mover uma peça.Os seguintes campos DEVEM ser incluídos:

  • localização:o URI do espaço para onde mover

As respostas bem-sucedidas têm um código de status 200 e conterão uma entidade igual à index carga útil com o estado atualizado do jogo.

400 se o usuário não tiver permissão para mover sua peça para lá ou se não for sua vez.

player

OBTENHA a descrição de um jogador.

Os seguintes campos DEVEM estar na resposta:

  • nome de usuário:Nome de usuário do jogador
  • href:URI que identifica o jogador deste jogo.

piece

As peças estão embutidas no index carga útil, mas PODE existir por conta própria.Cada piece DEVE ter os seguintes campos:

  • tipo:Um URI que identifica o tipo da peça.POR EXEMPLO.Bispo, Torre, Rei.OBTER este URI PODE fornecer informações sobre como esta peça funciona no jogo de xadrez.
  • href:Um URI que identifica a peça real neste quadro.Solicitações GET para este URI PODEM fornecer informações sobre esta peça específica.

Cada peça DEVE ter um move link.


Uma decisão alternativa de design que eu poderia ter tomado aqui seria fornecer um link individual para cada movimento válido.Pode haver boas razões para fazer isso, mas eu queria demonstrar que não é obrigatório.Provavelmente há vários outros recursos que você gostaria de incluir para lidar com coisas como ajudar o cliente a determinar de quem é a vez e outros enfeites.

Para jogos mais complicados, como Civilization, RTSs, FPSs ou MMOGs e outros, isso pode não ser tão prático, IMO.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top