Seelies, un jeu de stratégie persistant
#21
ça c'est un job pour defdelegate
Répondre
#22
Ah bon ? Mais là j'envoie à chaque fois à un module différent, et je ne peux pas pattern matcher dans le defdelegate (à ma connaissance).

Au pire ça s'écrit bien en ligne, après tout je n'ai besoin de pattern match que la commande.


def execute(game, command = %Seelies.StartGame{}), do: Seelies.StartGame.execute(game, command)
Répondre
#23
Erf oui désolé j'avais oublié que tu avais plusieurs clauses dans ce cas.

Citation : J'aime beaucoup l'idée de regrouper par bounded contexts

Bah dans le cas présent ça me paraîtrait logique d'avoir toutes les getters/setters dans le module `Game` et puis dans chaque commande le code qui vérifie que la commande peut run et ensuite les appels aux différents setters. Sauf que là avec CQRS tu as un module différent pour checker la commande puis pour apply l'event donc effectivement ça le fait pas trop.
Répondre
#24
En tout cas, pour ma part, merci à niahoo & sephi car ça m'a donné l'occasion de connaître Elixir que je découvre petit à petit.

Et justement, dans la liste de mes nombreux projets; je souhaitais éventuellement essayer de coder un petit jeu en FP, mais à la base je pensais plutôt choisir ocsigen (en Caml).

Du coup j'hésite...

Mais bon, je pense quand même que je choisirai ocsigen (dès que je pourrai me faire une partition unix), ne serait-ce parce que personne sur le forum ne semble encore avoir essayé (ce sera l'occasion de faire un retour dessus le cas échéant).
Répondre
#25
Pourquoi pas les deux ? ça peut faire beaucoup, mais Elixir est un langage serveur tandis qu'avec ocsigen tu fais uniquement du client si j'ai bien compris. Et le framework web est ultra cool.
Répondre
#26
Oui je verrai (c'est vrai que les OTP ça avait l'air intéressant) mais de toutes façons pour l'instant c'est encore des belles paroles de ma part (Edit : du coup, c'est phoenix le framework "ultra cool" ?).

Après non non, avec Eliom c'est forcément du serveur aussi, je pense.

D'ailleurs, et c'est marrant, tu peux même, je crois, mettre ton code client ET serveur dans le même fichier (c'était fait en tous cas pour leur appli de démo graffiti).
Répondre
#27
Phoenix c'est le framework pour faire du Web en Elixir.

La grande différence entre une application Elixir et une application écrite dans un langage de script plus conventionnel, c'est que le applications Elixir sont des processus qui tournent jusqu'à ce qu'on les arrête, là où un langage de script exécutera un script le temps d'une requête (Apache + mod_php ou Nginx + Rails). Le serveur Web (quand il y en a un) est intégré dans l'application et c'est juste du code qui tourne à côté et qui va appeler du code de l'application.

On travaille beaucoup avec des processus (par exemple un processus pour chaque partie de mon jeu) qui vivent longtemps (ou non : un processus lancé pour envoyer des mails va pouvoir s'arrêter dès qu'il aura terminé) et qui "vivent" tant que l'application tourne. On peut communiquer avec eux, etc.
Répondre
#28
Aujourd'hui, j'ai écrit les tests et le code pour résoudre les "ticks" d'exploitations.

test "Exploitation ticks make units bring some resources back to their territory" do
  :ok = Seelies.Router.dispatch(%Seelies.StartGame{game_id: "42", board: board()})
  :ok = Seelies.Router.dispatch(%Seelies.DeployStartingUnit{game_id: "42", unit_id: "u1", territory_id: "t1", species: :ant})
  :ok = Seelies.Router.dispatch(%Seelies.DeployStartingUnit{game_id: "42", unit_id: "u2", territory_id: "t5", species: :ant})
  :ok = Seelies.Router.dispatch(%Seelies.UnitStartsExploitingDeposit{game_id: "42", unit_id: "u1", deposit_id: "d1", time: 0})
  :ok = Seelies.Router.dispatch(%Seelies.UnitStartsExploitingDeposit{game_id: "42", unit_id: "u2", deposit_id: "d5", time: 0})
  :ok = Seelies.Router.dispatch(%Seelies.DepositsExploitationTicks{game_id: "42", time: 60})
  {:error, :already_exploiting_deposit} = Seelies.Router.dispatch(%Seelies.UnitStartsExploitingDeposit{game_id: "42", unit_id: "u1", deposit_id: "d1", time: 60})

  game = Commanded.Aggregates.Aggregate.aggregate_state(Seelies.Game, "42")
  assert Seelies.Game.resources(game, "t1").gold > 0
  assert Seelies.Game.resources(game, "t1").silver == 0
  assert Seelies.Game.resources(game, "t5").gold == 0
  assert Seelies.Game.resources(game, "t5").silver > 0

  :ok = Seelies.Router.dispatch(%Seelies.DepositsExploitationTicks{game_id: "42", time: 120})
  game_2 = Commanded.Aggregates.Aggregate.aggregate_state(Seelies.Game, "42")
  assert Seelies.Game.resources(game_2, "t1").gold == Seelies.Game.resources(game, "t1").gold * 2
  assert Seelies.Game.resources(game_2, "t1").silver == 0
  assert Seelies.Game.resources(game_2, "t5").gold == 0
  assert Seelies.Game.resources(game_2, "t5").silver == Seelies.Game.resources(game, "t5").silver * 2
end

Je suis assez content de ce système parce que je le trouve assez simple et très facile à tester.

Je vais maintenant passer au convoyage : je crée un convoi, j'y ajoute/retire des unités (un convoi va aussi vite que son unité la plus lent), des ressources (la capacité de transport dépend du nombre et du type d'unités qui forment le convoi), je le lance, il arrive à destination au moment prévu.
Répondre
#29
La partie d'id n°42 c'est ton jeu de données que tu utilises pour tous tes tests, c'est ça ?
Et tu vérifies qu'en 120s, tu ramènes 2 fois plus de ressources qu'en 60s sur les mêmes dépôts ?

Mais du coup par exemple, typiquement pour ce cas de TDD : imaginons qu'à un moment donné tu veuilles que le nb de ressources récupérées ait un petit delta (i.e. qu'il y ait une petite variation avec un random) alors tu devras réécrire ces tests-là ?
Répondre
#30
(07-29-2019, 06:18 PM)Meraxes a écrit : La partie d'id n°42 c'est ton jeu de données que tu utilises pour tous tes tests, c'est ça ?

Oui. Généralement j'appelle pas mal les trucs "crevette" ou "endive", quand ce sont des personnages souvent ce sont ceux des romans de Zelazny, etc. J'ai mes marottes. :p

(07-29-2019, 06:18 PM)Meraxes a écrit : Et tu vérifies qu'en 120s, tu ramènes 2 fois plus de ressources qu'en 60s sur les mêmes dépôts ?

Mais du coup par exemple, typiquement pour ce cas de TDD : imaginons qu'à un moment donné tu veuilles que le nb de ressources récupérées ait un petit delta (i.e. qu'il y ait une petite variation avec un random) alors tu devras réécrire ces tests-là ?

Ici, pour ne pas trop m'encombrer de valeurs, j'ai utilisé > 0 (parce que je n'ai pas envie de m'embêter à savoir réellement les valeurs que j'ai configuré pour la collecte de telle ou telle ressource pour tel ou tel type d'unité. Et après j'ai utilisé le double comme tu l'as remarqué.

Quand je teste de l'aléatoire, j'ai plusieurs stratégies :
- si je peux, j'injecte la valeur, comme ici avec les ID de mes différentes entités (si j'utilisais UUID() à l'intérieur des fonctions, le code serait plus difficile à tester)
- je fais des comparaisons et des encadrements (c'est sans doute ce que je ferais dans le cas que tu évoques)
- je teste la cardinalité d'une liste plutôt que son ordre exact
- etc.
Répondre




Utilisateur(s) parcourant ce sujet : 1 visiteur(s)